]> git.saurik.com Git - apple/libplatform.git/blob - src/simple/asl.c
4928a6ae8230d58f3fd080417a594a67768568a7
[apple/libplatform.git] / src / simple / asl.c
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
44 #if TARGET_OS_DRIVERKIT
45 // DriverKit processes log directly to kernel log
46 #include <sys/log_data.h>
47 OS_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
54 #define ASL_LOG_PATH _PATH_LOG
55
56 extern ssize_t __sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
57 extern int __gettimeofday(struct timeval *, struct timezone *);
58
59 struct ProgramVars
60 {
61 void* mh;
62 int* NXArgcPtr;
63 char*** NXArgvPtr;
64 char*** environPtr;
65 char** __prognamePtr;
66 };
67
68 struct asl_context {
69 bool asl_enabled;
70 const char *progname;
71 int asl_fd;
72 #if TARGET_OS_SIMULATOR && !TARGET_OS_IOSMAC
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
80 static struct asl_context* _simple_asl_get_context(void);
81 static void _simple_asl_init_context(void *ctx);
82 static int _simple_asl_connect(const char *log_path);
83 static void _simple_asl_connect_once(void * __unused arg);
84 static 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
91 __attribute__((visibility("hidden")))
92 void
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);
102 #if TARGET_OS_SIMULATOR
103 } else {
104 const char * progname = *_NSGetProgname();
105 if (progname)
106 ctx->progname = progname;
107 #endif
108 }
109 }
110
111 static int
112 _simple_asl_connect(const char *log_path)
113 {
114 int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
115 if (fd == -1) return -1;
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
134 static 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
141 static 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
149 #if TARGET_OS_SIMULATOR && !TARGET_OS_IOSMAC
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 }
183 #endif // !TARGET_OS_DRIVERKIT
184
185 static 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
200 static 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 }
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
221 if (_simple_sprintf(b, " 0"))
222 {
223 _simple_sfree(b);
224 return NULL;
225 }
226
227 return b;
228 }
229
230 void
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 {
238 if (_simple_sprintf(__b, " [")) break;
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
266 void
267 _simple_asl_send(_SIMPLE_STRING __b)
268 {
269 #if !TARGET_OS_DRIVERKIT
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
280 if (_simple_sprintf(__b, " [PID ")) break;
281 if (_simple_esprintf(__b, _simple_asl_escape_val, "%u", getpid())) break;
282 if (_simple_sprintf(__b, "] [UID ")) break;
283 if (_simple_esprintf(__b, _simple_asl_escape_val, "%u", getuid())) break;
284 if (_simple_sprintf(__b, "] [GID ")) break;
285 if (_simple_esprintf(__b, _simple_asl_escape_val, "%u", getgid())) break;
286 if (_simple_sprintf(__b, "] [Time ")) break;
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);
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
300 }
301
302 void
303 _simple_asl_log_prog(int level, const char *facility, const char *message, const char *prog)
304 {
305 _SIMPLE_STRING b = _simple_asl_msg_new();
306 if (b == NULL) return;
307
308 #if !TARGET_OS_DRIVERKIT
309 char lstr[2];
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);
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
332 _simple_sfree(b);
333 }
334
335 void
336 _simple_asl_log(int level, const char *facility, const char *message)
337 {
338 #if !TARGET_OS_DRIVERKIT
339 _simple_asl_log_prog(level, facility, message,
340 _simple_asl_get_context()->progname);
341 #else // TARGET_OS_DRIVERKIT
342 _simple_asl_log_prog(level, facility, message, NULL);
343 #endif // TARGET_OS_DRIVERKIT
344 }
345
346 #if !TARGET_OS_DRIVERKIT
347 static 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
354 static 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 }
362 #endif // !TARGET_OS_DRIVERKIT