2 * Copyright (c) 2004-2009 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 <sys/types.h>
25 #include <sys/socket.h>
27 #include <sys/ucred.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
36 #include <sys/fslog.h>
39 #include <vproc_priv.h>
40 #include <mach/mach.h>
43 #include <libkern/OSAtomic.h>
46 #define LIST_SIZE_DELTA 256
48 #define streq(A,B) (strcmp(A,B)==0)
49 #define forever for(;;)
50 #define IndexNull ((uint32_t)-1)
52 #define ASL_MSG_TYPE_MASK 0x0000000f
53 #define ASL_TYPE_ERROR 2
55 #define ASL_KEY_FACILITY "Facility"
57 #define FACILITY_USER "user"
58 #define FACILITY_CONSOLE "com.apple.console"
59 #define SYSTEM_RESERVED "com.apple.system"
60 #define SYSTEM_RESERVED_LEN 16
62 #define VERIFY_STATUS_OK 0
63 #define VERIFY_STATUS_INVALID_MESSAGE 1
64 #define VERIFY_STATUS_EXCEEDED_QUOTA 2
66 extern void disaster_message(asl_msg_t
*m
);
67 static char myname
[MAXHOSTNAMELEN
+ 1] = {0};
69 static OSSpinLock count_lock
= 0;
71 static vproc_transaction_t vproc_trans
= {0};
73 #define QUOTA_TABLE_SIZE 8192
74 #define QUOTA_TABLE_SLOTS 8
76 #define QUOTA_EXCEEDED_MESSAGE "*** process %d exceeded %d log message per second limit - remaining messages this second discarded ***"
77 #define QUOTA_EXCEEDED_LEVEL "3"
79 static time_t quota_table_time
= 0;
80 static pid_t quota_table_pid
[QUOTA_TABLE_SIZE
];
81 static int32_t quota_table_quota
[QUOTA_TABLE_SIZE
];
83 static const char *kern_notify_key
[] =
85 "com.apple.system.log.kernel.emergency",
86 "com.apple.system.log.kernel.alert",
87 "com.apple.system.log.kernel.critical",
88 "com.apple.system.log.kernel.error",
89 "com.apple.system.log.kernel.warning",
90 "com.apple.system.log.kernel.notice",
91 "com.apple.system.log.kernel.info",
92 "com.apple.system.log.kernel.debug"
99 TAILQ_ENTRY(asloutput
) entries
;
106 TAILQ_ENTRY(aslmatch
) entries
;
109 TAILQ_HEAD(ae
, aslevent
) Eventq
;
110 TAILQ_HEAD(ao
, asloutput
) Outq
;
111 TAILQ_HEAD(am
, aslmatch
) Matchq
;
114 _insertString(char *s
, char **l
, uint32_t x
)
118 if (s
== NULL
) return l
;
121 l
= (char **)malloc(2 * sizeof(char *));
122 if (l
== NULL
) return NULL
;
135 for (i
= 0; l
[i
] != NULL
; i
++);
136 len
= i
+ 1; /* count the NULL on the end of the list too! */
138 l
= (char **)reallocf(l
, (len
+ 1) * sizeof(char *));
139 if (l
== NULL
) return NULL
;
141 if ((x
>= (len
- 1)) || (x
== IndexNull
))
143 l
[len
- 1] = strdup(s
);
144 if (l
[len
- 1] == NULL
)
154 for (i
= len
; i
> x
; i
--) l
[i
] = l
[i
- 1];
156 if (l
[x
] == NULL
) return NULL
;
162 explode(const char *s
, const char *delim
)
169 if (s
== NULL
) return NULL
;
177 for (i
= 0; p
[i
] != '\0'; i
++)
181 /* not inside a quoted string: check for delimiters and quotes */
182 if (strchr(delim
, p
[i
]) != NULL
) break;
183 else if (p
[i
] == '\'') quote
= p
[i
];
184 else if (p
[i
] == '"') quote
= p
[i
];
188 /* inside a quoted string - look for matching quote */
189 if (p
[i
] == quote
) quote
= '\0';
195 if (t
== NULL
) return NULL
;
197 for (i
= 0; i
< n
; i
++) t
[i
] = p
[i
];
199 l
= _insertString(t
, l
, IndexNull
);
202 if (p
[i
] == '\0') return l
;
203 if (p
[i
+ 1] == '\0') l
= _insertString("", l
, IndexNull
);
215 if (l
== NULL
) return;
216 for (i
= 0; l
[i
] != NULL
; i
++) free(l
[i
]);
221 * Quotas are maintained using a very fast fixed-size table.
222 * We hash into the pid table (quota_table_pid) using the last 10
223 * bits of the pid, so the table has 1024 "buckets". The table is
224 * actually just an array with 8 entry slots (for collisions) per bucket.
225 * If there are more than 8 pids that hash to the same bucket, we
226 * re-use the one with the lowest message usage (highest remaining
227 * quota). This can lead to "generosity: if there are nine of more
228 * pids with the same last 10 bits all logging like crazy, we may
229 * end up allowing some of them to log more than their quota.
230 * That would be a remarkably rare occurrence.
234 quota_check(pid_t pid
, time_t now
, asl_msg_t
*msg
)
239 if (msg
== NULL
) return VERIFY_STATUS_INVALID_MESSAGE
;
240 if (global
.mps_limit
== 0) return VERIFY_STATUS_OK
;
242 if (quota_table_time
!= now
)
244 memset(quota_table_pid
, 0, sizeof(quota_table_pid
));
245 quota_table_time
= now
;
248 /* hash is last 10 bits of the pid, shifted up 3 bits to allow 8 slots per bucket */
249 x
= (pid
& 0x000003ff) << 3;
251 max
= quota_table_quota
[x
];
253 for (i
= 0; i
< QUOTA_TABLE_SLOTS
; i
++)
255 if (quota_table_pid
[x
] == 0)
257 quota_table_pid
[x
] = pid
;
258 quota_table_quota
[x
] = global
.mps_limit
;
259 return VERIFY_STATUS_OK
;
262 if (quota_table_pid
[x
] == pid
)
264 quota_table_quota
[x
] = quota_table_quota
[x
] - 1;
266 if (quota_table_quota
[x
] == 0)
268 quota_table_quota
[x
] = -1;
271 asprintf(&str
, QUOTA_EXCEEDED_MESSAGE
, (int)pid
, global
.mps_limit
);
274 asl_set(msg
, ASL_KEY_MSG
, str
);
276 asl_set(msg
, ASL_KEY_LEVEL
, QUOTA_EXCEEDED_LEVEL
);
279 return VERIFY_STATUS_OK
;
282 if (quota_table_quota
[x
] < 0) return VERIFY_STATUS_EXCEEDED_QUOTA
;
284 return VERIFY_STATUS_OK
;
287 if (quota_table_quota
[x
] > max
)
290 max
= quota_table_quota
[x
];
296 /* can't find the pid and no slots were available - reuse slot with highest remaining quota */
297 asldebug("Quotas: reused slot %d pid %d quota %d for new pid %d\n", maxx
, (int)quota_table_pid
[maxx
], quota_table_quota
[maxx
], (int)pid
);
298 quota_table_pid
[maxx
] = pid
;
299 quota_table_quota
[maxx
] = global
.mps_limit
;
301 return VERIFY_STATUS_OK
;
305 asl_check_option(asl_msg_t
*msg
, const char *opt
)
310 if (msg
== NULL
) return 0;
311 if (opt
== NULL
) return 0;
314 if (len
== 0) return 0;
316 p
= asl_get(msg
, ASL_KEY_OPTION
);
317 if (p
== NULL
) return 0;
321 while ((*p
== ' ') || (*p
== '\t') || (*p
== ',')) p
++;
322 if (*p
== '\0') return 0;
324 if (strncasecmp(p
, opt
, len
) == 0)
327 if ((*p
== ' ') || (*p
== '\t') || (*p
== ',') || (*p
== '\0')) return 1;
330 while ((*p
!= ' ') && (*p
!= '\t') && (*p
!= ',') && (*p
!= '\0')) p
++;
347 aslevent_log(asl_msg_t
*msg
, char *outid
)
352 for (i
= Outq
.tqh_first
; i
!= NULL
; i
= i
->entries
.tqe_next
)
354 if ((outid
!= NULL
) && (strcmp(i
->outid
, outid
) == 0))
356 status
= i
->sendmsg(msg
, outid
);
364 aslevent_addmatch(asl_msg_t
*query
, char *outid
)
366 struct aslmatch
*tmp
;
368 if (query
== NULL
) return -1;
369 if (outid
== NULL
) return -1;
371 tmp
= calloc(1, sizeof(struct aslmatch
));
372 if (tmp
== NULL
) return -1;
376 TAILQ_INSERT_TAIL(&Matchq
, tmp
, entries
);
382 asl_message_match_and_log(asl_msg_t
*msg
)
386 if (msg
== NULL
) return;
388 for (i
= Matchq
.tqh_first
; i
!= NULL
; i
= i
->entries
.tqe_next
)
390 if (asl_msg_cmp(i
->query
, msg
) != 0)
392 aslevent_log(msg
, i
->outid
);
398 aslevent_removefd(int fd
)
400 struct aslevent
*e
, *next
;
402 e
= Eventq
.tqh_first
;
406 next
= e
->entries
.tqe_next
;
424 if (gethostname(myname
, MAXHOSTNAMELEN
) < 0)
426 memset(myname
, 0, sizeof(myname
));
430 dot
= strchr(myname
, '.');
431 if (dot
!= NULL
) *dot
= '\0';
433 return (const char *)myname
;
437 asl_client_count_increment()
439 OSSpinLockLock(&count_lock
);
441 if (global
.client_count
== 0) vproc_trans
= vproc_transaction_begin(NULL
);
442 global
.client_count
++;
444 asldebug("global.client_count++ (%d)\n", global
.client_count
);
447 OSSpinLockUnlock(&count_lock
);
451 asl_client_count_decrement()
453 OSSpinLockLock(&count_lock
);
455 if (global
.client_count
> 0) global
.client_count
--;
456 if (global
.client_count
== 0) vproc_transaction_end(NULL
, vproc_trans
);
458 asldebug("global.client_count-- (%d)\n", global
.client_count
);
461 OSSpinLockUnlock(&count_lock
);
465 aslevent_addfd(int source
, int fd
, uint32_t flags
, aslreadfn readfn
, aslwritefn writefn
, aslexceptfn exceptfn
)
468 int found
= 0, status
;
469 #ifdef LOCAL_PEERCRED
475 struct sockaddr_storage ss
;
476 char *sender
, str
[256];
482 memset(&ss
, 0, sizeof(struct sockaddr_storage
));
483 memset(str
, 0, sizeof(str
));
485 len
= sizeof(struct sockaddr_storage
);
487 if (flags
& ADDFD_FLAGS_LOCAL
)
489 snprintf(str
, sizeof(str
), "localhost");
492 #ifdef LOCAL_PEERCRED
495 status
= getsockopt(fd
, LOCAL_PEERCRED
, 1, &cr
, &len
);
505 status
= getpeername(fd
, (struct sockaddr
*)&ss
, &len
);
510 /* UNIX Domain socket */
511 snprintf(str
, sizeof(str
), "localhost");
516 if (inet_ntop(ss
.ss_family
, (struct sockaddr
*)&ss
, str
, 256) == NULL
) sender
= str
;
521 asldebug("source %d fd %d flags 0x%08x UID %d GID %d Sender %s\n", source
, fd
, flags
, u
, g
, (sender
== NULL
) ? "NULL" : sender
);
523 for (e
= Eventq
.tqh_first
; e
!= NULL
; e
= e
->entries
.tqe_next
)
528 e
->writefn
= writefn
;
529 e
->exceptfn
= exceptfn
;
530 if (e
->sender
!= NULL
) free(e
->sender
);
534 e
->sender
= strdup(sender
);
535 if (e
->sender
== NULL
) return -1;
546 e
= calloc(1, sizeof(struct aslevent
));
547 if (e
== NULL
) return -1;
552 e
->writefn
= writefn
;
553 e
->exceptfn
= exceptfn
;
557 e
->sender
= strdup(sender
);
558 if (e
->sender
== NULL
) return -1;
564 TAILQ_INSERT_TAIL(&Eventq
, e
, entries
);
570 * Checks message content and sets attributes as required
572 * SOURCE_INTERNAL log messages sent by syslogd itself
573 * SOURCE_ASL_SOCKET legacy asl(3) TCP socket
574 * SOURCE_BSD_SOCKET legacy syslog(3) UDP socket
575 * SOURCE_UDP_SOCKET from the network
576 * SOURCE_KERN from the kernel
577 * SOURCE_ASL_MESSAGE mach messages sent from Libc by asl(3) and syslog(3)
578 * SOURCE_LAUNCHD forwarded from launchd
582 aslmsg_verify(uint32_t source
, struct aslevent
*e
, asl_msg_t
*msg
, int32_t *kern_post_level
)
584 const char *val
, *fac
;
588 uint32_t status
, level
, fnum
;
591 if (msg
== NULL
) return VERIFY_STATUS_INVALID_MESSAGE
;
593 if (kern_post_level
!= NULL
) *kern_post_level
= -1;
599 val
= asl_get(msg
, ASL_KEY_TIME
);
600 if (val
!= NULL
) tick
= asl_parse_time(val
);
602 /* Set time to now if it is unset or from the future (not allowed!) */
603 if ((tick
== 0) || (tick
> now
)) tick
= now
;
605 /* Canonical form: seconds since the epoch */
606 snprintf(buf
, sizeof(buf
) - 1, "%lu", tick
);
607 asl_set(msg
, ASL_KEY_TIME
, buf
);
610 if (e
== NULL
) asl_set(msg
, ASL_KEY_HOST
, whatsmyhostname());
611 else if (e
->sender
!= NULL
)
613 if (!strcmp(e
->sender
, "localhost")) asl_set(msg
, ASL_KEY_HOST
, whatsmyhostname());
614 else asl_set(msg
, ASL_KEY_HOST
, e
->sender
);
620 val
= asl_get(msg
, ASL_KEY_PID
);
621 if (val
== NULL
) asl_set(msg
, ASL_KEY_PID
, "0");
622 else pid
= (pid_t
)atoi(val
);
624 /* if PID is 1 (launchd), use the refpid if there is one */
627 val
= asl_get(msg
, ASL_KEY_REF_PID
);
628 if (val
!= NULL
) pid
= (pid_t
)atoi(val
);
631 /* if quotas are enabled and pid > 1 (not kernel or launchd) check quota */
632 if ((global
.mps_limit
> 0) && (pid
> 1))
634 status
= quota_check(pid
, now
, msg
);
635 if (status
!= VERIFY_STATUS_OK
) return status
;
640 val
= asl_get(msg
, ASL_KEY_UID
);
645 case SOURCE_INTERNAL
:
647 /* we know the UID is 0 */
649 asl_set(msg
, ASL_KEY_UID
, "0");
652 case SOURCE_ASL_SOCKET
:
653 case SOURCE_ASL_MESSAGE
:
656 /* we trust the UID in the message */
657 if (val
!= NULL
) uid
= atoi(val
);
660 case SOURCE_BSD_SOCKET
:
661 case SOURCE_UDP_SOCKET
:
665 if (e
== NULL
) asl_set(msg
, ASL_KEY_UID
, "-2");
666 else if (e
->uid
== 99) asl_set(msg
, ASL_KEY_UID
, "-2");
670 snprintf(buf
, sizeof(buf
), "%d", e
->uid
);
671 asl_set(msg
, ASL_KEY_UID
, buf
);
674 else if ((e
!= NULL
) && (e
->uid
!= 99))
677 snprintf(buf
, sizeof(buf
), "%d", e
->uid
);
678 asl_set(msg
, ASL_KEY_UID
, buf
);
683 asl_set(msg
, ASL_KEY_UID
, "-2");
688 val
= asl_get(msg
, ASL_KEY_GID
);
693 case SOURCE_INTERNAL
:
695 /* we know the GID is 0 */
696 asl_set(msg
, ASL_KEY_GID
, "0");
699 case SOURCE_ASL_SOCKET
:
700 case SOURCE_ASL_MESSAGE
:
703 /* we trust the GID in the message */
706 case SOURCE_BSD_SOCKET
:
707 case SOURCE_UDP_SOCKET
:
711 if (e
== NULL
) asl_set(msg
, ASL_KEY_GID
, "-2");
712 else if (e
->gid
== 99) asl_set(msg
, ASL_KEY_GID
, "-2");
715 snprintf(buf
, sizeof(buf
), "%d", e
->gid
);
716 asl_set(msg
, ASL_KEY_GID
, buf
);
719 else if ((e
!= NULL
) && (e
->gid
!= 99))
721 snprintf(buf
, sizeof(buf
), "%d", e
->gid
);
722 asl_set(msg
, ASL_KEY_GID
, buf
);
727 asl_set(msg
, ASL_KEY_GID
, "-2");
732 val
= asl_get(msg
, ASL_KEY_SENDER
);
739 asl_set(msg
, ASL_KEY_SENDER
, "kernel");
742 case SOURCE_INTERNAL
:
744 asl_set(msg
, ASL_KEY_SENDER
, "syslogd");
749 asl_set(msg
, ASL_KEY_SENDER
, "Unknown");
753 else if ((source
!= SOURCE_KERN
) && (uid
!= 0) && (!strcmp(val
, "kernel")))
755 /* allow UID 0 to send messages with "Sender kernel", but nobody else */
756 asl_set(msg
, ASL_KEY_SENDER
, "Unknown");
760 val
= asl_get(msg
, ASL_KEY_LEVEL
);
761 level
= ASL_LEVEL_DEBUG
;
762 if ((val
!= NULL
) && (val
[1] == '\0') && (val
[0] >= '0') && (val
[0] <= '7')) level
= val
[0] - '0';
763 snprintf(buf
, sizeof(buf
), "%d", level
);
764 asl_set(msg
, ASL_KEY_LEVEL
, buf
);
767 fac
= asl_get(msg
, ASL_KEY_FACILITY
);
770 if (source
== SOURCE_KERN
) fac
= "kern";
772 asl_set(msg
, ASL_KEY_FACILITY
, fac
);
774 else if (fac
[0] == '#')
777 if ((fac
[1] >= '0') && (fac
[1] <= '9'))
779 fnum
= atoi(fac
+ 1) << 3;
780 if ((fnum
== 0) && (strcmp(fac
+ 1, "0"))) fnum
= LOG_USER
;
783 fac
= asl_syslog_faciliy_num_to_name(fnum
);
784 asl_set(msg
, ASL_KEY_FACILITY
, fac
);
786 else if (!strncmp(fac
, SYSTEM_RESERVED
, SYSTEM_RESERVED_LEN
))
788 /* only UID 0 may use "com.apple.system" */
789 if (uid
!= 0) asl_set(msg
, ASL_KEY_FACILITY
, FACILITY_USER
);
793 * kernel messages are only readable by root and admin group.
795 if (source
== SOURCE_KERN
)
797 asl_set(msg
, ASL_KEY_READ_UID
, "0");
798 asl_set(msg
, ASL_KEY_READ_GID
, "80");
802 * Access Control: only UID 0 may use facility com.apple.system (or anything with that prefix).
803 * N.B. kernel can use any facility name.
806 /* Set DB Expire Time for com.apple.system.utmpx and lastlog */
807 if ((!strcmp(fac
, "com.apple.system.utmpx")) || (!strcmp(fac
, "com.apple.system.lastlog")))
809 snprintf(buf
, sizeof(buf
), "%lu", tick
+ global
.utmp_ttl
);
810 asl_set(msg
, ASL_KEY_EXPIRE_TIME
, buf
);
813 /* Set DB Expire Time for Filestsrem errors */
814 if (!strcmp(fac
, FSLOG_VAL_FACILITY
))
816 snprintf(buf
, sizeof(buf
), "%lu", tick
+ global
.fs_ttl
);
817 asl_set(msg
, ASL_KEY_EXPIRE_TIME
, buf
);
821 * special case handling of kernel disaster messages
823 if ((source
== SOURCE_KERN
) && (level
<= KERN_DISASTER_LEVEL
))
825 if (kern_post_level
!= NULL
) *kern_post_level
= level
;
826 disaster_message(msg
);
829 return VERIFY_STATUS_OK
;
833 aslevent_addoutput(aslsendmsgfn fn
, const char *outid
)
835 struct asloutput
*tmp
;
837 tmp
= calloc(1, sizeof(struct asloutput
));
838 if (tmp
== NULL
) return -1;
843 TAILQ_INSERT_TAIL(&Outq
, tmp
, entries
);
849 aslevent_fdsets(fd_set
*rd
, fd_set
*wr
, fd_set
*ex
)
854 // asldebug("--> aslevent_fdsets\n");
859 for (e
= Eventq
.tqh_first
; e
!= NULL
; e
= e
->entries
.tqe_next
)
861 if (e
->fd
< 0) continue;
863 // asldebug("adding fd %d\n", e->fd);
867 status
= MAX(e
->fd
, status
);
873 status
= MAX(e
->fd
, status
);
879 status
= MAX(e
->fd
, status
);
883 // asldebug("<--aslevent_fdsets\n");
890 struct aslevent
*e
, *next
;
892 e
= Eventq
.tqh_first
;
896 next
= e
->entries
.tqe_next
;
899 TAILQ_REMOVE(&Eventq
, e
, entries
);
900 if (e
->sender
!= NULL
) free(e
->sender
);
909 list_append_msg(asl_search_result_t
*list
, asl_msg_t
*msg
)
911 if (list
== NULL
) return;
912 if (msg
== NULL
) return;
915 * NB: curr is the list size
916 * grow list if necessary
918 if (list
->count
== list
->curr
)
922 list
->msg
= (asl_msg_t
**)calloc(LIST_SIZE_DELTA
, sizeof(asl_msg_t
*));
926 list
->msg
= (asl_msg_t
**)reallocf(list
->msg
, (list
->curr
+ LIST_SIZE_DELTA
) * sizeof(asl_msg_t
*));
929 if (list
->msg
== NULL
)
936 list
->curr
+= LIST_SIZE_DELTA
;
939 list
->msg
[list
->count
] = msg
;
944 work_enqueue(asl_msg_t
*m
)
946 pthread_mutex_lock(global
.work_queue_lock
);
947 list_append_msg(global
.work_queue
, m
);
948 pthread_mutex_unlock(global
.work_queue_lock
);
949 pthread_cond_signal(&global
.work_queue_cond
);
953 asl_enqueue_message(uint32_t source
, struct aslevent
*e
, asl_msg_t
*msg
)
958 if (msg
== NULL
) return;
960 /* set retain count to 1 */
964 status
= aslmsg_verify(source
, e
, msg
, &kplevel
);
965 if (status
== VERIFY_STATUS_OK
)
967 if ((source
== SOURCE_KERN
) && (kplevel
>= 0)) notify_post(kern_notify_key
[kplevel
]);
972 asl_msg_release(msg
);
977 asl_work_dequeue(uint32_t *count
)
981 pthread_mutex_lock(global
.work_queue_lock
);
982 pthread_cond_wait(&global
.work_queue_cond
, global
.work_queue_lock
);
987 if (global
.work_queue
->count
== 0)
989 pthread_mutex_unlock(global
.work_queue_lock
);
993 work
= global
.work_queue
->msg
;
994 *count
= global
.work_queue
->count
;
996 global
.work_queue
->count
= 0;
997 global
.work_queue
->curr
= 0;
998 global
.work_queue
->msg
= NULL
;
1000 pthread_mutex_unlock(global
.work_queue_lock
);
1005 aslevent_handleevent(fd_set
*rd
, fd_set
*wr
, fd_set
*ex
)
1012 // asldebug("--> aslevent_handleevent\n");
1016 for (e
= Eventq
.tqh_first
; e
!= NULL
; e
= e
->entries
.tqe_next
)
1024 if (FD_ISSET(e
->fd
, rd
) && (e
->readfn
!= NULL
))
1026 // asldebug("handling read event on %d\n", e->fd);
1027 msg
= e
->readfn(e
->fd
);
1028 if (msg
== NULL
) continue;
1030 asl_enqueue_message(e
->source
, e
, msg
);
1033 if (FD_ISSET(e
->fd
, ex
) && e
->exceptfn
)
1035 asldebug("handling except event on %d\n", e
->fd
);
1036 out
= e
->exceptfn(e
->fd
);
1037 if (out
== NULL
) asldebug("error writing message\n\n");
1041 if (cleanup
!= 0) aslevent_cleanup();
1043 // asldebug("<-- aslevent_handleevent\n");
1047 asl_log_string(const char *str
)
1051 if (str
== NULL
) return 1;
1053 msg
= asl_msg_from_string(str
);
1054 if (msg
== NULL
) return 1;
1056 asl_enqueue_message(SOURCE_INTERNAL
, NULL
, msg
);
1062 asldebug(const char *str
, ...)
1068 OSSpinLockLock(&global
.lock
);
1069 if (global
.debug
== 0)
1071 OSSpinLockUnlock(&global
.lock
);
1076 if (global
.debug_file
!= NULL
) dfp
= fopen(global
.debug_file
, "a");
1079 OSSpinLockUnlock(&global
.lock
);
1084 status
= vfprintf(dfp
, str
, v
);
1087 if (global
.debug_file
!= NULL
) fclose(dfp
);
1088 OSSpinLockUnlock(&global
.lock
);
1099 asprintf(&str
, "[%s syslogd] [%s %u] [%s %u] [%s -- MARK --] [%s 0] [%s 0] [Facility syslog]",
1101 ASL_KEY_LEVEL
, ASL_LEVEL_INFO
,
1102 ASL_KEY_PID
, getpid(),
1103 ASL_KEY_MSG
, ASL_KEY_UID
, ASL_KEY_GID
);
1105 asl_log_string(str
);
1106 if (str
!= NULL
) free(str
);
1110 asl_syslog_input_convert(const char *in
, int len
, char *rhost
, int kern
)
1112 int pf
, pri
, index
, n
;
1113 char *p
, *colon
, *brace
, *tmp
, *tval
, *sval
, *pval
, *mval
;
1120 if (in
== NULL
) return NULL
;
1121 if (len
<= 0) return NULL
;
1133 while ((index
< len
) && ((*p
== ' ') || (*p
== '\t')))
1139 if (index
>= len
) return NULL
;
1146 n
= sscanf(p
, "%d", &pf
);
1150 if (pf
> 0x7) fval
= asl_syslog_faciliy_num_to_name(pf
& LOG_FACMASK
);
1153 while ((index
< len
) && (*p
!= '>'))
1166 snprintf(prival
, sizeof(prival
), "%d", pri
);
1168 if (((len
- index
) > 15) && (p
[9] == ':') && (p
[12] == ':') && (p
[15] == ' '))
1171 if (tmp
== NULL
) return NULL
;
1176 tick
= asl_parse_time(tmp
);
1177 if (tick
== (time_t)-1)
1184 gmtime_r(&tick
, &time
);
1185 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
);
1194 msg
= (asl_msg_t
*)calloc(1, sizeof(asl_msg_t
));
1195 if (msg
== NULL
) return NULL
;
1198 asl_set(msg
, ASL_KEY_MSG
, p
);
1200 asl_set(msg
, ASL_KEY_LEVEL
, prival
);
1202 asl_set(msg
, ASL_KEY_PID
, "0");
1204 asl_set(msg
, ASL_KEY_HOST
, whatsmyhostname());
1209 colon
= strchr(p
, ':');
1210 brace
= strchr(p
, '[');
1214 if ((brace
!= NULL
) && (brace
< colon
))
1217 sval
= malloc(n
+ 1);
1218 if (sval
== NULL
) return NULL
;
1223 n
= colon
- (brace
+ 1) - 1;
1224 pval
= malloc(n
+ 1);
1225 if (pval
== NULL
) return NULL
;
1227 memcpy(pval
, (brace
+ 1), n
);
1233 sval
= malloc(n
+ 1);
1234 if (sval
== NULL
) return NULL
;
1254 mval
= malloc(n
+ 1);
1255 if (mval
== NULL
) return NULL
;
1261 if (fval
== NULL
) fval
= asl_syslog_faciliy_num_to_name(LOG_USER
);
1263 msg
= (asl_msg_t
*)calloc(1, sizeof(asl_msg_t
));
1264 if (msg
== NULL
) return NULL
;
1268 asl_set(msg
, ASL_KEY_TIME
, tval
);
1272 if (fval
!= NULL
) asl_set(msg
, "Facility", fval
);
1273 else asl_set(msg
, "Facility", "user");
1277 asl_set(msg
, ASL_KEY_SENDER
, sval
);
1283 asl_set(msg
, ASL_KEY_PID
, pval
);
1286 else asl_set(msg
, ASL_KEY_PID
, "-1");
1290 asl_set(msg
, ASL_KEY_MSG
, mval
);
1294 asl_set(msg
, ASL_KEY_LEVEL
, prival
);
1295 asl_set(msg
, ASL_KEY_UID
, "-2");
1296 asl_set(msg
, ASL_KEY_GID
, "-2");
1298 if (rhost
== NULL
) asl_set(msg
, ASL_KEY_HOST
, whatsmyhostname());
1299 else asl_set(msg
, ASL_KEY_HOST
, rhost
);
1301 if (msg
->count
== 0)
1303 asl_msg_release(msg
);
1311 asl_input_parse(const char *in
, int len
, char *rhost
, int kern
)
1314 int status
, x
, legacy
;
1316 asldebug("asl_input_parse: %s\n", (in
== NULL
) ? "NULL" : in
);
1318 if (in
== NULL
) return NULL
;
1323 /* calculate length if not provided */
1324 if (len
== 0) len
= strlen(in
);
1327 * Determine if the input is "old" syslog format or new ASL format.
1328 * Old format lines should start with "<", but they can just be straight text.
1329 * ASL input starts with a length (10 bytes) followed by a space and a '['.
1331 if ((in
[0] != '<') && (len
> 11))
1333 status
= sscanf(in
, "%d ", &x
);
1334 if ((status
== 1) && (in
[10] == ' ') && (in
[11] == '[')) legacy
= 0;
1337 if (legacy
== 1) return asl_syslog_input_convert(in
, len
, rhost
, kern
);
1339 m
= asl_msg_from_string(in
+ 11);
1340 if (m
== NULL
) return NULL
;
1342 if (rhost
!= NULL
) asl_set(m
, ASL_KEY_HOST
, rhost
);
1348 get_line_from_file(FILE *f
)
1353 out
= fgetln(f
, &len
);
1354 if (out
== NULL
) return NULL
;
1355 if (len
== 0) return NULL
;
1357 s
= malloc(len
+ 1);
1358 if (s
== NULL
) return NULL
;
1360 memcpy(s
, out
, len
);
1367 asl_msg_type(asl_msg_t
*m
)
1369 if (m
== NULL
) return ASL_TYPE_ERROR
;
1370 return (m
->type
& ASL_MSG_TYPE_MASK
);
1374 asl_msg_release(asl_msg_t
*m
)
1378 if (m
== NULL
) return;
1380 newval
= OSAtomicAdd32(-0x10, (int32_t*)&m
->type
) >> 4;
1381 assert(newval
>= 0);
1383 if (newval
> 0) return;
1389 asl_msg_retain(asl_msg_t
*m
)
1393 if (m
== NULL
) return NULL
;
1395 newval
= OSAtomicAdd32(0x10, (int32_t*)&m
->type
) >> 4;
1402 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
)
1409 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",
1410 when->tv_sec, when->tv_usec, from_pid, about_pid, sender_uid, sender_gid, priority, from_name, about_name, session_name, msg);
1413 m
= asl_new(ASL_TYPE_MSG
);
1414 if (m
== NULL
) return;
1417 if (priority
< ASL_LEVEL_EMERG
) priority
= ASL_LEVEL_EMERG
;
1418 if (priority
> ASL_LEVEL_DEBUG
) priority
= ASL_LEVEL_DEBUG
;
1419 snprintf(str
, sizeof(str
), "%d", priority
);
1421 asl_set(m
, ASL_KEY_LEVEL
, str
);
1426 snprintf(str
, sizeof(str
), "%lu", when
->tv_sec
);
1427 asl_set(m
, ASL_KEY_TIME
, str
);
1429 snprintf(str
, sizeof(str
), "%lu", 1000 * (unsigned long int)when
->tv_usec
);
1430 asl_set(m
, ASL_KEY_TIME_NSEC
, str
);
1435 snprintf(str
, sizeof(str
), "%lu", now
);
1436 asl_set(m
, ASL_KEY_TIME
, str
);
1440 asl_set(m
, ASL_KEY_HOST
, whatsmyhostname());
1443 asl_set(m
, ASL_KEY_FACILITY
, FACILITY_CONSOLE
);
1446 snprintf(str
, sizeof(str
), "%u", (unsigned int)sender_uid
);
1447 asl_set(m
, ASL_KEY_UID
, str
);
1450 snprintf(str
, sizeof(str
), "%u", (unsigned int)sender_gid
);
1451 asl_set(m
, ASL_KEY_GID
, str
);
1456 snprintf(str
, sizeof(str
), "%u", (unsigned int)from_pid
);
1457 asl_set(m
, ASL_KEY_PID
, str
);
1461 if ((about_pid
> 0) && (about_pid
!= from_pid
))
1463 snprintf(str
, sizeof(str
), "%u", (unsigned int)about_pid
);
1464 asl_set(m
, ASL_KEY_REF_PID
, str
);
1468 if (from_name
!= NULL
)
1470 asl_set(m
, ASL_KEY_SENDER
, from_name
);
1474 if (sender_uid
!= 0)
1476 snprintf(str
, sizeof(str
), "%d", (int)sender_uid
);
1477 asl_set(m
, ASL_KEY_READ_UID
, str
);
1480 /* Reference Process */
1481 if (about_name
!= NULL
)
1483 if ((from_name
!= NULL
) && (strcmp(from_name
, about_name
) != 0))
1485 asl_set(m
, ASL_KEY_REF_PROC
, about_name
);
1490 if (session_name
!= NULL
)
1492 asl_set(m
, ASL_KEY_SESSION
, session_name
);
1498 asl_set(m
, ASL_KEY_MSG
, msg
);
1501 /* verify and push to receivers */
1502 asl_enqueue_message(SOURCE_LAUNCHD
, NULL
, m
);
1510 _vprocmgr_log_drain(NULL
, NULL
, launchd_callback
);