]> git.saurik.com Git - apple/syslog.git/blame - syslogd.tproj/daemon.c
syslog-148.8.tar.gz
[apple/syslog.git] / syslogd.tproj / daemon.c
CommitLineData
b16a592a 1/*
db78b1bd 2 * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
b16a592a
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
5dd30d76
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
b16a592a
A
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
5dd30d76
A
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.
b16a592a
A
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <sys/un.h>
27#include <sys/ucred.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
b16a592a
A
32#include <netinet/in.h>
33#include <arpa/inet.h>
34#define SYSLOG_NAMES
35#include <syslog.h>
5dd30d76
A
36#include <sys/fslog.h>
37#include <vproc.h>
38#include <pthread.h>
39#include <vproc_priv.h>
40#include <mach/mach.h>
c4fdb7d1
A
41#include <assert.h>
42#include <libkern/OSAtomic.h>
b16a592a
A
43#include "daemon.h"
44
c4fdb7d1
A
45#define LIST_SIZE_DELTA 256
46
b16a592a 47#define streq(A,B) (strcmp(A,B)==0)
5dd30d76
A
48#define forever for(;;)
49
50#define ASL_MSG_TYPE_MASK 0x0000000f
51#define ASL_TYPE_ERROR 2
52
53#define ASL_KEY_FACILITY "Facility"
54
55#define FACILITY_USER "user"
56#define FACILITY_CONSOLE "com.apple.console"
57#define SYSTEM_RESERVED "com.apple.system"
58#define SYSTEM_RESERVED_LEN 16
59
c4fdb7d1
A
60#define VERIFY_STATUS_OK 0
61#define VERIFY_STATUS_INVALID_MESSAGE 1
62#define VERIFY_STATUS_EXCEEDED_QUOTA 2
b16a592a 63
a83ff38a 64extern void disaster_message(aslmsg m);
db78b1bd
A
65extern int asl_action_reset(void);
66
b16a592a 67static char myname[MAXHOSTNAMELEN + 1] = {0};
db78b1bd 68static int name_change_token = -1;
5dd30d76 69
c4fdb7d1
A
70static OSSpinLock count_lock = 0;
71
1496e7d1 72#ifndef CONFIG_IPHONE
c4fdb7d1 73static vproc_transaction_t vproc_trans = {0};
1496e7d1 74#endif
c4fdb7d1
A
75
76#define QUOTA_TABLE_SIZE 8192
77#define QUOTA_TABLE_SLOTS 8
78
79#define QUOTA_EXCEEDED_MESSAGE "*** process %d exceeded %d log message per second limit - remaining messages this second discarded ***"
db78b1bd 80#define QUOTA_KERN_EXCEEDED_MESSAGE "*** kernel exceeded %d log message per second limit - remaining messages this second discarded ***"
c4fdb7d1
A
81#define QUOTA_EXCEEDED_LEVEL "3"
82
db78b1bd
A
83#define DEFAULT_DB_FILE_MAX 25600000
84#define DEFAULT_DB_MEMORY_MAX 8192
85#define DEFAULT_DB_MINI_MAX 256
86#define DEFAULT_MPS_LIMIT 500
87#define DEFAULT_REMOTE_DELAY 5000
88#define DEFAULT_BSD_MAX_DUP_SEC 30
89#define DEFAULT_MARK_SEC 0
90#define DEFAULT_UTMP_TTL_SEC 31622400
91
c4fdb7d1
A
92static time_t quota_table_time = 0;
93static pid_t quota_table_pid[QUOTA_TABLE_SIZE];
94static int32_t quota_table_quota[QUOTA_TABLE_SIZE];
db78b1bd
A
95static int32_t kern_quota;
96static int32_t kern_level;
5dd30d76
A
97
98static const char *kern_notify_key[] =
99{
100 "com.apple.system.log.kernel.emergency",
101 "com.apple.system.log.kernel.alert",
102 "com.apple.system.log.kernel.critical",
103 "com.apple.system.log.kernel.error",
104 "com.apple.system.log.kernel.warning",
105 "com.apple.system.log.kernel.notice",
106 "com.apple.system.log.kernel.info",
107 "com.apple.system.log.kernel.debug"
108};
b16a592a 109
db78b1bd 110static int kern_notify_token[8] = {-1, -1, -1, -1, -1, -1, -1, -1 };
b16a592a 111
c4fdb7d1
A
112static char **
113_insertString(char *s, char **l, uint32_t x)
114{
115 int i, len;
116
117 if (s == NULL) return l;
118 if (l == NULL)
119 {
120 l = (char **)malloc(2 * sizeof(char *));
121 if (l == NULL) return NULL;
122
123 l[0] = strdup(s);
124 if (l[0] == NULL)
125 {
126 free(l);
127 return NULL;
128 }
129
130 l[1] = NULL;
131 return l;
132 }
133
134 for (i = 0; l[i] != NULL; i++);
135 len = i + 1; /* count the NULL on the end of the list too! */
136
137 l = (char **)reallocf(l, (len + 1) * sizeof(char *));
138 if (l == NULL) return NULL;
139
140 if ((x >= (len - 1)) || (x == IndexNull))
141 {
142 l[len - 1] = strdup(s);
143 if (l[len - 1] == NULL)
144 {
145 free(l);
146 return NULL;
147 }
148
149 l[len] = NULL;
150 return l;
151 }
152
153 for (i = len; i > x; i--) l[i] = l[i - 1];
154 l[x] = strdup(s);
155 if (l[x] == NULL) return NULL;
156
157 return l;
158}
159
160char **
161explode(const char *s, const char *delim)
162{
163 char **l = NULL;
164 const char *p;
165 char *t, quote;
166 int i, n;
167
168 if (s == NULL) return NULL;
169
170 quote = '\0';
171
172 p = s;
173 while (p[0] != '\0')
174 {
175 /* scan forward */
176 for (i = 0; p[i] != '\0'; i++)
177 {
178 if (quote == '\0')
179 {
180 /* not inside a quoted string: check for delimiters and quotes */
181 if (strchr(delim, p[i]) != NULL) break;
182 else if (p[i] == '\'') quote = p[i];
183 else if (p[i] == '"') quote = p[i];
184 }
185 else
186 {
187 /* inside a quoted string - look for matching quote */
188 if (p[i] == quote) quote = '\0';
189 }
190 }
191
192 n = i;
193 t = malloc(n + 1);
194 if (t == NULL) return NULL;
195
196 for (i = 0; i < n; i++) t[i] = p[i];
197 t[n] = '\0';
198 l = _insertString(t, l, IndexNull);
199 free(t);
200 t = NULL;
201 if (p[i] == '\0') return l;
202 if (p[i + 1] == '\0') l = _insertString("", l, IndexNull);
203 p = p + i + 1;
204 }
205
206 return l;
207}
208
209void
210freeList(char **l)
211{
212 int i;
213
214 if (l == NULL) return;
215 for (i = 0; l[i] != NULL; i++) free(l[i]);
216 free(l);
217}
218
219/*
220 * Quotas are maintained using a very fast fixed-size table.
221 * We hash into the pid table (quota_table_pid) using the last 10
222 * bits of the pid, so the table has 1024 "buckets". The table is
223 * actually just an array with 8 entry slots (for collisions) per bucket.
224 * If there are more than 8 pids that hash to the same bucket, we
225 * re-use the one with the lowest message usage (highest remaining
1496e7d1 226 * quota). This can lead to "generosity: if there are nine or more
c4fdb7d1
A
227 * pids with the same last 10 bits all logging like crazy, we may
228 * end up allowing some of them to log more than their quota.
229 * That would be a remarkably rare occurrence.
230 */
231
232static uint32_t
db78b1bd 233quota_check(pid_t pid, time_t now, aslmsg msg, uint32_t level)
c4fdb7d1
A
234{
235 int i, x, maxx, max;
db78b1bd 236 char *str, lstr[2];
c4fdb7d1
A
237
238 if (msg == NULL) return VERIFY_STATUS_INVALID_MESSAGE;
239 if (global.mps_limit == 0) return VERIFY_STATUS_OK;
240
241 if (quota_table_time != now)
242 {
243 memset(quota_table_pid, 0, sizeof(quota_table_pid));
db78b1bd
A
244 kern_quota = global.mps_limit;
245 kern_level = 7;
c4fdb7d1
A
246 quota_table_time = now;
247 }
248
db78b1bd
A
249 /* kernel gets it's own quota */
250 if (pid == 0)
251 {
252 if (level < kern_level) kern_level = level;
253 if (kern_quota > 0) kern_quota--;
254
255 if (kern_quota > 0) return VERIFY_STATUS_OK;
256 if (kern_quota < 0) return VERIFY_STATUS_EXCEEDED_QUOTA;
257
258 kern_quota = -1;
259
260 str = NULL;
261 asprintf(&str, QUOTA_KERN_EXCEEDED_MESSAGE, global.mps_limit);
262 if (str != NULL)
263 {
264 asl_set(msg, ASL_KEY_MSG, str);
265 free(str);
266 lstr[0] = kern_level + '0';
267 lstr[1] = 0;
268 asl_set(msg, ASL_KEY_LEVEL, lstr);
269 }
270
271 return VERIFY_STATUS_OK;
272 }
273
c4fdb7d1
A
274 /* hash is last 10 bits of the pid, shifted up 3 bits to allow 8 slots per bucket */
275 x = (pid & 0x000003ff) << 3;
276 maxx = x;
277 max = quota_table_quota[x];
278
279 for (i = 0; i < QUOTA_TABLE_SLOTS; i++)
280 {
281 if (quota_table_pid[x] == 0)
282 {
283 quota_table_pid[x] = pid;
284 quota_table_quota[x] = global.mps_limit;
1496e7d1 285
c4fdb7d1
A
286 return VERIFY_STATUS_OK;
287 }
288
289 if (quota_table_pid[x] == pid)
290 {
291 quota_table_quota[x] = quota_table_quota[x] - 1;
292
293 if (quota_table_quota[x] == 0)
294 {
295 quota_table_quota[x] = -1;
296
297 str = NULL;
298 asprintf(&str, QUOTA_EXCEEDED_MESSAGE, (int)pid, global.mps_limit);
299 if (str != NULL)
300 {
301 asl_set(msg, ASL_KEY_MSG, str);
302 free(str);
303 asl_set(msg, ASL_KEY_LEVEL, QUOTA_EXCEEDED_LEVEL);
304 }
305
306 return VERIFY_STATUS_OK;
307 }
308
1496e7d1
A
309 if (quota_table_quota[x] < 0)
310 {
1496e7d1
A
311 return VERIFY_STATUS_EXCEEDED_QUOTA;
312 }
c4fdb7d1
A
313
314 return VERIFY_STATUS_OK;
315 }
316
317 if (quota_table_quota[x] > max)
318 {
319 maxx = x;
320 max = quota_table_quota[x];
321 }
322
323 x += 1;
324 }
325
326 /* can't find the pid and no slots were available - reuse slot with highest remaining quota */
a83ff38a 327 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);
c4fdb7d1
A
328 quota_table_pid[maxx] = pid;
329 quota_table_quota[maxx] = global.mps_limit;
330
331 return VERIFY_STATUS_OK;
332}
333
334int
a83ff38a 335asl_check_option(aslmsg msg, const char *opt)
c4fdb7d1
A
336{
337 const char *p;
338 uint32_t len;
339
340 if (msg == NULL) return 0;
341 if (opt == NULL) return 0;
342
343 len = strlen(opt);
344 if (len == 0) return 0;
345
346 p = asl_get(msg, ASL_KEY_OPTION);
347 if (p == NULL) return 0;
348
349 while (*p != '\0')
350 {
351 while ((*p == ' ') || (*p == '\t') || (*p == ',')) p++;
352 if (*p == '\0') return 0;
353
354 if (strncasecmp(p, opt, len) == 0)
355 {
356 p += len;
357 if ((*p == ' ') || (*p == '\t') || (*p == ',') || (*p == '\0')) return 1;
358 }
359
360 while ((*p != ' ') && (*p != '\t') && (*p != ',') && (*p != '\0')) p++;
361 }
362
363 return 0;
364}
5dd30d76 365
db78b1bd
A
366const char *
367whatsmyhostname()
b16a592a 368{
db78b1bd
A
369 static dispatch_once_t once;
370 char *dot;
371 int check, status;
b16a592a 372
db78b1bd
A
373 dispatch_once(&once, ^{
374 snprintf(myname, sizeof(myname), "%s", "localhost");
375 notify_register_check(kNotifySCHostNameChange, &name_change_token);
376 });
a83ff38a 377
db78b1bd
A
378 check = 1;
379 status = 0;
a83ff38a 380
db78b1bd 381 if (name_change_token >= 0) status = notify_check(name_change_token, &check);
a83ff38a 382
db78b1bd 383 if ((status == 0) && (check == 0)) return (const char *)myname;
a83ff38a 384
db78b1bd 385 if (gethostname(myname, MAXHOSTNAMELEN) < 0)
a83ff38a 386 {
db78b1bd 387 snprintf(myname, sizeof(myname), "%s", "localhost");
a83ff38a 388 }
db78b1bd 389 else
b16a592a 390 {
db78b1bd
A
391 dot = strchr(myname, '.');
392 if (dot != NULL) *dot = '\0';
b16a592a
A
393 }
394
b16a592a
A
395 return (const char *)myname;
396}
397
c4fdb7d1
A
398void
399asl_client_count_increment()
400{
401 OSSpinLockLock(&count_lock);
402
1496e7d1 403#ifndef CONFIG_IPHONE
c4fdb7d1 404 if (global.client_count == 0) vproc_trans = vproc_transaction_begin(NULL);
1496e7d1 405#endif
c4fdb7d1
A
406 global.client_count++;
407#ifdef DEBUG
408 asldebug("global.client_count++ (%d)\n", global.client_count);
409#endif
410
411 OSSpinLockUnlock(&count_lock);
412}
413
414void
415asl_client_count_decrement()
416{
417 OSSpinLockLock(&count_lock);
418
419 if (global.client_count > 0) global.client_count--;
1496e7d1 420#ifndef CONFIG_IPHONE
c4fdb7d1 421 if (global.client_count == 0) vproc_transaction_end(NULL, vproc_trans);
1496e7d1 422#endif
c4fdb7d1
A
423#ifdef DEBUG
424 asldebug("global.client_count-- (%d)\n", global.client_count);
425#endif
426
427 OSSpinLockUnlock(&count_lock);
428}
429
c4fdb7d1
A
430/*
431 * Checks message content and sets attributes as required
432 *
433 * SOURCE_INTERNAL log messages sent by syslogd itself
434 * SOURCE_ASL_SOCKET legacy asl(3) TCP socket
435 * SOURCE_BSD_SOCKET legacy syslog(3) UDP socket
436 * SOURCE_UDP_SOCKET from the network
437 * SOURCE_KERN from the kernel
438 * SOURCE_ASL_MESSAGE mach messages sent from Libc by asl(3) and syslog(3)
439 * SOURCE_LAUNCHD forwarded from launchd
440 */
441
442static uint32_t
db78b1bd 443aslmsg_verify(aslmsg msg, uint32_t source, int32_t *kern_post_level, uid_t *uid_out)
b16a592a 444{
a83ff38a 445 const char *val, *fac, *ruval, *rgval;
c4fdb7d1 446 char buf[64];
5dd30d76 447 time_t tick, now;
5dd30d76 448 uid_t uid;
db78b1bd 449 gid_t gid;
c4fdb7d1
A
450 uint32_t status, level, fnum;
451 pid_t pid;
b16a592a 452
c4fdb7d1 453 if (msg == NULL) return VERIFY_STATUS_INVALID_MESSAGE;
5dd30d76 454
c4fdb7d1 455 if (kern_post_level != NULL) *kern_post_level = -1;
db78b1bd 456 if (uid_out != NULL) *uid_out = -2;
b16a592a
A
457
458 /* PID */
c4fdb7d1
A
459 pid = 0;
460
b16a592a
A
461 val = asl_get(msg, ASL_KEY_PID);
462 if (val == NULL) asl_set(msg, ASL_KEY_PID, "0");
c4fdb7d1
A
463 else pid = (pid_t)atoi(val);
464
465 /* if PID is 1 (launchd), use the refpid if there is one */
466 if (pid == 1)
467 {
468 val = asl_get(msg, ASL_KEY_REF_PID);
469 if (val != NULL) pid = (pid_t)atoi(val);
470 }
471
db78b1bd
A
472 /* Time */
473 now = time(NULL);
474
475 /* Level */
476 val = asl_get(msg, ASL_KEY_LEVEL);
477 level = ASL_LEVEL_DEBUG;
478 if ((val != NULL) && (val[1] == '\0') && (val[0] >= '0') && (val[0] <= '7')) level = val[0] - '0';
479 snprintf(buf, sizeof(buf), "%d", level);
480 asl_set(msg, ASL_KEY_LEVEL, buf);
481
a83ff38a 482 /*
db78b1bd 483 * check quota if no processes are watching
a83ff38a 484 */
db78b1bd 485 if (global.watchers_active == 0)
c4fdb7d1 486 {
db78b1bd 487 status = quota_check(pid, now, msg, level);
c4fdb7d1
A
488 if (status != VERIFY_STATUS_OK) return status;
489 }
b16a592a 490
db78b1bd
A
491 tick = 0;
492 val = asl_get(msg, ASL_KEY_TIME);
493 if (val != NULL) tick = asl_parse_time(val);
494
495 /* Set time to now if it is unset or from the future (not allowed!) */
496 if ((tick == 0) || (tick > now)) tick = now;
497
498 /* Canonical form: seconds since the epoch */
499 snprintf(buf, sizeof(buf) - 1, "%lu", tick);
500 asl_set(msg, ASL_KEY_TIME, buf);
501
502 val = asl_get(msg, ASL_KEY_HOST);
503 if (val == NULL) asl_set(msg, ASL_KEY_HOST, whatsmyhostname());
504
5dd30d76 505 uid = -2;
b16a592a 506 val = asl_get(msg, ASL_KEY_UID);
db78b1bd 507 if (val != NULL)
b16a592a 508 {
db78b1bd
A
509 uid = atoi(val);
510 if ((uid == 0) && strcmp(val, "0")) uid = -2;
511 if (uid_out != NULL) *uid_out = uid;
b16a592a
A
512 }
513
db78b1bd 514 gid = -2;
b16a592a 515 val = asl_get(msg, ASL_KEY_GID);
db78b1bd
A
516 if (val != NULL)
517 {
518 gid = atoi(val);
519 if ((gid == 0) && strcmp(val, "0")) gid = -2;
520 }
c4fdb7d1 521
db78b1bd 522 /* UID & GID */
c4fdb7d1 523 switch (source)
b16a592a 524 {
c4fdb7d1
A
525 case SOURCE_KERN:
526 case SOURCE_INTERNAL:
b16a592a 527 {
db78b1bd 528 asl_set(msg, ASL_KEY_UID, "0");
c4fdb7d1
A
529 asl_set(msg, ASL_KEY_GID, "0");
530 break;
531 }
532 case SOURCE_ASL_SOCKET:
533 case SOURCE_ASL_MESSAGE:
534 case SOURCE_LAUNCHD:
535 {
db78b1bd 536 /* we trust the UID & GID in the message */
c4fdb7d1
A
537 break;
538 }
c4fdb7d1
A
539 default:
540 {
db78b1bd
A
541 /* we do not trust the UID 0 or GID 0 or 80 in the message */
542 if (uid == 0) asl_set(msg, ASL_KEY_UID, "-2");
543 if ((gid == 0) || (gid == 80)) asl_set(msg, ASL_KEY_GID, "-2");
b16a592a 544 }
b16a592a
A
545 }
546
5dd30d76
A
547 /* Sender */
548 val = asl_get(msg, ASL_KEY_SENDER);
549 if (val == NULL)
550 {
c4fdb7d1
A
551 switch (source)
552 {
553 case SOURCE_KERN:
554 {
555 asl_set(msg, ASL_KEY_SENDER, "kernel");
556 break;
557 }
558 case SOURCE_INTERNAL:
559 {
560 asl_set(msg, ASL_KEY_SENDER, "syslogd");
561 break;
562 }
563 default:
564 {
565 asl_set(msg, ASL_KEY_SENDER, "Unknown");
566 }
567 }
5dd30d76 568 }
c4fdb7d1 569 else if ((source != SOURCE_KERN) && (uid != 0) && (!strcmp(val, "kernel")))
5dd30d76 570 {
c4fdb7d1 571 /* allow UID 0 to send messages with "Sender kernel", but nobody else */
5dd30d76
A
572 asl_set(msg, ASL_KEY_SENDER, "Unknown");
573 }
574
5dd30d76
A
575 /* Facility */
576 fac = asl_get(msg, ASL_KEY_FACILITY);
577 if (fac == NULL)
578 {
c4fdb7d1 579 if (source == SOURCE_KERN) fac = "kern";
5dd30d76
A
580 else fac = "user";
581 asl_set(msg, ASL_KEY_FACILITY, fac);
582 }
583 else if (fac[0] == '#')
584 {
585 fnum = LOG_USER;
586 if ((fac[1] >= '0') && (fac[1] <= '9'))
587 {
588 fnum = atoi(fac + 1) << 3;
589 if ((fnum == 0) && (strcmp(fac + 1, "0"))) fnum = LOG_USER;
590 }
591
592 fac = asl_syslog_faciliy_num_to_name(fnum);
593 asl_set(msg, ASL_KEY_FACILITY, fac);
594 }
c4fdb7d1
A
595 else if (!strncmp(fac, SYSTEM_RESERVED, SYSTEM_RESERVED_LEN))
596 {
597 /* only UID 0 may use "com.apple.system" */
598 if (uid != 0) asl_set(msg, ASL_KEY_FACILITY, FACILITY_USER);
599 }
600
601 /*
602 * kernel messages are only readable by root and admin group.
a83ff38a
A
603 * all other messages are admin-only readable unless they already
604 * have specific read access controls set.
c4fdb7d1
A
605 */
606 if (source == SOURCE_KERN)
607 {
608 asl_set(msg, ASL_KEY_READ_UID, "0");
609 asl_set(msg, ASL_KEY_READ_GID, "80");
610 }
a83ff38a
A
611 else
612 {
613 ruval = asl_get(msg, ASL_KEY_READ_UID);
614 rgval = asl_get(msg, ASL_KEY_READ_GID);
5dd30d76 615
a83ff38a
A
616 if ((ruval == NULL) && (rgval == NULL))
617 {
618 asl_set(msg, ASL_KEY_READ_GID, "80");
619 }
620 }
5dd30d76
A
621
622 /* Set DB Expire Time for com.apple.system.utmpx and lastlog */
623 if ((!strcmp(fac, "com.apple.system.utmpx")) || (!strcmp(fac, "com.apple.system.lastlog")))
624 {
57b0aad2 625 snprintf(buf, sizeof(buf), "%lu", tick + global.utmp_ttl);
5dd30d76
A
626 asl_set(msg, ASL_KEY_EXPIRE_TIME, buf);
627 }
628
db78b1bd 629 /* Set DB Expire Time for Filesystem errors */
5dd30d76
A
630 if (!strcmp(fac, FSLOG_VAL_FACILITY))
631 {
db78b1bd 632 snprintf(buf, sizeof(buf), "%lu", tick + FS_TTL_SEC);
5dd30d76
A
633 asl_set(msg, ASL_KEY_EXPIRE_TIME, buf);
634 }
635
5dd30d76
A
636 /*
637 * special case handling of kernel disaster messages
638 */
c4fdb7d1 639 if ((source == SOURCE_KERN) && (level <= KERN_DISASTER_LEVEL))
5dd30d76 640 {
c4fdb7d1 641 if (kern_post_level != NULL) *kern_post_level = level;
5dd30d76
A
642 disaster_message(msg);
643 }
b16a592a 644
c4fdb7d1 645 return VERIFY_STATUS_OK;
b16a592a
A
646}
647
c4fdb7d1 648void
a83ff38a 649list_append_msg(asl_search_result_t *list, aslmsg msg)
c4fdb7d1
A
650{
651 if (list == NULL) return;
652 if (msg == NULL) return;
653
654 /*
655 * NB: curr is the list size
656 * grow list if necessary
657 */
658 if (list->count == list->curr)
659 {
660 if (list->curr == 0)
661 {
662 list->msg = (asl_msg_t **)calloc(LIST_SIZE_DELTA, sizeof(asl_msg_t *));
663 }
664 else
665 {
666 list->msg = (asl_msg_t **)reallocf(list->msg, (list->curr + LIST_SIZE_DELTA) * sizeof(asl_msg_t *));
667 }
668
669 if (list->msg == NULL)
670 {
671 list->curr = 0;
672 list->count = 0;
673 return;
674 }
675
676 list->curr += LIST_SIZE_DELTA;
677 }
678
a83ff38a 679 list->msg[list->count] = (asl_msg_t *)msg;
c4fdb7d1
A
680 list->count++;
681}
682
683void
db78b1bd 684init_globals(void)
c4fdb7d1 685{
db78b1bd
A
686 OSSpinLockLock(&global.lock);
687
688 global.debug = 0;
689 free(global.debug_file);
690 global.debug_file = NULL;
691
692#ifdef CONFIG_IPHONE
693 global.dbtype = DB_TYPE_MINI;
694#else
695 global.dbtype = DB_TYPE_FILE;
696#endif
697 global.db_file_max = DEFAULT_DB_FILE_MAX;
698 global.db_memory_max = DEFAULT_DB_MEMORY_MAX;
699 global.db_mini_max = DEFAULT_DB_MINI_MAX;
700 global.mps_limit = DEFAULT_MPS_LIMIT;
701 global.remote_delay_time = DEFAULT_REMOTE_DELAY;
702 global.bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC;
703 global.mark_time = DEFAULT_MARK_SEC;
704 global.utmp_ttl = DEFAULT_UTMP_TTL_SEC;
705
706 OSSpinLockUnlock(&global.lock);
c4fdb7d1
A
707}
708
db78b1bd
A
709/*
710 * Used to set config parameters.
711 * Line format "= name value"
712 */
713int
714control_set_param(const char *s)
c4fdb7d1 715{
db78b1bd
A
716 char **l;
717 uint32_t intval, count, v32a, v32b, v32c;
c4fdb7d1 718
db78b1bd
A
719 if (s == NULL) return -1;
720 if (s[0] == '\0') return 0;
c4fdb7d1 721
db78b1bd
A
722 /* skip '=' and whitespace */
723 s++;
724 while ((*s == ' ') || (*s == '\t')) s++;
725
726 l = explode(s, " \t");
727 if (l == NULL) return -1;
728
729 for (count = 0; l[count] != NULL; count++);
730
731 /* name is required */
732 if (count == 0)
c4fdb7d1 733 {
db78b1bd
A
734 freeList(l);
735 return -1;
c4fdb7d1 736 }
db78b1bd
A
737
738 /* value is required */
739 if (count == 1)
c4fdb7d1 740 {
db78b1bd
A
741 freeList(l);
742 return -1;
c4fdb7d1 743 }
c4fdb7d1 744
db78b1bd
A
745 if (!strcasecmp(l[0], "debug"))
746 {
747 /* = debug {0|1} [file] */
748 intval = atoi(l[1]);
749 config_debug(intval, l[2]);
750 }
751 else if (!strcasecmp(l[0], "mark_time"))
a83ff38a 752 {
db78b1bd
A
753 /* = mark_time seconds */
754 OSSpinLockLock(&global.lock);
755 global.mark_time = atoll(l[1]);
756 OSSpinLockUnlock(&global.lock);
a83ff38a 757 }
db78b1bd
A
758 else if (!strcasecmp(l[0], "dup_delay"))
759 {
760 /* = bsd_max_dup_time seconds */
761 OSSpinLockLock(&global.lock);
762 global.bsd_max_dup_time = atoll(l[1]);
763 OSSpinLockUnlock(&global.lock);
764 }
765 else if (!strcasecmp(l[0], "remote_delay"))
766 {
767 /* = remote_delay microseconds */
768 OSSpinLockLock(&global.lock);
769 global.remote_delay_time = atol(l[1]);
770 OSSpinLockUnlock(&global.lock);
771 }
772 else if (!strcasecmp(l[0], "utmp_ttl"))
773 {
774 /* = utmp_ttl seconds */
775 OSSpinLockLock(&global.lock);
776 global.utmp_ttl = (time_t)atoll(l[1]);
777 OSSpinLockUnlock(&global.lock);
778 }
779 else if (!strcasecmp(l[0], "mps_limit"))
780 {
781 /* = mps_limit number */
782 OSSpinLockLock(&global.lock);
783 global.mps_limit = (uint32_t)atol(l[1]);
784 OSSpinLockUnlock(&global.lock);
785 }
786 else if (!strcasecmp(l[0], "max_file_size"))
787 {
788 /* = max_file_size bytes */
789 pthread_mutex_lock(global.db_lock);
c4fdb7d1 790
db78b1bd
A
791 if (global.dbtype & DB_TYPE_FILE)
792 {
793 asl_store_close(global.file_db);
794 global.file_db = NULL;
795 global.db_file_max = atoi(l[1]);
796 }
c4fdb7d1 797
db78b1bd
A
798 pthread_mutex_unlock(global.db_lock);
799 }
800 else if ((!strcasecmp(l[0], "db")) || (!strcasecmp(l[0], "database")) || (!strcasecmp(l[0], "datastore")))
c4fdb7d1 801 {
db78b1bd
A
802 /* NB this is private / unpublished */
803 /* = db type [max]... */
804
805 v32a = 0;
806 v32b = 0;
807 v32c = 0;
808
809 if ((l[1][0] >= '0') && (l[1][0] <= '9'))
810 {
811 intval = atoi(l[1]);
812 if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]);
813 if ((count >= 4) && (strcmp(l[3], "-"))) v32b = atoi(l[3]);
814 if ((count >= 5) && (strcmp(l[4], "-"))) v32c = atoi(l[4]);
815 }
816 else if (!strcasecmp(l[1], "file"))
817 {
818 intval = DB_TYPE_FILE;
819 if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]);
820 }
821 else if (!strncasecmp(l[1], "mem", 3))
822 {
823 intval = DB_TYPE_MEMORY;
824 if ((count >= 3) && (strcmp(l[2], "-"))) v32b = atoi(l[2]);
825 }
826 else if (!strncasecmp(l[1], "min", 3))
827 {
828 intval = DB_TYPE_MINI;
829 if ((count >= 3) && (strcmp(l[2], "-"))) v32c = atoi(l[2]);
830 }
831 else
832 {
833 freeList(l);
834 return -1;
835 }
836
837 if (v32a == 0) v32a = global.db_file_max;
838 if (v32b == 0) v32b = global.db_memory_max;
839 if (v32c == 0) v32c = global.db_mini_max;
840
841 config_data_store(intval, v32a, v32b, v32c);
c4fdb7d1
A
842 }
843
db78b1bd
A
844 freeList(l);
845 return 0;
846}
c4fdb7d1 847
db78b1bd
A
848static int
849control_message(aslmsg msg)
850{
851 const char *str = asl_get(msg, ASL_KEY_MSG);
c4fdb7d1 852
db78b1bd
A
853 if (str == NULL) return 0;
854
855 if (!strncmp(str, "= reset", 7))
856 {
857 init_globals();
858 return asl_action_reset();
859 }
860 else if (!strncmp(str, "= rotate", 8))
861 {
862 const char *p = str + 8;
863 while ((*p == ' ') || (*p == '\t')) p++;
864 if (*p == '\0') p = NULL;
865 return asl_action_file_rotate(p);
866 }
867 else if (!strncmp(str, "= ", 2))
868 {
869 return control_set_param(str);
870 }
871
872 return 0;
c4fdb7d1
A
873}
874
5dd30d76 875void
db78b1bd 876process_message(aslmsg msg, uint32_t source)
b16a592a 877{
db78b1bd
A
878 int32_t kplevel;
879 uint32_t status;
880 uid_t uid;
b16a592a 881
db78b1bd 882 if (msg == NULL) return;
5dd30d76 883
db78b1bd
A
884 kplevel = -1;
885 uid = -2;
b16a592a 886
db78b1bd
A
887 status = aslmsg_verify(msg, source, &kplevel, &uid);
888 if (status == VERIFY_STATUS_OK)
b16a592a 889 {
db78b1bd 890 if ((source == SOURCE_KERN) && (kplevel >= 0))
5dd30d76 891 {
db78b1bd
A
892 if (kplevel > 7) kplevel = 7;
893 if (kern_notify_token[kplevel] < 0)
894 {
895 status = notify_register_plain(kern_notify_key[kplevel], &(kern_notify_token[kplevel]));
896 if (status != 0) asldebug("notify_register_plain(%s) failed status %u\n", status);
897 }
b16a592a 898
db78b1bd 899 notify_post(kern_notify_key[kplevel]);
b16a592a
A
900 }
901
db78b1bd 902 if ((uid == 0) && asl_check_option(msg, ASL_OPT_CONTROL)) control_message(msg);
b16a592a 903
db78b1bd
A
904 /* send message to output modules */
905 asl_out_message(msg);
906 if (global.bsd_out_enabled) bsd_out_message(msg);
907 }
5dd30d76 908
db78b1bd 909 asl_free(msg);
b16a592a
A
910}
911
912int
db78b1bd 913internal_log_message(const char *str)
b16a592a 914{
a83ff38a 915 aslmsg msg;
b16a592a
A
916
917 if (str == NULL) return 1;
918
a83ff38a 919 msg = (aslmsg)asl_msg_from_string(str);
c4fdb7d1 920 if (msg == NULL) return 1;
5dd30d76 921
db78b1bd 922 dispatch_async(global.work_queue, ^{ process_message(msg, SOURCE_INTERNAL); });
5dd30d76 923
b16a592a
A
924 return 0;
925}
926
5dd30d76
A
927int
928asldebug(const char *str, ...)
929{
930 va_list v;
db78b1bd 931 FILE *dfp = NULL;
5dd30d76 932
db78b1bd 933 if (global.debug == 0) return 0;
5dd30d76 934
db78b1bd
A
935 if (global.debug_file == NULL) dfp = fopen(_PATH_SYSLOGD_LOG, "a");
936 else dfp = fopen(global.debug_file, "a");
937 if (dfp == NULL) return 0;
5dd30d76
A
938
939 va_start(v, str);
db78b1bd 940 vfprintf(dfp, str, v);
5dd30d76
A
941 va_end(v);
942
db78b1bd 943 fclose(dfp);
c4fdb7d1 944
db78b1bd 945 return 0;
5dd30d76
A
946}
947
b16a592a 948void
5dd30d76 949asl_mark(void)
b16a592a
A
950{
951 char *str;
952
953 str = NULL;
954 asprintf(&str, "[%s syslogd] [%s %u] [%s %u] [%s -- MARK --] [%s 0] [%s 0] [Facility syslog]",
955 ASL_KEY_SENDER,
956 ASL_KEY_LEVEL, ASL_LEVEL_INFO,
957 ASL_KEY_PID, getpid(),
958 ASL_KEY_MSG, ASL_KEY_UID, ASL_KEY_GID);
959
db78b1bd 960 internal_log_message(str);
b16a592a
A
961 if (str != NULL) free(str);
962}
963
a83ff38a
A
964aslmsg
965asl_syslog_input_convert(const char *in, int len, char *rhost, uint32_t source)
b16a592a
A
966{
967 int pf, pri, index, n;
a83ff38a 968 char *p, *colon, *brace, *space, *tmp, *tval, *hval, *sval, *pval, *mval;
b16a592a
A
969 char prival[8];
970 const char *fval;
a83ff38a 971 aslmsg msg;
b16a592a
A
972 struct tm time;
973 time_t tick;
974
975 if (in == NULL) return NULL;
976 if (len <= 0) return NULL;
977
b16a592a
A
978 pri = LOG_DEBUG;
979 tval = NULL;
a83ff38a 980 hval = NULL;
b16a592a
A
981 sval = NULL;
982 pval = NULL;
983 mval = NULL;
984 fval = NULL;
985
986 index = 0;
987 p = (char *)in;
988
a83ff38a 989 /* skip leading whitespace */
b16a592a
A
990 while ((index < len) && ((*p == ' ') || (*p == '\t')))
991 {
992 p++;
993 index++;
994 }
995
996 if (index >= len) return NULL;
997
a83ff38a 998 /* parse "<NN>" priority (level and facility) */
b16a592a
A
999 if (*p == '<')
1000 {
1001 p++;
1002 index++;
1003
1004 n = sscanf(p, "%d", &pf);
1005 if (n == 1)
1006 {
1007 pri = pf & 0x7;
1008 if (pf > 0x7) fval = asl_syslog_faciliy_num_to_name(pf & LOG_FACMASK);
1009 }
1010
1011 while ((index < len) && (*p != '>'))
1012 {
1013 p++;
1014 index++;
1015 }
1016
1017 if (index < len)
1018 {
1019 p++;
1020 index++;
1021 }
1022 }
1023
1024 snprintf(prival, sizeof(prival), "%d", pri);
1025
a83ff38a 1026 /* check if a timestamp is included */
b16a592a
A
1027 if (((len - index) > 15) && (p[9] == ':') && (p[12] == ':') && (p[15] == ' '))
1028 {
1029 tmp = malloc(16);
5dd30d76
A
1030 if (tmp == NULL) return NULL;
1031
b16a592a
A
1032 memcpy(tmp, p, 15);
1033 tmp[15] = '\0';
1034
1035 tick = asl_parse_time(tmp);
1036 if (tick == (time_t)-1)
1037 {
1038 tval = tmp;
1039 }
1040 else
1041 {
1042 free(tmp);
1043 gmtime_r(&tick, &time);
1044 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);
1045 }
1046
1047 p += 16;
1048 index += 16;
1049 }
1050
a83ff38a
A
1051 /* stop here for kernel messages */
1052 if (source == SOURCE_KERN)
b16a592a 1053 {
a83ff38a 1054 msg = asl_new(ASL_TYPE_MSG);
5dd30d76 1055 if (msg == NULL) return NULL;
b16a592a 1056
b16a592a 1057 asl_set(msg, ASL_KEY_MSG, p);
b16a592a 1058 asl_set(msg, ASL_KEY_LEVEL, prival);
b16a592a 1059 asl_set(msg, ASL_KEY_PID, "0");
b16a592a
A
1060
1061 return msg;
1062 }
1063
a83ff38a
A
1064 /* if message is from a network socket, hostname follows */
1065 if (source == SOURCE_UDP_SOCKET)
1066 {
1067 space = strchr(p, ' ');
1068 if (space != NULL)
1069 {
1070 n = space - p;
1071 hval = malloc(n + 1);
1072 if (hval == NULL) return NULL;
1073
1074 memcpy(hval, p, n);
1075 hval[n] = '\0';
1076
1077 p = space + 1;
1078 index += (n + 1);
1079 }
1080 }
1081
b16a592a
A
1082 colon = strchr(p, ':');
1083 brace = strchr(p, '[');
1084
a83ff38a 1085 /* check for "sender:" or sender[pid]:" */
b16a592a
A
1086 if (colon != NULL)
1087 {
1088 if ((brace != NULL) && (brace < colon))
1089 {
1090 n = brace - p;
1091 sval = malloc(n + 1);
5dd30d76
A
1092 if (sval == NULL) return NULL;
1093
b16a592a
A
1094 memcpy(sval, p, n);
1095 sval[n] = '\0';
1096
1097 n = colon - (brace + 1) - 1;
1098 pval = malloc(n + 1);
5dd30d76
A
1099 if (pval == NULL) return NULL;
1100
b16a592a
A
1101 memcpy(pval, (brace + 1), n);
1102 pval[n] = '\0';
1103 }
1104 else
1105 {
1106 n = colon - p;
1107 sval = malloc(n + 1);
5dd30d76
A
1108 if (sval == NULL) return NULL;
1109
b16a592a
A
1110 memcpy(sval, p, n);
1111 sval[n] = '\0';
1112 }
1113
1114 n = colon - p;
1115 p = colon + 1;
1116 index += (n + 1);
1117 }
1118
1119 if (*p == ' ')
1120 {
1121 p++;
1122 index++;
1123 }
1124
1125 n = len - index;
1126 if (n > 0)
1127 {
1128 mval = malloc(n + 1);
5dd30d76
A
1129 if (mval == NULL) return NULL;
1130
b16a592a
A
1131 memcpy(mval, p, n);
1132 mval[n] = '\0';
1133 }
1134
1135 if (fval == NULL) fval = asl_syslog_faciliy_num_to_name(LOG_USER);
1136
a83ff38a 1137 msg = asl_new(ASL_TYPE_MSG);
5dd30d76 1138 if (msg == NULL) return NULL;
b16a592a
A
1139
1140 if (tval != NULL)
1141 {
1142 asl_set(msg, ASL_KEY_TIME, tval);
1143 free(tval);
1144 }
1145
1146 if (fval != NULL) asl_set(msg, "Facility", fval);
1147 else asl_set(msg, "Facility", "user");
1148
1149 if (sval != NULL)
1150 {
1151 asl_set(msg, ASL_KEY_SENDER, sval);
1152 free(sval);
1153 }
1154
1155 if (pval != NULL)
1156 {
1157 asl_set(msg, ASL_KEY_PID, pval);
1158 free(pval);
1159 }
a83ff38a
A
1160 else
1161 {
1162 asl_set(msg, ASL_KEY_PID, "-1");
1163 }
b16a592a
A
1164
1165 if (mval != NULL)
1166 {
1167 asl_set(msg, ASL_KEY_MSG, mval);
1168 free(mval);
1169 }
1170
1171 asl_set(msg, ASL_KEY_LEVEL, prival);
1172 asl_set(msg, ASL_KEY_UID, "-2");
1173 asl_set(msg, ASL_KEY_GID, "-2");
1174
db78b1bd
A
1175 if (hval != NULL)
1176 {
1177 asl_set(msg, ASL_KEY_HOST, hval);
1178 free(hval);
1179 }
1180 else if (rhost != NULL)
1181 {
1182 asl_set(msg, ASL_KEY_HOST, rhost);
1183 }
b16a592a
A
1184
1185 return msg;
1186}
1187
a83ff38a
A
1188aslmsg
1189asl_input_parse(const char *in, int len, char *rhost, uint32_t source)
5dd30d76 1190{
a83ff38a 1191 aslmsg msg;
db78b1bd 1192 int status, x, legacy, off;
5dd30d76
A
1193
1194 asldebug("asl_input_parse: %s\n", (in == NULL) ? "NULL" : in);
1195
1196 if (in == NULL) return NULL;
1197
1198 legacy = 1;
a83ff38a 1199 msg = NULL;
5dd30d76
A
1200
1201 /* calculate length if not provided */
1202 if (len == 0) len = strlen(in);
1203
1204 /*
1205 * Determine if the input is "old" syslog format or new ASL format.
1206 * Old format lines should start with "<", but they can just be straight text.
db78b1bd
A
1207 * ASL input may start with a length (10 bytes) followed by a space and a '['.
1208 * The length is optional, so ASL messages may also just start with '['.
5dd30d76
A
1209 */
1210 if ((in[0] != '<') && (len > 11))
1211 {
1212 status = sscanf(in, "%d ", &x);
1213 if ((status == 1) && (in[10] == ' ') && (in[11] == '[')) legacy = 0;
1214 }
1215
a83ff38a 1216 if (legacy == 1) return asl_syslog_input_convert(in, len, rhost, source);
5dd30d76 1217
db78b1bd
A
1218 off = 11;
1219 if (in[0] == '[') off = 0;
1220
1221 msg = (aslmsg)asl_msg_from_string(in + off);
a83ff38a 1222 if (msg == NULL) return NULL;
5dd30d76 1223
a83ff38a 1224 if (rhost != NULL) asl_set(msg, ASL_KEY_HOST, rhost);
5dd30d76 1225
a83ff38a 1226 return msg;
5dd30d76
A
1227}
1228
b16a592a
A
1229char *
1230get_line_from_file(FILE *f)
1231{
1232 char *s, *out;
1233 size_t len;
1234
1235 out = fgetln(f, &len);
1236 if (out == NULL) return NULL;
1237 if (len == 0) return NULL;
1238
1239 s = malloc(len + 1);
5dd30d76
A
1240 if (s == NULL) return NULL;
1241
b16a592a
A
1242 memcpy(s, out, len);
1243
db78b1bd 1244 if (s[len - 1] != '\n') len++;
b16a592a
A
1245 s[len - 1] = '\0';
1246 return s;
1247}
5dd30d76 1248
5dd30d76
A
1249void
1250launchd_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)
1251{
a83ff38a 1252 aslmsg m;
5dd30d76 1253 char str[256];
5dd30d76
A
1254 time_t now;
1255
1256/*
1257 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",
1258 when->tv_sec, when->tv_usec, from_pid, about_pid, sender_uid, sender_gid, priority, from_name, about_name, session_name, msg);
1259*/
1260
5dd30d76
A
1261 m = asl_new(ASL_TYPE_MSG);
1262 if (m == NULL) return;
1263
1264 /* Level */
1265 if (priority < ASL_LEVEL_EMERG) priority = ASL_LEVEL_EMERG;
1266 if (priority > ASL_LEVEL_DEBUG) priority = ASL_LEVEL_DEBUG;
1267 snprintf(str, sizeof(str), "%d", priority);
57b0aad2 1268
5dd30d76
A
1269 asl_set(m, ASL_KEY_LEVEL, str);
1270
1271 /* Time */
1272 if (when != NULL)
1273 {
1274 snprintf(str, sizeof(str), "%lu", when->tv_sec);
1275 asl_set(m, ASL_KEY_TIME, str);
1276
1277 snprintf(str, sizeof(str), "%lu", 1000 * (unsigned long int)when->tv_usec);
1278 asl_set(m, ASL_KEY_TIME_NSEC, str);
1279 }
1280 else
1281 {
1282 now = time(NULL);
1283 snprintf(str, sizeof(str), "%lu", now);
1284 asl_set(m, ASL_KEY_TIME, str);
1285 }
1286
5dd30d76
A
1287 /* Facility */
1288 asl_set(m, ASL_KEY_FACILITY, FACILITY_CONSOLE);
1289
c4fdb7d1
A
1290 /* UID */
1291 snprintf(str, sizeof(str), "%u", (unsigned int)sender_uid);
1292 asl_set(m, ASL_KEY_UID, str);
1293
1294 /* GID */
1295 snprintf(str, sizeof(str), "%u", (unsigned int)sender_gid);
1296 asl_set(m, ASL_KEY_GID, str);
1297
5dd30d76
A
1298 /* PID */
1299 if (from_pid != 0)
1300 {
1301 snprintf(str, sizeof(str), "%u", (unsigned int)from_pid);
1302 asl_set(m, ASL_KEY_PID, str);
1303 }
1304
1305 /* Reference PID */
1306 if ((about_pid > 0) && (about_pid != from_pid))
1307 {
1308 snprintf(str, sizeof(str), "%u", (unsigned int)about_pid);
1309 asl_set(m, ASL_KEY_REF_PID, str);
1310 }
1311
1312 /* Sender */
57b0aad2
A
1313 if (from_name != NULL)
1314 {
1315 asl_set(m, ASL_KEY_SENDER, from_name);
1316 }
5dd30d76
A
1317
1318 /* ReadUID */
1319 if (sender_uid != 0)
1320 {
1321 snprintf(str, sizeof(str), "%d", (int)sender_uid);
1322 asl_set(m, ASL_KEY_READ_UID, str);
1323 }
1324
1325 /* Reference Process */
1326 if (about_name != NULL)
1327 {
57b0aad2
A
1328 if ((from_name != NULL) && (strcmp(from_name, about_name) != 0))
1329 {
1330 asl_set(m, ASL_KEY_REF_PROC, about_name);
1331 }
5dd30d76
A
1332 }
1333
1334 /* Session */
57b0aad2
A
1335 if (session_name != NULL)
1336 {
1337 asl_set(m, ASL_KEY_SESSION, session_name);
1338 }
5dd30d76
A
1339
1340 /* Message */
57b0aad2
A
1341 if (msg != NULL)
1342 {
1343 asl_set(m, ASL_KEY_MSG, msg);
1344 }
5dd30d76 1345
db78b1bd 1346 dispatch_async(global.work_queue, ^{ process_message(m, SOURCE_LAUNCHD); });
5dd30d76
A
1347}
1348