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 #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,
52 #else // !TARGET_OS_DRIVERKIT
54 #define ASL_LOG_PATH _PATH_LOG
56 extern ssize_t
__sendto(int, const void *, size_t, int, const struct sockaddr
*, socklen_t
);
57 extern int __gettimeofday(struct timeval
*, struct timezone
*);
72 #if TARGET_OS_SIMULATOR && !TARGET_OS_MACCATALYST
73 const char *sim_log_path
;
74 os_unfair_lock sim_connect_lock
;
76 os_once_t connect_once
;
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);
87 * Simplified ASL log interface; does not use malloc. Unfortunately, this
88 * requires knowledge of the format used by ASL.
91 __attribute__((visibility("hidden")))
93 _simple_asl_init(const char *envp
[], const struct ProgramVars
*vars
)
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
104 const char * progname
= *_NSGetProgname();
106 ctx
->progname
= progname
;
112 _simple_asl_connect(const char *log_path
)
114 int fd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
115 if (fd
== -1) return -1;
117 fcntl(fd
, F_SETFD
, FD_CLOEXEC
);
119 struct sockaddr_un addr
;
120 addr
.sun_family
= AF_UNIX
;
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
);
127 if (connect(fd
, (struct sockaddr
*)&addr
, sizeof(addr
)) == -1) {
135 _simple_asl_connect_once(void * __unused once_arg
)
137 struct asl_context
*ctx
= _simple_asl_get_context();
138 ctx
->asl_fd
= _simple_asl_connect(ASL_LOG_PATH
);
142 _simple_asl_get_fd(void)
144 struct asl_context
*ctx
= _simple_asl_get_context();
145 if (!ctx
->asl_enabled
) {
149 #if TARGET_OS_SIMULATOR && !TARGET_OS_MACCATALYST
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
);
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
169 ctx
->asl_fd
= sim_log_fd
;
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
);
176 os_unfair_lock_unlock(&ctx
->sim_connect_lock
);
179 os_once(&ctx
->connect_once
, NULL
, _simple_asl_connect_once
);
183 #endif // !TARGET_OS_DRIVERKIT
186 _simple_asl_escape_key(unsigned char c
)
190 case '\\': return "\\\\";
191 case '[': return "\\[";
192 case ']': return "\\]";
193 case '\n': return "\\n";
194 case ' ': return "\\s";
201 _simple_asl_escape_val(unsigned char c
)
205 case '\\': return "\\\\";
206 case '[': return "\\[";
207 case ']': return "\\]";
208 case '\n': return "\\n";
215 _simple_asl_msg_new(void)
217 _SIMPLE_STRING b
= _simple_salloc();
219 if (b
== NULL
) return NULL
;
221 if (_simple_sprintf(b
, " 0"))
231 _simple_asl_msg_set(_SIMPLE_STRING __b
, const char *__key
, const char *__val
)
233 if (__b
== NULL
) return;
234 if (__key
== NULL
) return;
238 if (_simple_sprintf(__b
, " [")) break;
239 if (_simple_esprintf(__b
, _simple_asl_escape_key
, "%s", __key
)) break;
242 if (_simple_esprintf(__b
, _simple_asl_escape_val
, " %s", __val
)) break;
243 if (!strcmp(__key
, "Message"))
247 /* remove trailing (escaped) newlines */
248 cp
= _simple_string(__b
);
253 if (strcmp(cp
, "\\n") != 0) break;
257 _simple_sresize(__b
);
261 if (_simple_sappend(__b
, "]")) break;
267 _simple_asl_send(_SIMPLE_STRING __b
)
269 #if !TARGET_OS_DRIVERKIT
271 int asl_fd
= _simple_asl_get_fd();
272 if (asl_fd
< 0) return;
274 __gettimeofday(&tv
, NULL
);
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;
292 cp
= _simple_string(__b
);
293 __sendto(asl_fd
, cp
, strlen(cp
), 0, NULL
, 0);
295 #else // TARGET_OS_DRIVERKIT
297 cp
= _simple_string(__b
);
298 log_data_as_kernel(0, OS_LOG_TYPE_DEFAULT
, cp
, strlen(cp
) + 1);
299 #endif // TARGET_OS_DRIVERKIT
303 _simple_asl_log_prog(int level
, const char *facility
, const char *message
, const char *prog
)
305 _SIMPLE_STRING b
= _simple_asl_msg_new();
306 if (b
== NULL
) return;
308 #if !TARGET_OS_DRIVERKIT
310 if (level
< 0) level
= 0;
311 if (level
> 7) level
= 7;
312 lstr
[0] = level
+ '0';
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
);
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
);
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
);
329 cp
= _simple_string(b
);
330 log_data_as_kernel(0, type
, cp
, strlen(cp
) + 1);
331 #endif // TARGET_OS_DRIVERKIT
336 _simple_asl_log(int level
, const char *facility
, const char *message
)
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
346 #if !TARGET_OS_DRIVERKIT
347 static struct asl_context
*
348 _simple_asl_get_context(void)
350 return os_alloc_once(OS_ALLOC_ONCE_KEY_LIBSYSTEM_PLATFORM_ASL
,
351 sizeof(struct asl_context
), _simple_asl_init_context
);
355 _simple_asl_init_context(void *arg
)
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";
362 #endif // !TARGET_OS_DRIVERKIT