]> git.saurik.com Git - apple/libplatform.git/blob - src/simple/asl.c
libplatform-126.1.2.tar.gz
[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 #define ASL_LOG_PATH _PATH_LOG
45
46 extern ssize_t __sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
47 extern int __gettimeofday(struct timeval *, struct timezone *);
48
49 struct ProgramVars
50 {
51 void* mh;
52 int* NXArgcPtr;
53 char*** NXArgvPtr;
54 char*** environPtr;
55 char** __prognamePtr;
56 };
57
58 struct asl_context {
59 bool asl_enabled;
60 const char *progname;
61 int asl_fd;
62 #if TARGET_IPHONE_SIMULATOR
63 const char *sim_log_path;
64 os_unfair_lock sim_connect_lock;
65 #else
66 os_once_t connect_once;
67 #endif
68 };
69
70 static struct asl_context* _simple_asl_get_context(void);
71 static void _simple_asl_init_context(void *ctx);
72 static int _simple_asl_connect(const char *log_path);
73 static void _simple_asl_connect_once(void * __unused arg);
74 static int _simple_asl_get_fd(void);
75
76 /*
77 * Simplified ASL log interface; does not use malloc. Unfortunately, this
78 * requires knowledge of the format used by ASL.
79 */
80
81 static const char *
82 _simple_asl_escape_key(unsigned char c)
83 {
84 switch(c)
85 {
86 case '\\': return "\\\\";
87 case '[': return "\\[";
88 case ']': return "\\]";
89 case '\n': return "\\n";
90 case ' ': return "\\s";
91 }
92
93 return NULL;
94 }
95
96 static const char *
97 _simple_asl_escape_val(unsigned char c)
98 {
99 switch(c)
100 {
101 case '\\': return "\\\\";
102 case '[': return "\\[";
103 case ']': return "\\]";
104 case '\n': return "\\n";
105 }
106
107 return NULL;
108 }
109
110 __attribute__((visibility("hidden")))
111 void
112 _simple_asl_init(const char *envp[], const struct ProgramVars *vars)
113 {
114 const char *str;
115 struct asl_context *ctx = _simple_asl_get_context();
116 str = _simple_getenv(envp, "ASL_DISABLE");
117 if ((str != NULL) && (!strcmp(str, "1"))) return;
118 ctx->asl_enabled = true;
119 if (vars && vars->__prognamePtr) {
120 ctx->progname = *(vars->__prognamePtr);
121 #if TARGET_IPHONE_SIMULATOR
122 } else {
123 const char * progname = *_NSGetProgname();
124 if (progname)
125 ctx->progname = progname;
126 #endif
127 }
128 }
129
130 static int
131 _simple_asl_connect(const char *log_path)
132 {
133 int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
134 if (fd == -1) return;
135
136 fcntl(fd, F_SETFD, FD_CLOEXEC);
137
138 struct sockaddr_un addr;
139 addr.sun_family = AF_UNIX;
140
141 size_t amt = strlen(log_path) + 1;
142 if (sizeof(addr.sun_path) < amt)
143 amt = sizeof(addr.sun_path);
144 memmove(addr.sun_path, log_path, amt);
145
146 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
147 close(fd);
148 return -1;
149 }
150 return fd;
151 }
152
153 static void
154 _simple_asl_connect_once(void * __unused once_arg)
155 {
156 struct asl_context *ctx = _simple_asl_get_context();
157 ctx->asl_fd = _simple_asl_connect(ASL_LOG_PATH);
158 }
159
160 static int
161 _simple_asl_get_fd(void)
162 {
163 struct asl_context *ctx = _simple_asl_get_context();
164 if (!ctx->asl_enabled) {
165 return -1;
166 }
167
168 #if TARGET_IPHONE_SIMULATOR
169 os_unfair_lock_lock_with_options(&ctx->sim_connect_lock,
170 OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION);
171 if (ctx->sim_log_path) {
172 // all setup has been done already
173 os_unfair_lock_unlock(&ctx->sim_connect_lock);
174 return ctx->asl_fd;
175 }
176 ctx->sim_log_path = _simple_getenv(
177 (const char **)*_NSGetEnviron(), "IOS_SIMULATOR_SYSLOG_SOCKET");
178 if (ctx->sim_log_path) {
179 // the first and only time the envvar is being checked
180 // asl_fd procured by the end of this call will be used forever
181 int sim_log_fd = _simple_asl_connect(ctx->sim_log_path);
182 if (sim_log_fd > -1) {
183 // successfully connected to the SIM path
184 if (ctx->asl_fd > -1) {
185 // close the ASL_LOG_PATH fd
186 close(ctx->asl_fd);
187 }
188 ctx->asl_fd = sim_log_fd;
189 }
190 }
191 if (ctx->asl_fd < 0) {
192 // either there is no envvar or it didn't work. fallback to ASL_LOG_PATH
193 ctx->asl_fd = _simple_asl_connect(ASL_LOG_PATH);
194 }
195 os_unfair_lock_unlock(&ctx->sim_connect_lock);
196 return ctx->asl_fd;
197 #else
198 os_once(&ctx->connect_once, NULL, _simple_asl_connect_once);
199 return ctx->asl_fd;
200 #endif
201 }
202
203 _SIMPLE_STRING
204 _simple_asl_msg_new(void)
205 {
206 _SIMPLE_STRING b = _simple_salloc();
207
208 if (b == NULL) return NULL;
209
210 if (_simple_sprintf(b, " 0", 0))
211 {
212 _simple_sfree(b);
213 return NULL;
214 }
215
216 return b;
217 }
218
219 void
220 _simple_asl_msg_set(_SIMPLE_STRING __b, const char *__key, const char *__val)
221 {
222 if (__b == NULL) return;
223 if (__key == NULL) return;
224
225 do
226 {
227 if (_simple_sprintf(__b, " [", 0)) break;
228 if (_simple_esprintf(__b, _simple_asl_escape_key, "%s", __key)) break;
229 if (__val != NULL)
230 {
231 if (_simple_esprintf(__b, _simple_asl_escape_val, " %s", __val)) break;
232 if (!strcmp(__key, "Message"))
233 {
234 char *cp;
235
236 /* remove trailing (escaped) newlines */
237 cp = _simple_string(__b);
238 cp += strlen(cp);
239 for (;;)
240 {
241 cp -= 2;
242 if (strcmp(cp, "\\n") != 0) break;
243 *cp = 0;
244 }
245
246 _simple_sresize(__b);
247 }
248 }
249
250 if (_simple_sappend(__b, "]")) break;
251 return;
252 } while (0);
253 }
254
255 void
256 _simple_asl_send(_SIMPLE_STRING __b)
257 {
258 struct timeval tv;
259 int asl_fd = _simple_asl_get_fd();
260 if (asl_fd < 0) return;
261
262 __gettimeofday(&tv, NULL);
263
264 do
265 {
266 char *cp;
267
268 if (_simple_sprintf(__b, " [PID ", 0)) break;
269 if (_simple_esprintf(__b, _simple_asl_escape_val, "%u", getpid())) break;
270 if (_simple_sprintf(__b, "] [UID ", 0)) break;
271 if (_simple_esprintf(__b, _simple_asl_escape_val, "%u", getuid())) break;
272 if (_simple_sprintf(__b, "] [GID ", 0)) break;
273 if (_simple_esprintf(__b, _simple_asl_escape_val, "%u", getgid())) break;
274 if (_simple_sprintf(__b, "] [Time ", 0)) break;
275 if (_simple_esprintf(__b, _simple_asl_escape_val, "%lu", tv.tv_sec)) break;
276 if (_simple_sappend(__b, "] [TimeNanoSec ")) break;
277 if (_simple_esprintf(__b, _simple_asl_escape_val, "%d", tv.tv_usec * 1000)) break;
278 if (_simple_sappend(__b, "]\n")) break;
279
280 cp = _simple_string(__b);
281 __sendto(asl_fd, cp, strlen(cp), 0, NULL, 0);
282 } while (0);
283 }
284
285 void
286 _simple_asl_log_prog(int level, const char *facility, const char *message, const char *prog)
287 {
288 char lstr[2];
289
290 _SIMPLE_STRING b = _simple_asl_msg_new();
291 if (b == NULL) return;
292
293 if (level < 0) level = 0;
294 if (level > 7) level = 7;
295 lstr[0] = level + '0';
296 lstr[1] = '\0';
297
298 _simple_asl_msg_set(b, "Sender", prog);
299 _simple_asl_msg_set(b, "Level", lstr);
300 _simple_asl_msg_set(b, "Facility", facility);
301 _simple_asl_msg_set(b, "Message", message);
302 _simple_asl_send(b);
303 _simple_sfree(b);
304 }
305
306 void
307 _simple_asl_log(int level, const char *facility, const char *message)
308 {
309 _simple_asl_log_prog(level, facility, message,
310 _simple_asl_get_context()->progname);
311 }
312
313 static struct asl_context *
314 _simple_asl_get_context(void)
315 {
316 return os_alloc_once(OS_ALLOC_ONCE_KEY_LIBSYSTEM_PLATFORM_ASL,
317 sizeof(struct asl_context), _simple_asl_init_context);
318 }
319
320 static void
321 _simple_asl_init_context(void *arg)
322 {
323 struct asl_context *ctx = (struct asl_context *)arg;
324 // ctx is zero-filled when it comes out of _os_alloc_once
325 ctx->progname = "unknown";
326 ctx->asl_fd = -1;
327 }