]> git.saurik.com Git - apple/syslog.git/blob - libsystem_asl.tproj/src/asl.c
syslog-356.70.1.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 CFLog messages to Activity Tracing */
563 val = NULL;
564 if ((asl_msg_lookup(msg, ASL_KEY_CFLOG_LOCAL_TIME, &val, NULL) == 0) && (val != NULL)) eval &= ~EVAL_SEND_TRACE;
565
566 val = NULL;
567 if (((asl_msg_lookup(msg, ASL_KEY_FACILITY, &val, NULL) == 0) && (val != NULL)) ||
568 ((asl_msg_lookup(asl->kvdict, ASL_KEY_FACILITY, &val, NULL) == 0) && (val != NULL)))
569 {
570 /* don't send lastlog/utmp messages to Activity Tracing */
571 if (!strcmp(val, FACILITY_LASTLOG) || !strcmp(val, FACILITY_UTMPX)) eval &= ~EVAL_SEND_TRACE;
572
573 /* don't send LOG_INSTALL messages to Activity Tracing */
574 if (!strcmp(val, asl_syslog_faciliy_num_to_name(LOG_INSTALL))) eval &= ~EVAL_SEND_TRACE;
575 }
576
577 return eval;
578 }
579
580 /*
581 * _asl_lib_vlog_text
582 * Internal routine used by asl_vlog.
583 * msg: an asl messsage
584 * eval: log level and send flags for the message
585 * format: A formating string
586 * ap: va_list for the format
587 * returns 0 for success, non-zero for failure
588 */
589
590 __private_extern__ ASL_STATUS
591 _asl_lib_vlog_text(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *format, va_list ap)
592 {
593 int saved_errno = errno;
594 int status;
595 char *str, *fmt, estr[NL_TEXTMAX];
596 uint32_t i, len, elen, expand;
597
598 if (format == NULL) return ASL_STATUS_INVALID_ARG;
599
600 /* insert strerror for %m */
601 len = 0;
602 elen = 0;
603
604 expand = 0;
605 for (i = 0; format[i] != '\0'; i++)
606 {
607 if (format[i] == '%')
608 {
609 if (format[i+1] == '\0') len++;
610 else if (format[i+1] == 'm')
611 {
612 expand = 1;
613 strerror_r(saved_errno, estr, sizeof(estr));
614 elen = strlen(estr);
615 len += elen;
616 i++;
617 }
618 else
619 {
620 len += 2;
621 i++;
622 }
623 }
624 else len++;
625 }
626
627 fmt = (char *)format;
628
629 if (expand != 0)
630 {
631 fmt = malloc(len + 1);
632 if (fmt == NULL) return ASL_STATUS_NO_MEMORY;
633
634 len = 0;
635
636 for (i = 0; format[i] != '\0'; i++)
637 {
638 if (format[i] == '%')
639 {
640 if (format[i+1] == '\0')
641 {
642 }
643 else if ((format[i+1] == 'm') && (elen != 0))
644 {
645 memcpy(fmt+len, estr, elen);
646 len += elen;
647 i++;
648 }
649 else
650 {
651 fmt[len++] = format[i++];
652 fmt[len++] = format[i];
653 }
654 }
655 else fmt[len++] = format[i];
656 }
657
658 fmt[len] = '\0';
659 }
660
661 str = NULL;
662 vasprintf(&str, fmt, ap);
663 if (expand != 0) free(fmt);
664
665 if (str == NULL) return ASL_STATUS_NO_MEMORY;
666
667 status = _asl_send_message_text(NULL, NULL, obj, eval, (asl_msg_t *)msg, str, true);
668 free(str);
669
670 return status;
671 }
672
673 /*
674 * _asl_lib_vlog
675 * Internal routine used by asl_vlog.
676 * msg: an asl messsage
677 * eval: log level and send flags for the message
678 * format: A formating string
679 * ap: va_list for the format
680 * returns 0 for success, non-zero for failure
681 */
682 __private_extern__ ASL_STATUS
683 _asl_lib_vlog(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *format, va_list ap)
684 {
685 int saved_errno = errno;
686 int status;
687 char *str, *fmt, estr[NL_TEXTMAX];
688 uint32_t i, len, elen, expand;
689
690 if (format == NULL) return ASL_STATUS_INVALID_ARG;
691
692 /* insert strerror for %m */
693 len = 0;
694 elen = 0;
695
696 expand = 0;
697 for (i = 0; format[i] != '\0'; i++)
698 {
699 if (format[i] == '%')
700 {
701 if (format[i+1] == '\0') len++;
702 else if (format[i+1] == 'm')
703 {
704 expand = 1;
705 strerror_r(saved_errno, estr, sizeof(estr));
706 elen = strlen(estr);
707 len += elen;
708 i++;
709 }
710 else
711 {
712 len += 2;
713 i++;
714 }
715 }
716 else len++;
717 }
718
719 fmt = (char *)format;
720
721 if (expand != 0)
722 {
723 fmt = malloc(len + 1);
724 if (fmt == NULL) return ASL_STATUS_NO_MEMORY;
725
726 len = 0;
727
728 for (i = 0; format[i] != '\0'; i++)
729 {
730 if (format[i] == '%')
731 {
732 if (format[i+1] == '\0')
733 {
734 }
735 else if ((format[i+1] == 'm') && (elen != 0))
736 {
737 memcpy(fmt+len, estr, elen);
738 len += elen;
739 i++;
740 }
741 else
742 {
743 fmt[len++] = format[i++];
744 fmt[len++] = format[i];
745 }
746 }
747 else fmt[len++] = format[i];
748 }
749
750 fmt[len] = '\0';
751 }
752
753 str = NULL;
754 vasprintf(&str, fmt, ap);
755 if (expand != 0) free(fmt);
756
757 if (str == NULL) return ASL_STATUS_NO_MEMORY;
758
759 status = _asl_send_message(obj, eval, (asl_msg_t *)msg, str);
760 free(str);
761
762 return status;
763 }
764
765 /*
766 * asl_vlog
767 * Similar to asl_log, but take a va_list instead of a list of arguments.
768 * msg: an asl message
769 * level: the log level of the associated message
770 * format: A formating string
771 * ap: va_list for the format
772 * returns 0 for success, non-zero for failure
773 */
774 int
775 asl_vlog(asl_object_t client, asl_object_t msg, int level, const char *format, va_list ap)
776 {
777 ASL_STATUS status = ASL_STATUS_OK;
778 uint32_t eval = _asl_evaluate_send(client, msg, level);
779 void *addr = __builtin_return_address(0);
780
781 if ((eval & EVAL_SEND_TRACE) && os_log_shim_enabled(addr))
782 {
783 va_list ap_copy;
784 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
785 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
786 os_log_type_t type = shim_asl_to_log_type[level];
787
788 va_copy(ap_copy, ap);
789 os_log_with_args(OS_LOG_DEFAULT, type, format, ap_copy, addr);
790 va_end(ap_copy);
791
792 if (eval & EVAL_TEXT_FILE)
793 {
794 status = _asl_lib_vlog_text(client, eval, msg, format, ap);
795 }
796 }
797 else if (eval & EVAL_ASL)
798 {
799 status = _asl_lib_vlog(client, eval, msg, format, ap);
800 }
801
802 return (status == ASL_STATUS_OK) ? 0 : -1;
803 }
804
805 /*
806 * _asl_lib_log
807 * SPI used by legacy (non-shim) ASL_PREFILTER_LOG. Converts format arguments to a va_list and
808 * forwards the call to _asl_lib_vlog.
809 * msg: an asl message
810 * eval: log level and send flags for the message
811 * format: A formating string
812 * ... args for format
813 * returns 0 for success, non-zero for failure
814 */
815 int
816 _asl_lib_log(asl_object_t client, uint32_t eval, asl_object_t msg, const char *format, ...)
817 {
818 int status = 0;
819
820 if (eval & EVAL_ASL)
821 {
822 va_list ap;
823
824 va_start(ap, format);
825 status = _asl_lib_vlog(client, eval, msg, format, ap);
826 va_end(ap);
827 }
828
829 return status;
830 }
831
832 /*
833 * asl_log
834 * Processes an ASL log message.
835 * msg: an asl message
836 * level: the log level of the associated message
837 * format: A formating string
838 * ... args for format
839 * returns 0 for success, non-zero for failure
840 */
841 int
842 asl_log(asl_object_t client, asl_object_t msg, int level, const char *format, ...)
843 {
844 ASL_STATUS status = ASL_STATUS_OK;
845 uint32_t eval = _asl_evaluate_send(client, msg, level);
846 void *addr = __builtin_return_address(0);
847
848 if ((eval & EVAL_SEND_TRACE) && os_log_shim_enabled(addr))
849 {
850 va_list ap;
851 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
852 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
853 os_log_type_t type = shim_asl_to_log_type[level];
854
855 va_start(ap, format);
856 os_log_with_args(OS_LOG_DEFAULT, type, format, ap, addr);
857 va_end(ap);
858
859 if (eval & EVAL_TEXT_FILE)
860 {
861 va_list ap;
862 va_start(ap, format);
863 status = _asl_lib_vlog_text(client, eval, msg, format, ap);
864 va_end(ap);
865 }
866 }
867 else if (eval & EVAL_ASL)
868 {
869 va_list ap;
870 va_start(ap, format);
871 status = _asl_lib_vlog(client, eval, msg, format, ap);
872 va_end(ap);
873 }
874
875 return (status == ASL_STATUS_OK) ? 0 : -1;
876 }
877
878 /*
879 * asl_log_message
880 * Like asl_log, supplies NULL client and msg.
881 * level: the log level of the associated message
882 * format: A formating string
883 * ... args for format
884 * returns 0 for success, non-zero for failure
885 */
886 int
887 asl_log_message(int level, const char *format, ...)
888 {
889 ASL_STATUS status = ASL_STATUS_OK;
890 uint32_t eval = _asl_evaluate_send(NULL, NULL, level);
891 void *addr = __builtin_return_address(0);
892
893 if ((eval & EVAL_SEND_TRACE) && os_log_shim_enabled(addr))
894 {
895 va_list ap;
896 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
897 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
898 os_log_type_t type = shim_asl_to_log_type[level];
899
900 va_start(ap, format);
901 os_log_with_args(OS_LOG_DEFAULT, type, format, ap, addr);
902 va_end(ap);
903
904 if (eval & EVAL_TEXT_FILE)
905 {
906 va_list ap;
907 va_start(ap, format);
908 status = _asl_lib_vlog_text(NULL, eval, NULL, format, ap);
909 va_end(ap);
910 }
911 }
912 else if (eval & EVAL_ASL)
913 {
914 va_list ap;
915 va_start(ap, format);
916 status = _asl_lib_vlog(NULL, eval, NULL, format, ap);
917 va_end(ap);
918 }
919
920 return (status == ASL_STATUS_OK) ? 0 : -1;
921 }
922
923 /*
924 * asl_get_filter: gets the values for the local, master, and remote filters,
925 * and indicates which one is active.
926 */
927 int
928 asl_get_filter(asl_object_t client, int *local, int *master, int *remote, int *active)
929 {
930 asl_client_t *asl, *asl_default;
931 int l, m, r, x;
932 int status, check;
933 uint64_t v64;
934
935 if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1;
936
937 l = 0;
938 m = 0;
939 r = 0;
940 x = 0;
941
942 asl_default = _asl_open_default();
943
944 asl = (asl_client_t *)client;
945 if (asl == NULL) asl = asl_default;
946 if (asl != NULL) l = asl->filter & EVAL_LEVEL_MASK;
947
948 if ((asl_default != NULL) && (!(asl_default->options & ASL_OPT_NO_REMOTE)))
949 {
950 pthread_mutex_lock(&_asl_global.lock);
951
952 if (_asl_global.rc_change_token >= 0)
953 {
954 /* initialize or re-check process-specific and master filters */
955 check = 0;
956 status = notify_check(_asl_global.rc_change_token, &check);
957 if ((status == NOTIFY_STATUS_OK) && (check != 0))
958 {
959 if (_asl_global.master_token >= 0)
960 {
961 v64 = 0;
962 status = notify_get_state(_asl_global.master_token, &v64);
963 if (status == NOTIFY_STATUS_OK) _asl_global.master_filter = v64;
964 }
965
966 if (_asl_global.notify_token >= 0)
967 {
968 v64 = 0;
969 status = notify_get_state(_asl_global.notify_token, &v64);
970 if (status == NOTIFY_STATUS_OK) _asl_global.proc_filter = v64;
971 }
972 }
973 }
974
975 m = _asl_global.master_filter;
976 if (m != 0) x = 1;
977
978 r = _asl_global.proc_filter;
979 if (r != 0) x = 2;
980
981 pthread_mutex_unlock(&_asl_global.lock);
982 }
983
984 if (local != NULL) *local = l;
985 if (master != NULL) *master = m;
986 if (remote != NULL) *remote = r;
987 if (active != NULL) *active = x;
988
989 return 0;
990 }
991
992 /* SPI for SHIM control */
993 uint32_t
994 asl_set_local_control(asl_object_t client, uint32_t filter)
995 {
996 asl_client_t *asl = (asl_client_t *)client;
997 if (asl == NULL)
998 {
999 asl = _asl_open_default();
1000 if (asl == NULL) return UINT32_MAX;
1001 }
1002 else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX;
1003
1004 return asl_client_set_control(asl, filter);
1005 }
1006
1007 uint32_t
1008 asl_get_local_control(asl_object_t client)
1009 {
1010 asl_client_t *asl = (asl_client_t *)client;
1011 if (asl == NULL)
1012 {
1013 asl = _asl_open_default();
1014 if (asl == NULL) return UINT32_MAX;
1015 }
1016 else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX;
1017
1018 return asl_client_get_control(asl);
1019 }
1020
1021 /*
1022 * Sets PID and OSActivityID values in a new message.
1023 * Also sets Level, Time, TimeNanoSec, Sender, Facility and Message if provided.
1024 */
1025 asl_msg_t *
1026 asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const char *sstr, const char *fstr, const char *mstr)
1027 {
1028 char aux_val[64];
1029 asl_msg_t *aux;
1030 int status;
1031 os_activity_id_t osaid;
1032
1033 aux = asl_msg_new(ASL_TYPE_MSG);
1034 if (aux == NULL) return NULL;
1035
1036 /* Level */
1037 if (level <= 7) asl_msg_set_key_val(aux, ASL_KEY_LEVEL, level_to_number_string[level]);
1038
1039 /* Time and TimeNanoSec */
1040 if (tv != NULL)
1041 {
1042 snprintf(aux_val, sizeof(aux_val), "%llu", (unsigned long long) tv->tv_sec);
1043 asl_msg_set_key_val(aux, ASL_KEY_TIME, aux_val);
1044
1045 snprintf(aux_val, sizeof(aux_val), "%d", tv->tv_usec * 1000);
1046 asl_msg_set_key_val(aux, ASL_KEY_TIME_NSEC, aux_val);
1047 }
1048
1049 /* Message */
1050 if (mstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_MSG, mstr);
1051
1052 /* PID */
1053 snprintf(aux_val, sizeof(aux_val), "%u", getpid());
1054 asl_msg_set_key_val(aux, ASL_KEY_PID, aux_val);
1055
1056 /* OSActivityID */
1057 osaid = os_activity_get_identifier(OS_ACTIVITY_CURRENT, NULL);
1058 if (osaid)
1059 {
1060 snprintf(aux_val, sizeof(aux_val), "0x%016llx", osaid);
1061 asl_msg_set_key_val(aux, ASL_KEY_OS_ACTIVITY_ID, aux_val);
1062 }
1063
1064 /* Sender */
1065 if ((sstr == NULL) && (asl != NULL))
1066 {
1067 /* See if the client has a value for ASL_KEY_SENDER */
1068 status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_SENDER, &sstr, NULL);
1069 if ((status != 0) || (sstr == NULL))
1070 {
1071 sstr = NULL;
1072
1073 /* See if the global cache has a value for ASL_KEY_SENDER */
1074 if (_asl_global.sender == NULL)
1075 {
1076 /* Get the process name with _NSGetArgv */
1077 char *name = *(*_NSGetArgv());
1078 if (name != NULL)
1079 {
1080 char *x = strrchr(name, '/');
1081 if (x != NULL) x++;
1082 else x = name;
1083
1084 /* Set the cache value */
1085 pthread_mutex_lock(&_asl_global.lock);
1086 if (_asl_global.sender == NULL) _asl_global.sender = strdup(x);
1087 pthread_mutex_unlock(&_asl_global.lock);
1088 }
1089 }
1090
1091 if (_asl_global.sender != NULL) asl_msg_set_key_val(aux, ASL_KEY_SENDER, _asl_global.sender);
1092 else asl_msg_set_key_val(aux, ASL_KEY_SENDER, "Unknown");
1093 }
1094 }
1095
1096 if (sstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_SENDER, sstr);
1097
1098 /* Facility */
1099 if ((fstr == NULL) && (asl != NULL))
1100 {
1101 status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_FACILITY, &fstr, NULL);
1102 if (status != 0) fstr = NULL;
1103 }
1104
1105 if (fstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_FACILITY, fstr);
1106
1107 return aux;
1108 }
1109
1110 #ifdef NOTDEF
1111 /*
1112 * Possibly useful someday...
1113 */
1114 asl_msg_t *
1115 asl_prepared_message(asl_client_t *asl, asl_msg_t *msg)
1116 {
1117 uint32_t i, len, level, outstatus;
1118 const char *val, *sstr, *fstr;
1119 struct timeval tval = {0, 0};
1120 int status;
1121 asl_msg_t *out;
1122
1123 if (asl == NULL)
1124 {
1125 asl = _asl_open_default();
1126 if (asl == NULL) return NULL;
1127 }
1128
1129 status = gettimeofday(&tval, NULL);
1130 if (status != 0)
1131 {
1132 time_t tick = time(NULL);
1133 tval.tv_sec = tick;
1134 tval.tv_usec = 0;
1135 }
1136
1137 val = NULL;
1138 status = asl_msg_lookup(msg, ASL_KEY_LEVEL, &val, NULL);
1139 if (status != 0) val = NULL;
1140
1141 level = ASL_LEVEL_DEBUG;
1142 if (val != NULL) level = atoi(val);
1143 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
1144
1145 sstr = NULL;
1146 status = asl_msg_lookup(msg, ASL_KEY_SENDER, &sstr, NULL);
1147 if (status != 0) sstr = NULL;
1148
1149 fstr = NULL;
1150 status = asl_msg_lookup(msg, ASL_KEY_FACILITY, &fstr, NULL);
1151 if (status != 0) fstr = NULL;
1152
1153 out = asl_base_msg(asl, level, &tval, sstr, fstr, NULL);
1154 out = asl_msg_merge(out, msg);
1155
1156 return out;
1157 }
1158 #endif
1159
1160 static void
1161 _asl_set_option(asl_msg_t *msg, const char *opt)
1162 {
1163 const char *val = NULL;
1164 uint32_t status;
1165
1166 if (msg == NULL) return;
1167 if (opt == NULL) return;
1168
1169 status = asl_msg_lookup(msg, ASL_KEY_OPTION, &val, NULL);
1170 if ((status != 0) || (val == NULL))
1171 {
1172 asl_msg_set_key_val(msg, ASL_KEY_OPTION, opt);
1173 }
1174 else
1175 {
1176 char *option = NULL;
1177 asprintf(&option, "%s %s", opt, val);
1178 asl_msg_set_key_val(msg, ASL_KEY_OPTION, option);
1179 free(option);
1180 }
1181 }
1182
1183 static ASL_STATUS
1184 _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)
1185 {
1186 int status;
1187 uint32_t level, lmask;
1188 asl_msg_t *release_sendmsg = NULL;
1189
1190 if (asl == NULL) {
1191 if (obj == NULL) {
1192 asl = _asl_open_default();
1193 if (asl == NULL) return ASL_STATUS_FAILED;
1194 } else {
1195 uint32_t objtype = asl_get_type(obj);
1196 if (objtype == ASL_TYPE_CLIENT) asl = (asl_client_t *)obj;
1197 }
1198 }
1199
1200 level = eval & EVAL_LEVEL_MASK;
1201 if (level > 7) level = 7;
1202 lmask = ASL_FILTER_MASK(level);
1203
1204 if (sendmsg == NULL) {
1205 struct timeval tval = {0, 0};
1206 const char *sstr, *fstr;
1207
1208 status = gettimeofday(&tval, NULL);
1209 if (status != 0) {
1210 time_t tick = time(NULL);
1211 tval.tv_sec = tick;
1212 tval.tv_usec = 0;
1213 }
1214
1215 sstr = NULL;
1216 status = asl_msg_lookup(msg, ASL_KEY_SENDER, &sstr, NULL);
1217 if (status != 0) {
1218 sstr = NULL;
1219 }
1220
1221 fstr = NULL;
1222 status = asl_msg_lookup(msg, ASL_KEY_FACILITY, &fstr, NULL);
1223 if (status != 0) {
1224 fstr = NULL;
1225 }
1226 sendmsg = asl_base_msg(asl, level, &tval, sstr, fstr, mstr);
1227 if (sendmsg == NULL) {
1228 return ASL_STATUS_FAILED;
1229 }
1230
1231 release_sendmsg = sendmsg = asl_msg_merge(sendmsg, msg);
1232 }
1233
1234 /* write to file descriptors */
1235 for (uint32_t i = 0; i < asl->out_count; i++) {
1236 if (shimmed) {
1237 if ((asl->out_list[i].fd != STDOUT_FILENO) && (asl->out_list[i].fd != STDERR_FILENO)) {
1238 continue; // new logging only support stdout/stderr
1239 }
1240 }
1241
1242 if ((asl->out_list[i].fd >= 0) && (asl->out_list[i].filter != 0) && ((asl->out_list[i].filter & lmask) != 0)) {
1243 char *str;
1244
1245 uint32_t len = 0;
1246 str = asl_format_message(sendmsg, asl->out_list[i].mfmt, asl->out_list[i].tfmt, asl->out_list[i].encoding, &len);
1247 if (str == NULL) continue;
1248
1249 status = write(asl->out_list[i].fd, str, len - 1);
1250 if (status < 0)
1251 {
1252 /* soft error for fd 2 (stderr) */
1253 if (asl->out_list[i].fd == 2) status = 0;
1254 asl->out_list[i].fd = -1;
1255 } else {
1256 status = 0;
1257 }
1258
1259 free(str);
1260 }
1261 }
1262 if (release_sendmsg) {
1263 asl_msg_release(release_sendmsg);
1264 }
1265
1266 return status;
1267 }
1268
1269 static ASL_STATUS
1270 _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstr)
1271 {
1272 uint32_t len, level, lmask, outstatus, objtype;
1273 const char *sstr, *fstr;
1274 struct timeval tval = {0, 0};
1275 int status;
1276 int use_global_lock = 0;
1277 kern_return_t kstatus;
1278 asl_msg_t *sendmsg;
1279 asl_msg_t *qd_msg = NULL;
1280 asl_client_t *asl = NULL;
1281 static dispatch_once_t noquota_once;
1282 __block int log_quota_msg = 0;
1283
1284 if ((eval & EVAL_ASL) == 0) return ASL_STATUS_OK;
1285
1286 if (obj == NULL)
1287 {
1288 asl = _asl_open_default();
1289 if (asl == NULL) return ASL_STATUS_FAILED;
1290 use_global_lock = 1;
1291 objtype = ASL_TYPE_CLIENT;
1292 }
1293 else
1294 {
1295 objtype = asl_get_type(obj);
1296 if (objtype == ASL_TYPE_CLIENT) asl = (asl_client_t *)obj;
1297 }
1298
1299 level = eval & EVAL_LEVEL_MASK;
1300 if (level > 7) level = 7;
1301 lmask = ASL_FILTER_MASK(level);
1302
1303 if ((objtype == ASL_TYPE_CLIENT) && (asl->aslfile != NULL)) use_global_lock = 1;
1304
1305 status = gettimeofday(&tval, NULL);
1306 if (status != 0)
1307 {
1308 time_t tick = time(NULL);
1309 tval.tv_sec = tick;
1310 tval.tv_usec = 0;
1311 }
1312
1313 sstr = NULL;
1314 status = asl_msg_lookup(msg, ASL_KEY_SENDER, &sstr, NULL);
1315 if (status != 0) sstr = NULL;
1316
1317 fstr = NULL;
1318 status = asl_msg_lookup(msg, ASL_KEY_FACILITY, &fstr, NULL);
1319 if (status != 0) fstr = NULL;
1320
1321 sendmsg = asl_base_msg(asl, level, &tval, sstr, fstr, mstr);
1322 if (sendmsg == NULL) return ASL_STATUS_FAILED;
1323
1324 /* Set "ASLOption store" if tunneling */
1325 if (eval & EVAL_TUNNEL) _asl_set_option(sendmsg, ASL_OPT_STORE);
1326
1327 outstatus = -1;
1328
1329 if (use_global_lock != 0) pthread_mutex_lock(&_asl_global.lock);
1330
1331 sendmsg = asl_msg_merge(sendmsg, msg);
1332
1333 if (objtype != ASL_TYPE_CLIENT)
1334 {
1335 asl_append(obj, (asl_object_t)sendmsg);
1336 asl_msg_release(sendmsg);
1337 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1338 return ASL_STATUS_OK;
1339 }
1340
1341 /*
1342 * If there is an aslfile this is a stand-alone file client.
1343 * Just save to the file.
1344 */
1345 if (asl->aslfile != NULL)
1346 {
1347 outstatus = ASL_STATUS_FAILED;
1348
1349 if (sendmsg != NULL)
1350 {
1351 outstatus = asl_file_save(asl->aslfile, sendmsg, &(asl->aslfileid));
1352 asl->aslfileid++;
1353 }
1354
1355 asl_msg_release(sendmsg);
1356
1357 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1358 return outstatus;
1359 }
1360
1361 _asl_global_init(0);
1362 outstatus = 0;
1363
1364 /*
1365 * ASL message quota
1366 * Quotas are disabled if:
1367 * - a remote control filter is in place (EVAL_TUNNEL)
1368 * - Environment variable ASL_QUOTA_DISABLED == 1
1369 * - /etc/asl/.noquota existed at the time that the process started
1370 *
1371 * We just check /etc/asl/.noquota once, since it would be
1372 * expensive to stat() for every log message.
1373 *
1374 * We only check the Environment variable once, since getenv() is
1375 * not thread safe. If someone is changing the environment,
1376 * this can crash.
1377 */
1378
1379 dispatch_once(&noquota_once, ^{
1380 struct stat sb;
1381 memset(&sb, 0, sizeof(struct stat));
1382
1383 int save_errno = errno;
1384
1385 if (stat(NOQUOTA_FILE_PATH, &sb) == 0)
1386 {
1387 _asl_global.quota = UINT32_MAX;
1388 }
1389 else
1390 {
1391 const char *qtest = getenv(NOQUOTA_ENV);
1392 if ((qtest != NULL) && (!strcmp(qtest, "1")))
1393 {
1394 _asl_global.quota = UINT32_MAX;
1395 log_quota_msg = 1;
1396 }
1397 }
1398
1399 /* reset errno since we want stat() to fail silently */
1400 errno = save_errno;
1401 });
1402
1403 if (log_quota_msg != 0)
1404 {
1405 qd_msg = asl_base_msg(asl, QUOTA_LEVEL, &tval, sstr, fstr, QUOTA_DISABLED_MSG);
1406 asl_msg_set_key_val(qd_msg, ASL_KEY_OPTION, ASL_OPT_STORE);
1407 }
1408
1409 if (((eval & EVAL_TUNNEL) == 0) && (_asl_global.quota != UINT32_MAX))
1410 {
1411 time_t last_send = _asl_global.last_send;
1412 time_t last_oq = _asl_global.last_oq_msg;
1413 uint32_t qcurr = _asl_global.quota;
1414 time_t delta;
1415 uint32_t qinc, qnew;
1416
1417 qnew = qcurr;
1418
1419 /* add QUOTA_MPS to quota for each second we've been idle */
1420 if (tval.tv_sec > last_send)
1421 {
1422 delta = tval.tv_sec - last_send;
1423
1424 qinc = QUOTA_MPH;
1425 if (delta < (QUOTA_MPH / QUOTA_MPS)) qinc = delta * QUOTA_MPS;
1426
1427 qnew = MIN(QUOTA_MPH, qcurr + qinc);
1428 OSAtomicCompareAndSwapLongBarrier(last_send, tval.tv_sec, (long *)&_asl_global.last_send);
1429 }
1430
1431 if (qnew == 0)
1432 {
1433 if ((tval.tv_sec - last_oq) > QUOTA_MSG_INTERVAL)
1434 {
1435 eval |= EVAL_QUOTA;
1436 OSAtomicCompareAndSwapLongBarrier(last_oq, tval.tv_sec, (long *)&_asl_global.last_oq_msg);
1437 }
1438 else
1439 {
1440 eval &= ~EVAL_SEND_ASL;
1441 }
1442 }
1443 else
1444 {
1445 OSAtomicCompareAndSwap32Barrier(qcurr, qnew - 1, (int32_t *)&_asl_global.quota);
1446 }
1447 }
1448
1449 if ((_asl_global.server_port != MACH_PORT_NULL) && (eval & EVAL_SEND_ASL))
1450 {
1451 asl_string_t *send_str;
1452 const char *str;
1453 size_t vmsize;
1454
1455 if (eval & EVAL_QUOTA)
1456 {
1457 asl_msg_set_key_val(sendmsg, ASL_KEY_LEVEL, QUOTA_LEVEL_STR);
1458 asl_msg_set_key_val(sendmsg, ASL_KEY_MSG, QUOTA_MSG);
1459 }
1460
1461 if (qd_msg != NULL)
1462 {
1463 send_str = asl_msg_to_string_raw(ASL_STRING_MIG, qd_msg, "raw");
1464 len = asl_string_length(send_str);
1465 vmsize = asl_string_allocated_size(send_str);
1466 str = asl_string_release_return_bytes(send_str);
1467 if (len != 0)
1468 {
1469 kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)str, len);
1470 if (kstatus != KERN_SUCCESS)
1471 {
1472 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1473 }
1474 }
1475 else if (vmsize != 0)
1476 {
1477 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1478 }
1479 asl_msg_release(qd_msg);
1480 }
1481
1482 send_str = asl_msg_to_string_raw(ASL_STRING_MIG, sendmsg, "raw");
1483 len = asl_string_length(send_str);
1484
1485 if (len > LIBASL_MAX_MSG_SIZE)
1486 {
1487 char tmp[256];
1488
1489 snprintf(tmp, sizeof(tmp), SIZE_LIMIT_MSG, len, LIBASL_MAX_MSG_SIZE);
1490 asl_msg_t *limitmsg = asl_base_msg(asl, ASL_LEVEL_CRIT, &tval, sstr, fstr, tmp);
1491
1492 asl_string_release(send_str);
1493 len = 0;
1494
1495 if (limitmsg != NULL)
1496 {
1497 /* Set "ASLOption store" if tunneling */
1498 if (eval & EVAL_TUNNEL) _asl_set_option(limitmsg, ASL_OPT_STORE);
1499
1500 send_str = asl_msg_to_string_raw(ASL_STRING_MIG, limitmsg, "raw");
1501 len = asl_string_length(send_str);
1502 asl_msg_release(limitmsg);
1503 }
1504 }
1505
1506 vmsize = asl_string_allocated_size(send_str);
1507 str = asl_string_release_return_bytes(send_str);
1508
1509 if (len != 0)
1510 {
1511 /* send a mach message to syslogd */
1512 kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)str, len);
1513 if (kstatus != KERN_SUCCESS)
1514 {
1515 /* retry once if the call failed */
1516 _asl_global_init(1);
1517 kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)str, len);
1518 if (kstatus != KERN_SUCCESS)
1519 {
1520 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1521 outstatus = -1;
1522 }
1523 }
1524 }
1525 else if (vmsize >0) vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1526 }
1527
1528 if ((sendmsg != NULL) && (asl->out_count > 0))
1529 {
1530 status = _asl_send_message_text(asl, sendmsg, obj, eval, msg, mstr, false);
1531 }
1532
1533 asl_msg_release(sendmsg);
1534
1535 if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock);
1536
1537 return outstatus;
1538 }
1539
1540 static void
1541 os_log_with_args_wrapper(void *addr, int level, const char *format, ...)
1542 {
1543 va_list ap;
1544 if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
1545 if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
1546 os_log_type_t type = shim_asl_to_log_type[level];
1547
1548 va_start(ap, format);
1549 os_log_with_args(OS_LOG_DEFAULT, type, format, ap, addr);
1550 va_end(ap);
1551 }
1552
1553 /*
1554 * asl_send: send a message
1555 * This routine may be used instead of asl_log() or asl_vlog() if asl_set()
1556 * has been used to set all of a message's attributes.
1557 * eval: hints about what to do with the message
1558 * msg: an asl message
1559 * returns 0 for success, non-zero for failure
1560 */
1561 __private_extern__ ASL_STATUS
1562 asl_client_internal_send(asl_object_t obj, asl_object_t msg, void *addr)
1563 {
1564 int status = ASL_STATUS_OK;
1565 uint32_t eval = _asl_evaluate_send(obj, msg, -1);
1566
1567 const char *message = asl_msg_get_val_for_key((asl_msg_t *)msg, ASL_KEY_MSG);
1568
1569 if ((eval & EVAL_SEND_TRACE) && message && message[0] && os_log_shim_enabled(addr))
1570 {
1571 int level = ASL_LEVEL_DEBUG;
1572 const char *lval = asl_msg_get_val_for_key((asl_msg_t *)msg, ASL_KEY_LEVEL);
1573 if (lval != NULL) level = atoi(lval);
1574
1575 /*
1576 * If the return address and the format string are from different
1577 * binaries, os_log_with_args will not record the return address.
1578 * Work around this by passing a dynamic format string.
1579 */
1580 char dynamic_format[] = "%s";
1581 os_log_with_args_wrapper(addr, level, dynamic_format, message);
1582
1583 if (eval & EVAL_TEXT_FILE)
1584 {
1585 status = _asl_send_message_text(NULL, NULL, obj, eval, (asl_msg_t *)msg, NULL, true);
1586 }
1587 }
1588 else if (eval & EVAL_ASL)
1589 {
1590 status = _asl_send_message(obj, eval, (asl_msg_t *)msg, NULL);
1591 }
1592
1593 return status;
1594 }
1595
1596 #pragma mark -
1597 #pragma mark auxiliary files and URLs
1598
1599 static ASL_STATUS
1600 _asl_aux_save_context(asl_aux_context_t *ctx)
1601 {
1602 if (ctx == NULL) return ASL_STATUS_FAILED;
1603
1604 pthread_mutex_lock(&_asl_global.lock);
1605
1606 _asl_global.aux_ctx = (asl_aux_context_t **)reallocf(_asl_global.aux_ctx, (_asl_global.aux_count + 1) * sizeof(asl_aux_context_t *));
1607 if (_asl_global.aux_ctx == NULL)
1608 {
1609 _asl_global.aux_count = 0;
1610 pthread_mutex_unlock(&_asl_global.lock);
1611 return ASL_STATUS_FAILED;
1612 }
1613
1614 _asl_global.aux_ctx[_asl_global.aux_count++] = ctx;
1615
1616 pthread_mutex_unlock(&_asl_global.lock);
1617
1618 return ASL_STATUS_OK;
1619 }
1620
1621 /*
1622 * Creates an auxiliary file that may be used to save arbitrary data. The ASL message msg
1623 * will be saved at the time that the auxiliary file is created. The message will include
1624 * any keys and values found in msg, and it will include the title and Uniform Type
1625 * Identifier specified. Output parameter out_fd will contain the file descriptor of the
1626 * new auxiliary file.
1627 */
1628 static ASL_STATUS
1629 _asl_auxiliary(asl_msg_t *msg, const char *title, const char *uti, const char *url, int *out_fd)
1630 {
1631 asl_msg_t *aux;
1632 asl_string_t *send_str;
1633 const char *str;
1634 fileport_t fileport;
1635 kern_return_t kstatus;
1636 size_t len, vmsize;
1637 uint32_t newurllen, where;
1638 int status, fd, fdpair[2];
1639 caddr_t newurl;
1640 dispatch_queue_t pipe_q;
1641 dispatch_io_t pipe_channel;
1642 dispatch_semaphore_t sem;
1643
1644 aux = asl_msg_new(ASL_TYPE_MSG);
1645
1646 if (url != NULL) asl_msg_set_key_val(aux, ASL_KEY_AUX_URL, url);
1647 if (title != NULL) asl_msg_set_key_val(aux, ASL_KEY_AUX_TITLE, title);
1648 if (uti == NULL) asl_msg_set_key_val(aux, ASL_KEY_AUX_UTI, "public.data");
1649 else asl_msg_set_key_val(aux, ASL_KEY_AUX_UTI, uti);
1650
1651 aux = asl_msg_merge(aux, msg);
1652
1653 /* if (out_fd == NULL), this is from asl_log_auxiliary_location */
1654 if (out_fd == NULL)
1655 {
1656 uint32_t eval = _asl_evaluate_send(NULL, (asl_object_t)aux, -1);
1657 status = _asl_send_message(NULL, eval, aux, NULL);
1658 asl_msg_release(aux);
1659 return status;
1660 }
1661
1662 where = asl_store_location();
1663 if (where == ASL_STORE_LOCATION_MEMORY)
1664 {
1665 /* create a pipe */
1666 asl_aux_context_t *ctx = (asl_aux_context_t *)calloc(1, sizeof(asl_aux_context_t));
1667 if (ctx == NULL) return ASL_STATUS_FAILED;
1668
1669 status = pipe(fdpair);
1670 if (status < 0)
1671 {
1672 free(ctx);
1673 return ASL_STATUS_FAILED;
1674 }
1675
1676 /* give read end to dispatch_io_read */
1677 fd = fdpair[0];
1678 sem = dispatch_semaphore_create(0);
1679 ctx->sem = sem;
1680 ctx->fd = fdpair[1];
1681
1682 status = _asl_aux_save_context(ctx);
1683 if (status != ASL_STATUS_OK)
1684 {
1685 close(fdpair[0]);
1686 close(fdpair[1]);
1687 dispatch_release(sem);
1688 free(ctx);
1689 return ASL_STATUS_FAILED;
1690 }
1691
1692 pipe_q = dispatch_queue_create("ASL_AUX_PIPE_Q", NULL);
1693 pipe_channel = dispatch_io_create(DISPATCH_IO_STREAM, fd, pipe_q, ^(int err){
1694 close(fd);
1695 });
1696
1697 *out_fd = fdpair[1];
1698
1699 dispatch_io_set_low_water(pipe_channel, SIZE_MAX);
1700
1701 dispatch_io_read(pipe_channel, 0, SIZE_MAX, pipe_q, ^(bool done, dispatch_data_t pipedata, int err){
1702 if (err == 0)
1703 {
1704 size_t len = dispatch_data_get_size(pipedata);
1705 if (len > 0)
1706 {
1707 const char *bytes = NULL;
1708 char *encoded;
1709 uint32_t eval;
1710
1711 dispatch_data_t md = dispatch_data_create_map(pipedata, (const void **)&bytes, &len);
1712 encoded = asl_core_encode_buffer(bytes, len);
1713 asl_msg_set_key_val(aux, ASL_KEY_AUX_DATA, encoded);
1714 free(encoded);
1715 eval = _asl_evaluate_send(NULL, (asl_object_t)aux, -1);
1716 _asl_send_message(NULL, eval, aux, NULL);
1717 asl_msg_release(aux);
1718 dispatch_release(md);
1719 }
1720 }
1721
1722 if (done)
1723 {
1724 dispatch_semaphore_signal(sem);
1725 dispatch_release(pipe_channel);
1726 dispatch_release(pipe_q);
1727 }
1728 });
1729
1730 return ASL_STATUS_OK;
1731 }
1732
1733 _asl_global_init(0);
1734 if (_asl_global.server_port == MACH_PORT_NULL) return ASL_STATUS_FAILED;
1735
1736 send_str = asl_msg_to_string_raw(ASL_STRING_MIG, aux, "raw");
1737 len = asl_string_length(send_str);
1738 vmsize = asl_string_allocated_size(send_str);
1739 str = asl_string_release_return_bytes(send_str);
1740
1741 if (len == 0)
1742 {
1743 asl_msg_release(aux);
1744 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1745 return ASL_STATUS_FAILED;
1746 }
1747
1748 status = 0;
1749 fileport = MACH_PORT_NULL;
1750 status = KERN_SUCCESS;
1751
1752 kstatus = _asl_server_create_aux_link(_asl_global.server_port, (caddr_t)str, len, &fileport, &newurl, &newurllen, &status);
1753 if (kstatus != KERN_SUCCESS)
1754 {
1755 /* retry once if the call failed */
1756 _asl_global_init(1);
1757 kstatus = _asl_server_create_aux_link(_asl_global.server_port, (caddr_t)str, len, &fileport, &newurl, &newurllen, &status);
1758 if (kstatus != KERN_SUCCESS)
1759 {
1760 vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
1761 asl_msg_release(aux);
1762 return ASL_STATUS_FAILED;
1763 }
1764 }
1765
1766 if (status != 0)
1767 {
1768 asl_msg_release(aux);
1769 return status;
1770 }
1771
1772 if (newurl != NULL)
1773 {
1774 asl_msg_set_key_val(aux, ASL_KEY_AUX_URL, newurl);
1775 vm_deallocate(mach_task_self(), (vm_address_t)newurl, newurllen);
1776 }
1777
1778 if (fileport == MACH_PORT_NULL)
1779 {
1780 asl_msg_release(aux);
1781 return ASL_STATUS_FAILED;
1782 }
1783
1784 fd = fileport_makefd(fileport);
1785 mach_port_deallocate(mach_task_self(), fileport);
1786 if (fd < 0)
1787 {
1788 asl_msg_release(aux);
1789 status = -1;
1790 }
1791 else
1792 {
1793 asl_aux_context_t *ctx = (asl_aux_context_t *)calloc(1, sizeof(asl_aux_context_t));
1794 if (ctx == NULL)
1795 {
1796 status = -1;
1797 }
1798 else
1799 {
1800 *out_fd = fd;
1801
1802 ctx->fd = fd;
1803 ctx->msg = aux;
1804
1805 status = _asl_aux_save_context(ctx);
1806 }
1807 }
1808
1809 return status;
1810 }
1811
1812 int
1813 asl_create_auxiliary_file(asl_object_t msg, const char *title, const char *uti, int *out_fd)
1814 {
1815 if (out_fd == NULL) return -1;
1816
1817 ASL_STATUS status = _asl_auxiliary((asl_msg_t *)msg, title, uti, NULL, out_fd);
1818 return (status == ASL_STATUS_OK) ? 0 : -1;
1819 }
1820
1821 int
1822 asl_log_auxiliary_location(asl_object_t msg, const char *title, const char *uti, const char *url)
1823 {
1824 ASL_STATUS status = _asl_auxiliary((asl_msg_t *)msg, title, uti, url, NULL);
1825 return (status == ASL_STATUS_OK) ? 0 : -1;
1826 }
1827
1828 /*
1829 * Close an auxiliary file.
1830 * Sends the cached auxiliary message to syslogd.
1831 * Returns 0 on success, -1 on error.
1832 */
1833 int
1834 asl_close_auxiliary_file(int fd)
1835 {
1836 int i, j, status;
1837 asl_msg_t *aux_msg;
1838 dispatch_semaphore_t aux_sem = NULL;
1839
1840 pthread_mutex_lock(&(_asl_global.lock));
1841
1842 aux_msg = NULL;
1843 status = -1;
1844
1845 for (i = 0; i < _asl_global.aux_count; i++)
1846 {
1847 if (_asl_global.aux_ctx[i]->fd == fd)
1848 {
1849 status = 0;
1850
1851 aux_msg = _asl_global.aux_ctx[i]->msg;
1852 aux_sem = _asl_global.aux_ctx[i]->sem;
1853
1854 free(_asl_global.aux_ctx[i]);
1855
1856 for (j = i + 1; j < _asl_global.aux_count; i++, j++)
1857 {
1858 _asl_global.aux_ctx[i] = _asl_global.aux_ctx[j];
1859 }
1860
1861 _asl_global.aux_count--;
1862
1863 if (_asl_global.aux_count == 0)
1864 {
1865 free(_asl_global.aux_ctx);
1866 _asl_global.aux_ctx = NULL;
1867 }
1868 else
1869 {
1870 _asl_global.aux_ctx = (asl_aux_context_t **)reallocf(_asl_global.aux_ctx, _asl_global.aux_count * sizeof(asl_aux_context_t *));
1871 if (_asl_global.aux_ctx == NULL)
1872 {
1873 _asl_global.aux_count = 0;
1874 status = -1;
1875 }
1876 }
1877
1878 break;
1879 }
1880 }
1881
1882 pthread_mutex_unlock(&(_asl_global.lock));
1883
1884 close(fd);
1885
1886 if (aux_msg != NULL)
1887 {
1888 uint32_t eval = _asl_evaluate_send(NULL, (asl_object_t)aux_msg, -1);
1889 if (_asl_send_message(NULL, eval, aux_msg, NULL) != ASL_STATUS_OK) status = -1;
1890 asl_msg_release(aux_msg);
1891 }
1892
1893 if (aux_sem != NULL)
1894 {
1895 dispatch_semaphore_wait(aux_sem, DISPATCH_TIME_FOREVER);
1896 dispatch_release(aux_sem);
1897 }
1898
1899 return status;
1900 }
1901
1902 #pragma mark -
1903
1904 asl_msg_t *
1905 _asl_server_control_query(void)
1906 {
1907 asl_msg_list_t *list = NULL;
1908 char *res;
1909 uint32_t len, reslen, status;
1910 uint64_t cmax, qmin;
1911 kern_return_t kstatus;
1912 caddr_t vmstr;
1913 asl_msg_t *m = NULL;
1914 static const char ctlstr[] = "1\nQ [= ASLOption control]\n";
1915
1916 _asl_global_init(0);
1917 if (_asl_global.server_port == MACH_PORT_NULL) return NULL;
1918
1919 len = strlen(ctlstr) + 1;
1920
1921 qmin = 0;
1922 cmax = 0;
1923 res = NULL;
1924 reslen = 0;
1925
1926 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
1927 if (kstatus != KERN_SUCCESS) return NULL;
1928
1929 memmove(vmstr, ctlstr, len);
1930
1931 status = 0;
1932 kstatus = _asl_server_query_2(_asl_global.server_port, vmstr, len, qmin, FETCH_BATCH, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
1933 if (kstatus != KERN_SUCCESS)
1934 {
1935 /* retry once if the call failed */
1936 _asl_global_init(1);
1937 kstatus = _asl_server_query_2(_asl_global.server_port, vmstr, len, qmin, FETCH_BATCH, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
1938 }
1939
1940 list = asl_msg_list_from_string(res);
1941 vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
1942
1943 if (list == NULL) return NULL;
1944 if (list->count > 0) m = asl_msg_retain(list->msg[0]);
1945 asl_msg_list_release(list);
1946 return m;
1947 }
1948
1949 /*
1950 * Returns ASL_STORE_LOCATION_FILE or ASL_STORE_LOCATION_MEMORY
1951 */
1952 int
1953 asl_store_location()
1954 {
1955 kern_return_t kstatus;
1956 char *res;
1957 uint32_t reslen, status;
1958 uint64_t cmax;
1959
1960 _asl_global_init(0);
1961 if (_asl_global.server_port == MACH_PORT_NULL) return ASL_STORE_LOCATION_FILE;
1962
1963 res = NULL;
1964 reslen = 0;
1965 cmax = 0;
1966 status = ASL_STATUS_OK;
1967
1968 kstatus = _asl_server_query_2(_asl_global.server_port, NULL, 0, 0, -1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
1969 if (kstatus != KERN_SUCCESS)
1970 {
1971 /* retry once if the call failed */
1972 _asl_global_init(1);
1973 kstatus = _asl_server_query_2(_asl_global.server_port, NULL, 0, 0, -1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status);
1974 }
1975
1976 /* res should never be returned, but just to be certain we don't leak VM ... */
1977 if (res != NULL) vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
1978
1979 if (kstatus != KERN_SUCCESS) return ASL_STORE_LOCATION_FILE;
1980 if (status == ASL_STATUS_OK) return ASL_STORE_LOCATION_MEMORY;
1981 return ASL_STORE_LOCATION_FILE;
1982 }
1983
1984 asl_object_t
1985 asl_open_path(const char *path, uint32_t opts)
1986 {
1987 struct stat sb;
1988 asl_file_t *fout = NULL;
1989 asl_store_t *sout = NULL;
1990
1991 if (opts == 0) opts = ASL_OPT_OPEN_READ;
1992
1993 if (opts & ASL_OPT_OPEN_READ)
1994 {
1995 if (path == NULL)
1996 {
1997 if (asl_store_open_read(ASL_PLACE_DATABASE_DEFAULT, &sout) != ASL_STATUS_OK) return NULL;
1998 return (asl_object_t)sout;
1999 }
2000
2001 memset(&sb, 0, sizeof(struct stat));
2002 if (stat(path, &sb) < 0) return NULL;
2003
2004 if (sb.st_mode & S_IFREG)
2005 {
2006 if (asl_file_open_read(path, &fout) != ASL_STATUS_OK) return NULL;
2007 return (asl_object_t)fout;
2008 }
2009 else if (sb.st_mode & S_IFDIR)
2010 {
2011 if (asl_store_open_read(path, &sout) != ASL_STATUS_OK) return NULL;
2012 return (asl_object_t)sout;
2013 }
2014
2015 return NULL;
2016 }
2017 else if (opts & ASL_OPT_OPEN_WRITE)
2018 {
2019 if (path == NULL) return NULL;
2020
2021 memset(&sb, 0, sizeof(struct stat));
2022 if (stat(path, &sb) < 0)
2023 {
2024 if (errno != ENOENT) return NULL;
2025
2026 if (opts & ASL_OPT_CREATE_STORE)
2027 {
2028 if (asl_store_open_write(path, &sout) != ASL_STATUS_OK) return NULL;
2029 return (asl_object_t)sout;
2030 }
2031 else
2032 {
2033 if (asl_file_open_write(path, 0644, geteuid(), getegid(), &fout) != ASL_STATUS_OK) return NULL;
2034 return (asl_object_t)fout;
2035 }
2036 }
2037 else if (sb.st_mode & S_IFREG)
2038 {
2039 if (asl_file_open_write(path, 0644, geteuid(), getegid(), &fout) != ASL_STATUS_OK) return NULL;
2040 return (asl_object_t)fout;
2041 }
2042 else if (sb.st_mode & S_IFDIR)
2043 {
2044 if (asl_store_open_write(path, &sout) != ASL_STATUS_OK) return NULL;
2045 return (asl_object_t)sout;
2046 }
2047 }
2048
2049 return NULL;
2050 }