2 * Copyright (c) 2004-2012 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@
24 #include <TargetConditionals.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
28 #include <sys/ucred.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
37 #include <sys/fslog.h>
39 #include <mach/mach.h>
40 #include <libkern/OSAtomic.h>
42 #include <uuid/uuid.h>
43 #include <asl_private.h>
44 #include <os/transaction_private.h>
49 #define LIST_SIZE_DELTA 256
50 #define STATS_TABLE_SIZE 256
52 #define forever for(;;)
54 #define ASL_MSG_TYPE_MASK 0x0000000f
55 #define ASL_TYPE_ERROR 2
57 #define ASL_KEY_FACILITY "Facility"
59 #define FACILITY_USER "user"
60 #define FACILITY_CONSOLE "com.apple.console"
61 #define SYSTEM_RESERVED "com.apple.system"
62 #define SYSTEM_RESERVED_LEN 16
64 #define VERIFY_STATUS_OK 0
65 #define VERIFY_STATUS_INVALID_MESSAGE 1
66 #define VERIFY_STATUS_EXCEEDED_QUOTA 2
68 extern void disaster_message(asl_msg_t
*m
);
69 extern int asl_action_reset(void);
70 extern int asl_action_control_set_param(const char *s
);
72 static char myname
[MAXHOSTNAMELEN
+ 1] = {0};
73 static int name_change_token
= -1;
75 static OSSpinLock count_lock
= 0;
77 #if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
78 static os_transaction_t main_transaction
;
81 #define DEFAULT_MEMORY_MAX SYSLOGD_WORK_QUEUE_MEMORY
83 #define QUOTA_KERN_EXCEEDED_MESSAGE "*** kernel exceeded %d log message per second limit - remaining messages this second discarded ***"
85 #define DEFAULT_DB_FILE_MAX 25600000
86 #define DEFAULT_DB_MEMORY_MAX 256
87 #define DEFAULT_DB_MEMORY_STR_MAX 1024000
88 #define DEFAULT_MPS_LIMIT 500
89 #define DEFAULT_REMOTE_DELAY 5000
90 #define DEFAULT_BSD_MAX_DUP_SEC 30
91 #define DEFAULT_MARK_SEC 0
92 #define DEFAULT_UTMP_TTL_SEC 31622400
93 #define DEFAULT_STATS_INTERVAL 600
95 #define ASL_STATS_LEVEL 5
97 static time_t quota_time
= 0;
98 static int32_t kern_quota
;
99 static int32_t kern_level
;
101 static const char *kern_notify_key
[] =
103 "com.apple.system.log.kernel.emergency",
104 "com.apple.system.log.kernel.alert",
105 "com.apple.system.log.kernel.critical",
106 "com.apple.system.log.kernel.error",
107 "com.apple.system.log.kernel.warning",
108 "com.apple.system.log.kernel.notice",
109 "com.apple.system.log.kernel.info",
110 "com.apple.system.log.kernel.debug"
113 static int kern_notify_token
[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
115 static stats_table_t
*
118 stats_table_t
*t
= (stats_table_t
*)malloc(sizeof(stats_table_t
));
119 if (t
== NULL
) return NULL
;
121 t
->bucket_count
= STATS_TABLE_SIZE
;
122 t
->bucket
= (sender_stats_t
**)calloc(t
->bucket_count
, sizeof(sender_stats_t
*));
123 if (t
->bucket
== NULL
)
136 stats_table_final(stats_table_t
*t
)
142 if (t
== NULL
) return NULL
;
144 msg
= asl_msg_new(ASL_TYPE_MSG
);
145 if (msg
== NULL
) return NULL
;
147 asl_msg_set_key_val(msg
, ASL_KEY_MSG
, "ASL Sender Statistics");
148 asl_msg_set_key_val(msg
, ASL_KEY_SENDER
, "syslogd");
149 asl_msg_set_key_val(msg
, ASL_KEY_FACILITY
, "com.apple.asl.statistics");
150 snprintf(val
, sizeof(val
), "%d", global
.pid
);
151 asl_msg_set_key_val(msg
, ASL_KEY_PID
, val
);
152 snprintf(val
, sizeof(val
), "%d", ASL_STATS_LEVEL
);
153 asl_msg_set_key_val(msg
, ASL_KEY_LEVEL
, val
);
154 snprintf(val
, sizeof(val
), "%u", t
->mcount
);
155 asl_msg_set_key_val(msg
, "MsgCount", val
);
156 snprintf(val
, sizeof(val
), "%u", t
->shim_count
);
157 asl_msg_set_key_val(msg
, "ShimCount", val
);
159 for (i
= 0; i
< t
->bucket_count
; i
++)
165 char val
[64], *key
= NULL
;
166 sender_stats_t
*n
= s
->next
;
168 snprintf(val
, sizeof(val
), "%llu %llu", s
->count
, s
->size
);
169 asprintf(&key
, "*%s", s
->sender
);
170 if (key
!= NULL
) asl_msg_set_key_val(msg
, key
, val
);
185 stats_table_update(stats_table_t
*t
, const char *sender
, uint64_t msg_size
)
191 if (t
== NULL
) return;
192 if (sender
== NULL
) return;
196 for (p
= (uint8_t *)sender
; *p
!= '\0'; p
++) i
= (i
<< 1) ^ (i
^ *p
);
197 i
%= STATS_TABLE_SIZE
;
199 for (s
= t
->bucket
[i
]; s
!= NULL
; s
= s
->next
)
201 if ((s
->sender
!= NULL
) && (strcmp(sender
, s
->sender
) == 0))
209 s
= (sender_stats_t
*)malloc(sizeof(sender_stats_t
));
210 s
->sender
= strdup(sender
);
211 if (s
->sender
== NULL
)
219 s
->next
= t
->bucket
[i
];
224 kern_quota_check(time_t now
, asl_msg_t
*msg
, uint32_t level
)
228 if (msg
== NULL
) return VERIFY_STATUS_INVALID_MESSAGE
;
229 if (global
.mps_limit
== 0) return VERIFY_STATUS_OK
;
231 if (quota_time
!= now
)
233 kern_quota
= global
.mps_limit
;
238 if (level
< kern_level
) kern_level
= level
;
239 if (kern_quota
> 0) kern_quota
--;
241 if (kern_quota
> 0) return VERIFY_STATUS_OK
;
242 if (kern_quota
< 0) return VERIFY_STATUS_EXCEEDED_QUOTA
;
247 asprintf(&str
, QUOTA_KERN_EXCEEDED_MESSAGE
, global
.mps_limit
);
250 asl_msg_set_key_val(msg
, ASL_KEY_MSG
, str
);
252 lstr
[0] = kern_level
+ '0';
254 asl_msg_set_key_val(msg
, ASL_KEY_LEVEL
, lstr
);
257 return VERIFY_STATUS_OK
;
261 stats_msg(const char *sender
, time_t now
, asl_msg_t
*msg
)
266 /* flush stats after N seconds */
267 if ((global
.stats_interval
!= 0) && ((now
- global
.stats_last
) >= global
.stats_interval
) && (global
.stats
!= NULL
))
269 asl_msg_t
*msg
= stats_table_final(global
.stats
);
270 process_message(msg
, SOURCE_INTERNAL
);
272 global
.stats_last
= now
;
275 if (global
.stats
== NULL
) global
.stats
= stats_table_new();
277 for (x
= msg
; x
!= NULL
; x
= x
->next
) msize
+= x
->mem_size
;
279 const char *shim_vers
= asl_msg_get_val_for_key(msg
, "ASLSHIM");
280 global
.stats
->mcount
++;
281 if (shim_vers
!= NULL
) global
.stats
->shim_count
++;
283 /* update count and total size - total and for this sender */
284 stats_table_update(global
.stats
, "*", msize
);
285 stats_table_update(global
.stats
, sender
, msize
);
291 static dispatch_once_t once
;
294 if (global
.hostname
!= NULL
) return global
.hostname
;
296 dispatch_once(&once
, ^{
297 snprintf(myname
, sizeof(myname
), "%s", "localhost");
298 notify_register_check(kNotifySCHostNameChange
, &name_change_token
);
304 if (name_change_token
>= 0) status
= notify_check(name_change_token
, &check
);
306 if ((status
== 0) && (check
== 0)) return (const char *)myname
;
308 if (gethostname(myname
, MAXHOSTNAMELEN
) < 0)
310 snprintf(myname
, sizeof(myname
), "%s", "localhost");
315 dot
= strchr(myname
, '.');
316 if (dot
!= NULL
) *dot
= '\0';
319 return (const char *)myname
;
323 asl_client_count_increment()
325 OSSpinLockLock(&count_lock
);
327 #if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
328 if (global
.client_count
== 0) main_transaction
= os_transaction_create("com.apple.syslogd");
330 global
.client_count
++;
332 OSSpinLockUnlock(&count_lock
);
336 asl_client_count_decrement()
338 OSSpinLockLock(&count_lock
);
340 if (global
.client_count
> 0) global
.client_count
--;
341 #if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
342 if (global
.client_count
== 0) os_release(main_transaction
);
345 OSSpinLockUnlock(&count_lock
);
349 * Checks message content and sets attributes as required
351 * SOURCE_INTERNAL log messages sent by syslogd itself
352 * SOURCE_ASL_SOCKET legacy asl(3) TCP socket
353 * SOURCE_BSD_SOCKET legacy syslog(3) UDP socket
354 * SOURCE_UDP_SOCKET from the network
355 * SOURCE_KERN from the kernel
356 * SOURCE_ASL_MESSAGE mach messages sent from Libc by asl(3) and syslog(3)
357 * SOURCE_LAUNCHD forwarded from launchd
361 aslmsg_verify(asl_msg_t
*msg
, uint32_t source
, int32_t *kern_post_level
, uid_t
*uid_out
)
363 const char *val
, *fac
, *ruval
, *rgval
, *sval
= NULL
;
368 uint32_t status
, level
, fnum
;
371 struct proc_uniqidentifierinfo pinfo
;
373 if (msg
== NULL
) return VERIFY_STATUS_INVALID_MESSAGE
;
378 if (kern_post_level
!= NULL
) *kern_post_level
= -1;
379 if (uid_out
!= NULL
) *uid_out
= -2;
384 val
= asl_msg_get_val_for_key(msg
, ASL_KEY_PID
);
385 if (val
== NULL
) asl_msg_set_key_val(msg
, ASL_KEY_PID
, "0");
386 else pid
= (pid_t
)atoi(val
);
388 /* if PID is 1 (launchd), use the RefPID and RefProc provided */
391 val
= asl_msg_get_val_for_key(msg
, ASL_KEY_REF_PID
);
392 if (val
!= NULL
) pid
= (pid_t
)atoi(val
);
394 sval
= asl_msg_get_val_for_key(msg
, ASL_KEY_REF_PROC
);
398 val
= asl_msg_get_val_for_key(msg
, ASL_KEY_LEVEL
);
399 level
= ASL_LEVEL_DEBUG
;
400 if (source
== SOURCE_KERN
) level
= ASL_LEVEL_NOTICE
;
402 if ((val
!= NULL
) && (val
[1] == '\0') && (val
[0] >= '0') && (val
[0] <= '7')) level
= val
[0] - '0';
403 snprintf(buf
, sizeof(buf
), "%d", level
);
404 asl_msg_set_key_val(msg
, ASL_KEY_LEVEL
, buf
);
407 /* check kernel quota if enabled and no processes are watching */
408 if ((pid
== 0) && (global
.mps_limit
> 0) && (global
.watchers_active
== 0))
410 status
= kern_quota_check(now
, msg
, level
);
411 if (status
!= VERIFY_STATUS_OK
) return status
;
416 /* set Sender_Mach_UUID */
417 uuid_clear(pinfo
.p_uuid
);
418 if (proc_pidinfo(pid
, PROC_PIDUNIQIDENTIFIERINFO
, 1, &pinfo
, sizeof(pinfo
)) == sizeof(pinfo
))
420 uuid_unparse(pinfo
.p_uuid
, ustr
);
421 asl_msg_set_key_val(msg
, ASL_KEY_SENDER_MACH_UUID
, ustr
);
426 val
= asl_msg_get_val_for_key(msg
, ASL_KEY_TIME
);
427 if (val
!= NULL
) tick
= asl_core_parse_time(val
, NULL
);
429 /* Set time to now if it is unset or from the future (not allowed!) */
430 if ((tick
== 0) || (tick
> now
)) tick
= now
;
432 /* Canonical form: seconds since the epoch */
433 snprintf(buf
, sizeof(buf
) - 1, "%llu", (unsigned long long) tick
);
434 asl_msg_set_key_val(msg
, ASL_KEY_TIME
, buf
);
437 val
= asl_msg_get_val_for_key(msg
, ASL_KEY_HOST
);
438 if (val
== NULL
) asl_msg_set_key_val(msg
, ASL_KEY_HOST
, whatsmyhostname());
442 val
= asl_msg_get_val_for_key(msg
, ASL_KEY_UID
);
445 asl_msg_set_key_val(msg
, ASL_KEY_UID
, "-2");
450 if ((uid
== 0) && strcmp(val
, "0"))
453 asl_msg_set_key_val(msg
, ASL_KEY_UID
, "-2");
458 val
= asl_msg_get_val_for_key(msg
, ASL_KEY_GID
);
461 asl_msg_set_key_val(msg
, ASL_KEY_GID
, "-2");
466 if ((gid
== 0) && strcmp(val
, "0"))
469 asl_msg_set_key_val(msg
, ASL_KEY_GID
, "-2");
476 case SOURCE_INTERNAL
:
479 asl_msg_set_key_val(msg
, ASL_KEY_UID
, "0");
482 asl_msg_set_key_val(msg
, ASL_KEY_GID
, "0");
486 case SOURCE_ASL_MESSAGE
:
493 /* do not trust the UID 0 or GID 0 or 80 in SOURCE_BSD_SOCKET or SOURCE_UNKNOWN */
497 asl_msg_set_key_val(msg
, ASL_KEY_UID
, "-2");
500 if ((gid
== 0) || (gid
== 80))
503 asl_msg_set_key_val(msg
, ASL_KEY_GID
, "-2");
508 if (uid_out
!= NULL
) *uid_out
= uid
;
511 if (sval
== NULL
) sval
= asl_msg_get_val_for_key(msg
, ASL_KEY_SENDER
);
519 asl_msg_set_key_val(msg
, ASL_KEY_SENDER
, sval
);
522 case SOURCE_INTERNAL
:
525 asl_msg_set_key_val(msg
, ASL_KEY_SENDER
, sval
);
530 asl_msg_set_key_val(msg
, ASL_KEY_SENDER
, "Unknown");
534 else if ((source
!= SOURCE_KERN
) && (uid
!= 0) && (!strcmp(sval
, "kernel")))
536 /* allow UID 0 to send messages with "Sender kernel", but nobody else */
537 asl_msg_set_key_val(msg
, ASL_KEY_SENDER
, "Unknown");
542 fac
= asl_msg_get_val_for_key(msg
, ASL_KEY_FACILITY
);
545 if (source
== SOURCE_KERN
) fac
= "kern";
547 asl_msg_set_key_val(msg
, ASL_KEY_FACILITY
, fac
);
549 else if (fac
[0] == '#')
552 if ((fac
[1] >= '0') && (fac
[1] <= '9'))
554 fnum
= atoi(fac
+ 1) << 3;
555 if ((fnum
== 0) && (strcmp(fac
+ 1, "0"))) fnum
= LOG_USER
;
558 fac
= asl_syslog_faciliy_num_to_name(fnum
);
559 asl_msg_set_key_val(msg
, ASL_KEY_FACILITY
, fac
);
561 else if (!strncmp(fac
, SYSTEM_RESERVED
, SYSTEM_RESERVED_LEN
))
563 /* only UID 0 may use "com.apple.system" */
564 if (uid
!= 0) asl_msg_set_key_val(msg
, ASL_KEY_FACILITY
, FACILITY_USER
);
568 * kernel messages are only readable by root and admin group.
569 * all other messages are admin-only readable unless they already
570 * have specific read access controls set.
572 if (source
== SOURCE_KERN
)
574 asl_msg_set_key_val(msg
, ASL_KEY_READ_UID
, "0");
575 asl_msg_set_key_val(msg
, ASL_KEY_READ_GID
, "80");
579 ruval
= asl_msg_get_val_for_key(msg
, ASL_KEY_READ_UID
);
580 rgval
= asl_msg_get_val_for_key(msg
, ASL_KEY_READ_GID
);
582 if ((ruval
== NULL
) && (rgval
== NULL
))
584 asl_msg_set_key_val(msg
, ASL_KEY_READ_GID
, "80");
588 /* Set DB Expire Time for com.apple.system.utmpx and lastlog */
589 if ((!strcmp(fac
, "com.apple.system.utmpx")) || (!strcmp(fac
, "com.apple.system.lastlog")))
591 snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long) tick
+ global
.utmp_ttl
);
592 asl_msg_set_key_val(msg
, ASL_KEY_EXPIRE_TIME
, buf
);
596 * special case handling of kernel disaster messages
598 if ((source
== SOURCE_KERN
) && (level
<= KERN_DISASTER_LEVEL
))
600 if (kern_post_level
!= NULL
) *kern_post_level
= level
;
601 disaster_message(msg
);
605 * gather sender stats
607 if (source
!= SOURCE_INTERNAL
) stats_msg(sval
, now
, msg
);
609 return VERIFY_STATUS_OK
;
613 list_append_msg(asl_msg_list_t
*list
, asl_msg_t
*msg
)
615 if (list
== NULL
) return;
616 if (msg
== NULL
) return;
619 * NB: curr is the list size
620 * grow list if necessary
622 if (list
->count
== list
->curr
)
626 list
->msg
= (asl_msg_t
**)calloc(LIST_SIZE_DELTA
, sizeof(asl_msg_t
*));
630 list
->msg
= (asl_msg_t
**)reallocf(list
->msg
, (list
->curr
+ LIST_SIZE_DELTA
) * sizeof(asl_msg_t
*));
633 if (list
->msg
== NULL
)
640 list
->curr
+= LIST_SIZE_DELTA
;
643 list
->msg
[list
->count
] = (asl_msg_t
*)msg
;
652 OSSpinLockLock(&global
.lock
);
654 global
.pid
= getpid();
656 free(global
.debug_file
);
657 global
.debug_file
= NULL
;
658 global
.launchd_enabled
= 1;
660 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
661 global
.dbtype
= DB_TYPE_MEMORY
;
663 global
.dbtype
= DB_TYPE_FILE
;
665 global
.db_file_max
= DEFAULT_DB_FILE_MAX
;
666 global
.db_memory_max
= DEFAULT_DB_MEMORY_MAX
;
667 global
.db_memory_str_max
= DEFAULT_DB_MEMORY_STR_MAX
;
668 global
.mps_limit
= DEFAULT_MPS_LIMIT
;
669 global
.remote_delay_time
= DEFAULT_REMOTE_DELAY
;
670 global
.bsd_max_dup_time
= DEFAULT_BSD_MAX_DUP_SEC
;
671 global
.mark_time
= DEFAULT_MARK_SEC
;
672 global
.utmp_ttl
= DEFAULT_UTMP_TTL_SEC
;
673 global
.memory_max
= DEFAULT_MEMORY_MAX
;
674 global
.stats_interval
= DEFAULT_STATS_INTERVAL
;
676 global
.asl_out_module
= asl_out_module_init();
677 OSSpinLockUnlock(&global
.lock
);
679 if (global
.asl_out_module
!= NULL
)
681 for (r
= global
.asl_out_module
->ruleset
; r
!= NULL
; r
= r
->next
)
683 if ((r
->action
== ACTION_SET_PARAM
) && (r
->query
== NULL
) && (!strncmp(r
->options
, "debug", 5))) control_set_param(r
->options
, true);
689 * Used to set config parameters.
690 * Line format "= name value"
693 control_set_param(const char *s
, bool eval
)
696 uint32_t intval
, count
, v32a
, v32b
, v32c
;
698 if (s
== NULL
) return -1;
699 if (s
[0] == '\0') return 0;
701 /* skip '=' and whitespace */
703 while ((*s
== ' ') || (*s
== '\t')) s
++;
705 l
= explode(s
, " \t");
706 if (l
== NULL
) return -1;
708 for (count
= 0; l
[count
] != NULL
; count
++);
710 /* name is required */
717 /* Check variables that allow 0 or 1 / boolean */
718 if (!strcasecmp(l
[0], "debug"))
720 /* = debug [0|1] [file] */
723 intval
= (eval
) ? 1 : 0;
724 config_debug(intval
, NULL
);
726 else if (!strcmp(l
[1], "0"))
728 config_debug(0, l
[2]);
730 else if (!strcmp(l
[1], "1"))
732 config_debug(1, l
[2]);
736 intval
= (eval
) ? 1 : 0;
737 config_debug(intval
, l
[1]);
744 /* value is required */
751 if (!strcasecmp(l
[0], "hostname"))
753 /* = hostname name */
754 OSSpinLockLock(&global
.lock
);
757 global
.hostname
= strdup(l
[1]);
761 free(global
.hostname
);
762 global
.hostname
= NULL
;
764 OSSpinLockUnlock(&global
.lock
);
766 else if (!strcasecmp(l
[0], "mark_time"))
768 /* = mark_time seconds */
769 OSSpinLockLock(&global
.lock
);
770 if (eval
) global
.mark_time
= atoll(l
[1]);
771 else global
.mark_time
= 0;
772 OSSpinLockUnlock(&global
.lock
);
774 else if (!strcasecmp(l
[0], "dup_delay"))
776 /* = bsd_max_dup_time seconds */
777 OSSpinLockLock(&global
.lock
);
778 if (eval
) global
.bsd_max_dup_time
= atoll(l
[1]);
779 else global
.bsd_max_dup_time
= DEFAULT_BSD_MAX_DUP_SEC
;
780 OSSpinLockUnlock(&global
.lock
);
782 else if (!strcasecmp(l
[0], "remote_delay"))
784 /* = remote_delay microseconds */
785 OSSpinLockLock(&global
.lock
);
786 if (eval
) global
.remote_delay_time
= atol(l
[1]);
787 else global
.remote_delay_time
= DEFAULT_REMOTE_DELAY
;
788 OSSpinLockUnlock(&global
.lock
);
790 else if (!strcasecmp(l
[0], "utmp_ttl"))
792 /* = utmp_ttl seconds */
793 OSSpinLockLock(&global
.lock
);
794 if (eval
) global
.utmp_ttl
= (time_t)atoll(l
[1]);
795 else global
.utmp_ttl
= DEFAULT_UTMP_TTL_SEC
;
796 OSSpinLockUnlock(&global
.lock
);
798 else if (!strcasecmp(l
[0], "mps_limit"))
800 /* = mps_limit number */
801 OSSpinLockLock(&global
.lock
);
802 if (eval
) global
.mps_limit
= (uint32_t)atol(l
[1]);
803 else global
.mps_limit
= DEFAULT_MPS_LIMIT
;
804 OSSpinLockUnlock(&global
.lock
);
806 else if (!strcasecmp(l
[0], "memory_max"))
808 /* = memory_max number */
809 OSSpinLockLock(&global
.lock
);
810 if (eval
) global
.memory_max
= (int64_t)atoll(l
[1]);
811 else global
.memory_max
= DEFAULT_MEMORY_MAX
;
812 OSSpinLockUnlock(&global
.lock
);
814 else if (!strcasecmp(l
[0], "stats_interval"))
816 /* = stats_interval number */
817 OSSpinLockLock(&global
.lock
);
818 if (eval
) global
.stats_interval
= (time_t)atoll(l
[1]);
819 else global
.stats_interval
= DEFAULT_STATS_INTERVAL
;
820 OSSpinLockUnlock(&global
.lock
);
822 else if (!strcasecmp(l
[0], "max_file_size"))
824 /* = max_file_size bytes */
825 pthread_mutex_lock(global
.db_lock
);
827 if (global
.dbtype
& DB_TYPE_FILE
)
829 asl_store_close(global
.file_db
);
830 global
.file_db
= NULL
;
831 if (eval
) global
.db_file_max
= atoi(l
[1]);
832 else global
.db_file_max
= DEFAULT_DB_FILE_MAX
;
835 pthread_mutex_unlock(global
.db_lock
);
837 else if ((!strcasecmp(l
[0], "db")) || (!strcasecmp(l
[0], "database")) || (!strcasecmp(l
[0], "datastore")))
839 /* NB this is private / unpublished */
840 /* = db type [max]... */
847 if ((l
[1][0] >= '0') && (l
[1][0] <= '9'))
850 if ((count
>= 3) && (strcmp(l
[2], "-"))) v32a
= atoi(l
[2]);
851 if ((count
>= 4) && (strcmp(l
[3], "-"))) v32b
= atoi(l
[3]);
852 if ((count
>= 5) && (strcmp(l
[4], "-"))) v32c
= atoi(l
[4]);
854 else if (!strcasecmp(l
[1], "file"))
856 intval
= DB_TYPE_FILE
;
857 if ((count
>= 3) && (strcmp(l
[2], "-"))) v32a
= atoi(l
[2]);
859 else if (!strncasecmp(l
[1], "mem", 3))
861 intval
= DB_TYPE_MEMORY
;
862 if ((count
>= 3) && (strcmp(l
[2], "-"))) v32b
= atoi(l
[2]);
870 if (v32a
== 0) v32a
= global
.db_file_max
;
871 if (v32b
== 0) v32b
= global
.db_memory_max
;
872 if (v32c
== 0) v32c
= global
.db_memory_str_max
;
874 config_data_store(intval
, v32a
, v32b
, v32c
);
878 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
879 intval
= DB_TYPE_MEMORY
;
881 intval
= DB_TYPE_FILE
;
883 config_data_store(intval
, DEFAULT_DB_FILE_MAX
, DEFAULT_DB_MEMORY_MAX
, DEFAULT_DB_MEMORY_STR_MAX
);
892 control_message(asl_msg_t
*msg
)
894 const char *str
= asl_msg_get_val_for_key(msg
, ASL_KEY_MSG
);
896 if (str
== NULL
) return 0;
898 if (!strncmp(str
, "= reset", 7))
901 return asl_action_reset();
903 else if (!strncmp(str
, "= crash", 7))
907 else if (!strncmp(str
, "@ ", 2))
909 return asl_action_control_set_param(str
);
911 else if (!strncmp(str
, "= ", 2))
913 return control_set_param(str
, true);
921 process_message(asl_msg_t
*msg
, uint32_t source
)
924 static bool wq_draining
= false;
925 bool is_control
= false;
928 if (msg
== NULL
) return;
930 is_control
= asl_check_option(msg
, ASL_OPT_CONTROL
) != 0;
932 if ((!is_control
) && wq_draining
)
934 if (global
.memory_size
>= (global
.memory_max
/ 2))
936 asldebug("Work queue draining: dropped message.\n");
937 asl_msg_release(msg
);
942 asldebug("Work queue re-enabled at 1/2 max. size %lld max %lld\n", global
.memory_size
, global
.memory_max
);
947 os_transaction_t transaction
= os_transaction_create("com.apple.syslogd.message");
949 for (x
= msg
; x
!= NULL
; x
= x
->next
) msize
+= x
->mem_size
;
951 if ((global
.memory_size
+ msize
) >= global
.memory_max
)
956 asl_msg_release(msg
);
958 asldebug("Work queue disabled. msize %lld size %lld max %lld\n", msize
, global
.memory_size
+ msize
, global
.memory_max
);
959 snprintf(str
, sizeof(str
), "[Sender syslogd] [Level 2] [PID %u] [Message Internal memory size limit %lld exceeded - dropping messages] [UID 0] [UID 0] [Facility syslog]", global
.pid
, global
.memory_max
);
960 msg
= asl_msg_from_string(str
);
963 OSAtomicAdd64(msize
, &global
.memory_size
);
964 OSAtomicIncrement32(&global
.work_queue_count
);
966 dispatch_async(global
.work_queue
, ^{
974 status
= aslmsg_verify(msg
, source
, &kplevel
, &uid
);
975 if (status
== VERIFY_STATUS_OK
)
978 if ((source
== SOURCE_KERN
) && (kplevel
>= 0))
980 if (kplevel
> 7) kplevel
= 7;
981 if (kern_notify_token
[kplevel
] < 0)
983 status
= notify_register_plain(kern_notify_key
[kplevel
], &(kern_notify_token
[kplevel
]));
984 if (status
!= 0) asldebug("notify_register_plain(%s) failed status %u\n", status
);
987 notify_post(kern_notify_key
[kplevel
]);
990 if ((uid
== 0) && is_control
) control_message(msg
);
993 * Send message to output module chain (asl is first).
994 * The last module in the chain will decrement global.memory_size.
996 asl_out_message(msg
, msize
);
1000 OSAtomicAdd64(-1ll * msize
, &global
.memory_size
);
1003 asl_msg_release(msg
);
1005 OSAtomicDecrement32(&global
.work_queue_count
);
1006 os_release(transaction
);
1011 internal_log_message(const char *str
)
1015 if (str
== NULL
) return 1;
1017 msg
= asl_msg_from_string(str
);
1018 if (msg
== NULL
) return 1;
1020 process_message(msg
, SOURCE_INTERNAL
);
1026 asldebug(const char *str
, ...)
1031 if (global
.debug
== 0) return 0;
1033 if (global
.debug_file
== NULL
) dfp
= fopen(_PATH_SYSLOGD_LOG
, "a");
1034 else dfp
= fopen(global
.debug_file
, "a");
1035 if (dfp
== NULL
) return 0;
1038 fprintf(dfp
, "W %d %llu", global
.work_queue_count
, global
.memory_size
);
1039 if (global
.memory_db
!= NULL
) fprintf(dfp
, " M %u %u %lu", global
.memory_db
->record_count
, global
.memory_db
->string_count
, global
.memory_db
->curr_string_mem
);
1040 fprintf(dfp
, " ; ");
1041 vfprintf(dfp
, str
, v
);
1054 asprintf(&str
, "[Sender syslogd] [Level 6] [PID %u] [Message -- MARK --] [UID 0] [UID 0] [Facility syslog]", global
.pid
);
1055 internal_log_message(str
);
1060 asl_syslog_input_convert(const char *in
, int len
, char *rhost
, uint32_t source
)
1062 int pf
, pri
, index
, n
;
1063 char *p
, *colon
, *brace
, *space
, *tmp
, *tval
, *hval
, *sval
, *pval
, *mval
;
1070 if (in
== NULL
) return NULL
;
1071 if (len
<= 0) return NULL
;
1074 if (source
== SOURCE_KERN
) pri
= LOG_NOTICE
;
1086 /* skip leading whitespace */
1087 while ((index
< len
) && ((*p
== ' ') || (*p
== '\t')))
1093 if (index
>= len
) return NULL
;
1095 /* parse "<NN>" priority (level and facility) */
1101 n
= sscanf(p
, "%d", &pf
);
1105 if (pf
> 0x7) fval
= asl_syslog_faciliy_num_to_name(pf
& LOG_FACMASK
);
1108 while ((index
< len
) && (*p
!= '>'))
1121 snprintf(prival
, sizeof(prival
), "%d", pri
);
1123 /* check if a timestamp is included */
1124 if (((len
- index
) > 15) && (p
[9] == ':') && (p
[12] == ':') && (p
[15] == ' '))
1127 if (tmp
== NULL
) return NULL
;
1132 tick
= asl_core_parse_time(tmp
, NULL
);
1133 if (tick
== (time_t)-1)
1140 gmtime_r(&tick
, &time
);
1141 asprintf(&tval
, "%d.%02d.%02d %02d:%02d:%02d UTC", time
.tm_year
+ 1900, time
.tm_mon
+ 1, time
.tm_mday
, time
.tm_hour
, time
.tm_min
, time
.tm_sec
);
1148 /* stop here for kernel messages */
1149 if (source
== SOURCE_KERN
)
1151 msg
= asl_msg_new(ASL_TYPE_MSG
);
1152 if (msg
== NULL
) return NULL
;
1154 asl_msg_set_key_val(msg
, ASL_KEY_MSG
, p
);
1155 asl_msg_set_key_val(msg
, ASL_KEY_LEVEL
, prival
);
1156 asl_msg_set_key_val(msg
, ASL_KEY_PID
, "0");
1161 /* if message is from a network socket, hostname follows */
1162 if (source
== SOURCE_UDP_SOCKET
)
1164 space
= strchr(p
, ' ');
1168 hval
= malloc(n
+ 1);
1169 if (hval
== NULL
) return NULL
;
1179 colon
= strchr(p
, ':');
1180 brace
= strchr(p
, '[');
1182 /* check for "sender:" or sender[pid]:" */
1185 if ((brace
!= NULL
) && (brace
< colon
))
1188 sval
= malloc(n
+ 1);
1189 if (sval
== NULL
) return NULL
;
1194 n
= colon
- (brace
+ 1) - 1;
1195 pval
= malloc(n
+ 1);
1196 if (pval
== NULL
) return NULL
;
1198 memcpy(pval
, (brace
+ 1), n
);
1204 sval
= malloc(n
+ 1);
1205 if (sval
== NULL
) return NULL
;
1225 mval
= malloc(n
+ 1);
1226 if (mval
== NULL
) return NULL
;
1232 if (fval
== NULL
) fval
= asl_syslog_faciliy_num_to_name(LOG_USER
);
1234 msg
= asl_msg_new(ASL_TYPE_MSG
);
1235 if (msg
== NULL
) return NULL
;
1239 asl_msg_set_key_val(msg
, ASL_KEY_TIME
, tval
);
1243 if (fval
!= NULL
) asl_msg_set_key_val(msg
, "Facility", fval
);
1244 else asl_msg_set_key_val(msg
, "Facility", "user");
1248 asl_msg_set_key_val(msg
, ASL_KEY_SENDER
, sval
);
1254 asl_msg_set_key_val(msg
, ASL_KEY_PID
, pval
);
1259 asl_msg_set_key_val(msg
, ASL_KEY_PID
, "-1");
1264 asl_msg_set_key_val(msg
, ASL_KEY_MSG
, mval
);
1268 asl_msg_set_key_val(msg
, ASL_KEY_LEVEL
, prival
);
1269 asl_msg_set_key_val(msg
, ASL_KEY_UID
, "-2");
1270 asl_msg_set_key_val(msg
, ASL_KEY_GID
, "-2");
1274 asl_msg_set_key_val(msg
, ASL_KEY_HOST
, hval
);
1277 else if (rhost
!= NULL
)
1279 asl_msg_set_key_val(msg
, ASL_KEY_HOST
, rhost
);
1286 asl_input_parse(const char *in
, int len
, char *rhost
, uint32_t source
)
1289 int status
, x
, legacy
, off
;
1291 asldebug("asl_input_parse: %s\n", (in
== NULL
) ? "NULL" : in
);
1293 if (in
== NULL
) return NULL
;
1298 /* calculate length if not provided */
1299 if (len
== 0) len
= strlen(in
);
1302 * Determine if the input is "old" syslog format or new ASL format.
1303 * Old format lines should start with "<", but they can just be straight text.
1304 * ASL input may start with a length (10 bytes) followed by a space and a '['.
1305 * The length is optional, so ASL messages may also just start with '['.
1307 if ((in
[0] != '<') && (len
> 11))
1309 status
= sscanf(in
, "%d ", &x
);
1310 if ((status
== 1) && (in
[10] == ' ') && (in
[11] == '[')) legacy
= 0;
1313 if (legacy
== 1) return asl_syslog_input_convert(in
, len
, rhost
, source
);
1316 if (in
[0] == '[') off
= 0;
1318 msg
= asl_msg_from_string(in
+ off
);
1319 if (msg
== NULL
) return NULL
;
1321 if (rhost
!= NULL
) asl_msg_set_key_val(msg
, ASL_KEY_HOST
, rhost
);
1326 #if !TARGET_OS_SIMULATOR
1328 launchd_callback(struct timeval
*when
, pid_t from_pid
, pid_t about_pid
, uid_t sender_uid
, gid_t sender_gid
, int priority
, const char *from_name
, const char *about_name
, const char *session_name
, const char *msg
)
1334 if (global
.launchd_enabled
== 0) return;
1337 asldebug("launchd_callback Time %lu %lu PID %u RefPID %u UID %d GID %d PRI %d Sender %s Ref %s Session %s Message %s\n",
1338 when->tv_sec, when->tv_usec, from_pid, about_pid, sender_uid, sender_gid, priority, from_name, about_name, session_name, msg);
1341 m
= asl_msg_new(ASL_TYPE_MSG
);
1342 if (m
== NULL
) return;
1345 if (priority
< ASL_LEVEL_EMERG
) priority
= ASL_LEVEL_EMERG
;
1346 if (priority
> ASL_LEVEL_DEBUG
) priority
= ASL_LEVEL_DEBUG
;
1347 snprintf(str
, sizeof(str
), "%d", priority
);
1349 asl_msg_set_key_val(m
, ASL_KEY_LEVEL
, str
);
1354 snprintf(str
, sizeof(str
), "%llu", (unsigned long long) when
->tv_sec
);
1355 asl_msg_set_key_val(m
, ASL_KEY_TIME
, str
);
1357 snprintf(str
, sizeof(str
), "%lu", 1000 * (unsigned long int)when
->tv_usec
);
1358 asl_msg_set_key_val(m
, ASL_KEY_TIME_NSEC
, str
);
1363 snprintf(str
, sizeof(str
), "%llu", (unsigned long long) now
);
1364 asl_msg_set_key_val(m
, ASL_KEY_TIME
, str
);
1368 asl_msg_set_key_val(m
, ASL_KEY_FACILITY
, FACILITY_CONSOLE
);
1371 snprintf(str
, sizeof(str
), "%u", (unsigned int)sender_uid
);
1372 asl_msg_set_key_val(m
, ASL_KEY_UID
, str
);
1375 snprintf(str
, sizeof(str
), "%u", (unsigned int)sender_gid
);
1376 asl_msg_set_key_val(m
, ASL_KEY_GID
, str
);
1381 snprintf(str
, sizeof(str
), "%u", (unsigned int)from_pid
);
1382 asl_msg_set_key_val(m
, ASL_KEY_PID
, str
);
1386 if ((about_pid
> 0) && (about_pid
!= from_pid
))
1388 snprintf(str
, sizeof(str
), "%u", (unsigned int)about_pid
);
1389 asl_msg_set_key_val(m
, ASL_KEY_REF_PID
, str
);
1393 if (from_name
!= NULL
)
1395 asl_msg_set_key_val(m
, ASL_KEY_SENDER
, from_name
);
1399 if (sender_uid
!= 0)
1401 snprintf(str
, sizeof(str
), "%d", (int)sender_uid
);
1402 asl_msg_set_key_val(m
, ASL_KEY_READ_UID
, str
);
1405 /* Reference Process */
1406 if (about_name
!= NULL
)
1408 if ((from_name
!= NULL
) && (strcmp(from_name
, about_name
) != 0))
1410 asl_msg_set_key_val(m
, ASL_KEY_REF_PROC
, about_name
);
1415 if (session_name
!= NULL
)
1417 asl_msg_set_key_val(m
, ASL_KEY_SESSION
, session_name
);
1423 asl_msg_set_key_val(m
, ASL_KEY_MSG
, msg
);
1426 process_message(m
, SOURCE_LAUNCHD
);