2 * Copyright (c) 2004-2013 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
37 #include <sys/fcntl.h>
38 #include <sys/param.h>
39 #include <sys/fileport.h>
40 #include <crt_externs.h>
44 #include <mach/mach.h>
45 #include <mach/std_types.h>
47 #include <mach/mach_types.h>
48 #include <sys/types.h>
49 #include <servers/bootstrap.h>
50 #include <bootstrap_priv.h>
52 #include <dispatch/dispatch.h>
53 #include <libkern/OSAtomic.h>
54 #include <os/activity.h>
56 #include <asl_client.h>
59 #include <asl_msg_list.h>
60 #include <asl_store.h>
61 #include <asl_private.h>
63 #define forever for(;;)
65 #define FETCH_BATCH 256
67 #define LEVEL_MASK 0x0000000f
68 #define EVAL_MASK 0x000000f0
69 #define EVAL_IGNORE 0x00000000
70 #define EVAL_ASLFILE 0x00000010
71 #define EVAL_SEND 0x00000020
72 #define EVAL_TUNNEL 0x00000040
73 #define EVAL_FILE 0x00000080
74 #define EVAL_QUOTA 0x00000100
77 * Clients get a max of 36000 messages per hour.
78 * Their quota gets refilled at a rate of 10 messages per second.
80 #define QUOTA_MPH 36000
82 #define QUOTA_MSG_INTERVAL 60
83 #define NOQUOTA_ENV "ASL_QUOTA_DISABLED"
84 #define QUOTA_DISABLED_MSG "*** MESSAGE QUOTA DISABLED FOR THIS PROCESS ***"
85 #define QUOTA_MSG "*** LOG MESSAGE QUOTA EXCEEDED - SOME MESSAGES FROM THIS PROCESS HAVE BEEN DISCARDED ***"
87 #define QUOTA_LEVEL_STR "2"
90 static ASL_STATUS
_asl_send_message(asl_object_t obj
, uint32_t eval
, asl_msg_t
*msg
, const char *mstring
);
91 __private_extern__ asl_client_t
*_asl_open_default();
94 uint32_t notify_register_plain(const char *name
, int *out_token
);
96 /* fork handling in asl_fd.c */
97 extern void _asl_redirect_fork_child(void);
103 dispatch_semaphore_t sem
;
112 uint64_t proc_filter
;
113 uint64_t master_filter
;
117 mach_port_t server_port
;
119 pthread_mutex_t lock
;
121 asl_aux_context_t
**aux_ctx
;
125 __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
};
127 static const char *level_to_number_string
[] = {"0", "1", "2", "3", "4", "5", "6", "7"};
129 #define ASL_SERVICE_NAME "com.apple.system.logger"
132 * Called from the child process inside fork() to clean up
133 * inherited state from the parent process.
135 * NB. A lock isn't required, since we're single threaded in this call.
140 _asl_global
.notify_count
= 0;
141 _asl_global
.rc_change_token
= -1;
142 _asl_global
.master_token
= -1;
143 _asl_global
.notify_token
= -1;
144 _asl_global
.quota
= 0;
145 _asl_global
.last_send
= 0;
146 _asl_global
.last_oq_msg
= 0;
148 _asl_global
.server_port
= MACH_PORT_NULL
;
150 pthread_mutex_init(&(_asl_global
.lock
), NULL
);
152 _asl_redirect_fork_child();
156 * asl_remote_notify_name: returns the notification key for remote-control filter
157 * changes for this process.
160 asl_remote_notify_name()
162 pid_t pid
= getpid();
163 uid_t euid
= geteuid();
166 if (euid
== 0) asprintf(&str
, "%s.%d", NOTIFY_PREFIX_SYSTEM
, pid
);
167 else asprintf(&str
, "user.uid.%d.syslog.%d", euid
, pid
);
173 _asl_notify_open(int do_lock
)
178 if (do_lock
!= 0) pthread_mutex_lock(&_asl_global
.lock
);
180 _asl_global
.notify_count
++;
182 if (_asl_global
.notify_token
!= -1)
184 if (do_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
185 return ASL_STATUS_OK
;
188 if (_asl_global
.rc_change_token
== -1)
190 status
= notify_register_check(NOTIFY_RC
, &_asl_global
.rc_change_token
);
191 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.rc_change_token
= -1;
194 if (_asl_global
.master_token
== -1)
196 status
= notify_register_plain(NOTIFY_SYSTEM_MASTER
, &_asl_global
.master_token
);
197 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.master_token
= -1;
200 notify_name
= asl_remote_notify_name();
201 if (notify_name
!= NULL
)
203 status
= notify_register_plain(notify_name
, &_asl_global
.notify_token
);
205 if (status
!= NOTIFY_STATUS_OK
) _asl_global
.notify_token
= -1;
208 if (do_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
210 if (_asl_global
.notify_token
== -1) return ASL_STATUS_FAILED
;
211 return ASL_STATUS_OK
;
218 pthread_mutex_lock(&_asl_global
.lock
);
220 if (_asl_global
.notify_count
> 0) _asl_global
.notify_count
--;
222 if (_asl_global
.notify_count
> 0)
224 pthread_mutex_unlock(&_asl_global
.lock
);
228 if (_asl_global
.rc_change_token
>= 0) notify_cancel(_asl_global
.rc_change_token
);
229 _asl_global
.rc_change_token
= -1;
231 if (_asl_global
.master_token
>= 0) notify_cancel(_asl_global
.master_token
);
232 _asl_global
.master_token
= -1;
234 if (_asl_global
.notify_token
>= 0) notify_cancel(_asl_global
.notify_token
);
235 _asl_global
.notify_token
= -1;
237 pthread_mutex_unlock(&_asl_global
.lock
);
242 _asl_global_init(int reset
)
244 _asl_global
.server_port
= asl_core_get_service_port(reset
);
248 #pragma mark asl_client
251 asl_open(const char *ident
, const char *facility
, uint32_t opts
)
253 asl_client_t
*asl
= asl_client_open(ident
, facility
, opts
);
254 if (asl
== NULL
) return NULL
;
257 if (!(opts
& ASL_OPT_NO_REMOTE
)) _asl_notify_open(1);
259 return (asl_object_t
)asl
;
263 asl_open_from_file(int fd
, const char *ident
, const char *facility
)
265 return (asl_object_t
)asl_client_open_from_file(fd
, ident
, facility
);
269 asl_close(asl_object_t obj
)
274 __private_extern__ asl_client_t
*
277 static dispatch_once_t once
;
279 dispatch_once(&once
, ^{
281 * Do a sleight-of-hand with ASL_OPT_NO_REMOTE to avoid a deadlock
282 * since asl_open(xxx, yyy, 0) calls _asl_notify_open(1)
283 * which locks _asl_global.lock.
285 _asl_global
.asl
= (asl_client_t
*)asl_open(NULL
, NULL
, ASL_OPT_NO_REMOTE
);
287 /* Reset options to clear ASL_OPT_NO_REMOTE bit */
288 if (_asl_global
.asl
!= NULL
) _asl_global
.asl
->options
= 0;
290 /* Now call _asl_notify_open(0) to finish the work */
294 return _asl_global
.asl
;
298 * asl_add_file: write log messages to the given file descriptor
299 * Log messages will be written to this file as well as to the server.
302 asl_add_output_file(asl_object_t client
, int fd
, const char *mfmt
, const char *tfmt
, int filter
, int text_encoding
)
304 int status
, use_global_lock
= 0;
307 if ((client
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1;
309 asl
= (asl_client_t
*)client
;
312 asl
= _asl_open_default();
313 if (asl
== NULL
) return -1;
314 pthread_mutex_lock(&_asl_global
.lock
);
318 status
= asl_client_add_output_file(asl
, fd
, mfmt
, tfmt
, filter
, text_encoding
);
320 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
321 return (status
== ASL_STATUS_OK
) ? 0 : -1;
324 /* returns previous filter value or -1 on error */
326 asl_set_output_file_filter(asl_object_t client
, int fd
, int filter
)
329 int use_global_lock
= 0;
332 if ((client
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1;
334 asl
= (asl_client_t
*)client
;
337 asl
= _asl_open_default();
338 if (asl
== NULL
) return -1;
339 pthread_mutex_lock(&_asl_global
.lock
);
343 last
= asl_client_set_output_file_filter(asl
, fd
, filter
);
345 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
349 /* SPI - Deprecated */
351 asl_add_output(asl_object_t client
, int fd
, const char *mfmt
, const char *tfmt
, uint32_t text_encoding
)
353 return asl_add_output_file(client
, fd
, mfmt
, tfmt
, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
), text_encoding
);
356 /* SPI - Deprecated */
358 asl_add_log_file(asl_object_t client
, int fd
)
360 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
);
364 * asl_remove_output: stop writing log messages to the given file descriptor
367 asl_remove_output_file(asl_object_t client
, int fd
)
369 int status
, use_global_lock
= 0;
372 if ((client
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1;
374 asl
= (asl_client_t
*)client
;
377 asl
= _asl_open_default();
378 if (asl
== NULL
) return -1;
379 pthread_mutex_lock(&_asl_global
.lock
);
383 status
= asl_client_remove_output_file(asl
, fd
);
385 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
386 return (status
== ASL_STATUS_OK
) ? 0 : -1;
390 asl_remove_output(asl_object_t client
, int fd
)
392 return asl_remove_output_file(client
, fd
);
396 asl_remove_log_file(asl_object_t client
, int fd
)
398 return asl_remove_output_file(client
, fd
);
401 /* returns previous filter value or -1 on error */
403 asl_set_filter(asl_object_t client
, int f
)
405 int last
, use_global_lock
= 0;
408 if ((client
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1;
410 asl
= (asl_client_t
*)client
;
413 asl
= _asl_open_default();
414 if (asl
== NULL
) return -1;
415 pthread_mutex_lock(&_asl_global
.lock
);
419 last
= asl_client_set_filter(asl
, f
);
421 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
427 #pragma mark message sending
430 * Evaluate client / message / level to determine what to do with a message.
431 * Checks filters, tunneling, and log files. Returns EVAL_IGNORE if the message
432 * can be ignored. Otherwise it returns the bits below, ORed with the level.
434 * EVAL_ASLFILE - will write to an asl file (see asl_open_from_file)
435 * EVAL_SEND - will send to syslogd
436 * EVAL_TUNNEL - will send to syslogd with tunneling enabled
437 * EVAL_FILE - will write to file
440 _asl_evaluate_send(asl_object_t client
, asl_object_t m
, int slevel
)
443 asl_msg_t
*msg
= (asl_msg_t
*)m
;
444 uint32_t level
, lmask
, filter
, status
, tunnel
;
449 level
= ASL_LEVEL_DEBUG
;
450 if (slevel
>= 0) level
= slevel
;
453 if ((asl_msg_lookup(msg
, ASL_KEY_LEVEL
, &val
, NULL
) == 0) && (val
!= NULL
)) level
= atoi(val
);
455 if (level
< ASL_LEVEL_EMERG
) level
= ASL_LEVEL_EMERG
;
456 else if (level
> ASL_LEVEL_DEBUG
) level
= ASL_LEVEL_DEBUG
;
458 if ((client
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
))
460 /* sending to something other than a client */
461 return (level
| EVAL_SEND
);
464 asl
= (asl_client_t
*)client
;
467 asl
= _asl_open_default();
468 if (asl
== NULL
) return EVAL_IGNORE
;
471 if (asl
->aslfile
!= NULL
) return (level
| EVAL_ASLFILE
);
473 lmask
= ASL_FILTER_MASK(level
);
475 filter
= asl
->filter
& 0xff;
476 tunnel
= (asl
->filter
& ASL_FILTER_MASK_TUNNEL
) >> 8;
478 if (!(asl
->options
& ASL_OPT_NO_REMOTE
))
480 pthread_mutex_lock(&_asl_global
.lock
);
482 if (_asl_global
.rc_change_token
>= 0)
484 /* initialize or re-check process-specific and master filters */
486 status
= notify_check(_asl_global
.rc_change_token
, &check
);
487 if ((status
== NOTIFY_STATUS_OK
) && (check
!= 0))
489 if (_asl_global
.master_token
>= 0)
492 status
= notify_get_state(_asl_global
.master_token
, &v64
);
493 if (status
== NOTIFY_STATUS_OK
) _asl_global
.master_filter
= v64
;
496 if (_asl_global
.notify_token
>= 0)
499 status
= notify_get_state(_asl_global
.notify_token
, &v64
);
500 if (status
== NOTIFY_STATUS_OK
) _asl_global
.proc_filter
= v64
;
505 pthread_mutex_unlock(&_asl_global
.lock
);
506 /* master filter overrides local filter */
507 if (_asl_global
.master_filter
!= 0)
509 filter
= _asl_global
.master_filter
;
513 /* process-specific filter overrides local and master */
514 if (_asl_global
.proc_filter
!= 0)
516 filter
= _asl_global
.proc_filter
;
521 if ((filter
!= 0) && ((filter
& lmask
) != 0))
524 if (tunnel
!= 0) level
|= EVAL_TUNNEL
;
525 if (asl
->out_count
> 0) level
|= EVAL_FILE
;
530 if ((asl
->options
& ASL_OPT_SYSLOG_LEGACY
) && (filter
!= 0) && ((filter
& lmask
) == 0))
535 if (asl
->out_count
> 0) return (level
| EVAL_FILE
);
542 * Internal routine used by asl_vlog.
543 * msg: an asl messsage
544 * eval: log level and send flags for the message
545 * format: A formating string
546 * ap: va_list for the format
547 * returns 0 for success, non-zero for failure
550 _asl_lib_vlog(asl_object_t obj
, uint32_t eval
, asl_object_t msg
, const char *format
, va_list ap
)
552 int saved_errno
= errno
;
554 char *str
, *fmt
, estr
[NL_TEXTMAX
];
555 uint32_t i
, len
, elen
, expand
;
557 if (format
== NULL
) return ASL_STATUS_INVALID_ARG
;
559 /* insert strerror for %m */
564 for (i
= 0; format
[i
] != '\0'; i
++)
566 if (format
[i
] == '%')
568 if (format
[i
+1] == '\0') len
++;
569 else if (format
[i
+1] == 'm')
572 strerror_r(saved_errno
, estr
, sizeof(estr
));
586 fmt
= (char *)format
;
590 fmt
= malloc(len
+ 1);
593 if (estr
!= NULL
) free(estr
);
594 return ASL_STATUS_NO_MEMORY
;
599 for (i
= 0; format
[i
] != '\0'; i
++)
601 if (format
[i
] == '%')
603 if (format
[i
+1] == '\0')
606 else if ((format
[i
+1] == 'm') && (elen
!= 0))
608 memcpy(fmt
+len
, estr
, elen
);
614 fmt
[len
++] = format
[i
++];
615 fmt
[len
++] = format
[i
];
618 else fmt
[len
++] = format
[i
];
625 vasprintf(&str
, fmt
, ap
);
626 if (expand
!= 0) free(fmt
);
628 if (str
== NULL
) return ASL_STATUS_NO_MEMORY
;
630 status
= _asl_send_message(obj
, eval
, (asl_msg_t
*)msg
, str
);
638 * Similar to asl_log, but take a va_list instead of a list of arguments.
639 * msg: an asl message
640 * level: the log level of the associated message
641 * format: A formating string
642 * ap: va_list for the format
643 * returns 0 for success, non-zero for failure
646 asl_vlog(asl_object_t client
, asl_object_t msg
, int level
, const char *format
, va_list ap
)
648 uint32_t eval
= _asl_evaluate_send(client
, msg
, level
);
649 if (eval
== EVAL_IGNORE
) return 0;
651 ASL_STATUS status
= _asl_lib_vlog(client
, eval
, msg
, format
, ap
);
652 return (status
== ASL_STATUS_OK
) ? 0 : -1;
657 * SPI used by ASL_PREFILTER_LOG. Converts format arguments to a va_list and
658 * forwards the call to _asl_lib_vlog.
659 * msg: an asl message
660 * eval: log level and send flags for the message
661 * format: A formating string
662 * ... args for format
663 * returns 0 for success, non-zero for failure
666 _asl_lib_log(asl_object_t client
, uint32_t eval
, asl_object_t msg
, const char *format
, ...)
669 if (eval
== EVAL_IGNORE
) return 0;
672 va_start(ap
, format
);
673 status
= _asl_lib_vlog(client
, eval
, msg
, format
, ap
);
681 * Processes an ASL log message.
682 * msg: an asl message
683 * level: the log level of the associated message
684 * format: A formating string
685 * ... args for format
686 * returns 0 for success, non-zero for failure
689 asl_log(asl_object_t client
, asl_object_t msg
, int level
, const char *format
, ...)
692 uint32_t eval
= _asl_evaluate_send(client
, msg
, level
);
693 if (eval
== EVAL_IGNORE
) return 0;
696 va_start(ap
, format
);
697 status
= _asl_lib_vlog(client
, eval
, msg
, format
, ap
);
700 return (status
== ASL_STATUS_OK
) ? 0 : -1;
705 * Like asl_log, supplies NULL client and msg.
706 * level: the log level of the associated message
707 * format: A formating string
708 * ... args for format
709 * returns 0 for success, non-zero for failure
712 asl_log_message(int level
, const char *format
, ...)
715 uint32_t eval
= _asl_evaluate_send(NULL
, NULL
, level
);
716 if (eval
== EVAL_IGNORE
) return 0;
719 va_start(ap
, format
);
720 status
= _asl_lib_vlog(NULL
, eval
, NULL
, format
, ap
);
723 return (status
== ASL_STATUS_OK
) ? 0 : -1;
727 * asl_get_filter: gets the values for the local, master, and remote filters,
728 * and indicates which one is active.
731 asl_get_filter(asl_object_t client
, int *local
, int *master
, int *remote
, int *active
)
733 asl_client_t
*asl
, *asl_default
;
738 if ((client
!= NULL
) && (asl_get_type(client
) != ASL_TYPE_CLIENT
)) return -1;
745 asl_default
= _asl_open_default();
747 asl
= (asl_client_t
*)client
;
748 if (asl
== NULL
) asl
= asl_default
;
749 if (asl
!= NULL
) l
= asl
->filter
& 0xff;
751 if ((asl_default
!= NULL
) && (!(asl_default
->options
& ASL_OPT_NO_REMOTE
)))
753 pthread_mutex_lock(&_asl_global
.lock
);
755 if (_asl_global
.rc_change_token
>= 0)
757 /* initialize or re-check process-specific and master filters */
759 status
= notify_check(_asl_global
.rc_change_token
, &check
);
760 if ((status
== NOTIFY_STATUS_OK
) && (check
!= 0))
762 if (_asl_global
.master_token
>= 0)
765 status
= notify_get_state(_asl_global
.master_token
, &v64
);
766 if (status
== NOTIFY_STATUS_OK
) _asl_global
.master_filter
= v64
;
769 if (_asl_global
.notify_token
>= 0)
772 status
= notify_get_state(_asl_global
.notify_token
, &v64
);
773 if (status
== NOTIFY_STATUS_OK
) _asl_global
.proc_filter
= v64
;
778 m
= _asl_global
.master_filter
;
781 r
= _asl_global
.proc_filter
;
784 pthread_mutex_unlock(&_asl_global
.lock
);
787 if (local
!= NULL
) *local
= l
;
788 if (master
!= NULL
) *master
= m
;
789 if (remote
!= NULL
) *remote
= r
;
790 if (active
!= NULL
) *active
= x
;
796 * Sets Host, PID, UID, GID, and OSActivityID values in a new message.
797 * Also sets Level, Time, TimeNanoSec, Sender, Facility and Message if provided.
800 asl_base_msg(asl_client_t
*asl
, uint32_t level
, const struct timeval
*tv
, const char *sstr
, const char *fstr
, const char *mstr
)
803 char aux_host
[_POSIX_HOST_NAME_MAX
];
806 unsigned int osacount
= 1;
807 os_activity_t osaid
= 0;
809 aux
= asl_msg_new(ASL_TYPE_MSG
);
810 if (aux
== NULL
) return NULL
;
813 if (level
<= 7) asl_msg_set_key_val(aux
, ASL_KEY_LEVEL
, level_to_number_string
[level
]);
815 /* Time and TimeNanoSec */
818 snprintf(aux_val
, sizeof(aux_val
), "%lu", tv
->tv_sec
);
819 asl_msg_set_key_val(aux
, ASL_KEY_TIME
, aux_val
);
821 snprintf(aux_val
, sizeof(aux_val
), "%d", tv
->tv_usec
* 1000);
822 asl_msg_set_key_val(aux
, ASL_KEY_TIME_NSEC
, aux_val
);
826 if (mstr
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_MSG
, mstr
);
829 memset(&aux_host
, 0, _POSIX_HOST_NAME_MAX
);
830 if (gethostname(aux_host
, _POSIX_HOST_NAME_MAX
) == 0) asl_msg_set_key_val(aux
, ASL_KEY_HOST
, aux_host
);
833 snprintf(aux_val
, sizeof(aux_val
), "%u", getpid());
834 asl_msg_set_key_val(aux
, ASL_KEY_PID
, aux_val
);
837 snprintf(aux_val
, sizeof(aux_val
), "%d", getuid());
838 asl_msg_set_key_val(aux
, ASL_KEY_UID
, aux_val
);
841 snprintf(aux_val
, sizeof(aux_val
), "%d", getgid());
842 asl_msg_set_key_val(aux
, ASL_KEY_GID
, aux_val
);
845 if (os_activity_get_active(&osaid
, &osacount
) == 1)
847 snprintf(aux_val
, sizeof(aux_val
), "0x%016llx", (uint64_t)osaid
);
848 asl_msg_set_key_val(aux
, ASL_KEY_OS_ACTIVITY_ID
, aux_val
);
854 /* See if the client has a value for ASL_KEY_SENDER */
855 status
= asl_msg_lookup((asl_msg_t
*)asl
->kvdict
, ASL_KEY_SENDER
, &sstr
, NULL
);
856 if ((status
!= 0) || (sstr
== NULL
))
860 /* See if the global cache has a value for ASL_KEY_SENDER */
861 if (_asl_global
.sender
== NULL
)
863 /* Get the process name with _NSGetArgv */
864 char *name
= *(*_NSGetArgv());
867 char *x
= strrchr(name
, '/');
871 /* Set the cache value */
872 pthread_mutex_lock(&_asl_global
.lock
);
873 if (_asl_global
.sender
== NULL
) _asl_global
.sender
= strdup(x
);
874 pthread_mutex_unlock(&_asl_global
.lock
);
878 if (_asl_global
.sender
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, _asl_global
.sender
);
879 else asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, "Unknown");
883 if (sstr
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_SENDER
, sstr
);
888 status
= asl_msg_lookup((asl_msg_t
*)asl
->kvdict
, ASL_KEY_FACILITY
, &fstr
, NULL
);
889 if (status
!= 0) fstr
= NULL
;
892 if (fstr
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_FACILITY
, fstr
);
899 * Possibly useful someday...
902 asl_prepared_message(asl_client_t
*asl
, asl_msg_t
*msg
)
904 uint32_t i
, len
, level
, outstatus
;
905 const char *val
, *sstr
, *fstr
;
906 struct timeval tval
= {0, 0};
912 asl
= _asl_open_default();
913 if (asl
== NULL
) return NULL
;
916 status
= gettimeofday(&tval
, NULL
);
919 time_t tick
= time(NULL
);
925 status
= asl_msg_lookup(msg
, ASL_KEY_LEVEL
, &val
, NULL
);
926 if (status
!= 0) val
= NULL
;
928 level
= ASL_LEVEL_DEBUG
;
929 if (val
!= NULL
) level
= atoi(val
);
930 if (level
> ASL_LEVEL_DEBUG
) level
= ASL_LEVEL_DEBUG
;
933 status
= asl_msg_lookup(msg
, ASL_KEY_SENDER
, &sstr
, NULL
);
934 if (status
!= 0) sstr
= NULL
;
937 status
= asl_msg_lookup(msg
, ASL_KEY_FACILITY
, &fstr
, NULL
);
938 if (status
!= 0) fstr
= NULL
;
940 out
= asl_base_msg(asl
, level
, &tval
, sstr
, fstr
, NULL
);
941 out
= asl_msg_merge(out
, msg
);
948 _asl_send_message(asl_object_t obj
, uint32_t eval
, asl_msg_t
*msg
, const char *mstr
)
950 uint32_t i
, len
, level
, lmask
, outstatus
, objtype
;
951 const char *sstr
, *fstr
;
952 struct timeval tval
= {0, 0};
954 int use_global_lock
= 0;
955 kern_return_t kstatus
;
957 asl_msg_t
*qd_msg
= NULL
;
958 asl_client_t
*asl
= NULL
;
959 static dispatch_once_t noquota_once
;
961 if (eval
== EVAL_IGNORE
) return ASL_STATUS_OK
;
965 asl
= _asl_open_default();
966 if (asl
== NULL
) return ASL_STATUS_FAILED
;
968 objtype
= ASL_TYPE_CLIENT
;
972 objtype
= asl_get_type(obj
);
973 if (objtype
== ASL_TYPE_CLIENT
) asl
= (asl_client_t
*)obj
;
974 else asl
= _asl_open_default();
977 level
= eval
& LEVEL_MASK
;
978 if (level
> 7) level
= 7;
980 lmask
= ASL_FILTER_MASK(level
);
982 if ((objtype
== ASL_TYPE_CLIENT
) && (asl
->aslfile
!= NULL
)) use_global_lock
= 1;
984 status
= gettimeofday(&tval
, NULL
);
987 time_t tick
= time(NULL
);
993 status
= asl_msg_lookup(msg
, ASL_KEY_SENDER
, &sstr
, NULL
);
994 if (status
!= 0) sstr
= NULL
;
997 status
= asl_msg_lookup(msg
, ASL_KEY_FACILITY
, &fstr
, NULL
);
998 if (status
!= 0) fstr
= NULL
;
1000 sendmsg
= asl_base_msg(asl
, level
, &tval
, sstr
, fstr
, mstr
);
1001 if (sendmsg
== NULL
) return ASL_STATUS_FAILED
;
1003 /* Set "ASLOption store" if tunneling */
1004 if (eval
& EVAL_TUNNEL
)
1006 const char *val
= NULL
;
1007 status
= asl_msg_lookup(msg
, ASL_KEY_OPTION
, &val
, NULL
);
1008 if ((status
!= 0) || (val
== NULL
))
1010 asl_msg_set_key_val(sendmsg
, ASL_KEY_OPTION
, ASL_OPT_STORE
);
1014 char *option
= NULL
;
1015 asprintf(&option
, "%s %s", ASL_OPT_STORE
, val
);
1016 asl_msg_set_key_val(sendmsg
, ASL_KEY_OPTION
, option
);
1023 if (use_global_lock
!= 0) pthread_mutex_lock(&_asl_global
.lock
);
1025 sendmsg
= asl_msg_merge(sendmsg
, msg
);
1027 if (objtype
!= ASL_TYPE_CLIENT
)
1029 asl_append(obj
, (asl_object_t
)sendmsg
);
1030 asl_msg_release(sendmsg
);
1031 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1032 return ASL_STATUS_OK
;
1036 * If there is an aslfile this is a stand-alone file client.
1037 * Just save to the file.
1039 if (asl
->aslfile
!= NULL
)
1041 outstatus
= ASL_STATUS_FAILED
;
1043 if (sendmsg
!= NULL
)
1045 outstatus
= asl_file_save(asl
->aslfile
, sendmsg
, &(asl
->aslfileid
));
1049 asl_msg_release(sendmsg
);
1051 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1055 _asl_global_init(0);
1060 * Quotas are disabled if:
1061 * - a remote control filter is in place (EVAL_TUNNEL)
1062 * - Environment variable ASL_QUOTA_DISABLED == 1
1063 * - /etc/asl/.noquota existed at the time that the process started
1065 * Note that we just check /etc/asl/.noquota once, since it would be
1066 * expensive to stat() for every log message.
1069 dispatch_once(&noquota_once
, ^{
1071 memset(&sb
, 0, sizeof(struct stat
));
1072 if (stat(NOQUOTA_FILE_PATH
, &sb
) == 0) _asl_global
.quota
= UINT32_MAX
;
1075 if (_asl_global
.quota
!= UINT32_MAX
)
1077 const char *qtest
= getenv(NOQUOTA_ENV
);
1078 if ((qtest
!= NULL
) && (!strcmp(qtest
, "1")))
1080 _asl_global
.quota
= UINT32_MAX
;
1082 qd_msg
= asl_base_msg(asl
, QUOTA_LEVEL
, &tval
, sstr
, fstr
, QUOTA_DISABLED_MSG
);
1083 asl_msg_set_key_val(qd_msg
, ASL_KEY_OPTION
, ASL_OPT_STORE
);
1087 if (((eval
& EVAL_TUNNEL
) == 0) && (_asl_global
.quota
!= UINT32_MAX
))
1089 time_t last_send
= _asl_global
.last_send
;
1090 time_t last_oq
= _asl_global
.last_oq_msg
;
1091 uint32_t qcurr
= _asl_global
.quota
;
1093 uint32_t qinc
, qnew
;
1097 /* add QUOTA_MPS to quota for each second we've been idle */
1098 if (tval
.tv_sec
> last_send
)
1100 delta
= tval
.tv_sec
- last_send
;
1103 if (delta
< (QUOTA_MPH
/ QUOTA_MPS
)) qinc
= delta
* QUOTA_MPS
;
1105 qnew
= MIN(QUOTA_MPH
, qcurr
+ qinc
);
1106 OSAtomicCompareAndSwapLongBarrier(last_send
, tval
.tv_sec
, (long *)&_asl_global
.last_send
);
1111 if ((tval
.tv_sec
- last_oq
) > QUOTA_MSG_INTERVAL
)
1114 OSAtomicCompareAndSwapLongBarrier(last_oq
, tval
.tv_sec
, (long *)&_asl_global
.last_oq_msg
);
1123 OSAtomicCompareAndSwap32Barrier(qcurr
, qnew
- 1, (int32_t *)&_asl_global
.quota
);
1127 if ((_asl_global
.server_port
!= MACH_PORT_NULL
) && (eval
& EVAL_SEND
))
1129 asl_string_t
*send_str
;
1133 if (eval
& EVAL_QUOTA
)
1135 asl_msg_set_key_val(sendmsg
, ASL_KEY_LEVEL
, QUOTA_LEVEL_STR
);
1136 asl_msg_set_key_val(sendmsg
, ASL_KEY_MSG
, QUOTA_MSG
);
1141 send_str
= asl_msg_to_string_raw(ASL_STRING_MIG
, qd_msg
, "raw");
1142 len
= asl_string_length(send_str
);
1143 vmsize
= asl_string_allocated_size(send_str
);
1144 str
= asl_string_release_return_bytes(send_str
);
1145 if (len
!= 0) kstatus
= _asl_server_message(_asl_global
.server_port
, (caddr_t
)str
, len
);
1146 if ((str
!= NULL
) && (vmsize
!= 0)) vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1147 asl_msg_release(qd_msg
);
1150 send_str
= asl_msg_to_string_raw(ASL_STRING_MIG
, sendmsg
, "raw");
1151 len
= asl_string_length(send_str
);
1152 vmsize
= asl_string_allocated_size(send_str
);
1153 str
= asl_string_release_return_bytes(send_str
);
1157 /* send a mach message to syslogd */
1158 kstatus
= _asl_server_message(_asl_global
.server_port
, (caddr_t
)str
, len
);
1159 if (kstatus
!= KERN_SUCCESS
)
1161 /* retry once if the call failed */
1162 _asl_global_init(1);
1163 kstatus
= _asl_server_message(_asl_global
.server_port
, (caddr_t
)str
, len
);
1164 if (kstatus
!= KERN_SUCCESS
)
1166 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1171 else if (vmsize
>0) vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1174 if ((sendmsg
!= NULL
) && (asl
->out_count
> 0))
1176 /* write to file descriptors */
1177 for (i
= 0; i
< asl
->out_count
; i
++)
1179 if ((asl
->out_list
[i
].fd
>= 0) && (asl
->out_list
[i
].filter
!= 0) && ((asl
->out_list
[i
].filter
& lmask
) != 0))
1184 str
= asl_format_message(sendmsg
, asl
->out_list
[i
].mfmt
, asl
->out_list
[i
].tfmt
, asl
->out_list
[i
].encoding
, &len
);
1185 if (str
== NULL
) continue;
1187 status
= write(asl
->out_list
[i
].fd
, str
, len
- 1);
1190 /* soft error for fd 2 (stderr) */
1191 if (asl
->out_list
[i
].fd
!= 2) outstatus
= -1;
1192 asl
->out_list
[i
].fd
= -1;
1200 asl_msg_release(sendmsg
);
1202 if (use_global_lock
!= 0) pthread_mutex_unlock(&_asl_global
.lock
);
1208 * asl_send: send a message
1209 * This routine may be used instead of asl_log() or asl_vlog() if asl_set()
1210 * has been used to set all of a message's attributes.
1211 * eval: hints about what to do with the message
1212 * msg: an asl message
1213 * returns 0 for success, non-zero for failure
1215 __private_extern__ ASL_STATUS
1216 asl_client_internal_send(asl_object_t obj
, asl_object_t msg
)
1218 int status
= ASL_STATUS_OK
;
1219 uint32_t eval
= _asl_evaluate_send(obj
, msg
, -1);
1220 if (eval
!= 0) status
= _asl_send_message(obj
, eval
, (asl_msg_t
*)msg
, NULL
);
1226 #pragma mark auxiliary files and URLs
1229 _asl_aux_save_context(asl_aux_context_t
*ctx
)
1231 if (ctx
== NULL
) return ASL_STATUS_FAILED
;
1233 pthread_mutex_lock(&_asl_global
.lock
);
1235 _asl_global
.aux_ctx
= (asl_aux_context_t
**)reallocf(_asl_global
.aux_ctx
, (_asl_global
.aux_count
+ 1) * sizeof(asl_aux_context_t
*));
1236 if (_asl_global
.aux_ctx
== NULL
)
1238 _asl_global
.aux_count
= 0;
1239 pthread_mutex_unlock(&_asl_global
.lock
);
1240 return ASL_STATUS_FAILED
;
1243 _asl_global
.aux_ctx
[_asl_global
.aux_count
++] = ctx
;
1245 pthread_mutex_unlock(&_asl_global
.lock
);
1247 return ASL_STATUS_OK
;
1251 * Creates an auxiliary file that may be used to save arbitrary data. The ASL message msg
1252 * will be saved at the time that the auxiliary file is created. The message will include
1253 * any keys and values found in msg, and it will include the title and Uniform Type
1254 * Identifier specified. Output parameter out_fd will contain the file descriptor of the
1255 * new auxiliary file.
1258 _asl_auxiliary(asl_msg_t
*msg
, const char *title
, const char *uti
, const char *url
, int *out_fd
)
1261 asl_string_t
*send_str
;
1263 fileport_t fileport
;
1264 kern_return_t kstatus
;
1266 uint32_t newurllen
, where
;
1267 int status
, fd
, fdpair
[2];
1269 dispatch_queue_t pipe_q
;
1270 dispatch_io_t pipe_channel
;
1271 dispatch_semaphore_t sem
;
1273 aux
= asl_msg_new(ASL_TYPE_MSG
);
1275 if (url
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_AUX_URL
, url
);
1276 if (title
!= NULL
) asl_msg_set_key_val(aux
, ASL_KEY_AUX_TITLE
, title
);
1277 if (uti
== NULL
) asl_msg_set_key_val(aux
, ASL_KEY_AUX_UTI
, "public.data");
1278 else asl_msg_set_key_val(aux
, ASL_KEY_AUX_UTI
, uti
);
1280 aux
= asl_msg_merge(aux
, msg
);
1282 /* if (out_fd == NULL), this is from asl_log_auxiliary_location */
1285 uint32_t eval
= _asl_evaluate_send(NULL
, (asl_object_t
)aux
, -1);
1286 status
= _asl_send_message(NULL
, eval
, aux
, NULL
);
1287 asl_msg_release(aux
);
1291 where
= asl_store_location();
1292 if (where
== ASL_STORE_LOCATION_MEMORY
)
1295 asl_aux_context_t
*ctx
= (asl_aux_context_t
*)calloc(1, sizeof(asl_aux_context_t
));
1296 if (ctx
== NULL
) return ASL_STATUS_FAILED
;
1298 status
= pipe(fdpair
);
1302 return ASL_STATUS_FAILED
;
1305 /* give read end to dispatch_io_read */
1307 sem
= dispatch_semaphore_create(0);
1309 ctx
->fd
= fdpair
[1];
1311 status
= _asl_aux_save_context(ctx
);
1312 if (status
!= ASL_STATUS_OK
)
1316 dispatch_release(sem
);
1318 return ASL_STATUS_FAILED
;
1321 pipe_q
= dispatch_queue_create("ASL_AUX_PIPE_Q", NULL
);
1322 pipe_channel
= dispatch_io_create(DISPATCH_IO_STREAM
, fd
, pipe_q
, ^(int err
){
1326 *out_fd
= fdpair
[1];
1328 dispatch_io_set_low_water(pipe_channel
, SIZE_MAX
);
1330 dispatch_io_read(pipe_channel
, 0, SIZE_MAX
, pipe_q
, ^(bool done
, dispatch_data_t pipedata
, int err
){
1333 size_t len
= dispatch_data_get_size(pipedata
);
1336 const char *bytes
= NULL
;
1340 dispatch_data_t md
= dispatch_data_create_map(pipedata
, (const void **)&bytes
, &len
);
1341 encoded
= asl_core_encode_buffer(bytes
, len
);
1342 asl_msg_set_key_val(aux
, ASL_KEY_AUX_DATA
, encoded
);
1344 eval
= _asl_evaluate_send(NULL
, (asl_object_t
)aux
, -1);
1345 _asl_send_message(NULL
, eval
, aux
, NULL
);
1346 asl_msg_release(aux
);
1347 dispatch_release(md
);
1353 dispatch_semaphore_signal(sem
);
1354 dispatch_release(pipe_channel
);
1355 dispatch_release(pipe_q
);
1359 return ASL_STATUS_OK
;
1362 _asl_global_init(0);
1363 if (_asl_global
.server_port
== MACH_PORT_NULL
) return ASL_STATUS_FAILED
;
1365 send_str
= asl_msg_to_string_raw(ASL_STRING_MIG
, aux
, "raw");
1366 len
= asl_string_length(send_str
);
1367 vmsize
= asl_string_allocated_size(send_str
);
1368 str
= asl_string_release_return_bytes(send_str
);
1372 asl_msg_release(aux
);
1373 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1374 return ASL_STATUS_FAILED
;
1378 fileport
= MACH_PORT_NULL
;
1379 status
= KERN_SUCCESS
;
1381 kstatus
= _asl_server_create_aux_link(_asl_global
.server_port
, (caddr_t
)str
, len
, &fileport
, &newurl
, &newurllen
, &status
);
1382 if (kstatus
!= KERN_SUCCESS
)
1384 /* retry once if the call failed */
1385 _asl_global_init(1);
1386 kstatus
= _asl_server_create_aux_link(_asl_global
.server_port
, (caddr_t
)str
, len
, &fileport
, &newurl
, &newurllen
, &status
);
1387 if (kstatus
!= KERN_SUCCESS
)
1389 vm_deallocate(mach_task_self(), (vm_address_t
)str
, vmsize
);
1390 asl_msg_release(aux
);
1391 return ASL_STATUS_FAILED
;
1397 asl_msg_release(aux
);
1403 asl_msg_set_key_val(aux
, ASL_KEY_AUX_URL
, newurl
);
1404 vm_deallocate(mach_task_self(), (vm_address_t
)newurl
, newurllen
);
1407 if (fileport
== MACH_PORT_NULL
)
1409 asl_msg_release(aux
);
1410 return ASL_STATUS_FAILED
;
1413 fd
= fileport_makefd(fileport
);
1414 mach_port_deallocate(mach_task_self(), fileport
);
1417 asl_msg_release(aux
);
1422 asl_aux_context_t
*ctx
= (asl_aux_context_t
*)calloc(1, sizeof(asl_aux_context_t
));
1434 status
= _asl_aux_save_context(ctx
);
1442 asl_create_auxiliary_file(asl_object_t msg
, const char *title
, const char *uti
, int *out_fd
)
1444 if (out_fd
== NULL
) return -1;
1446 ASL_STATUS status
= _asl_auxiliary((asl_msg_t
*)msg
, title
, uti
, NULL
, out_fd
);
1447 return (status
== ASL_STATUS_OK
) ? 0 : -1;
1451 asl_log_auxiliary_location(asl_object_t msg
, const char *title
, const char *uti
, const char *url
)
1453 ASL_STATUS status
= _asl_auxiliary((asl_msg_t
*)msg
, title
, uti
, url
, NULL
);
1454 return (status
== ASL_STATUS_OK
) ? 0 : -1;
1458 * Close an auxiliary file.
1459 * Sends the cached auxiliary message to syslogd.
1460 * Returns 0 on success, -1 on error.
1463 asl_close_auxiliary_file(int fd
)
1467 dispatch_semaphore_t aux_sem
= NULL
;
1469 pthread_mutex_lock(&(_asl_global
.lock
));
1474 for (i
= 0; i
< _asl_global
.aux_count
; i
++)
1476 if (_asl_global
.aux_ctx
[i
]->fd
== fd
)
1480 aux_msg
= _asl_global
.aux_ctx
[i
]->msg
;
1481 aux_sem
= _asl_global
.aux_ctx
[i
]->sem
;
1483 free(_asl_global
.aux_ctx
[i
]);
1485 for (j
= i
+ 1; j
< _asl_global
.aux_count
; i
++, j
++)
1487 _asl_global
.aux_ctx
[i
] = _asl_global
.aux_ctx
[j
];
1490 _asl_global
.aux_count
--;
1492 if (_asl_global
.aux_count
== 0)
1494 free(_asl_global
.aux_ctx
);
1495 _asl_global
.aux_ctx
= NULL
;
1499 _asl_global
.aux_ctx
= (asl_aux_context_t
**)reallocf(_asl_global
.aux_ctx
, _asl_global
.aux_count
* sizeof(asl_aux_context_t
*));
1500 if (_asl_global
.aux_ctx
== NULL
)
1502 _asl_global
.aux_count
= 0;
1511 pthread_mutex_unlock(&(_asl_global
.lock
));
1515 if (aux_msg
!= NULL
)
1517 uint32_t eval
= _asl_evaluate_send(NULL
, (asl_object_t
)aux_msg
, -1);
1518 if (_asl_send_message(NULL
, eval
, aux_msg
, NULL
) != ASL_STATUS_OK
) status
= -1;
1519 asl_msg_release(aux_msg
);
1522 if (aux_sem
!= NULL
)
1524 dispatch_semaphore_wait(aux_sem
, DISPATCH_TIME_FOREVER
);
1525 dispatch_release(aux_sem
);
1534 _asl_server_control_query(void)
1536 asl_msg_list_t
*list
= NULL
;
1538 uint32_t len
, reslen
, status
;
1539 uint64_t cmax
, qmin
;
1540 kern_return_t kstatus
;
1542 asl_msg_t
*m
= NULL
;
1543 static const char ctlstr
[] = "1\nQ [= ASLOption control]\n";
1545 _asl_global_init(0);
1546 if (_asl_global
.server_port
== MACH_PORT_NULL
) return NULL
;
1548 len
= strlen(ctlstr
) + 1;
1555 kstatus
= vm_allocate(mach_task_self(), (vm_address_t
*)&vmstr
, len
, TRUE
);
1556 if (kstatus
!= KERN_SUCCESS
) return NULL
;
1558 memmove(vmstr
, ctlstr
, len
);
1561 kstatus
= _asl_server_query_2(_asl_global
.server_port
, vmstr
, len
, qmin
, FETCH_BATCH
, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
);
1562 if (kstatus
!= KERN_SUCCESS
)
1564 /* retry once if the call failed */
1565 _asl_global_init(1);
1566 kstatus
= _asl_server_query_2(_asl_global
.server_port
, vmstr
, len
, qmin
, FETCH_BATCH
, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
);
1569 list
= asl_msg_list_from_string(res
);
1570 vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
);
1572 if (list
== NULL
) return NULL
;
1573 if (list
->count
> 0) m
= asl_msg_retain(list
->msg
[0]);
1574 asl_msg_list_release(list
);
1579 * Returns ASL_STORE_LOCATION_FILE or ASL_STORE_LOCATION_MEMORY
1582 asl_store_location()
1584 kern_return_t kstatus
;
1586 uint32_t reslen
, status
;
1589 _asl_global_init(0);
1590 if (_asl_global
.server_port
== MACH_PORT_NULL
) return ASL_STORE_LOCATION_FILE
;
1595 status
= ASL_STATUS_OK
;
1597 kstatus
= _asl_server_query_2(_asl_global
.server_port
, NULL
, 0, 0, -1, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
);
1598 if (kstatus
!= KERN_SUCCESS
)
1600 /* retry once if the call failed */
1601 _asl_global_init(1);
1602 kstatus
= _asl_server_query_2(_asl_global
.server_port
, NULL
, 0, 0, -1, 0, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
);
1605 /* res should never be returned, but just to be certain we don't leak VM ... */
1606 if (res
!= NULL
) vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
);
1608 if (kstatus
!= KERN_SUCCESS
) return ASL_STORE_LOCATION_FILE
;
1609 if (status
== ASL_STATUS_OK
) return ASL_STORE_LOCATION_MEMORY
;
1610 return ASL_STORE_LOCATION_FILE
;
1614 asl_open_path(const char *path
, uint32_t opts
)
1617 asl_file_t
*fout
= NULL
;
1618 asl_store_t
*sout
= NULL
;
1620 if (opts
== 0) opts
= ASL_OPT_OPEN_READ
;
1622 if (opts
& ASL_OPT_OPEN_READ
)
1626 if (asl_store_open_read(ASL_PLACE_DATABASE_DEFAULT
, &sout
) != ASL_STATUS_OK
) return NULL
;
1627 return (asl_object_t
)sout
;
1630 memset(&sb
, 0, sizeof(struct stat
));
1631 if (stat(path
, &sb
) < 0) return NULL
;
1633 if (sb
.st_mode
& S_IFREG
)
1635 if (asl_file_open_read(path
, &fout
) != ASL_STATUS_OK
) return NULL
;
1636 return (asl_object_t
)fout
;
1638 else if (sb
.st_mode
& S_IFDIR
)
1640 if (asl_store_open_read(path
, &sout
) != ASL_STATUS_OK
) return NULL
;
1641 return (asl_object_t
)sout
;
1646 else if (opts
& ASL_OPT_OPEN_WRITE
)
1648 if (path
== NULL
) return NULL
;
1650 memset(&sb
, 0, sizeof(struct stat
));
1651 if (stat(path
, &sb
) < 0)
1653 if (errno
!= ENOENT
) return NULL
;
1655 if (opts
& ASL_OPT_CREATE_STORE
)
1657 if (asl_store_open_write(path
, &sout
) != ASL_STATUS_OK
) return NULL
;
1658 return (asl_object_t
)fout
;
1662 if (asl_file_open_write(path
, 0644, geteuid(), getegid(), &fout
) != ASL_STATUS_OK
) return NULL
;
1663 return (asl_object_t
)fout
;
1666 else if (sb
.st_mode
& S_IFREG
)
1668 if (asl_file_open_write(path
, 0644, geteuid(), getegid(), &fout
) != ASL_STATUS_OK
) return NULL
;
1669 return (asl_object_t
)fout
;
1671 else if (sb
.st_mode
& S_IFDIR
)
1673 if (asl_store_open_write(path
, &sout
) != ASL_STATUS_OK
) return NULL
;
1674 return (asl_object_t
)sout
;