2 * Copyright (c) 2005, 2006, 2009 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
28 #include <sys/syslog.h>
30 #include <sys/socket.h>
32 #include <crt_externs.h>
34 #include <TargetConditionals.h>
39 #include <os/lock_private.h>
40 #include <os/alloc_once_private.h>
41 #include <platform/string.h>
42 #include <platform/compat.h>
44 #define ASL_LOG_PATH _PATH_LOG
46 extern ssize_t
__sendto(int, const void *, size_t, int, const struct sockaddr
*, socklen_t
);
47 extern int __gettimeofday(struct timeval
*, struct timezone
*);
62 #if TARGET_IPHONE_SIMULATOR
63 const char *sim_log_path
;
64 os_unfair_lock sim_connect_lock
;
66 os_once_t connect_once
;
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);
77 * Simplified ASL log interface; does not use malloc. Unfortunately, this
78 * requires knowledge of the format used by ASL.
82 _simple_asl_escape_key(unsigned char c
)
86 case '\\': return "\\\\";
87 case '[': return "\\[";
88 case ']': return "\\]";
89 case '\n': return "\\n";
90 case ' ': return "\\s";
97 _simple_asl_escape_val(unsigned char c
)
101 case '\\': return "\\\\";
102 case '[': return "\\[";
103 case ']': return "\\]";
104 case '\n': return "\\n";
110 __attribute__((visibility("hidden")))
112 _simple_asl_init(const char *envp
[], const struct ProgramVars
*vars
)
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
123 const char * progname
= *_NSGetProgname();
125 ctx
->progname
= progname
;
131 _simple_asl_connect(const char *log_path
)
133 int fd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
134 if (fd
== -1) return;
136 fcntl(fd
, F_SETFD
, FD_CLOEXEC
);
138 struct sockaddr_un addr
;
139 addr
.sun_family
= AF_UNIX
;
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
);
146 if (connect(fd
, (struct sockaddr
*)&addr
, sizeof(addr
)) == -1) {
154 _simple_asl_connect_once(void * __unused once_arg
)
156 struct asl_context
*ctx
= _simple_asl_get_context();
157 ctx
->asl_fd
= _simple_asl_connect(ASL_LOG_PATH
);
161 _simple_asl_get_fd(void)
163 struct asl_context
*ctx
= _simple_asl_get_context();
164 if (!ctx
->asl_enabled
) {
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
);
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
188 ctx
->asl_fd
= sim_log_fd
;
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
);
195 os_unfair_lock_unlock(&ctx
->sim_connect_lock
);
198 os_once(&ctx
->connect_once
, NULL
, _simple_asl_connect_once
);
204 _simple_asl_msg_new(void)
206 _SIMPLE_STRING b
= _simple_salloc();
208 if (b
== NULL
) return NULL
;
210 if (_simple_sprintf(b
, " 0", 0))
220 _simple_asl_msg_set(_SIMPLE_STRING __b
, const char *__key
, const char *__val
)
222 if (__b
== NULL
) return;
223 if (__key
== NULL
) return;
227 if (_simple_sprintf(__b
, " [", 0)) break;
228 if (_simple_esprintf(__b
, _simple_asl_escape_key
, "%s", __key
)) break;
231 if (_simple_esprintf(__b
, _simple_asl_escape_val
, " %s", __val
)) break;
232 if (!strcmp(__key
, "Message"))
236 /* remove trailing (escaped) newlines */
237 cp
= _simple_string(__b
);
242 if (strcmp(cp
, "\\n") != 0) break;
246 _simple_sresize(__b
);
250 if (_simple_sappend(__b
, "]")) break;
256 _simple_asl_send(_SIMPLE_STRING __b
)
259 int asl_fd
= _simple_asl_get_fd();
260 if (asl_fd
< 0) return;
262 __gettimeofday(&tv
, NULL
);
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;
280 cp
= _simple_string(__b
);
281 __sendto(asl_fd
, cp
, strlen(cp
), 0, NULL
, 0);
286 _simple_asl_log_prog(int level
, const char *facility
, const char *message
, const char *prog
)
290 _SIMPLE_STRING b
= _simple_asl_msg_new();
291 if (b
== NULL
) return;
293 if (level
< 0) level
= 0;
294 if (level
> 7) level
= 7;
295 lstr
[0] = level
+ '0';
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
);
307 _simple_asl_log(int level
, const char *facility
, const char *message
)
309 _simple_asl_log_prog(level
, facility
, message
,
310 _simple_asl_get_context()->progname
);
313 static struct asl_context
*
314 _simple_asl_get_context(void)
316 return os_alloc_once(OS_ALLOC_ONCE_KEY_LIBSYSTEM_PLATFORM_ASL
,
317 sizeof(struct asl_context
), _simple_asl_init_context
);
321 _simple_asl_init_context(void *arg
)
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";