]> git.saurik.com Git - apple/syslog.git/blob - libsystem_asl.tproj/src/asl.c
syslog-349.30.2.tar.gz
[apple/syslog.git] / libsystem_asl.tproj / src / asl.c
1 /*
2 * Copyright (c) 2004-2015 Apple 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 <string.h>
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <unistd.h>
30 #include <stdarg.h>
31 #include <syslog.h>
32 #include <errno.h>
33 #include <limits.h>
34 #include <time.h>
35 #include <sys/stat.h>
36 #include <sys/time.h>
37 #include <sys/fcntl.h>
38 #include <sys/param.h>
39 #include <sys/fileport.h>
40 #include <crt_externs.h>
41 #include <asl.h>
42 #include <regex.h>
43 #include <notify.h>
44 #include <mach/mach.h>
45 #include <mach/std_types.h>
46 #include <mach/mig.h>
47 #include <mach/mach_types.h>
48 #include <sys/types.h>
49 #include <servers/bootstrap.h>
50 #include <bootstrap_priv.h>
51 #include <pthread.h>
52 #include <dispatch/dispatch.h>
53 #include <libkern/OSAtomic.h>
54 #include <os/activity.h>
55 #include <os/log.h>
56 #include <os/log_private.h>
57 #include <asl_ipc.h>
58 #include <asl_client.h>
59 #include <asl_core.h>
60 #include <asl_msg.h>
61 #include <asl_msg_list.h>
62 #include <asl_store.h>
63 #include <asl_private.h>
64
65 #define forever for(;;)
66
67 #define FETCH_BATCH 256
68
69 #define EVAL_DEFAULT_ACTION (EVAL_SEND_ASL | EVAL_SEND_TRACE)
70 #define EVAL_ASL (EVAL_SEND_ASL | EVAL_TEXT_FILE | EVAL_ASL_FILE)
71
72 /*
73 * Clients get a max of 36000 messages per hour.
74 * Their quota gets refilled at a rate of 10 messages per second.
75 */
76 #define QUOTA_MPH 36000
77 #define QUOTA_MPS 10
78 #define QUOTA_MSG_INTERVAL 60
79 #define NOQUOTA_ENV "ASL_QUOTA_DISABLED"
80 #define QUOTA_DISABLED_MSG "*** MESSAGE QUOTA DISABLED FOR THIS PROCESS ***"
81 #define QUOTA_MSG "*** LOG MESSAGE QUOTA EXCEEDED - SOME MESSAGES FROM THIS PROCESS HAVE BEEN DISCARDED ***"
82 #define QUOTA_LEVEL ASL_LEVEL_CRIT
83 #define QUOTA_LEVEL_STR ASL_STRING_CRIT
84
85 /*
86 * Limit the size of messages sent to syslogd.
87 */
88 #define SIZE_LIMIT_MSG "*** ASL MESSAGE SIZE (%u bytes) EXCEEDED MAXIMIMUM SIZE (%u bytes) ***"
89
90 static const os_log_type_t shim_asl_to_log_type[8] = {
91 OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_EMERG
92 OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_ALERT
93 OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_CRIT
94 OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_ERR
95 OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_WARNING
96 OS_LOG_TYPE_DEFAULT, // ASL_LEVEL_NOTICE
97 OS_LOG_TYPE_INFO, // ASL_LEVEL_INFO
98 OS_LOG_TYPE_DEBUG // ASL_LEVEL_DEBUG
99 };
100
101 /* forward */
102 static ASL_STATUS _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstring);
103 static ASL_STATUS _asl_send_message_text(asl_client_t *asl, asl_msg_t *sendmsg, asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstring, bool shimmed);
104 __private_extern__ asl_client_t *_asl_open_default();
105
106 /* notify SPI */
107 uint32_t notify_register_plain(const char *name, int *out_token);
108
109 /* fork handling in asl_fd.c */
110 extern void _asl_redirect_fork_child(void);
111
112 typedef struct
113 {
114 int fd;
115 asl_msg_t *msg;
116 dispatch_semaphore_t sem;
117 } asl_aux_context_t;
118
119 typedef struct
120 {
121 int notify_count;
122 int rc_change_token;
123 int notify_token;
124 int master_token;
125 uint64_t proc_filter;
126 uint64_t master_filter;
127 time_t last_send;
128 time_t last_oq_msg;
129 uint32_t quota;
130 mach_port_t server_port;
131 char *sender;
132 pthread_mutex_t lock;
133 int aux_count;
134 asl_aux_context_t **aux_ctx;
135 asl_client_t *asl;
136 } _asl_global_t;
137
138 __private_extern__ _asl_global_t _asl_global = {0, -1, -1, -1, 0LL, 0LL, 0LL, 0LL, 0, MACH_PORT_NULL, NULL, PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL};
139
140 static const char *level_to_number_string[] = {"0", "1", "2", "3", "4", "5", "6", "7"};
141
142 #define ASL_SERVICE_NAME "com.apple.system.logger"
143
144 /*
145 * Called from the child process inside fork() to clean up
146 * inherited state from the parent process.
147 *
148 * NB. A lock isn't required, since we're single threaded in this call.
149 */
150 void
151 _asl_fork_child()
152 {
153 _asl_global.notify_count = 0;
154 _asl_global.rc_change_token = -1;
155 _asl_global.master_token = -1;
156 _asl_global.notify_token = -1;
157 _asl_global.quota = 0;
158 _asl_global.last_send = 0;
159 _asl_global.last_oq_msg = 0;
160
161 _asl_global.server_port = MACH_PORT_NULL;
162
163 pthread_mutex_init(&(_asl_global.lock), NULL);
164
165 _asl_redirect_fork_child();
166 }
167
168 /*
169 * asl_remote_notify_name: returns the notification key for remote-control filter
170 * changes for this process.
171 */
172 char *
173 asl_remote_notify_name()
174 {
175 pid_t pid = getpid();
176 uid_t euid = geteuid();
177 char *str = NULL;
178
179 if (euid == 0) asprintf(&str, "%s.%d", NOTIFY_PREFIX_SYSTEM, pid);
180 else asprintf(&str, "user.uid.%d.syslog.%d", euid, pid);
181
182 return str;
183 }
184
185 static ASL_STATUS
186 _asl_notify_open(int do_lock)
187 {
188 char *notify_name;
189 uint32_t status;
190
191 if (do_lock != 0) pthread_mutex_lock(&_asl_global.lock);
192
193 _asl_global.notify_count++;
194
195 if (_asl_global.notify_token != -1)
196 {
197 if (do_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
198 return ASL_STATUS_OK;
199 }
200
201 if (_asl_global.rc_change_token == -1)
202 {
203 status = notify_register_check(NOTIFY_RC, &_asl_global.rc_change_token);
204 if (status != NOTIFY_STATUS_OK) _asl_global.rc_change_token = -1;
205 }
206
207 if (_asl_global.master_token == -1)
208 {
209 status = notify_register_plain(NOTIFY_SYSTEM_MASTER, &_asl_global.master_token);
210 if (status != NOTIFY_STATUS_OK) _asl_global.master_token = -1;
211 }
212
213 notify_name = asl_remote_notify_name();
214 if (notify_name != NULL)
215 {
216 status = notify_register_plain(notify_name, &_asl_global.notify_token);
217 free(notify_name);
218 if (status != NOTIFY_STATUS_OK) _asl_global.notify_token = -1;
219 }
220
221 if (do_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
222
223 if (_asl_global.notify_token == -1) return ASL_STATUS_FAILED;
224 return ASL_STATUS_OK;
225 }
226
227 #ifdef UNDEF
228 static void
229 _asl_notify_close()
230 {
231 pthread_mutex_lock(&_asl_global.lock);
232
233 if (_asl_global.notify_count > 0) _asl_global.notify_count--;
234
235 if (_asl_global.notify_count > 0)
236 {
237 pthread_mutex_unlock(&_asl_global.lock);
238 return;
239 }
240
241 if (_asl_global.rc_change_token >= 0) notify_cancel(_asl_global.rc_change_token);
242 _asl_global.rc_change_token = -1;
243
244 if (_asl_global.master_token >= 0) notify_cancel(_asl_global.master_token);
245 _asl_global.master_token = -1;
246
247 if (_asl_global.notify_token >= 0) notify_cancel(_asl_global.notify_token);
248 _asl_global.notify_token = -1;
249
250 pthread_mutex_unlock(&_asl_global.lock);
251 }
252 #endif
253
254 static void
255 _asl_global_init(int reset)
256 {
257 _asl_global.server_port = asl_core_get_service_port(reset);
258 }
259
260 #pragma mark -
261 #pragma mark asl_client
262
263 asl_object_t
264 asl_open(const char *ident, const char *facility, uint32_t opts)
265 {
266 asl_client_t *asl = asl_client_open(ident, facility, opts);
267 if (asl == NULL) return NULL;
268
269 _asl_global_init(0);
270 if (!(opts & ASL_OPT_NO_REMOTE)) _asl_notify_open(1);
271
272 return (asl_object_t)asl;
273 }
274
275 asl_object_t
276 asl_open_from_file(int fd, const char *ident, const char *facility)
277 {
278 return (asl_object_t)asl_client_open_from_file(fd, ident, facility);
279 }
280
281 void
282 asl_close(asl_object_t obj)
283 {
284 asl_release(obj);
285 }
286
287 __private_extern__ asl_client_t *
288 _asl_open_default()
289 {
290 static dispatch_once_t once;
291
292 dispatch_once(&once, ^{
293 /*
294 * Do a sleight-of-hand with ASL_OPT_NO_REMOTE to avoid a deadlock
295 * since asl_open(xxx, yyy, 0) calls _asl_notify_open(1)
296 * which locks _asl_global.lock.
297 */
298 _asl_global.asl = (asl_client_t *)asl_open(NULL, NULL, ASL_OPT_NO_REMOTE);
299
300 /* Reset options to clear ASL_OPT_NO_REMOTE bit */
301 if (_asl_global.asl != NULL) _asl_global.asl->options = 0;
302
303 /* Now call _asl_notify_open(0) to finish the work */
304 _asl_notify_open(0);
305 });
306
307 return _asl_global.asl;
308 }
309
310 /*
311 * asl_add_file: write log messages to the given file descriptor
312 * Log messages will be written to this file as well as to the server.
313 */
314 int
315 asl_add_output_file(asl_object_t client, int fd, const char *mfmt, const char *tfmt, int filter, int text_encoding)
316 {
317 int status, use_global_lock = 0;
318 asl_client_t *asl;
319
320 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1;
321
322 asl = (asl_client_t *)client;
323 if (asl == NULL)
324 {
325 asl = _asl_open_default();
326 if (asl == NULL) return -1;
327 pthread_mutex_lock(&_asl_global.lock);
328 use_global_lock = 1;
329 }
330
331 status = asl_client_add_output_file(asl, fd, mfmt, tfmt, filter, text_encoding);
332
333 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
334 return (status == ASL_STATUS_OK) ? 0 : -1;
335 }
336
337 /* returns previous filter value or -1 on error */
338 int
339 asl_set_output_file_filter(asl_object_t client, int fd, int filter)
340 {
341 uint32_t last;
342 int use_global_lock = 0;
343 asl_client_t *asl;
344
345 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1;
346
347 asl = (asl_client_t *)client;
348 if (asl == NULL)
349 {
350 asl = _asl_open_default();
351 if (asl == NULL) return -1;
352 pthread_mutex_lock(&_asl_global.lock);
353 use_global_lock = 1;
354 }
355
356 last = asl_client_set_output_file_filter(asl, fd, filter);
357
358 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
359 return last;
360 }
361
362 /* SPI - Deprecated */
363 int
364 asl_add_output(asl_object_t client, int fd, const char *mfmt, const char *tfmt, uint32_t text_encoding)
365 {
366 return asl_add_output_file(client, fd, mfmt, tfmt, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG), text_encoding);
367 }
368
369 /* SPI - Deprecated */
370 int
371 asl_add_log_file(asl_object_t client, int fd)
372 {
373 return asl_add_output_file(client, fd, ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG), ASL_ENCODE_SAFE);
374 }
375
376 /*
377 * asl_remove_output: stop writing log messages to the given file descriptor
378 */
379 int
380 asl_remove_output_file(asl_object_t client, int fd)
381 {
382 int status, use_global_lock = 0;
383 asl_client_t *asl;
384
385 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1;
386
387 asl = (asl_client_t *)client;
388 if (asl == NULL)
389 {
390 asl = _asl_open_default();
391 if (asl == NULL) return -1;
392 pthread_mutex_lock(&_asl_global.lock);
393 use_global_lock = 1;
394 }
395
396 status = asl_client_remove_output_file(asl, fd);
397
398 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
399 return (status == ASL_STATUS_OK) ? 0 : -1;
400 }
401
402 int
403 asl_remove_output(asl_object_t client, int fd)
404 {
405 return asl_remove_output_file(client, fd);
406 }
407
408 int
409 asl_remove_log_file(asl_object_t client, int fd)
410 {
411 return asl_remove_output_file(client, fd);
412 }
413
414 /* returns previous filter value or -1 on error */
415 int
416 asl_set_filter(asl_object_t client, int f)
417 {
418 int last, use_global_lock = 0;
419 asl_client_t *asl;
420
421 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1;
422
423 asl = (asl_client_t *)client;
424 if (asl == NULL)
425 {
426 asl = _asl_open_default();
427 if (asl == NULL) return -1;
428 pthread_mutex_lock(&_asl_global.lock);
429 use_global_lock = 1;
430 }
431
432 last = asl_client_set_filter(asl, f);
433
434 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
435 return last;
436 }
437
438
439 #pragma mark -
440 #pragma mark message sending
441
442 /*
443 * Evaluate client / message / level to determine what to do with a message.
444 * Checks filters, tunneling, and log files.
445 * Returns the bits below, ORed with the message level.
446 *
447 * EVAL_SEND_ASL - send this message to syslogd
448 * EVAL_SEND_TRACE - log this message with Activity Tracing
449 * EVAL_ASL_FILE - write to a standalone ASL file (see asl_open_from_file)
450 * EVAL_TEXT_FILE - write this message to a text file / stderr
451 * EVAL_TUNNEL - tunneling enabled when sending to syslogd
452 */
453 uint32_t
454 _asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel)
455 {
456 asl_client_t *asl;
457 asl_msg_t *msg = (asl_msg_t *)m;
458 uint32_t level, lmask, filter, status, tunnel;
459 int check;
460 uint64_t v64;
461 const char *val;
462 uint32_t eval;
463
464 level = ASL_LEVEL_DEBUG;
465 if (slevel >= 0) level = slevel;
466
467 val = NULL;
468 if ((asl_msg_lookup(msg, ASL_KEY_LEVEL, &val, NULL) == 0) && (val != NULL)) level = atoi(val);
469
470 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
471 else if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
472
473 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT))
474 {
475 /* sending to something other than a client */
476 return EVAL_ACTIVE | EVAL_SEND_ASL | level;
477 }
478
479 asl = (asl_client_t *)client;
480 if ((asl != NULL) && (asl->aslfile != NULL)) return (EVAL_ASL_FILE | level);
481
482 if (asl == NULL) asl = _asl_open_default();
483 if (asl == NULL)
484 {
485 eval = EVAL_ACTIVE | EVAL_DEFAULT_ACTION | level;
486 eval &= ~EVAL_SEND_ASL;
487 return eval;
488 }
489
490 eval = (asl_client_get_control(asl) & EVAL_ACTION_MASK) | level;
491
492 filter = asl->filter & 0xff;
493 tunnel = (asl->filter & ASL_FILTER_MASK_TUNNEL) >> 8;
494 if (tunnel != 0) eval |= EVAL_TUNNEL;
495
496 if ((asl->options & ASL_OPT_NO_REMOTE) == 0)
497 {
498 pthread_mutex_lock(&_asl_global.lock);
499
500 if (_asl_global.rc_change_token >= 0)
501 {
502 /* initialize or re-check process-specific and master filters */
503 check = 0;
504 status = notify_check(_asl_global.rc_change_token, &check);
505 if ((status == NOTIFY_STATUS_OK) && (check != 0))
506 {
507 if (_asl_global.master_token >= 0)
508 {
509 v64 = 0;
510 status = notify_get_state(_asl_global.master_token, &v64);
511 if (status == NOTIFY_STATUS_OK) _asl_global.master_filter = v64;
512 }
513
514 if (_asl_global.notify_token >= 0)
515 {
516 v64 = 0;
517 status = notify_get_state(_asl_global.notify_token, &v64);
518 if (status == NOTIFY_STATUS_OK) _asl_global.proc_filter = v64;
519 }
520 }
521 }
522
523 if (_asl_global.master_filter & EVAL_ACTIVE)
524 {
525 /* clear bits and set according to master */
526 eval &= ~(EVAL_SEND_ASL | EVAL_SEND_TRACE);
527 eval |= (_asl_global.master_filter & (EVAL_SEND_ASL | EVAL_SEND_TRACE));
528 eval |= EVAL_TUNNEL;
529
530 if ((_asl_global.master_filter & EVAL_LEVEL_MASK) != 0) filter = _asl_global.proc_filter & EVAL_LEVEL_MASK;
531 }
532
533 if (_asl_global.proc_filter & EVAL_ACTIVE)
534 {
535 /* clear bits and set according to proc */
536 eval &= ~(EVAL_SEND_ASL | EVAL_SEND_TRACE | EVAL_TEXT_FILE);
537 eval |= (_asl_global.proc_filter & (EVAL_SEND_ASL | EVAL_SEND_TRACE | EVAL_TEXT_FILE));
538 eval |= EVAL_TUNNEL;
539
540 if ((_asl_global.proc_filter & EVAL_LEVEL_MASK) != 0) filter = _asl_global.proc_filter & EVAL_LEVEL_MASK;
541 }
542
543 pthread_mutex_unlock(&_asl_global.lock);
544 }
545
546 lmask = ASL_FILTER_MASK(level);
547 if ((filter != 0) && ((filter & lmask) == 0)) eval &= ~EVAL_SEND_ASL;
548 if (asl->out_count > 0) eval |= EVAL_TEXT_FILE;
549
550 /* don't send MessageTracer messages to Activity Tracing */
551 val = NULL;
552 if ((asl_msg_lookup(msg, ASL_KEY_MESSAGETRACER, &val, NULL) == 0) && (val != NULL)) eval &= ~EVAL_SEND_TRACE;
553
554 /* don't send PowerManagement messages to Activity Tracing */
555 val = NULL;
556 if ((asl_msg_lookup(msg, ASL_KEY_POWERMANAGEMENT, &val, NULL) == 0) && (val != NULL)) eval &= ~EVAL_SEND_TRACE;
557
558 /* don't send control messages to Activity Tracing */
559 val = NULL;
560 if ((asl_msg_lookup(msg, ASL_KEY_OPTION, &val, NULL) == 0) && (val != NULL)) eval &= ~EVAL_SEND_TRACE;
561
562 /* don't send lastlog/utmp messages to Activity Tracing */
563 val = NULL;
564 if ((asl_msg_lookup(msg, ASL_KEY_FACILITY, &val, NULL) == 0) && (val != NULL) && (!strcmp(val, ASL_KEY_LASTLOG))) eval &= ~EVAL_SEND_TRACE;
565
566 /* don't send CFLog messages to Activity Tracing */
567 val = NULL;
568 if ((asl_msg_lookup(msg, ASL_KEY_CFLOG_LOCAL_TIME, &val, NULL) == 0) && (val != NULL)) eval &= ~EVAL_SEND_TRACE;
569
570 return eval;
571 }
572
573 /*
574 * _asl_lib_vlog_text
575 * Internal routine used by asl_vlog.
576 * msg: an asl messsage
577 * eval: log level and send flags for the message
578 * format: A formating string
579 * ap: va_list for the format
580 * returns 0 for success, non-zero for failure
581 */
582
583 __private_extern__ ASL_STATUS
584 _asl_lib_vlog_text(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *format, va_list ap)
585 {
586 int saved_errno = errno;
587 int status;
588 char *str, *fmt, estr[NL_TEXTMAX];
589 uint32_t i, len, elen, expand;
590
591 if (format == NULL) return ASL_STATUS_INVALID_ARG;
592
593 /* insert strerror for %m */
594 len = 0;
595 elen = 0;
596
597 expand = 0;
598 for (i = 0; format[i] != '\0'; i++)
599 {
600 if (format[i] == '%')
601 {
602 if (format[i+1] == '\0') len++;
603 else if (format[i+1] == 'm')
604 {
605 expand = 1;
606 strerror_r(saved_errno, estr, sizeof(estr));
607 elen = strlen(estr);
608 len += elen;
609 i++;
610 }
611 else
612 {
613 len += 2;
614 i++;
615 }
616 }
617 else len++;
618 }
619
620 fmt = (char *)format;
621
622 if (expand != 0)
623 {
624 fmt = malloc(len + 1);
625 if (fmt == NULL) return ASL_STATUS_NO_MEMORY;
626
627 len = 0;
628
629 for (i = 0; format[i] != '\0'; i++)
630 {
631 if (format[i] == '%')
632 {
633 if (format[i+1] == '\0')
634 {
635 }
636 else if ((format[i+1] == 'm') && (elen != 0))
637 {
638 memcpy(fmt+len, estr, elen);
639 len += elen;
640 i++;
641 }
642 else
643 {
644 fmt[len++] = format[i++];
645 fmt[len++] = format[i];
646 }
647 }
648 else fmt[len++] = format[i];
649 }
650
651 fmt[len] = '\0';
652 }
653
654 str = NULL;
655 vasprintf(&str, fmt, ap);
656 if (expand != 0) free(fmt);
657
658 if (str == NULL) return ASL_STATUS_NO_MEMORY;
659
660 status = _asl_send_message_text(NULL, NULL, obj, eval, (asl_msg_t *)msg, str, true);
661 free(str);
662
663 return status;
664 }
665
666 /*
667 * _asl_lib_vlog
668 * Internal routine used by asl_vlog.
669 * msg: an asl messsage
670 * eval: log level and send flags for the message
671 * format: A formating string
672 * ap: va_list for the format
673 * returns 0 for success, non-zero for failure
674 */
675 __private_extern__ ASL_STATUS
676 _asl_lib_vlog(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *format, va_list ap)
677 {
678 int saved_errno = errno;
679 int status;
680 char *str, *fmt, estr[NL_TEXTMAX];
681 uint32_t i, len, elen, expand;
682
683 if (format == NULL) return ASL_STATUS_INVALID_ARG;
684
685 /* insert strerror for %m */
686 len = 0;
687 elen = 0;
688
689 expand = 0;
690 for (i = 0; format[i] != '\0'; i++)
691 {
692 if (format[i] == '%')
693 {
694 if (format[i+1] == '\0') len++;
695 else if (format[i+1] == 'm')
696 {
697 expand = 1;
698 strerror_r(saved_errno, estr, sizeof(estr));
699 elen = strlen(estr);
700 len += elen;
701 i++;
702 }
703 else
704 {
705 len += 2;
706 i++;
707 }
708 }
709 else len++;
710 }
711
712 fmt = (char *)format;
713
714 if (expand != 0)
715 {
716 fmt = malloc(len + 1);
717 if (fmt == NULL) return ASL_STATUS_NO_MEMORY;
718
719 len = 0;
720
721 for (i = 0; format[i] != '\0'; i++)
722 {
723 if (format[i] == '%')
724 {
725 if (format[i+1] == '\0')
726 {
727 }
728 else if ((format[i+1] == 'm') && (elen != 0))
729 {
730 memcpy(fmt+len, estr, elen);
731 len += elen;
732 i++;
733 }
734 else
735 {
736 fmt[len++] = format[i++];
737 fmt[len++] = format[i];
738 }
739 }
740 else fmt[len++] = format[i];
741 }
742
743 fmt[len] = '\0';
744 }
745
746 str = NULL;
747 vasprintf(&str, fmt, ap);
748 if (expand != 0) free(fmt);
749
750 if (str == NULL) return ASL_STATUS_NO_MEMORY;
751
752 status = _asl_send_message(obj, eval, (asl_msg_t *)msg, str);
753 free(str);
754
755 return status;
756 }
757
758 /*
759 * asl_vlog
760 * Similar to asl_log, but take a va_list instead of a list of arguments.
761 * msg: an asl message
762 * level: the log level of the associated message
763 * format: A formating string
764 * ap: va_list for the format
765 * returns 0 for success, non-zero for failure
766 */
767 int
768 asl_vlog(asl_object_t client, asl_object_t msg, int level, const char *format, va_list ap)
769 {
770 ASL_STATUS status = ASL_STATUS_OK;
771 uint32_t eval = _asl_evaluate_send(client, msg, level);
772 void *addr = __builtin_return_address(0);
773
774 if ((eval & EVAL_SEND_TRACE) && os_log_shim_enabled(addr))
775 {
776 va_list ap_copy;
777 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
778 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
779 os_log_type_t type = shim_asl_to_log_type[level];
780
781 va_copy(ap_copy, ap);
782 os_log_with_args(OS_LOG_DEFAULT, type, format, ap_copy, addr);
783 va_end(ap_copy);
784
785 if (eval & EVAL_TEXT_FILE)
786 {
787 status = _asl_lib_vlog_text(client, eval, msg, format, ap);
788 }
789 }
790 else if (eval & EVAL_ASL)
791 {
792 status = _asl_lib_vlog(client, eval, msg, format, ap);
793 }
794
795 return (status == ASL_STATUS_OK) ? 0 : -1;
796 }
797
798 /*
799 * _asl_lib_log
800 * SPI used by legacy (non-shim) ASL_PREFILTER_LOG. Converts format arguments to a va_list and
801 * forwards the call to _asl_lib_vlog.
802 * msg: an asl message
803 * eval: log level and send flags for the message
804 * format: A formating string
805 * ... args for format
806 * returns 0 for success, non-zero for failure
807 */
808 int
809 _asl_lib_log(asl_object_t client, uint32_t eval, asl_object_t msg, const char *format, ...)
810 {
811 int status = 0;
812
813 if (eval & EVAL_ASL)
814 {
815 va_list ap;
816
817 va_start(ap, format);
818 status = _asl_lib_vlog(client, eval, msg, format, ap);
819 va_end(ap);
820 }
821
822 return status;
823 }
824
825 /*
826 * asl_log
827 * Processes an ASL log message.
828 * msg: an asl message
829 * level: the log level of the associated message
830 * format: A formating string
831 * ... args for format
832 * returns 0 for success, non-zero for failure
833 */
834 int
835 asl_log(asl_object_t client, asl_object_t msg, int level, const char *format, ...)
836 {
837 ASL_STATUS status = ASL_STATUS_OK;
838 uint32_t eval = _asl_evaluate_send(client, msg, level);
839 void *addr = __builtin_return_address(0);
840
841 if ((eval & EVAL_SEND_TRACE) && os_log_shim_enabled(addr))
842 {
843 va_list ap;
844 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
845 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
846 os_log_type_t type = shim_asl_to_log_type[level];
847
848 va_start(ap, format);
849 os_log_with_args(OS_LOG_DEFAULT, type, format, ap, addr);
850 va_end(ap);
851
852 if (eval & EVAL_TEXT_FILE)
853 {
854 va_list ap;
855 va_start(ap, format);
856 status = _asl_lib_vlog_text(client, eval, msg, format, ap);
857 va_end(ap);
858 }
859 }
860 else if (eval & EVAL_ASL)
861 {
862 va_list ap;
863 va_start(ap, format);
864 status = _asl_lib_vlog(client, eval, msg, format, ap);
865 va_end(ap);
866 }
867
868 return (status == ASL_STATUS_OK) ? 0 : -1;
869 }
870
871 /*
872 * asl_log_message
873 * Like asl_log, supplies NULL client and msg.
874 * level: the log level of the associated message
875 * format: A formating string
876 * ... args for format
877 * returns 0 for success, non-zero for failure
878 */
879 int
880 asl_log_message(int level, const char *format, ...)
881 {
882 ASL_STATUS status = ASL_STATUS_OK;
883 uint32_t eval = _asl_evaluate_send(NULL, NULL, level);
884 void *addr = __builtin_return_address(0);
885
886 if ((eval & EVAL_SEND_TRACE) && os_log_shim_enabled(addr))
887 {
888 va_list ap;
889 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
890 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
891 os_log_type_t type = shim_asl_to_log_type[level];
892
893 va_start(ap, format);
894 os_log_with_args(OS_LOG_DEFAULT, type, format, ap, addr);
895 va_end(ap);
896
897 if (eval & EVAL_TEXT_FILE)
898 {
899 va_list ap;
900 va_start(ap, format);
901 status = _asl_lib_vlog_text(NULL, eval, NULL, format, ap);
902 va_end(ap);
903 }
904 }
905 else if (eval & EVAL_ASL)
906 {
907 va_list ap;
908 va_start(ap, format);
909 status = _asl_lib_vlog(NULL, eval, NULL, format, ap);
910 va_end(ap);
911 }
912
913 return (status == ASL_STATUS_OK) ? 0 : -1;
914 }
915
916 /*
917 * asl_get_filter: gets the values for the local, master, and remote filters,
918 * and indicates which one is active.
919 */
920 int
921 asl_get_filter(asl_object_t client, int *local, int *master, int *remote, int *active)
922 {
923 asl_client_t *asl, *asl_default;
924 int l, m, r, x;
925 int status, check;
926 uint64_t v64;
927
928 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1;
929
930 l = 0;
931 m = 0;
932 r = 0;
933 x = 0;
934
935 asl_default = _asl_open_default();
936
937 asl = (asl_client_t *)client;
938 if (asl == NULL) asl = asl_default;
939 if (asl != NULL) l = asl->filter & EVAL_LEVEL_MASK;
940
941 if ((asl_default != NULL) && (!(asl_default->options & ASL_OPT_NO_REMOTE)))
942 {
943 pthread_mutex_lock(&_asl_global.lock);
944
945 if (_asl_global.rc_change_token >= 0)
946 {
947 /* initialize or re-check process-specific and master filters */
948 check = 0;
949 status = notify_check(_asl_global.rc_change_token, &check);
950 if ((status == NOTIFY_STATUS_OK) && (check != 0))
951 {
952 if (_asl_global.master_token >= 0)
953 {
954 v64 = 0;
955 status = notify_get_state(_asl_global.master_token, &v64);
956 if (status == NOTIFY_STATUS_OK) _asl_global.master_filter = v64;
957 }
958
959 if (_asl_global.notify_token >= 0)
960 {
961 v64 = 0;
962 status = notify_get_state(_asl_global.notify_token, &v64);
963 if (status == NOTIFY_STATUS_OK) _asl_global.proc_filter = v64;
964 }
965 }
966 }
967
968 m = _asl_global.master_filter;
969 if (m != 0) x = 1;
970
971 r = _asl_global.proc_filter;
972 if (r != 0) x = 2;
973
974 pthread_mutex_unlock(&_asl_global.lock);
975 }
976
977 if (local != NULL) *local = l;
978 if (master != NULL) *master = m;
979 if (remote != NULL) *remote = r;
980 if (active != NULL) *active = x;
981
982 return 0;
983 }
984
985 /* SPI for SHIM control */
986 uint32_t
987 asl_set_local_control(asl_object_t client, uint32_t filter)
988 {
989 asl_client_t *asl = (asl_client_t *)client;
990 if (asl == NULL)
991 {
992 asl = _asl_open_default();
993 if (asl == NULL) return UINT32_MAX;
994 }
995 else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX;
996
997 return asl_client_set_control(asl, filter);
998 }
999
1000 uint32_t
1001 asl_get_local_control(asl_object_t client)
1002 {
1003 asl_client_t *asl = (asl_client_t *)client;
1004 if (asl == NULL)
1005 {
1006 asl = _asl_open_default();
1007 if (asl == NULL) return UINT32_MAX;
1008 }
1009 else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX;
1010
1011 return asl_client_get_control(asl);
1012 }
1013
1014 /*
1015 * Sets PID and OSActivityID values in a new message.
1016 * Also sets Level, Time, TimeNanoSec, Sender, Facility and Message if provided.
1017 */
1018 asl_msg_t *
1019 asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const char *sstr, const char *fstr, const char *mstr)
1020 {
1021 char aux_val[64];
1022 asl_msg_t *aux;
1023 int status;
1024 unsigned int osacount = 1;
1025 os_activity_t osaid = 0;
1026
1027 aux = asl_msg_new(ASL_TYPE_MSG);
1028 if (aux == NULL) return NULL;
1029
1030 /* Level */
1031 if (level <= 7) asl_msg_set_key_val(aux, ASL_KEY_LEVEL, level_to_number_string[level]);
1032
1033 /* Time and TimeNanoSec */
1034 if (tv != NULL)
1035 {
1036 snprintf(aux_val, sizeof(aux_val), "%llu", (unsigned long long) tv->tv_sec);
1037 asl_msg_set_key_val(aux, ASL_KEY_TIME, aux_val);
1038
1039 snprintf(aux_val, sizeof(aux_val), "%d", tv->tv_usec * 1000);
1040 asl_msg_set_key_val(aux, ASL_KEY_TIME_NSEC, aux_val);
1041 }
1042
1043 /* Message */
1044 if (mstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_MSG, mstr);
1045
1046 /* PID */
1047 snprintf(aux_val, sizeof(aux_val), "%u", getpid());
1048 asl_msg_set_key_val(aux, ASL_KEY_PID, aux_val);
1049
1050 /* OSActivityID */
1051 if (os_activity_get_active(&osaid, &osacount) == 1)
1052 {
1053 snprintf(aux_val, sizeof(aux_val), "0x%016llx", (uint64_t)osaid);
1054 asl_msg_set_key_val(aux, ASL_KEY_OS_ACTIVITY_ID, aux_val);
1055 }
1056
1057 /* Sender */
1058 if ((sstr == NULL) && (asl != NULL))
1059 {
1060 /* See if the client has a value for ASL_KEY_SENDER */
1061 status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_SENDER, &sstr, NULL);
1062 if ((status != 0) || (sstr == NULL))
1063 {
1064 sstr = NULL;
1065
1066 /* See if the global cache has a value for ASL_KEY_SENDER */
1067 if (_asl_global.sender == NULL)
1068 {
1069 /* Get the process name with _NSGetArgv */
1070 char *name = *(*_NSGetArgv());
1071 if (name != NULL)
1072 {
1073 char *x = strrchr(name, '/');
1074 if (x != NULL) x++;
1075 else x = name;
1076
1077 /* Set the cache value */
1078 pthread_mutex_lock(&_asl_global.lock);
1079 if (_asl_global.sender == NULL) _asl_global.sender = strdup(x);
1080 pthread_mutex_unlock(&_asl_global.lock);
1081 }
1082 }
1083
1084 if (_asl_global.sender != NULL) asl_msg_set_key_val(aux, ASL_KEY_SENDER, _asl_global.sender);
1085 else asl_msg_set_key_val(aux, ASL_KEY_SENDER, "Unknown");
1086 }
1087 }
1088
1089 if (sstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_SENDER, sstr);
1090
1091 /* Facility */
1092 if ((fstr == NULL) && (asl != NULL))
1093 {
1094 status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_FACILITY, &fstr, NULL);
1095 if (status != 0) fstr = NULL;
1096 }
1097
1098 if (fstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_FACILITY, fstr);
1099
1100 return aux;
1101 }
1102
1103 #ifdef NOTDEF
1104 /*
1105 * Possibly useful someday...
1106 */
1107 asl_msg_t *
1108 asl_prepared_message(asl_client_t *asl, asl_msg_t *msg)
1109 {
1110 uint32_t i, len, level, outstatus;
1111 const char *val, *sstr, *fstr;
1112 struct timeval tval = {0, 0};
1113 int status;
1114 asl_msg_t *out;
1115
1116 if (asl == NULL)
1117 {
1118 asl = _asl_open_default();
1119 if (asl == NULL) return NULL;
1120 }
1121
1122 status = gettimeofday(&tval, NULL);
1123 if (status != 0)
1124 {
1125 time_t tick = time(NULL);
1126 tval.tv_sec = tick;
1127 tval.tv_usec = 0;
1128 }
1129
1130 val = NULL;
1131 status = asl_msg_lookup(msg, ASL_KEY_LEVEL, &val, NULL);
1132 if (status != 0) val = NULL;
1133
1134 level = ASL_LEVEL_DEBUG;
1135 if (val != NULL) level = atoi(val);
1136 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
1137
1138 sstr = NULL;
1139 status = asl_msg_lookup(msg, ASL_KEY_SENDER, &sstr, NULL);
1140 if (status != 0) sstr = NULL;
1141
1142 fstr = NULL;
1143 status = asl_msg_lookup(msg, ASL_KEY_FACILITY, &fstr, NULL);
1144 if (status != 0) fstr = NULL;
1145
1146 out = asl_base_msg(asl, level, &tval, sstr, fstr, NULL);
1147 out = asl_msg_merge(out, msg);
1148
1149 return out;
1150 }
1151 #endif
1152
1153 static void
1154 _asl_set_option(asl_msg_t *msg, const char *opt)
1155 {
1156 const char *val = NULL;
1157 uint32_t status;
1158
1159 if (msg == NULL) return;
1160 if (opt == NULL) return;
1161
1162 status = asl_msg_lookup(msg, ASL_KEY_OPTION, &val, NULL);
1163 if ((status != 0) || (val == NULL))
1164 {
1165 asl_msg_set_key_val(msg, ASL_KEY_OPTION, opt);
1166 }
1167 else
1168 {
1169 char *option = NULL;
1170 asprintf(&option, "%s %s", opt, val);
1171 asl_msg_set_key_val(msg, ASL_KEY_OPTION, option);
1172 free(option);
1173 }
1174 }
1175
1176 static ASL_STATUS
1177 _asl_send_message_text(asl_client_t *asl, asl_msg_t *sendmsg, asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstr, bool shimmed)
1178 {
1179 int status;
1180 uint32_t level, lmask;
1181 asl_msg_t *release_sendmsg = NULL;
1182
1183 if (asl == NULL) {
1184 if (obj == NULL) {
1185 asl = _asl_open_default();
1186 if (asl == NULL) return ASL_STATUS_FAILED;
1187 } else {
1188 uint32_t objtype = asl_get_type(obj);
1189 if (objtype == ASL_TYPE_CLIENT) asl = (asl_client_t *)obj;
1190 }
1191 }
1192
1193 level = eval & EVAL_LEVEL_MASK;
1194 if (level > 7) level = 7;
1195 lmask = ASL_FILTER_MASK(level);
1196
1197 if (sendmsg == NULL) {
1198 struct timeval tval = {0, 0};
1199 const char *sstr, *fstr;
1200
1201 status = gettimeofday(&tval, NULL);
1202 if (status != 0) {
1203 time_t tick = time(NULL);
1204 tval.tv_sec = tick;
1205 tval.tv_usec = 0;
1206 }
1207
1208 sstr = NULL;
1209 status = asl_msg_lookup(msg, ASL_KEY_SENDER, &sstr, NULL);
1210 if (status != 0) {
1211 sstr = NULL;
1212 }
1213
1214 fstr = NULL;
1215 status = asl_msg_lookup(msg, ASL_KEY_FACILITY, &fstr, NULL);
1216 if (status != 0) {
1217 fstr = NULL;
1218 }
1219 sendmsg = asl_base_msg(asl, level, &tval, sstr, fstr, mstr);
1220 if (sendmsg == NULL) {
1221 return ASL_STATUS_FAILED;
1222 }
1223
1224 release_sendmsg = sendmsg = asl_msg_merge(sendmsg, msg);
1225 }
1226
1227 /* write to file descriptors */
1228 for (uint32_t i = 0; i < asl->out_count; i++) {
1229 if (shimmed) {
1230 if ((asl->out_list[i].fd != STDOUT_FILENO) && (asl->out_list[i].fd != STDERR_FILENO)) {
1231 continue; // new logging only support stdout/stderr
1232 }
1233 }
1234
1235 if ((asl->out_list[i].fd >= 0) && (asl->out_list[i].filter != 0) && ((asl->out_list[i].filter & lmask) != 0)) {
1236 char *str;
1237
1238 uint32_t len = 0;
1239 str = asl_format_message(sendmsg, asl->out_list[i].mfmt, asl->out_list[i].tfmt, asl->out_list[i].encoding, &len);
1240 if (str == NULL) continue;
1241
1242 status = write(asl->out_list[i].fd, str, len - 1);
1243 if (status < 0)
1244 {
1245 /* soft error for fd 2 (stderr) */
1246 if (asl->out_list[i].fd == 2) status = 0;
1247 asl->out_list[i].fd = -1;
1248 } else {
1249 status = 0;
1250 }
1251
1252 free(str);
1253 }
1254 }
1255 if (release_sendmsg) {
1256 asl_msg_release(release_sendmsg);
1257 }
1258
1259 return status;
1260 }
1261
1262 static ASL_STATUS
1263 _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstr)
1264 {
1265 uint32_t len, level, lmask, outstatus, objtype;
1266 const char *sstr, *fstr;
1267 struct timeval tval = {0, 0};
1268 int status;
1269 int use_global_lock = 0;
1270 kern_return_t kstatus;
1271 asl_msg_t *sendmsg;
1272 asl_msg_t *qd_msg = NULL;
1273 asl_client_t *asl = NULL;
1274 static dispatch_once_t noquota_once;
1275 __block int log_quota_msg = 0;
1276
1277 if ((eval & EVAL_ASL) == 0) return ASL_STATUS_OK;
1278
1279 if (obj == NULL)
1280 {
1281 asl = _asl_open_default();
1282 if (asl == NULL) return ASL_STATUS_FAILED;
1283 use_global_lock = 1;
1284 objtype = ASL_TYPE_CLIENT;
1285 }
1286 else
1287 {
1288 objtype = asl_get_type(obj);
1289 if (objtype == ASL_TYPE_CLIENT) asl = (asl_client_t *)obj;
1290 }
1291
1292 level = eval & EVAL_LEVEL_MASK;
1293 if (level > 7) level = 7;
1294 lmask = ASL_FILTER_MASK(level);
1295
1296 if ((objtype == ASL_TYPE_CLIENT) && (asl->aslfile != NULL)) use_global_lock = 1;
1297
1298 status = gettimeofday(&tval, NULL);
1299 if (status != 0)
1300 {
1301 time_t tick = time(NULL);
1302 tval.tv_sec = tick;
1303 tval.tv_usec = 0;
1304 }
1305
1306 sstr = NULL;
1307 status = asl_msg_lookup(msg, ASL_KEY_SENDER, &sstr, NULL);
1308 if (status != 0) sstr = NULL;
1309
1310 fstr = NULL;
1311 status = asl_msg_lookup(msg, ASL_KEY_FACILITY, &fstr, NULL);
1312 if (status != 0) fstr = NULL;
1313
1314 sendmsg = asl_base_msg(asl, level, &tval, sstr, fstr, mstr);
1315 if (sendmsg == NULL) return ASL_STATUS_FAILED;
1316
1317 /* Set "ASLOption store" if tunneling */
1318 if (eval & EVAL_TUNNEL) _asl_set_option(sendmsg, ASL_OPT_STORE);
1319
1320 outstatus = -1;
1321
1322 if (use_global_lock != 0) pthread_mutex_lock(&_asl_global.lock);
1323
1324 sendmsg = asl_msg_merge(sendmsg, msg);
1325
1326 if (objtype != ASL_TYPE_CLIENT)
1327 {
1328 asl_append(obj, (asl_object_t)sendmsg);
1329 asl_msg_release(sendmsg);
1330 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1331 return ASL_STATUS_OK;
1332 }
1333
1334 /*
1335 * If there is an aslfile this is a stand-alone file client.
1336 * Just save to the file.
1337 */
1338 if (asl->aslfile != NULL)
1339 {
1340 outstatus = ASL_STATUS_FAILED;
1341
1342 if (sendmsg != NULL)
1343 {
1344 outstatus = asl_file_save(asl->aslfile, sendmsg, &(asl->aslfileid));
1345 asl->aslfileid++;
1346 }
1347
1348 asl_msg_release(sendmsg);
1349
1350 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1351 return outstatus;
1352 }
1353
1354 _asl_global_init(0);
1355 outstatus = 0;
1356
1357 /*
1358 * ASL message quota
1359 * Quotas are disabled if:
1360 * - a remote control filter is in place (EVAL_TUNNEL)
1361 * - Environment variable ASL_QUOTA_DISABLED == 1
1362 * - /etc/asl/.noquota existed at the time that the process started
1363 *
1364 * We just check /etc/asl/.noquota once, since it would be
1365 * expensive to stat() for every log message.
1366 *
1367 * We only check the Environment variable once, since getenv() is
1368 * not thread safe. If someone is changing the environment,
1369 * this can crash.
1370 */
1371
1372 dispatch_once(&noquota_once, ^{
1373 struct stat sb;
1374 memset(&sb, 0, sizeof(struct stat));
1375
1376 int save_errno = errno;
1377
1378 if (stat(NOQUOTA_FILE_PATH, &sb) == 0)
1379 {
1380 _asl_global.quota = UINT32_MAX;
1381 }
1382 else
1383 {
1384 const char *qtest = getenv(NOQUOTA_ENV);
1385 if ((qtest != NULL) && (!strcmp(qtest, "1")))
1386 {
1387 _asl_global.quota = UINT32_MAX;
1388 log_quota_msg = 1;
1389 }
1390 }
1391
1392 /* reset errno since we want stat() to fail silently */
1393 errno = save_errno;
1394 });
1395
1396 if (log_quota_msg != 0)
1397 {
1398 qd_msg = asl_base_msg(asl, QUOTA_LEVEL, &tval, sstr, fstr, QUOTA_DISABLED_MSG);
1399 asl_msg_set_key_val(qd_msg, ASL_KEY_OPTION, ASL_OPT_STORE);
1400 }
1401
1402 if (((eval & EVAL_TUNNEL) == 0) && (_asl_global.quota != UINT32_MAX))
1403 {
1404 time_t last_send = _asl_global.last_send;
1405 time_t last_oq = _asl_global.last_oq_msg;
1406 uint32_t qcurr = _asl_global.quota;
1407 time_t delta;
1408 uint32_t qinc, qnew;
1409
1410 qnew = qcurr;
1411
1412 /* add QUOTA_MPS to quota for each second we've been idle */
1413 if (tval.tv_sec > last_send)
1414 {
1415 delta = tval.tv_sec - last_send;
1416
1417 qinc = QUOTA_MPH;
1418 if (delta < (QUOTA_MPH / QUOTA_MPS)) qinc = delta * QUOTA_MPS;
1419
1420 qnew = MIN(QUOTA_MPH, qcurr + qinc);
1421 OSAtomicCompareAndSwapLongBarrier(last_send, tval.tv_sec, (long *)&_asl_global.last_send);
1422 }
1423
1424 if (qnew == 0)
1425 {
1426 if ((tval.tv_sec - last_oq) > QUOTA_MSG_INTERVAL)
1427 {
1428 eval |= EVAL_QUOTA;
1429 OSAtomicCompareAndSwapLongBarrier(last_oq, tval.tv_sec, (long *)&_asl_global.last_oq_msg);
1430 }
1431 else
1432 {
1433 eval &= ~EVAL_SEND_ASL;
1434 }
1435 }
1436 else
1437 {
1438 OSAtomicCompareAndSwap32Barrier(qcurr, qnew - 1, (int32_t *)&_asl_global.quota);
1439 }
1440 }
1441
1442 if ((_asl_global.server_port != MACH_PORT_NULL) && (eval & EVAL_SEND_ASL))
1443 {
1444 asl_string_t *send_str;
1445 const char *str;
1446 size_t vmsize;
1447
1448 if (eval & EVAL_QUOTA)
1449 {
1450 asl_msg_set_key_val(sendmsg, ASL_KEY_LEVEL, QUOTA_LEVEL_STR);
1451 asl_msg_set_key_val(sendmsg, ASL_KEY_MSG, QUOTA_MSG);
1452 }
1453
1454 if (qd_msg != NULL)
1455 {
1456 send_str = asl_msg_to_string_raw(ASL_STRING_MIG, qd_msg, "raw");
1457 len = asl_string_length(send_str);
1458 vmsize = asl_string_allocated_size(send_str);
1459 str = asl_string_release_return_bytes(send_str);
1460 if (len != 0)
1461 {
1462 kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)str, len);
1463 if (kstatus != KERN_SUCCESS)
1464 {
1465 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1466 }
1467 }
1468 else if (vmsize != 0)
1469 {
1470 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1471 }
1472 asl_msg_release(qd_msg);
1473 }
1474
1475 send_str = asl_msg_to_string_raw(ASL_STRING_MIG, sendmsg, "raw");
1476 len = asl_string_length(send_str);
1477
1478 if (len > LIBASL_MAX_MSG_SIZE)
1479 {
1480 char tmp[256];
1481
1482 snprintf(tmp, sizeof(tmp), SIZE_LIMIT_MSG, len, LIBASL_MAX_MSG_SIZE);
1483 asl_msg_t *limitmsg = asl_base_msg(asl, ASL_LEVEL_CRIT, &tval, sstr, fstr, tmp);
1484
1485 asl_string_release(send_str);
1486 len = 0;
1487
1488 if (limitmsg != NULL)
1489 {
1490 /* Set "ASLOption store" if tunneling */
1491 if (eval & EVAL_TUNNEL) _asl_set_option(limitmsg, ASL_OPT_STORE);
1492
1493 send_str = asl_msg_to_string_raw(ASL_STRING_MIG, limitmsg, "raw");
1494 len = asl_string_length(send_str);
1495 asl_msg_release(limitmsg);
1496 }
1497 }
1498
1499 vmsize = asl_string_allocated_size(send_str);
1500 str = asl_string_release_return_bytes(send_str);
1501
1502 if (len != 0)
1503 {
1504 /* send a mach message to syslogd */
1505 kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)str, len);
1506 if (kstatus != KERN_SUCCESS)
1507 {
1508 /* retry once if the call failed */
1509 _asl_global_init(1);
1510 kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)str, len);
1511 if (kstatus != KERN_SUCCESS)
1512 {
1513 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1514 outstatus = -1;
1515 }
1516 }
1517 }
1518 else if (vmsize >0) vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1519 }
1520
1521 if ((sendmsg != NULL) && (asl->out_count > 0))
1522 {
1523 status = _asl_send_message_text(asl, sendmsg, obj, eval, msg, mstr, false);
1524 }
1525
1526 asl_msg_release(sendmsg);
1527
1528 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1529
1530 return outstatus;
1531 }
1532
1533 static void
1534 os_log_with_args_wrapper(void *addr, int level, const char *format, ...)
1535 {
1536 va_list ap;
1537 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
1538 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
1539 os_log_type_t type = shim_asl_to_log_type[level];
1540
1541 va_start(ap, format);
1542 os_log_with_args(OS_LOG_DEFAULT, type, format, ap, addr);
1543 va_end(ap);
1544 }
1545
1546 /*
1547 * asl_send: send a message
1548 * This routine may be used instead of asl_log() or asl_vlog() if asl_set()
1549 * has been used to set all of a message's attributes.
1550 * eval: hints about what to do with the message
1551 * msg: an asl message
1552 * returns 0 for success, non-zero for failure
1553 */
1554 __private_extern__ ASL_STATUS
1555 asl_client_internal_send(asl_object_t obj, asl_object_t msg, void *addr)
1556 {
1557 int status = ASL_STATUS_OK;
1558 uint32_t eval = _asl_evaluate_send(obj, msg, -1);
1559
1560 const char *message = asl_msg_get_val_for_key((asl_msg_t *)msg, ASL_KEY_MSG);
1561
1562 if ((eval & EVAL_SEND_TRACE) && message && message[0] && os_log_shim_enabled(addr))
1563 {
1564 int level = ASL_LEVEL_DEBUG;
1565 const char *lval = asl_msg_get_val_for_key((asl_msg_t *)msg, ASL_KEY_LEVEL);
1566 if (lval != NULL) level = atoi(lval);
1567
1568 /*
1569 * If the return address and the format string are from different
1570 * binaries, os_log_with_args will not record the return address.
1571 * Work around this by passing a dynamic format string.
1572 */
1573 char dynamic_format[] = "%s";
1574 os_log_with_args_wrapper(addr, level, dynamic_format, message);
1575
1576 if (eval & EVAL_TEXT_FILE)
1577 {
1578 status = _asl_send_message_text(NULL, NULL, obj, eval, (asl_msg_t *)msg, NULL, true);
1579 }
1580 }
1581 else if (eval & EVAL_ASL)
1582 {
1583 status = _asl_send_message(obj, eval, (asl_msg_t *)msg, NULL);
1584 }
1585
1586 return status;
1587 }
1588
1589 #pragma mark -
1590 #pragma mark auxiliary files and URLs
1591
1592 static ASL_STATUS
1593 _asl_aux_save_context(asl_aux_context_t *ctx)
1594 {
1595 if (ctx == NULL) return ASL_STATUS_FAILED;
1596
1597 pthread_mutex_lock(&_asl_global.lock);
1598
1599 _asl_global.aux_ctx = (asl_aux_context_t **)reallocf(_asl_global.aux_ctx, (_asl_global.aux_count + 1) * sizeof(asl_aux_context_t *));
1600 if (_asl_global.aux_ctx == NULL)
1601 {
1602 _asl_global.aux_count = 0;
1603 pthread_mutex_unlock(&_asl_global.lock);
1604 return ASL_STATUS_FAILED;
1605 }
1606
1607 _asl_global.aux_ctx[_asl_global.aux_count++] = ctx;
1608
1609 pthread_mutex_unlock(&_asl_global.lock);
1610
1611 return ASL_STATUS_OK;
1612 }
1613
1614 /*
1615 * Creates an auxiliary file that may be used to save arbitrary data. The ASL message msg
1616 * will be saved at the time that the auxiliary file is created. The message will include
1617 * any keys and values found in msg, and it will include the title and Uniform Type
1618 * Identifier specified. Output parameter out_fd will contain the file descriptor of the
1619 * new auxiliary file.
1620 */
1621 static ASL_STATUS
1622 _asl_auxiliary(asl_msg_t *msg, const char *title, const char *uti, const char *url, int *out_fd)
1623 {
1624 asl_msg_t *aux;
1625 asl_string_t *send_str;
1626 const char *str;
1627 fileport_t fileport;
1628 kern_return_t kstatus;
1629 size_t len, vmsize;
1630 uint32_t newurllen, where;
1631 int status, fd, fdpair[2];
1632 caddr_t newurl;
1633 dispatch_queue_t pipe_q;
1634 dispatch_io_t pipe_channel;
1635 dispatch_semaphore_t sem;
1636
1637 aux = asl_msg_new(ASL_TYPE_MSG);
1638
1639 if (url != NULL) asl_msg_set_key_val(aux, ASL_KEY_AUX_URL, url);
1640 if (title != NULL) asl_msg_set_key_val(aux, ASL_KEY_AUX_TITLE, title);
1641 if (uti == NULL) asl_msg_set_key_val(aux, ASL_KEY_AUX_UTI, "public.data");
1642 else asl_msg_set_key_val(aux, ASL_KEY_AUX_UTI, uti);
1643
1644 aux = asl_msg_merge(aux, msg);
1645
1646 /* if (out_fd == NULL), this is from asl_log_auxiliary_location */
1647 if (out_fd == NULL)
1648 {
1649 uint32_t eval = _asl_evaluate_send(NULL, (asl_object_t)aux, -1);
1650 status = _asl_send_message(NULL, eval, aux, NULL);
1651 asl_msg_release(aux);
1652 return status;
1653 }
1654
1655 where = asl_store_location();
1656 if (where == ASL_STORE_LOCATION_MEMORY)
1657 {
1658 /* create a pipe */
1659 asl_aux_context_t *ctx = (asl_aux_context_t *)calloc(1, sizeof(asl_aux_context_t));
1660 if (ctx == NULL) return ASL_STATUS_FAILED;
1661
1662 status = pipe(fdpair);
1663 if (status < 0)
1664 {
1665 free(ctx);
1666 return ASL_STATUS_FAILED;
1667 }
1668
1669 /* give read end to dispatch_io_read */
1670 fd = fdpair[0];
1671 sem = dispatch_semaphore_create(0);
1672 ctx->sem = sem;
1673 ctx->fd = fdpair[1];
1674
1675 status = _asl_aux_save_context(ctx);
1676 if (status != ASL_STATUS_OK)
1677 {
1678 close(fdpair[0]);
1679 close(fdpair[1]);
1680 dispatch_release(sem);
1681 free(ctx);
1682 return ASL_STATUS_FAILED;
1683 }
1684
1685 pipe_q = dispatch_queue_create("ASL_AUX_PIPE_Q", NULL);
1686 pipe_channel = dispatch_io_create(DISPATCH_IO_STREAM, fd, pipe_q, ^(int err){
1687 close(fd);
1688 });
1689
1690 *out_fd = fdpair[1];
1691
1692 dispatch_io_set_low_water(pipe_channel, SIZE_MAX);
1693
1694 dispatch_io_read(pipe_channel, 0, SIZE_MAX, pipe_q, ^(bool done, dispatch_data_t pipedata, int err){
1695 if (err == 0)
1696 {
1697 size_t len = dispatch_data_get_size(pipedata);
1698 if (len > 0)
1699 {
1700 const char *bytes = NULL;
1701 char *encoded;
1702 uint32_t eval;
1703
1704 dispatch_data_t md = dispatch_data_create_map(pipedata, (const void **)&bytes, &len);
1705 encoded = asl_core_encode_buffer(bytes, len);
1706 asl_msg_set_key_val(aux, ASL_KEY_AUX_DATA, encoded);
1707 free(encoded);
1708 eval = _asl_evaluate_send(NULL, (asl_object_t)aux, -1);
1709 _asl_send_message(NULL, eval, aux, NULL);
1710 asl_msg_release(aux);
1711 dispatch_release(md);
1712 }
1713 }
1714
1715 if (done)
1716 {
1717 dispatch_semaphore_signal(sem);
1718 dispatch_release(pipe_channel);
1719 dispatch_release(pipe_q);
1720 }
1721 });
1722
1723 return ASL_STATUS_OK;
1724 }
1725
1726 _asl_global_init(0);
1727 if (_asl_global.server_port == MACH_PORT_NULL) return ASL_STATUS_FAILED;
1728
1729 send_str = asl_msg_to_string_raw(ASL_STRING_MIG, aux, "raw");
1730 len = asl_string_length(send_str);
1731 vmsize = asl_string_allocated_size(send_str);
1732 str = asl_string_release_return_bytes(send_str);
1733
1734 if (len == 0)
1735 {
1736 asl_msg_release(aux);
1737 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1738 return ASL_STATUS_FAILED;
1739 }
1740
1741 status = 0;
1742 fileport = MACH_PORT_NULL;
1743 status = KERN_SUCCESS;
1744
1745 kstatus = _asl_server_create_aux_link(_asl_global.server_port, (caddr_t)str, len, &fileport, &newurl, &newurllen, &status);
1746 if (kstatus != KERN_SUCCESS)
1747 {
1748 /* retry once if the call failed */
1749 _asl_global_init(1);
1750 kstatus = _asl_server_create_aux_link(_asl_global.server_port, (caddr_t)str, len, &fileport, &newurl, &newurllen, &status);
1751 if (kstatus != KERN_SUCCESS)
1752 {
1753 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1754 asl_msg_release(aux);
1755 return ASL_STATUS_FAILED;
1756 }
1757 }
1758
1759 if (status != 0)
1760 {
1761 asl_msg_release(aux);
1762 return status;
1763 }
1764
1765 if (newurl != NULL)
1766 {
1767 asl_msg_set_key_val(aux, ASL_KEY_AUX_URL, newurl);
1768 vm_deallocate(mach_task_self(), (vm_address_t)newurl, newurllen);
1769 }
1770
1771 if (fileport == MACH_PORT_NULL)
1772 {
1773 asl_msg_release(aux);
1774 return ASL_STATUS_FAILED;
1775 }
1776
1777 fd = fileport_makefd(fileport);
1778 mach_port_deallocate(mach_task_self(), fileport);
1779 if (fd < 0)
1780 {
1781 asl_msg_release(aux);
1782 status = -1;
1783 }
1784 else
1785 {
1786 asl_aux_context_t *ctx = (asl_aux_context_t *)calloc(1, sizeof(asl_aux_context_t));
1787 if (ctx == NULL)
1788 {
1789 status = -1;
1790 }
1791 else
1792 {
1793 *out_fd = fd;
1794
1795 ctx->fd = fd;
1796 ctx->msg = aux;
1797
1798 status = _asl_aux_save_context(ctx);
1799 }
1800 }
1801
1802 return status;
1803 }
1804
1805 int
1806 asl_create_auxiliary_file(asl_object_t msg, const char *title, const char *uti, int *out_fd)
1807 {
1808 if (out_fd == NULL) return -1;
1809
1810 ASL_STATUS status = _asl_auxiliary((asl_msg_t *)msg, title, uti, NULL, out_fd);
1811 return (status == ASL_STATUS_OK) ? 0 : -1;
1812 }
1813
1814 int
1815 asl_log_auxiliary_location(asl_object_t msg, const char *title, const char *uti, const char *url)
1816 {
1817 ASL_STATUS status = _asl_auxiliary((asl_msg_t *)msg, title, uti, url, NULL);
1818 return (status == ASL_STATUS_OK) ? 0 : -1;
1819 }
1820
1821 /*
1822 * Close an auxiliary file.
1823 * Sends the cached auxiliary message to syslogd.
1824 * Returns 0 on success, -1 on error.
1825 */
1826 int
1827 asl_close_auxiliary_file(int fd)
1828 {
1829 int i, j, status;
1830 asl_msg_t *aux_msg;
1831 dispatch_semaphore_t aux_sem = NULL;
1832
1833 pthread_mutex_lock(&(_asl_global.lock));
1834
1835 aux_msg = NULL;
1836 status = -1;
1837
1838 for (i = 0; i < _asl_global.aux_count; i++)
1839 {
1840 if (_asl_global.aux_ctx[i]->fd == fd)
1841 {
1842 status = 0;
1843
1844 aux_msg = _asl_global.aux_ctx[i]->msg;
1845 aux_sem = _asl_global.aux_ctx[i]->sem;
1846
1847 free(_asl_global.aux_ctx[i]);
1848
1849 for (j = i + 1; j < _asl_global.aux_count; i++, j++)
1850 {
1851 _asl_global.aux_ctx[i] = _asl_global.aux_ctx[j];
1852 }
1853
1854 _asl_global.aux_count--;
1855
1856 if (_asl_global.aux_count == 0)
1857 {
1858 free(_asl_global.aux_ctx);
1859 _asl_global.aux_ctx = NULL;
1860 }
1861 else
1862 {
1863 _asl_global.aux_ctx = (asl_aux_context_t **)reallocf(_asl_global.aux_ctx, _asl_global.aux_count * sizeof(asl_aux_context_t *));
1864 if (_asl_global.aux_ctx == NULL)
1865 {
1866 _asl_global.aux_count = 0;
1867 status = -1;
1868 }
1869 }
1870
1871 break;
1872 }
1873 }
1874
1875 pthread_mutex_unlock(&(_asl_global.lock));
1876
1877 close(fd);
1878
1879 if (aux_msg != NULL)
1880 {
1881 uint32_t eval = _asl_evaluate_send(NULL, (asl_object_t)aux_msg, -1);
1882 if (_asl_send_message(NULL, eval, aux_msg, NULL) != ASL_STATUS_OK) status = -1;
1883 asl_msg_release(aux_msg);
1884 }
1885
1886 if (aux_sem != NULL)
1887 {
1888 dispatch_semaphore_wait(aux_sem, DISPATCH_TIME_FOREVER);
1889 dispatch_release(aux_sem);
1890 }
1891
1892 return status;
1893 }
1894
1895 #pragma mark -
1896
1897 asl_msg_t *
1898 _asl_server_control_query(void)
1899 {
1900 asl_msg_list_t *list = NULL;
1901 char *res;
1902 uint32_t len, reslen, status;
1903 uint64_t cmax, qmin;
1904 kern_return_t kstatus;
1905 caddr_t vmstr;
1906 asl_msg_t *m = NULL;
1907 static const char ctlstr[] = "1\nQ [= ASLOption control]\n";
1908
1909 _asl_global_init(0);
1910 if (_asl_global.server_port == MACH_PORT_NULL) return NULL;
1911
1912 len = strlen(ctlstr) + 1;
1913
1914 qmin = 0;
1915 cmax = 0;
1916 res = NULL;
1917 reslen = 0;
1918
1919 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
1920 if (kstatus != KERN_SUCCESS) return NULL;
1921
1922 memmove(vmstr, ctlstr, len);
1923
1924 status = 0;
1925 kstatus = _asl_server_query_2(_asl_global.server_port, vmstr, len, qmin, FETCH_BATCH, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
1926 if (kstatus != KERN_SUCCESS)
1927 {
1928 /* retry once if the call failed */
1929 _asl_global_init(1);
1930 kstatus = _asl_server_query_2(_asl_global.server_port, vmstr, len, qmin, FETCH_BATCH, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
1931 }
1932
1933 list = asl_msg_list_from_string(res);
1934 vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
1935
1936 if (list == NULL) return NULL;
1937 if (list->count > 0) m = asl_msg_retain(list->msg[0]);
1938 asl_msg_list_release(list);
1939 return m;
1940 }
1941
1942 /*
1943 * Returns ASL_STORE_LOCATION_FILE or ASL_STORE_LOCATION_MEMORY
1944 */
1945 int
1946 asl_store_location()
1947 {
1948 kern_return_t kstatus;
1949 char *res;
1950 uint32_t reslen, status;
1951 uint64_t cmax;
1952
1953 _asl_global_init(0);
1954 if (_asl_global.server_port == MACH_PORT_NULL) return ASL_STORE_LOCATION_FILE;
1955
1956 res = NULL;
1957 reslen = 0;
1958 cmax = 0;
1959 status = ASL_STATUS_OK;
1960
1961 kstatus = _asl_server_query_2(_asl_global.server_port, NULL, 0, 0, -1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
1962 if (kstatus != KERN_SUCCESS)
1963 {
1964 /* retry once if the call failed */
1965 _asl_global_init(1);
1966 kstatus = _asl_server_query_2(_asl_global.server_port, NULL, 0, 0, -1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
1967 }
1968
1969 /* res should never be returned, but just to be certain we don't leak VM ... */
1970 if (res != NULL) vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
1971
1972 if (kstatus != KERN_SUCCESS) return ASL_STORE_LOCATION_FILE;
1973 if (status == ASL_STATUS_OK) return ASL_STORE_LOCATION_MEMORY;
1974 return ASL_STORE_LOCATION_FILE;
1975 }
1976
1977 asl_object_t
1978 asl_open_path(const char *path, uint32_t opts)
1979 {
1980 struct stat sb;
1981 asl_file_t *fout = NULL;
1982 asl_store_t *sout = NULL;
1983
1984 if (opts == 0) opts = ASL_OPT_OPEN_READ;
1985
1986 if (opts & ASL_OPT_OPEN_READ)
1987 {
1988 if (path == NULL)
1989 {
1990 if (asl_store_open_read(ASL_PLACE_DATABASE_DEFAULT, &sout) != ASL_STATUS_OK) return NULL;
1991 return (asl_object_t)sout;
1992 }
1993
1994 memset(&sb, 0, sizeof(struct stat));
1995 if (stat(path, &sb) < 0) return NULL;
1996
1997 if (sb.st_mode & S_IFREG)
1998 {
1999 if (asl_file_open_read(path, &fout) != ASL_STATUS_OK) return NULL;
2000 return (asl_object_t)fout;
2001 }
2002 else if (sb.st_mode & S_IFDIR)
2003 {
2004 if (asl_store_open_read(path, &sout) != ASL_STATUS_OK) return NULL;
2005 return (asl_object_t)sout;
2006 }
2007
2008 return NULL;
2009 }
2010 else if (opts & ASL_OPT_OPEN_WRITE)
2011 {
2012 if (path == NULL) return NULL;
2013
2014 memset(&sb, 0, sizeof(struct stat));
2015 if (stat(path, &sb) < 0)
2016 {
2017 if (errno != ENOENT) return NULL;
2018
2019 if (opts & ASL_OPT_CREATE_STORE)
2020 {
2021 if (asl_store_open_write(path, &sout) != ASL_STATUS_OK) return NULL;
2022 return (asl_object_t)sout;
2023 }
2024 else
2025 {
2026 if (asl_file_open_write(path, 0644, geteuid(), getegid(), &fout) != ASL_STATUS_OK) return NULL;
2027 return (asl_object_t)fout;
2028 }
2029 }
2030 else if (sb.st_mode & S_IFREG)
2031 {
2032 if (asl_file_open_write(path, 0644, geteuid(), getegid(), &fout) != ASL_STATUS_OK) return NULL;
2033 return (asl_object_t)fout;
2034 }
2035 else if (sb.st_mode & S_IFDIR)
2036 {
2037 if (asl_store_open_write(path, &sout) != ASL_STATUS_OK) return NULL;
2038 return (asl_object_t)sout;
2039 }
2040 }
2041
2042 return NULL;
2043 }