]> git.saurik.com Git - apple/libplatform.git/blame - src/simple/asl.c
libplatform-254.40.4.tar.gz
[apple/libplatform.git] / src / simple / asl.c
CommitLineData
ada7c492
A
1/*
2 * Copyright (c) 2005, 2006, 2009 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <stdlib.h>
25#include <stdbool.h>
26#include <unistd.h>
27#include <fcntl.h>
28#include <sys/syslog.h>
29#include <sys/time.h>
30#include <sys/socket.h>
31#include <sys/un.h>
32#include <crt_externs.h>
33
34#include <TargetConditionals.h>
35
36#include <_simple.h>
37
38#include <os/lock.h>
39#include <os/lock_private.h>
40#include <os/alloc_once_private.h>
41#include <platform/string.h>
42#include <platform/compat.h>
43
89154bfb
A
44#if TARGET_OS_DRIVERKIT
45// DriverKit processes log directly to kernel log
46#include <sys/log_data.h>
47OS_ENUM(os_log_type, uint8_t,
48 OS_LOG_TYPE_DEFAULT = 0x00,
49 OS_LOG_TYPE_INFO = 0x01,
50 OS_LOG_TYPE_DEBUG = 0x02,
51);
52#else // !TARGET_OS_DRIVERKIT
53
ada7c492
A
54#define ASL_LOG_PATH _PATH_LOG
55
56extern ssize_t __sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
57extern int __gettimeofday(struct timeval *, struct timezone *);
58
59struct ProgramVars
60{
61 void* mh;
62 int* NXArgcPtr;
63 char*** NXArgvPtr;
64 char*** environPtr;
65 char** __prognamePtr;
66};
67
68struct asl_context {
69 bool asl_enabled;
70 const char *progname;
71 int asl_fd;
442fbc9d 72#if TARGET_OS_SIMULATOR && !TARGET_OS_MACCATALYST
ada7c492
A
73 const char *sim_log_path;
74 os_unfair_lock sim_connect_lock;
75#else
76 os_once_t connect_once;
77#endif
78};
79
80static struct asl_context* _simple_asl_get_context(void);
81static void _simple_asl_init_context(void *ctx);
82static int _simple_asl_connect(const char *log_path);
83static void _simple_asl_connect_once(void * __unused arg);
84static int _simple_asl_get_fd(void);
85
86/*
87 * Simplified ASL log interface; does not use malloc. Unfortunately, this
88 * requires knowledge of the format used by ASL.
89 */
90
ada7c492
A
91__attribute__((visibility("hidden")))
92void
93_simple_asl_init(const char *envp[], const struct ProgramVars *vars)
94{
95 const char *str;
96 struct asl_context *ctx = _simple_asl_get_context();
97 str = _simple_getenv(envp, "ASL_DISABLE");
98 if ((str != NULL) && (!strcmp(str, "1"))) return;
99 ctx->asl_enabled = true;
100 if (vars && vars->__prognamePtr) {
101 ctx->progname = *(vars->__prognamePtr);
438624e0 102#if TARGET_OS_SIMULATOR
ada7c492
A
103 } else {
104 const char * progname = *_NSGetProgname();
105 if (progname)
106 ctx->progname = progname;
107#endif
108 }
109}
110
111static int
112_simple_asl_connect(const char *log_path)
113{
114 int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
89154bfb 115 if (fd == -1) return -1;
ada7c492
A
116
117 fcntl(fd, F_SETFD, FD_CLOEXEC);
118
119 struct sockaddr_un addr;
120 addr.sun_family = AF_UNIX;
121
122 size_t amt = strlen(log_path) + 1;
123 if (sizeof(addr.sun_path) < amt)
124 amt = sizeof(addr.sun_path);
125 memmove(addr.sun_path, log_path, amt);
126
127 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
128 close(fd);
129 return -1;
130 }
131 return fd;
132}
133
134static void
135_simple_asl_connect_once(void * __unused once_arg)
136{
137 struct asl_context *ctx = _simple_asl_get_context();
138 ctx->asl_fd = _simple_asl_connect(ASL_LOG_PATH);
139}
140
141static int
142_simple_asl_get_fd(void)
143{
144 struct asl_context *ctx = _simple_asl_get_context();
145 if (!ctx->asl_enabled) {
146 return -1;
147 }
148
442fbc9d 149#if TARGET_OS_SIMULATOR && !TARGET_OS_MACCATALYST
ada7c492
A
150 os_unfair_lock_lock_with_options(&ctx->sim_connect_lock,
151 OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION);
152 if (ctx->sim_log_path) {
153 // all setup has been done already
154 os_unfair_lock_unlock(&ctx->sim_connect_lock);
155 return ctx->asl_fd;
156 }
157 ctx->sim_log_path = _simple_getenv(
158 (const char **)*_NSGetEnviron(), "IOS_SIMULATOR_SYSLOG_SOCKET");
159 if (ctx->sim_log_path) {
160 // the first and only time the envvar is being checked
161 // asl_fd procured by the end of this call will be used forever
162 int sim_log_fd = _simple_asl_connect(ctx->sim_log_path);
163 if (sim_log_fd > -1) {
164 // successfully connected to the SIM path
165 if (ctx->asl_fd > -1) {
166 // close the ASL_LOG_PATH fd
167 close(ctx->asl_fd);
168 }
169 ctx->asl_fd = sim_log_fd;
170 }
171 }
172 if (ctx->asl_fd < 0) {
173 // either there is no envvar or it didn't work. fallback to ASL_LOG_PATH
174 ctx->asl_fd = _simple_asl_connect(ASL_LOG_PATH);
175 }
176 os_unfair_lock_unlock(&ctx->sim_connect_lock);
177 return ctx->asl_fd;
178#else
179 os_once(&ctx->connect_once, NULL, _simple_asl_connect_once);
180 return ctx->asl_fd;
181#endif
182}
89154bfb
A
183#endif // !TARGET_OS_DRIVERKIT
184
185static const char *
186_simple_asl_escape_key(unsigned char c)
187{
188 switch(c)
189 {
190 case '\\': return "\\\\";
191 case '[': return "\\[";
192 case ']': return "\\]";
193 case '\n': return "\\n";
194 case ' ': return "\\s";
195 }
196
197 return NULL;
198}
199
200static const char *
201_simple_asl_escape_val(unsigned char c)
202{
203 switch(c)
204 {
205 case '\\': return "\\\\";
206 case '[': return "\\[";
207 case ']': return "\\]";
208 case '\n': return "\\n";
209 }
210
211 return NULL;
212}
ada7c492
A
213
214_SIMPLE_STRING
215_simple_asl_msg_new(void)
216{
217 _SIMPLE_STRING b = _simple_salloc();
218
219 if (b == NULL) return NULL;
220
e45b4692 221 if (_simple_sprintf(b, " 0"))
ada7c492
A
222 {
223 _simple_sfree(b);
224 return NULL;
225 }
226
227 return b;
228}
229
230void
231_simple_asl_msg_set(_SIMPLE_STRING __b, const char *__key, const char *__val)
232{
233 if (__b == NULL) return;
234 if (__key == NULL) return;
235
236 do
237 {
e45b4692 238 if (_simple_sprintf(__b, " [")) break;
ada7c492
A
239 if (_simple_esprintf(__b, _simple_asl_escape_key, "%s", __key)) break;
240 if (__val != NULL)
241 {
242 if (_simple_esprintf(__b, _simple_asl_escape_val, " %s", __val)) break;
243 if (!strcmp(__key, "Message"))
244 {
245 char *cp;
246
247 /* remove trailing (escaped) newlines */
248 cp = _simple_string(__b);
249 cp += strlen(cp);
250 for (;;)
251 {
252 cp -= 2;
253 if (strcmp(cp, "\\n") != 0) break;
254 *cp = 0;
255 }
256
257 _simple_sresize(__b);
258 }
259 }
260
261 if (_simple_sappend(__b, "]")) break;
262 return;
263 } while (0);
264}
265
266void
267_simple_asl_send(_SIMPLE_STRING __b)
268{
89154bfb 269#if !TARGET_OS_DRIVERKIT
ada7c492
A
270 struct timeval tv;
271 int asl_fd = _simple_asl_get_fd();
272 if (asl_fd < 0) return;
273
274 __gettimeofday(&tv, NULL);
275
276 do
277 {
278 char *cp;
279
e45b4692 280 if (_simple_sprintf(__b, " [PID ")) break;
ada7c492 281 if (_simple_esprintf(__b, _simple_asl_escape_val, "%u", getpid())) break;
e45b4692 282 if (_simple_sprintf(__b, "] [UID ")) break;
ada7c492 283 if (_simple_esprintf(__b, _simple_asl_escape_val, "%u", getuid())) break;
e45b4692 284 if (_simple_sprintf(__b, "] [GID ")) break;
ada7c492 285 if (_simple_esprintf(__b, _simple_asl_escape_val, "%u", getgid())) break;
e45b4692 286 if (_simple_sprintf(__b, "] [Time ")) break;
ada7c492
A
287 if (_simple_esprintf(__b, _simple_asl_escape_val, "%lu", tv.tv_sec)) break;
288 if (_simple_sappend(__b, "] [TimeNanoSec ")) break;
289 if (_simple_esprintf(__b, _simple_asl_escape_val, "%d", tv.tv_usec * 1000)) break;
290 if (_simple_sappend(__b, "]\n")) break;
291
292 cp = _simple_string(__b);
293 __sendto(asl_fd, cp, strlen(cp), 0, NULL, 0);
294 } while (0);
89154bfb
A
295#else // TARGET_OS_DRIVERKIT
296 char *cp;
297 cp = _simple_string(__b);
298 log_data_as_kernel(0, OS_LOG_TYPE_DEFAULT, cp, strlen(cp) + 1);
299#endif // TARGET_OS_DRIVERKIT
ada7c492
A
300}
301
302void
303_simple_asl_log_prog(int level, const char *facility, const char *message, const char *prog)
304{
ada7c492
A
305 _SIMPLE_STRING b = _simple_asl_msg_new();
306 if (b == NULL) return;
307
89154bfb
A
308#if !TARGET_OS_DRIVERKIT
309 char lstr[2];
ada7c492
A
310 if (level < 0) level = 0;
311 if (level > 7) level = 7;
312 lstr[0] = level + '0';
313 lstr[1] = '\0';
314
315 _simple_asl_msg_set(b, "Sender", prog);
316 _simple_asl_msg_set(b, "Level", lstr);
317 _simple_asl_msg_set(b, "Facility", facility);
318 _simple_asl_msg_set(b, "Message", message);
319 _simple_asl_send(b);
89154bfb
A
320#else // TARGET_OS_DRIVERKIT
321 if (prog) _simple_asl_msg_set(b, "Sender", prog);
322 _simple_asl_msg_set(b, "Facility", facility);
323 _simple_asl_msg_set(b, "Message", message);
324
325 os_log_type_t type = level > ASL_LEVEL_INFO ? OS_LOG_TYPE_DEFAULT :
326 (level > ASL_LEVEL_DEBUG ? OS_LOG_TYPE_INFO : OS_LOG_TYPE_DEBUG);
327
328 char *cp;
329 cp = _simple_string(b);
330 log_data_as_kernel(0, type, cp, strlen(cp) + 1);
331#endif // TARGET_OS_DRIVERKIT
ada7c492
A
332 _simple_sfree(b);
333}
334
335void
336_simple_asl_log(int level, const char *facility, const char *message)
337{
89154bfb 338#if !TARGET_OS_DRIVERKIT
ada7c492
A
339 _simple_asl_log_prog(level, facility, message,
340 _simple_asl_get_context()->progname);
89154bfb
A
341#else // TARGET_OS_DRIVERKIT
342 _simple_asl_log_prog(level, facility, message, NULL);
343#endif // TARGET_OS_DRIVERKIT
ada7c492
A
344}
345
89154bfb 346#if !TARGET_OS_DRIVERKIT
ada7c492
A
347static struct asl_context *
348_simple_asl_get_context(void)
349{
350 return os_alloc_once(OS_ALLOC_ONCE_KEY_LIBSYSTEM_PLATFORM_ASL,
351 sizeof(struct asl_context), _simple_asl_init_context);
352}
353
354static void
355_simple_asl_init_context(void *arg)
356{
357 struct asl_context *ctx = (struct asl_context *)arg;
358 // ctx is zero-filled when it comes out of _os_alloc_once
359 ctx->progname = "unknown";
360 ctx->asl_fd = -1;
361}
89154bfb 362#endif // !TARGET_OS_DRIVERKIT