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>
42 #include <libkern/OSAtomic.h>
45 #define LIST_SIZE_DELTA 256
47 #define streq(A,B) (strcmp(A,B)==0)
48 #define forever for(;;)
49 #define IndexNull ((uint32_t)-1)
51 #define ASL_MSG_TYPE_MASK 0x0000000f
52 #define ASL_TYPE_ERROR 2
54 #define ASL_KEY_FACILITY "Facility"
56 #define FACILITY_USER "user"
57 #define FACILITY_CONSOLE "com.apple.console"
58 #define SYSTEM_RESERVED "com.apple.system"
59 #define SYSTEM_RESERVED_LEN 16
61 #define VERIFY_STATUS_OK 0
62 #define VERIFY_STATUS_INVALID_MESSAGE 1
63 #define VERIFY_STATUS_EXCEEDED_QUOTA 2
65 extern void disaster_message(asl_msg_t
*m
);
66 static char myname
[MAXHOSTNAMELEN
+ 1] = {0};
68 static OSSpinLock count_lock
= 0;
71 static vproc_transaction_t vproc_trans
= {0};
74 #define QUOTA_TABLE_SIZE 8192
75 #define QUOTA_TABLE_SLOTS 8
77 #define QUOTA_EXCEEDED_MESSAGE "*** process %d exceeded %d log message per second limit - remaining messages this second discarded ***"
78 #define QUOTA_EXCEEDED_LEVEL "3"
80 static time_t quota_table_time
= 0;
81 static pid_t quota_table_pid
[QUOTA_TABLE_SIZE
];
82 static int32_t quota_table_quota
[QUOTA_TABLE_SIZE
];
84 static const char *kern_notify_key
[] =
86 "com.apple.system.log.kernel.emergency",
87 "com.apple.system.log.kernel.alert",
88 "com.apple.system.log.kernel.critical",
89 "com.apple.system.log.kernel.error",
90 "com.apple.system.log.kernel.warning",
91 "com.apple.system.log.kernel.notice",
92 "com.apple.system.log.kernel.info",
93 "com.apple.system.log.kernel.debug"
100 TAILQ_ENTRY(asloutput
) entries
;
107 TAILQ_ENTRY(aslmatch
) entries
;
110 TAILQ_HEAD(ae
, aslevent
) Eventq
;
111 TAILQ_HEAD(ao
, asloutput
) Outq
;
112 TAILQ_HEAD(am
, aslmatch
) Matchq
;
115 _insertString(char *s
, char **l
, uint32_t x
)
119 if (s
== NULL
) return l
;
122 l
= (char **)malloc(2 * sizeof(char *));
123 if (l
== NULL
) return NULL
;
136 for (i
= 0; l
[i
] != NULL
; i
++);
137 len
= i
+ 1; /* count the NULL on the end of the list too! */
139 l
= (char **)reallocf(l
, (len
+ 1) * sizeof(char *));
140 if (l
== NULL
) return NULL
;
142 if ((x
>= (len
- 1)) || (x
== IndexNull
))
144 l
[len
- 1] = strdup(s
);
145 if (l
[len
- 1] == NULL
)
155 for (i
= len
; i
> x
; i
--) l
[i
] = l
[i
- 1];
157 if (l
[x
] == NULL
) return NULL
;
163 explode(const char *s
, const char *delim
)
170 if (s
== NULL
) return NULL
;
178 for (i
= 0; p
[i
] != '\0'; i
++)
182 /* not inside a quoted string: check for delimiters and quotes */
183 if (strchr(delim
, p
[i
]) != NULL
) break;
184 else if (p
[i
] == '\'') quote
= p
[i
];
185 else if (p
[i
] == '"') quote
= p
[i
];
189 /* inside a quoted string - look for matching quote */
190 if (p
[i
] == quote
) quote
= '\0';
196 if (t
== NULL
) return NULL
;
198 for (i
= 0; i
< n
; i
++) t
[i
] = p
[i
];
200 l
= _insertString(t
, l
, IndexNull
);
203 if (p
[i
] == '\0') return l
;
204 if (p
[i
+ 1] == '\0') l
= _insertString("", l
, IndexNull
);
216 if (l
== NULL
) return;
217 for (i
= 0; l
[i
] != NULL
; i
++) free(l
[i
]);
222 * Quotas are maintained using a very fast fixed-size table.
223 * We hash into the pid table (quota_table_pid) using the last 10
224 * bits of the pid, so the table has 1024 "buckets". The table is
225 * actually just an array with 8 entry slots (for collisions) per bucket.
226 * If there are more than 8 pids that hash to the same bucket, we
227 * re-use the one with the lowest message usage (highest remaining
228 * quota). This can lead to "generosity: if there are nine or more
229 * pids with the same last 10 bits all logging like crazy, we may
230 * end up allowing some of them to log more than their quota.
231 * That would be a remarkably rare occurrence.
235 quota_check(pid_t pid
, time_t now
, asl_msg_t
*msg
)
240 if (msg
== NULL
) return VERIFY_STATUS_INVALID_MESSAGE
;
241 if (global
.mps_limit
== 0) return VERIFY_STATUS_OK
;
243 OSSpinLockLock(&global
.lock
);
245 if (quota_table_time
!= now
)
247 memset(quota_table_pid
, 0, sizeof(quota_table_pid
));
248 quota_table_time
= now
;
251 /* hash is last 10 bits of the pid, shifted up 3 bits to allow 8 slots per bucket */
252 x
= (pid
& 0x000003ff) << 3;
254 max
= quota_table_quota
[x
];
256 for (i
= 0; i
< QUOTA_TABLE_SLOTS
; i
++)
258 if (quota_table_pid
[x
] == 0)
260 quota_table_pid
[x
] = pid
;
261 quota_table_quota
[x
] = global
.mps_limit
;
263 OSSpinLockUnlock(&global
.lock
);
264 return VERIFY_STATUS_OK
;
267 if (quota_table_pid
[x
] == pid
)
269 quota_table_quota
[x
] = quota_table_quota
[x
] - 1;
271 if (quota_table_quota
[x
] == 0)
273 quota_table_quota
[x
] = -1;
276 asprintf(&str
, QUOTA_EXCEEDED_MESSAGE
, (int)pid
, global
.mps_limit
);
279 asl_set(msg
, ASL_KEY_MSG
, str
);
281 asl_set(msg
, ASL_KEY_LEVEL
, QUOTA_EXCEEDED_LEVEL
);
284 OSSpinLockUnlock(&global
.lock
);
285 return VERIFY_STATUS_OK
;
288 if (quota_table_quota
[x
] < 0)
290 OSSpinLockUnlock(&global
.lock
);
291 return VERIFY_STATUS_EXCEEDED_QUOTA
;
294 OSSpinLockUnlock(&global
.lock
);
295 return VERIFY_STATUS_OK
;
298 if (quota_table_quota
[x
] > max
)
301 max
= quota_table_quota
[x
];
307 /* can't find the pid and no slots were available - reuse slot with highest remaining quota */
308 quota_table_pid
[maxx
] = pid
;
309 quota_table_quota
[maxx
] = global
.mps_limit
;
311 OSSpinLockUnlock(&global
.lock
);
312 return VERIFY_STATUS_OK
;
316 asl_check_option(asl_msg_t
*msg
, const char *opt
)
321 if (msg
== NULL
) return 0;
322 if (opt
== NULL
) return 0;
325 if (len
== 0) return 0;
327 p
= asl_get(msg
, ASL_KEY_OPTION
);
328 if (p
== NULL
) return 0;
332 while ((*p
== ' ') || (*p
== '\t') || (*p
== ',')) p
++;
333 if (*p
== '\0') return 0;
335 if (strncasecmp(p
, opt
, len
) == 0)
338 if ((*p
== ' ') || (*p
== '\t') || (*p
== ',') || (*p
== '\0')) return 1;
341 while ((*p
!= ' ') && (*p
!= '\t') && (*p
!= ',') && (*p
!= '\0')) p
++;
358 aslevent_log(asl_msg_t
*msg
, char *outid
)
363 for (i
= Outq
.tqh_first
; i
!= NULL
; i
= i
->entries
.tqe_next
)
365 if ((outid
!= NULL
) && (strcmp(i
->outid
, outid
) == 0))
367 status
= i
->sendmsg(msg
, outid
);
375 aslevent_addmatch(asl_msg_t
*query
, char *outid
)
377 struct aslmatch
*tmp
;
379 if (query
== NULL
) return -1;
380 if (outid
== NULL
) return -1;
382 tmp
= calloc(1, sizeof(struct aslmatch
));
383 if (tmp
== NULL
) return -1;
387 TAILQ_INSERT_TAIL(&Matchq
, tmp
, entries
);
393 asl_message_match_and_log(asl_msg_t
*msg
)
397 if (msg
== NULL
) return;
399 for (i
= Matchq
.tqh_first
; i
!= NULL
; i
= i
->entries
.tqe_next
)
401 if (asl_msg_cmp(i
->query
, msg
) != 0)
403 aslevent_log(msg
, i
->outid
);
409 aslevent_removefd(int fd
)
411 struct aslevent
*e
, *next
;
413 e
= Eventq
.tqh_first
;
417 next
= e
->entries
.tqe_next
;
435 if (gethostname(myname
, MAXHOSTNAMELEN
) < 0)
437 memset(myname
, 0, sizeof(myname
));
441 dot
= strchr(myname
, '.');
442 if (dot
!= NULL
) *dot
= '\0';
444 return (const char *)myname
;
448 asl_client_count_increment()
450 OSSpinLockLock(&count_lock
);
452 #ifndef CONFIG_IPHONE
453 if (global
.client_count
== 0) vproc_trans
= vproc_transaction_begin(NULL
);
455 global
.client_count
++;
457 asldebug("global.client_count++ (%d)\n", global
.client_count
);
460 OSSpinLockUnlock(&count_lock
);
464 asl_client_count_decrement()
466 OSSpinLockLock(&count_lock
);
468 if (global
.client_count
> 0) global
.client_count
--;
469 #ifndef CONFIG_IPHONE
470 if (global
.client_count
== 0) vproc_transaction_end(NULL
, vproc_trans
);
473 asldebug("global.client_count-- (%d)\n", global
.client_count
);
476 OSSpinLockUnlock(&count_lock
);
480 aslevent_addfd(int source
, int fd
, uint32_t flags
, aslreadfn readfn
, aslwritefn writefn
, aslexceptfn exceptfn
)
483 int found
= 0, status
;
484 #ifdef LOCAL_PEERCRED
490 struct sockaddr_storage ss
;
491 char *sender
, str
[256];
497 memset(&ss
, 0, sizeof(struct sockaddr_storage
));
498 memset(str
, 0, sizeof(str
));
500 len
= sizeof(struct sockaddr_storage
);
502 if (flags
& ADDFD_FLAGS_LOCAL
)
504 snprintf(str
, sizeof(str
), "localhost");
507 #ifdef LOCAL_PEERCRED
510 status
= getsockopt(fd
, LOCAL_PEERCRED
, 1, &cr
, &len
);
520 status
= getpeername(fd
, (struct sockaddr
*)&ss
, &len
);
525 /* UNIX Domain socket */
526 snprintf(str
, sizeof(str
), "localhost");
531 if (inet_ntop(ss
.ss_family
, (struct sockaddr
*)&ss
, str
, 256) == NULL
) sender
= str
;
536 asldebug("source %d fd %d flags 0x%08x UID %d GID %d Sender %s\n", source
, fd
, flags
, u
, g
, (sender
== NULL
) ? "NULL" : sender
);
538 for (e
= Eventq
.tqh_first
; e
!= NULL
; e
= e
->entries
.tqe_next
)
543 e
->writefn
= writefn
;
544 e
->exceptfn
= exceptfn
;
545 if (e
->sender
!= NULL
) free(e
->sender
);
549 e
->sender
= strdup(sender
);
550 if (e
->sender
== NULL
) return -1;
561 e
= calloc(1, sizeof(struct aslevent
));
562 if (e
== NULL
) return -1;
567 e
->writefn
= writefn
;
568 e
->exceptfn
= exceptfn
;
572 e
->sender
= strdup(sender
);
573 if (e
->sender
== NULL
) return -1;
579 TAILQ_INSERT_TAIL(&Eventq
, e
, entries
);
585 * Checks message content and sets attributes as required
587 * SOURCE_INTERNAL log messages sent by syslogd itself
588 * SOURCE_ASL_SOCKET legacy asl(3) TCP socket
589 * SOURCE_BSD_SOCKET legacy syslog(3) UDP socket
590 * SOURCE_UDP_SOCKET from the network
591 * SOURCE_KERN from the kernel
592 * SOURCE_ASL_MESSAGE mach messages sent from Libc by asl(3) and syslog(3)
593 * SOURCE_LAUNCHD forwarded from launchd
597 aslmsg_verify(uint32_t source
, struct aslevent
*e
, asl_msg_t
*msg
, int32_t *kern_post_level
)
599 const char *val
, *fac
;
603 uint32_t status
, level
, fnum
;
606 if (msg
== NULL
) return VERIFY_STATUS_INVALID_MESSAGE
;
608 if (kern_post_level
!= NULL
) *kern_post_level
= -1;
614 val
= asl_get(msg
, ASL_KEY_TIME
);
615 if (val
!= NULL
) tick
= asl_parse_time(val
);
617 /* Set time to now if it is unset or from the future (not allowed!) */
618 if ((tick
== 0) || (tick
> now
)) tick
= now
;
620 /* Canonical form: seconds since the epoch */
621 snprintf(buf
, sizeof(buf
) - 1, "%lu", tick
);
622 asl_set(msg
, ASL_KEY_TIME
, buf
);
625 if (e
== NULL
) asl_set(msg
, ASL_KEY_HOST
, whatsmyhostname());
626 else if (e
->sender
!= NULL
)
628 if (!strcmp(e
->sender
, "localhost")) asl_set(msg
, ASL_KEY_HOST
, whatsmyhostname());
629 else asl_set(msg
, ASL_KEY_HOST
, e
->sender
);
635 val
= asl_get(msg
, ASL_KEY_PID
);
636 if (val
== NULL
) asl_set(msg
, ASL_KEY_PID
, "0");
637 else pid
= (pid_t
)atoi(val
);
639 /* if PID is 1 (launchd), use the refpid if there is one */
642 val
= asl_get(msg
, ASL_KEY_REF_PID
);
643 if (val
!= NULL
) pid
= (pid_t
)atoi(val
);
646 /* if quotas are enabled and pid > 1 (not kernel or launchd) check quota */
647 if ((global
.mps_limit
> 0) && (pid
> 1))
649 status
= quota_check(pid
, now
, msg
);
650 if (status
!= VERIFY_STATUS_OK
) return status
;
655 val
= asl_get(msg
, ASL_KEY_UID
);
660 case SOURCE_INTERNAL
:
662 /* we know the UID is 0 */
664 asl_set(msg
, ASL_KEY_UID
, "0");
667 case SOURCE_ASL_SOCKET
:
668 case SOURCE_ASL_MESSAGE
:
671 /* we trust the UID in the message */
672 if (val
!= NULL
) uid
= atoi(val
);
675 case SOURCE_BSD_SOCKET
:
676 case SOURCE_UDP_SOCKET
:
680 if (e
== NULL
) asl_set(msg
, ASL_KEY_UID
, "-2");
681 else if (e
->uid
== 99) asl_set(msg
, ASL_KEY_UID
, "-2");
685 snprintf(buf
, sizeof(buf
), "%d", e
->uid
);
686 asl_set(msg
, ASL_KEY_UID
, buf
);
689 else if ((e
!= NULL
) && (e
->uid
!= 99))
692 snprintf(buf
, sizeof(buf
), "%d", e
->uid
);
693 asl_set(msg
, ASL_KEY_UID
, buf
);
698 asl_set(msg
, ASL_KEY_UID
, "-2");
703 val
= asl_get(msg
, ASL_KEY_GID
);
708 case SOURCE_INTERNAL
:
710 /* we know the GID is 0 */
711 asl_set(msg
, ASL_KEY_GID
, "0");
714 case SOURCE_ASL_SOCKET
:
715 case SOURCE_ASL_MESSAGE
:
718 /* we trust the GID in the message */
721 case SOURCE_BSD_SOCKET
:
722 case SOURCE_UDP_SOCKET
:
726 if (e
== NULL
) asl_set(msg
, ASL_KEY_GID
, "-2");
727 else if (e
->gid
== 99) asl_set(msg
, ASL_KEY_GID
, "-2");
730 snprintf(buf
, sizeof(buf
), "%d", e
->gid
);
731 asl_set(msg
, ASL_KEY_GID
, buf
);
734 else if ((e
!= NULL
) && (e
->gid
!= 99))
736 snprintf(buf
, sizeof(buf
), "%d", e
->gid
);
737 asl_set(msg
, ASL_KEY_GID
, buf
);
742 asl_set(msg
, ASL_KEY_GID
, "-2");
747 val
= asl_get(msg
, ASL_KEY_SENDER
);
754 asl_set(msg
, ASL_KEY_SENDER
, "kernel");
757 case SOURCE_INTERNAL
:
759 asl_set(msg
, ASL_KEY_SENDER
, "syslogd");
764 asl_set(msg
, ASL_KEY_SENDER
, "Unknown");
768 else if ((source
!= SOURCE_KERN
) && (uid
!= 0) && (!strcmp(val
, "kernel")))
770 /* allow UID 0 to send messages with "Sender kernel", but nobody else */
771 asl_set(msg
, ASL_KEY_SENDER
, "Unknown");
775 val
= asl_get(msg
, ASL_KEY_LEVEL
);
776 level
= ASL_LEVEL_DEBUG
;
777 if ((val
!= NULL
) && (val
[1] == '\0') && (val
[0] >= '0') && (val
[0] <= '7')) level
= val
[0] - '0';
778 snprintf(buf
, sizeof(buf
), "%d", level
);
779 asl_set(msg
, ASL_KEY_LEVEL
, buf
);
782 fac
= asl_get(msg
, ASL_KEY_FACILITY
);
785 if (source
== SOURCE_KERN
) fac
= "kern";
787 asl_set(msg
, ASL_KEY_FACILITY
, fac
);
789 else if (fac
[0] == '#')
792 if ((fac
[1] >= '0') && (fac
[1] <= '9'))
794 fnum
= atoi(fac
+ 1) << 3;
795 if ((fnum
== 0) && (strcmp(fac
+ 1, "0"))) fnum
= LOG_USER
;
798 fac
= asl_syslog_faciliy_num_to_name(fnum
);
799 asl_set(msg
, ASL_KEY_FACILITY
, fac
);
801 else if (!strncmp(fac
, SYSTEM_RESERVED
, SYSTEM_RESERVED_LEN
))
803 /* only UID 0 may use "com.apple.system" */
804 if (uid
!= 0) asl_set(msg
, ASL_KEY_FACILITY
, FACILITY_USER
);
808 * kernel messages are only readable by root and admin group.
810 if (source
== SOURCE_KERN
)
812 asl_set(msg
, ASL_KEY_READ_UID
, "0");
813 asl_set(msg
, ASL_KEY_READ_GID
, "80");
817 * Access Control: only UID 0 may use facility com.apple.system (or anything with that prefix).
818 * N.B. kernel can use any facility name.
821 /* Set DB Expire Time for com.apple.system.utmpx and lastlog */
822 if ((!strcmp(fac
, "com.apple.system.utmpx")) || (!strcmp(fac
, "com.apple.system.lastlog")))
824 snprintf(buf
, sizeof(buf
), "%lu", tick
+ global
.utmp_ttl
);
825 asl_set(msg
, ASL_KEY_EXPIRE_TIME
, buf
);
828 /* Set DB Expire Time for Filestsrem errors */
829 if (!strcmp(fac
, FSLOG_VAL_FACILITY
))
831 snprintf(buf
, sizeof(buf
), "%lu", tick
+ global
.fs_ttl
);
832 asl_set(msg
, ASL_KEY_EXPIRE_TIME
, buf
);
836 * special case handling of kernel disaster messages
838 if ((source
== SOURCE_KERN
) && (level
<= KERN_DISASTER_LEVEL
))
840 if (kern_post_level
!= NULL
) *kern_post_level
= level
;
841 disaster_message(msg
);
844 return VERIFY_STATUS_OK
;
848 aslevent_addoutput(aslsendmsgfn fn
, const char *outid
)
850 struct asloutput
*tmp
;
852 tmp
= calloc(1, sizeof(struct asloutput
));
853 if (tmp
== NULL
) return -1;
858 TAILQ_INSERT_TAIL(&Outq
, tmp
, entries
);
864 aslevent_fdsets(fd_set
*rd
, fd_set
*wr
, fd_set
*ex
)
869 // asldebug("--> aslevent_fdsets\n");
874 for (e
= Eventq
.tqh_first
; e
!= NULL
; e
= e
->entries
.tqe_next
)
876 if (e
->fd
< 0) continue;
878 // asldebug("adding fd %d\n", e->fd);
882 status
= MAX(e
->fd
, status
);
888 status
= MAX(e
->fd
, status
);
894 status
= MAX(e
->fd
, status
);
898 // asldebug("<--aslevent_fdsets\n");
905 struct aslevent
*e
, *next
;
907 e
= Eventq
.tqh_first
;
911 next
= e
->entries
.tqe_next
;
914 TAILQ_REMOVE(&Eventq
, e
, entries
);
915 if (e
->sender
!= NULL
) free(e
->sender
);
924 list_append_msg(asl_search_result_t
*list
, asl_msg_t
*msg
)
926 if (list
== NULL
) return;
927 if (msg
== NULL
) return;
930 * NB: curr is the list size
931 * grow list if necessary
933 if (list
->count
== list
->curr
)
937 list
->msg
= (asl_msg_t
**)calloc(LIST_SIZE_DELTA
, sizeof(asl_msg_t
*));
941 list
->msg
= (asl_msg_t
**)reallocf(list
->msg
, (list
->curr
+ LIST_SIZE_DELTA
) * sizeof(asl_msg_t
*));
944 if (list
->msg
== NULL
)
951 list
->curr
+= LIST_SIZE_DELTA
;
954 list
->msg
[list
->count
] = msg
;
959 work_enqueue(asl_msg_t
*m
)
961 pthread_mutex_lock(global
.work_queue_lock
);
962 list_append_msg(global
.work_queue
, m
);
963 pthread_mutex_unlock(global
.work_queue_lock
);
964 pthread_cond_signal(&global
.work_queue_cond
);
968 asl_enqueue_message(uint32_t source
, struct aslevent
*e
, asl_msg_t
*msg
)
973 if (msg
== NULL
) return;
975 /* set retain count to 1 */
979 status
= aslmsg_verify(source
, e
, msg
, &kplevel
);
980 if (status
== VERIFY_STATUS_OK
)
982 if ((source
== SOURCE_KERN
) && (kplevel
>= 0)) notify_post(kern_notify_key
[kplevel
]);
987 asl_msg_release(msg
);
992 asl_work_dequeue(uint32_t *count
)
996 pthread_mutex_lock(global
.work_queue_lock
);
997 pthread_cond_wait(&global
.work_queue_cond
, global
.work_queue_lock
);
1002 if (global
.work_queue
->count
== 0)
1004 pthread_mutex_unlock(global
.work_queue_lock
);
1008 work
= global
.work_queue
->msg
;
1009 *count
= global
.work_queue
->count
;
1011 global
.work_queue
->count
= 0;
1012 global
.work_queue
->curr
= 0;
1013 global
.work_queue
->msg
= NULL
;
1015 pthread_mutex_unlock(global
.work_queue_lock
);
1020 aslevent_handleevent(fd_set
*rd
, fd_set
*wr
, fd_set
*ex
)
1027 // asldebug("--> aslevent_handleevent\n");
1031 for (e
= Eventq
.tqh_first
; e
!= NULL
; e
= e
->entries
.tqe_next
)
1039 if (FD_ISSET(e
->fd
, rd
) && (e
->readfn
!= NULL
))
1041 // asldebug("handling read event on %d\n", e->fd);
1042 msg
= e
->readfn(e
->fd
);
1043 if (msg
== NULL
) continue;
1045 asl_enqueue_message(e
->source
, e
, msg
);
1048 if (FD_ISSET(e
->fd
, ex
) && e
->exceptfn
)
1050 asldebug("handling except event on %d\n", e
->fd
);
1051 out
= e
->exceptfn(e
->fd
);
1052 if (out
== NULL
) asldebug("error writing message\n\n");
1056 if (cleanup
!= 0) aslevent_cleanup();
1058 // asldebug("<-- aslevent_handleevent\n");
1062 asl_log_string(const char *str
)
1066 if (str
== NULL
) return 1;
1068 msg
= asl_msg_from_string(str
);
1069 if (msg
== NULL
) return 1;
1071 asl_enqueue_message(SOURCE_INTERNAL
, NULL
, msg
);
1077 asldebug(const char *str
, ...)
1083 OSSpinLockLock(&global
.lock
);
1084 if (global
.debug
== 0)
1086 OSSpinLockUnlock(&global
.lock
);
1091 if (global
.debug_file
!= NULL
) dfp
= fopen(global
.debug_file
, "a");
1094 OSSpinLockUnlock(&global
.lock
);
1099 status
= vfprintf(dfp
, str
, v
);
1102 if (global
.debug_file
!= NULL
) fclose(dfp
);
1103 OSSpinLockUnlock(&global
.lock
);
1114 asprintf(&str
, "[%s syslogd] [%s %u] [%s %u] [%s -- MARK --] [%s 0] [%s 0] [Facility syslog]",
1116 ASL_KEY_LEVEL
, ASL_LEVEL_INFO
,
1117 ASL_KEY_PID
, getpid(),
1118 ASL_KEY_MSG
, ASL_KEY_UID
, ASL_KEY_GID
);
1120 asl_log_string(str
);
1121 if (str
!= NULL
) free(str
);
1125 asl_syslog_input_convert(const char *in
, int len
, char *rhost
, int kern
)
1127 int pf
, pri
, index
, n
;
1128 char *p
, *colon
, *brace
, *tmp
, *tval
, *sval
, *pval
, *mval
;
1135 if (in
== NULL
) return NULL
;
1136 if (len
<= 0) return NULL
;
1148 while ((index
< len
) && ((*p
== ' ') || (*p
== '\t')))
1154 if (index
>= len
) return NULL
;
1161 n
= sscanf(p
, "%d", &pf
);
1165 if (pf
> 0x7) fval
= asl_syslog_faciliy_num_to_name(pf
& LOG_FACMASK
);
1168 while ((index
< len
) && (*p
!= '>'))
1181 snprintf(prival
, sizeof(prival
), "%d", pri
);
1183 if (((len
- index
) > 15) && (p
[9] == ':') && (p
[12] == ':') && (p
[15] == ' '))
1186 if (tmp
== NULL
) return NULL
;
1191 tick
= asl_parse_time(tmp
);
1192 if (tick
== (time_t)-1)
1199 gmtime_r(&tick
, &time
);
1200 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
);
1209 msg
= (asl_msg_t
*)calloc(1, sizeof(asl_msg_t
));
1210 if (msg
== NULL
) return NULL
;
1213 asl_set(msg
, ASL_KEY_MSG
, p
);
1215 asl_set(msg
, ASL_KEY_LEVEL
, prival
);
1217 asl_set(msg
, ASL_KEY_PID
, "0");
1219 asl_set(msg
, ASL_KEY_HOST
, whatsmyhostname());
1224 colon
= strchr(p
, ':');
1225 brace
= strchr(p
, '[');
1229 if ((brace
!= NULL
) && (brace
< colon
))
1232 sval
= malloc(n
+ 1);
1233 if (sval
== NULL
) return NULL
;
1238 n
= colon
- (brace
+ 1) - 1;
1239 pval
= malloc(n
+ 1);
1240 if (pval
== NULL
) return NULL
;
1242 memcpy(pval
, (brace
+ 1), n
);
1248 sval
= malloc(n
+ 1);
1249 if (sval
== NULL
) return NULL
;
1269 mval
= malloc(n
+ 1);
1270 if (mval
== NULL
) return NULL
;
1276 if (fval
== NULL
) fval
= asl_syslog_faciliy_num_to_name(LOG_USER
);
1278 msg
= (asl_msg_t
*)calloc(1, sizeof(asl_msg_t
));
1279 if (msg
== NULL
) return NULL
;
1283 asl_set(msg
, ASL_KEY_TIME
, tval
);
1287 if (fval
!= NULL
) asl_set(msg
, "Facility", fval
);
1288 else asl_set(msg
, "Facility", "user");
1292 asl_set(msg
, ASL_KEY_SENDER
, sval
);
1298 asl_set(msg
, ASL_KEY_PID
, pval
);
1301 else asl_set(msg
, ASL_KEY_PID
, "-1");
1305 asl_set(msg
, ASL_KEY_MSG
, mval
);
1309 asl_set(msg
, ASL_KEY_LEVEL
, prival
);
1310 asl_set(msg
, ASL_KEY_UID
, "-2");
1311 asl_set(msg
, ASL_KEY_GID
, "-2");
1313 if (rhost
== NULL
) asl_set(msg
, ASL_KEY_HOST
, whatsmyhostname());
1314 else asl_set(msg
, ASL_KEY_HOST
, rhost
);
1316 if (msg
->count
== 0)
1318 asl_msg_release(msg
);
1326 asl_input_parse(const char *in
, int len
, char *rhost
, int kern
)
1329 int status
, x
, legacy
;
1331 asldebug("asl_input_parse: %s\n", (in
== NULL
) ? "NULL" : in
);
1333 if (in
== NULL
) return NULL
;
1338 /* calculate length if not provided */
1339 if (len
== 0) len
= strlen(in
);
1342 * Determine if the input is "old" syslog format or new ASL format.
1343 * Old format lines should start with "<", but they can just be straight text.
1344 * ASL input starts with a length (10 bytes) followed by a space and a '['.
1346 if ((in
[0] != '<') && (len
> 11))
1348 status
= sscanf(in
, "%d ", &x
);
1349 if ((status
== 1) && (in
[10] == ' ') && (in
[11] == '[')) legacy
= 0;
1352 if (legacy
== 1) return asl_syslog_input_convert(in
, len
, rhost
, kern
);
1354 m
= asl_msg_from_string(in
+ 11);
1355 if (m
== NULL
) return NULL
;
1357 if (rhost
!= NULL
) asl_set(m
, ASL_KEY_HOST
, rhost
);
1363 get_line_from_file(FILE *f
)
1368 out
= fgetln(f
, &len
);
1369 if (out
== NULL
) return NULL
;
1370 if (len
== 0) return NULL
;
1372 s
= malloc(len
+ 1);
1373 if (s
== NULL
) return NULL
;
1375 memcpy(s
, out
, len
);
1382 asl_msg_type(asl_msg_t
*m
)
1384 if (m
== NULL
) return ASL_TYPE_ERROR
;
1385 return (m
->type
& ASL_MSG_TYPE_MASK
);
1389 asl_msg_release(asl_msg_t
*m
)
1393 if (m
== NULL
) return;
1395 newval
= OSAtomicAdd32(-0x10, (int32_t*)&m
->type
) >> 4;
1396 assert(newval
>= 0);
1398 if (newval
> 0) return;
1404 asl_msg_retain(asl_msg_t
*m
)
1408 if (m
== NULL
) return NULL
;
1410 newval
= OSAtomicAdd32(0x10, (int32_t*)&m
->type
) >> 4;
1417 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
)
1424 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",
1425 when->tv_sec, when->tv_usec, from_pid, about_pid, sender_uid, sender_gid, priority, from_name, about_name, session_name, msg);
1428 m
= asl_new(ASL_TYPE_MSG
);
1429 if (m
== NULL
) return;
1432 if (priority
< ASL_LEVEL_EMERG
) priority
= ASL_LEVEL_EMERG
;
1433 if (priority
> ASL_LEVEL_DEBUG
) priority
= ASL_LEVEL_DEBUG
;
1434 snprintf(str
, sizeof(str
), "%d", priority
);
1436 asl_set(m
, ASL_KEY_LEVEL
, str
);
1441 snprintf(str
, sizeof(str
), "%lu", when
->tv_sec
);
1442 asl_set(m
, ASL_KEY_TIME
, str
);
1444 snprintf(str
, sizeof(str
), "%lu", 1000 * (unsigned long int)when
->tv_usec
);
1445 asl_set(m
, ASL_KEY_TIME_NSEC
, str
);
1450 snprintf(str
, sizeof(str
), "%lu", now
);
1451 asl_set(m
, ASL_KEY_TIME
, str
);
1455 asl_set(m
, ASL_KEY_HOST
, whatsmyhostname());
1458 asl_set(m
, ASL_KEY_FACILITY
, FACILITY_CONSOLE
);
1461 snprintf(str
, sizeof(str
), "%u", (unsigned int)sender_uid
);
1462 asl_set(m
, ASL_KEY_UID
, str
);
1465 snprintf(str
, sizeof(str
), "%u", (unsigned int)sender_gid
);
1466 asl_set(m
, ASL_KEY_GID
, str
);
1471 snprintf(str
, sizeof(str
), "%u", (unsigned int)from_pid
);
1472 asl_set(m
, ASL_KEY_PID
, str
);
1476 if ((about_pid
> 0) && (about_pid
!= from_pid
))
1478 snprintf(str
, sizeof(str
), "%u", (unsigned int)about_pid
);
1479 asl_set(m
, ASL_KEY_REF_PID
, str
);
1483 if (from_name
!= NULL
)
1485 asl_set(m
, ASL_KEY_SENDER
, from_name
);
1489 if (sender_uid
!= 0)
1491 snprintf(str
, sizeof(str
), "%d", (int)sender_uid
);
1492 asl_set(m
, ASL_KEY_READ_UID
, str
);
1495 /* Reference Process */
1496 if (about_name
!= NULL
)
1498 if ((from_name
!= NULL
) && (strcmp(from_name
, about_name
) != 0))
1500 asl_set(m
, ASL_KEY_REF_PROC
, about_name
);
1505 if (session_name
!= NULL
)
1507 asl_set(m
, ASL_KEY_SESSION
, session_name
);
1513 asl_set(m
, ASL_KEY_MSG
, msg
);
1516 /* verify and push to receivers */
1517 asl_enqueue_message(SOURCE_LAUNCHD
, NULL
, m
);
1525 _vprocmgr_log_drain(NULL
, NULL
, launchd_callback
);