]> git.saurik.com Git - apple/syslog.git/blob - util.tproj/syslog.c
syslog-100.0.1.tar.gz
[apple/syslog.git] / util.tproj / syslog.c
1 /*
2 * Copyright (c) 2007-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
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,
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <ctype.h>
28 #include <time.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <dirent.h>
32 #include <fcntl.h>
33 #include <sys/socket.h>
34 #include <sys/sysctl.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <mach/mach.h>
38 #include <servers/bootstrap.h>
39 #include <netdb.h>
40 #include <notify.h>
41 #include <asl.h>
42 #include <asl_private.h>
43 #include <asl_ipc.h>
44 #include <asl_core.h>
45 #include <asl_store.h>
46 #include <asl_file.h>
47
48 #define MOD_CASE_FOLD 'C'
49 #define MOD_REGEX 'R'
50 #define MOD_SUBSTRING 'S'
51 #define MOD_PREFIX 'A'
52 #define MOD_SUFFIX 'Z'
53 #define MOD_NUMERIC 'N'
54
55 #define OP_EQ "eq"
56 #define OP_NE "ne"
57 #define OP_GT "gt"
58 #define OP_GE "ge"
59 #define OP_LT "lt"
60 #define OP_LE "le"
61
62 #define ASL_QUERY_OP_NOT 0x1000
63
64 #define QUERY_FLAG_SEARCH_REVERSE 0x00000001
65
66 #define FACILITY_CONSOLE "com.apple.console"
67
68 /* Shared with Libc */
69 #define NOTIFY_RC "com.apple.asl.remote"
70
71 #define SEARCH_EOF -1
72 #define SEARCH_NULL 0
73 #define SEARCH_MATCH 1
74
75 #define PROC_NOT_FOUND -1
76 #define PROC_NOT_UNIQUE -2
77
78 #define RC_MASTER -1
79 #define RC_SYSLOGD -2
80
81 #define CHUNK 64
82 #define forever for(;;)
83
84 #define SEND_FORMAT_LEGACY 0
85 #define SEND_FORMAT_ASL 1
86
87 #define TIME_SEC 0x00000010
88 #define TIME_UTC 0x00000020
89 #define TIME_LCL 0x00000040
90
91 #define FORMAT_RAW 0x00000100
92 #define FORMAT_LEGACY 0x00000200
93 #define FORMAT_STD 0x00000400
94 #define FORMAT_XML 0x00000800
95
96 #define EXPORT 0x00000100
97
98 #define ASL_FILTER_MASK_PACEWNID 0xff
99 #define ASL_FILTER_MASK_PACEWNI 0x7f
100 #define ASL_FILTER_MASK_PACEWN 0x3f
101 #define ASL_FILTER_MASK_PACEW 0x1f
102 #define ASL_FILTER_MASK_PACE 0x0f
103 #define ASL_FILTER_MASK_PAC 0x07
104
105 #define FETCH_BATCH 1024
106
107 #define DB_SELECT_STORE 0
108 #define DB_SELECT_FILES 1
109 #define DB_SELECT_SYSLOGD 2
110 #define DB_SELECT_LEGACY 3
111
112 static asl_file_list_t *db_files = NULL;
113 static asl_store_t *store = NULL;
114 static asl_file_t *legacy = NULL;
115 static asl_file_t *export = NULL;
116
117 #ifdef CONFIG_IPHONE
118 static uint32_t dbselect = DB_SELECT_SYSLOGD;
119 #else
120 static uint32_t dbselect = DB_SELECT_STORE;
121 #endif
122
123 /* notify SPI */
124 uint32_t notify_register_plain(const char *name, int *out_token);
125
126 extern char *asl_msg_to_string(aslmsg msg, uint32_t *len);
127 extern asl_msg_t *asl_msg_from_string(const char *buf);
128 extern char *asl_list_to_string(asl_search_result_t *list, uint32_t *outlen);
129 extern asl_search_result_t *asl_list_from_string(const char *buf);
130 extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b);
131 extern time_t asl_parse_time(const char *in);
132 /* END PRIVATE API */
133
134 #define ASL_SERVICE_NAME "com.apple.system.logger"
135 static mach_port_t asl_server_port = MACH_PORT_NULL;
136
137 static const char *myname = "syslog";
138
139 void
140 usage()
141 {
142 fprintf(stderr, "usage:\n");
143 fprintf(stderr, "%s -s [-r host] [-l level] message...\n", myname);
144 fprintf(stderr, " send a message\n");
145 fprintf(stderr, "\n");
146 fprintf(stderr, "%s -s [-r host] -k key val [key val]...\n", myname);
147 fprintf(stderr, " send a message with the given keys and values\n");
148 fprintf(stderr, "\n");
149 fprintf(stderr, "%s -c process [filter]\n", myname);
150 fprintf(stderr, " get (set if filter is specified) syslog filter for process (pid or name)\n");
151 fprintf(stderr, " level may be any combination of the characters \"p a c e w n i d\"\n");
152 fprintf(stderr, " p = Emergency (\"Panic\")\n");
153 fprintf(stderr, " a = Alert\n");
154 fprintf(stderr, " c = Critical\n");
155 fprintf(stderr, " e = Error\n");
156 fprintf(stderr, " w = Warning\n");
157 fprintf(stderr, " n = Notice\n");
158 fprintf(stderr, " i = Info\n");
159 fprintf(stderr, " d = Debug\n");
160 fprintf(stderr, " a minus sign preceeding a single letter means \"up to\" that level\n");
161 fprintf(stderr, "\n");
162 fprintf(stderr, "%s [-f file...] [-d path...] [-x file] [-w [N]] [-F format] [-u] [-k key [[op] val]]... [-o -k key [[op] val]] ...]...\n", myname);
163 fprintf(stderr, " -f read named file[s], rather than standard log message store.\n");
164 fprintf(stderr, " -d read all file in named directory path, rather than standard log message store.\n");
165 fprintf(stderr, " -x export to named ASL format file, rather than printing\n");
166 fprintf(stderr, " -w watch data store (^C to quit)\n");
167 fprintf(stderr, " prints the last N matching lines (default 10) before waiting\n");
168 fprintf(stderr, " \"-w 0\" prints all matching lines before waiting\n");
169 fprintf(stderr, " -F output format may be \"std\", \"raw\", \"bsd\", or \"xml\"\n");
170 fprintf(stderr, " format may also be a string containing variables of the form\n");
171 fprintf(stderr, " $Key or $(Key) - use the latter for non-whitespace delimited variables\n");
172 fprintf(stderr, " -T timestamp format may be \"sec\" (seconds), \"utc\" (UTC), or \"local\" (local timezone)\n");
173 fprintf(stderr, " -E text encoding may be \"vis\", \"safe\", or \"none\"\n");
174 fprintf(stderr, " -u print timestamps using UTC (equivalent to \"-T utc\")\n");
175 fprintf(stderr, " -k key/value match\n");
176 fprintf(stderr, " if no operator or value is given, checks for the existance of the key\n");
177 fprintf(stderr, " if no operator is given, default is \"%s\"\n", OP_EQ);
178 fprintf(stderr, " -C alias for \"-k Facility com.apple.console\"\n");
179 fprintf(stderr, " -o begins a new query\n");
180 fprintf(stderr, " queries are \'OR\'ed together\n");
181 fprintf(stderr, "operators are zero or more modifiers followed by a comparison\n");
182 fprintf(stderr, " %s equal\n", OP_EQ);
183 fprintf(stderr, " %s not equal\n", OP_NE);
184 fprintf(stderr, " %s greater than\n", OP_GT);
185 fprintf(stderr, " %s greater or equal\n", OP_GE);
186 fprintf(stderr, " %s less than\n", OP_LT);
187 fprintf(stderr, " %s less or equal\n", OP_LE);
188 fprintf(stderr, "optional modifiers for operators\n");
189 fprintf(stderr, " %c case-fold\n", MOD_CASE_FOLD);
190 fprintf(stderr, " %c regular expression\n", MOD_REGEX);
191 fprintf(stderr, " %c substring\n", MOD_SUBSTRING);
192 fprintf(stderr, " %c prefix\n", MOD_PREFIX);
193 fprintf(stderr, " %c suffix\n", MOD_SUFFIX);
194 fprintf(stderr, " %c numeric comparison\n", MOD_NUMERIC);
195 }
196
197 const char *
198 notify_status_string(int status)
199 {
200 if (status == NOTIFY_STATUS_OK) return "OK";
201 if (status == NOTIFY_STATUS_INVALID_NAME) return "Process not registered";
202 if (status == NOTIFY_STATUS_NOT_AUTHORIZED) return "Not authorized";
203 return "Operation failed";
204 }
205
206 const char *
207 asl_level_string(int level)
208 {
209 if (level == ASL_LEVEL_EMERG) return ASL_STRING_EMERG;
210 if (level == ASL_LEVEL_ALERT) return ASL_STRING_ALERT;
211 if (level == ASL_LEVEL_CRIT) return ASL_STRING_CRIT;
212 if (level == ASL_LEVEL_ERR) return ASL_STRING_ERR;
213 if (level == ASL_LEVEL_WARNING) return ASL_STRING_WARNING;
214 if (level == ASL_LEVEL_NOTICE) return ASL_STRING_NOTICE;
215 if (level == ASL_LEVEL_INFO) return ASL_STRING_INFO;
216 if (level == ASL_LEVEL_DEBUG) return ASL_STRING_DEBUG;
217 return "Unknown";
218 }
219
220 int
221 procinfo(char *pname, int *pid, int *uid)
222 {
223 int mib[4];
224 int i, status, nprocs;
225 size_t miblen, size;
226 struct kinfo_proc *procs, *newprocs;
227
228 size = 0;
229 procs = NULL;
230
231 mib[0] = CTL_KERN;
232 mib[1] = KERN_PROC;
233 mib[2] = KERN_PROC_ALL;
234 mib[3] = 0;
235 miblen = 3;
236
237 status = sysctl(mib, miblen, NULL, &size, NULL, 0);
238 do
239 {
240 size += size / 10;
241 newprocs = reallocf(procs, size);
242 if (newprocs == NULL)
243 {
244 if (procs != NULL) free(procs);
245 return PROC_NOT_FOUND;
246 }
247
248 procs = newprocs;
249 status = sysctl(mib, miblen, procs, &size, NULL, 0);
250 } while ((status == -1) && (errno == ENOMEM));
251
252 if (status == -1)
253 {
254 if (procs != NULL) free(procs);
255 return PROC_NOT_FOUND;
256 }
257
258 if (size % sizeof(struct kinfo_proc) != 0)
259 {
260 if (procs != NULL) free(procs);
261 return PROC_NOT_FOUND;
262 }
263
264 if (procs == NULL) return PROC_NOT_FOUND;
265
266 nprocs = size / sizeof(struct kinfo_proc);
267
268 if (pname == NULL)
269 {
270 /* Search for a pid */
271 for (i = 0; i < nprocs; i++)
272 {
273 if (*pid == procs[i].kp_proc.p_pid)
274 {
275 *uid = procs[i].kp_eproc.e_ucred.cr_uid;
276 return 0;
277 }
278 }
279
280 return PROC_NOT_FOUND;
281 }
282
283 *pid = PROC_NOT_FOUND;
284
285 for (i = 0; i < nprocs; i++)
286 {
287 if (!strcmp(procs[i].kp_proc.p_comm, pname))
288 {
289 if (*pid != PROC_NOT_FOUND)
290 {
291 free(procs);
292 return PROC_NOT_UNIQUE;
293 }
294
295 *pid = procs[i].kp_proc.p_pid;
296 *uid = procs[i].kp_eproc.e_ucred.cr_uid;
297 }
298 }
299
300 free(procs);
301 if (*pid == PROC_NOT_FOUND) return PROC_NOT_FOUND;
302
303 return 0;
304 }
305
306 int
307 rcontrol_get_string(const char *name, int *val)
308 {
309 int t, status;
310 uint64_t x;
311
312 status = notify_register_plain(name, &t);
313 if (status != NOTIFY_STATUS_OK) return status;
314
315 x = 0;
316 status = notify_get_state(t, &x);
317 notify_cancel(t);
318
319 *val = x;
320
321 return status;
322 }
323
324 int
325 rcontrol_set_string(const char *name, int filter)
326 {
327 int t, status;
328 uint64_t x;
329
330 status = notify_register_plain(name, &t);
331 if (status != NOTIFY_STATUS_OK) return status;
332
333 x = filter;
334 status = notify_set_state(t, x);
335 notify_post(NOTIFY_RC);
336 notify_cancel(t);
337 return status;
338 }
339
340 int
341 asl_string_to_filter(char *s)
342 {
343 int f, i;
344
345 if (s == NULL) return 0;
346 if (s[0] == '\0') return 0;
347
348 if ((s[0] >= '0') && (s[0] <= '9')) return ASL_FILTER_MASK(atoi(s));
349
350 if (s[0] == '-')
351 {
352 if ((s[1] == 'P') || (s[1] == 'p')) i = ASL_LEVEL_EMERG;
353 else if ((s[1] == 'A') || (s[1] == 'a')) i = ASL_LEVEL_ALERT;
354 else if ((s[1] == 'C') || (s[1] == 'c')) i = ASL_LEVEL_CRIT;
355 else if ((s[1] == 'E') || (s[1] == 'e')) i = ASL_LEVEL_ERR;
356 else if ((s[1] == 'X') || (s[1] == 'x')) i = ASL_LEVEL_ERR;
357 else if ((s[1] == 'W') || (s[1] == 'w')) i = ASL_LEVEL_WARNING;
358 else if ((s[1] == 'N') || (s[1] == 'n')) i = ASL_LEVEL_NOTICE;
359 else if ((s[1] == 'I') || (s[1] == 'i')) i = ASL_LEVEL_INFO;
360 else if ((s[1] == 'D') || (s[1] == 'd')) i = ASL_LEVEL_DEBUG;
361 else i = atoi(s + 1);
362 f = ASL_FILTER_MASK_UPTO(i);
363 return f;
364 }
365
366 f = 0;
367 for (i = 0; s[i] != '\0'; i++)
368 {
369 if ((s[i] == 'P') || (s[i] == 'p')) f |= ASL_FILTER_MASK_EMERG;
370 else if ((s[i] == 'A') || (s[i] == 'a')) f |= ASL_FILTER_MASK_ALERT;
371 else if ((s[i] == 'C') || (s[i] == 'c')) f |= ASL_FILTER_MASK_CRIT;
372 else if ((s[i] == 'E') || (s[i] == 'e')) f |= ASL_FILTER_MASK_ERR;
373 else if ((s[i] == 'X') || (s[i] == 'x')) f |= ASL_FILTER_MASK_ERR;
374 else if ((s[i] == 'W') || (s[i] == 'w')) f |= ASL_FILTER_MASK_WARNING;
375 else if ((s[i] == 'N') || (s[i] == 'n')) f |= ASL_FILTER_MASK_NOTICE;
376 else if ((s[i] == 'I') || (s[i] == 'i')) f |= ASL_FILTER_MASK_INFO;
377 else if ((s[i] == 'D') || (s[i] == 'd')) f |= ASL_FILTER_MASK_DEBUG;
378 }
379
380 return f;
381 }
382
383 char *
384 asl_filter_string(int f)
385 {
386 static char str[1024];
387 int i;
388
389 memset(str, 0, sizeof(str));
390 i = 0;
391
392 if ((f == ASL_FILTER_MASK_PACEWNID) != 0)
393 {
394 strcat(str, "Emergency - Debug");
395 return str;
396 }
397
398 if ((f == ASL_FILTER_MASK_PACEWNI) != 0)
399 {
400 strcat(str, "Emergency - Info");
401 return str;
402 }
403
404 if ((f == ASL_FILTER_MASK_PACEWN) != 0)
405 {
406 strcat(str, "Emergency - Notice");
407 return str;
408 }
409
410 if ((f == ASL_FILTER_MASK_PACEW) != 0)
411 {
412 strcat(str, "Emergency - Warning");
413 return str;
414 }
415
416 if ((f == ASL_FILTER_MASK_PACE) != 0)
417 {
418 strcat(str, "Emergency - Error");
419 return str;
420 }
421
422 if ((f == ASL_FILTER_MASK_PAC) != 0)
423 {
424 strcat(str, "Emergency - Critical");
425 return str;
426 }
427
428 if ((f & ASL_FILTER_MASK_EMERG) != 0)
429 {
430 strcat(str, "Emergency");
431 i++;
432 }
433
434 if ((f & ASL_FILTER_MASK_ALERT) != 0)
435 {
436 if (i > 0) strcat(str, ", ");
437 strcat(str, "Alert");
438 i++;
439 }
440
441 if ((f & ASL_FILTER_MASK_CRIT) != 0)
442 {
443 if (i > 0) strcat(str, ", ");
444 strcat(str, "Critical");
445 i++;
446 }
447
448 if ((f & ASL_FILTER_MASK_ERR) != 0)
449 {
450 if (i > 0) strcat(str, ", ");
451 strcat(str, "Error");
452 i++;
453 }
454
455 if ((f & ASL_FILTER_MASK_WARNING) != 0)
456 {
457 if (i > 0) strcat(str, ", ");
458 strcat(str, "Warning");
459 i++;
460 }
461
462 if ((f & ASL_FILTER_MASK_NOTICE) != 0)
463 {
464 if (i > 0) strcat(str, ", ");
465 strcat(str, "Notice");
466 i++;
467 }
468
469 if ((f & ASL_FILTER_MASK_INFO) != 0)
470 {
471 if (i > 0) strcat(str, ", ");
472 strcat(str, "Info");
473 i++;
474 }
475
476 if ((f & ASL_FILTER_MASK_DEBUG) != 0)
477 {
478 if (i > 0) strcat(str, ", ");
479 strcat(str, "Debug");
480 i++;
481 }
482
483 if (i == 0) sprintf(str, "Off");
484
485 return str;
486 }
487
488 const char *
489 rcontrol_name(pid_t pid, uid_t uid)
490 {
491 static char str[1024];
492
493 if (pid == RC_SYSLOGD) return NOTIFY_SYSTEM_ASL_FILTER;
494 if (pid == RC_MASTER) return NOTIFY_SYSTEM_MASTER;
495
496 memset(str, 0, sizeof(str));
497 if (uid == 0) snprintf(str, sizeof(str) - 1, "%s.%d", NOTIFY_PREFIX_SYSTEM, pid);
498 else snprintf(str, sizeof(str) - 1, "user.uid.%d.syslog.%d", uid, pid);
499 return str;
500 }
501
502 int
503 rcontrol_get(pid_t pid, uid_t uid)
504 {
505 int filter, status;
506 const char *name;
507
508 filter = 0;
509
510 if (pid < 0)
511 {
512 name = "Master";
513 if (pid == RC_SYSLOGD) name = "ASL Data Store";
514
515 status = rcontrol_get_string(rcontrol_name(pid, uid), &filter);
516 if (status == NOTIFY_STATUS_OK)
517 {
518 printf("%s filter mask: %s\n", name, asl_filter_string(filter));
519 return 0;
520 }
521
522 printf("Unable to determine %s filter mask\n", name);
523 return -1;
524 }
525
526 status = rcontrol_get_string(rcontrol_name(pid, uid), &filter);
527 if (status == NOTIFY_STATUS_OK)
528 {
529 printf("Process %d syslog filter mask: %s\n", pid, asl_filter_string(filter));
530 return 0;
531 }
532
533 printf("Unable to determine syslog filter mask for pid %d\n", pid);
534 return -1;
535 }
536
537 int
538 rcontrol_set(pid_t pid, uid_t uid, int filter)
539 {
540 int status;
541 const char *name;
542
543 if (pid < 0)
544 {
545 name = "Master";
546 if (pid == RC_SYSLOGD) name = "ASL Data Store";
547 status = rcontrol_set_string(rcontrol_name(pid, uid), filter);
548
549 if (status == NOTIFY_STATUS_OK)
550 {
551 printf("Set %s syslog filter mask: %s\n", name, asl_filter_string(filter));
552 return 0;
553 }
554
555 printf("Unable to set %s syslog filter mask: %s\n", name, notify_status_string(status));
556 return -1;
557 }
558
559 status = rcontrol_set_string(rcontrol_name(pid, uid), filter);
560 if (status == NOTIFY_STATUS_OK)
561 {
562 if (pid == RC_SYSLOGD) status = notify_post(NOTIFY_SYSTEM_ASL_FILTER);
563 printf("Set process %d syslog filter mask set: %s\n", pid, asl_filter_string(filter));
564 return 0;
565 }
566
567 printf("Unable to set syslog filter mask for pid %d: %s\n", pid, notify_status_string(status));
568 return -1;
569 }
570
571 int
572 rsend(aslmsg msg, char *rhost)
573 {
574 char *str, *out;
575 uint32_t len, level;
576 char *timestr;
577 const char *val;
578 time_t tick;
579 struct tm gtime;
580 int s;
581 struct sockaddr_in dst;
582 struct hostent *h;
583 char myname[MAXHOSTNAMELEN + 1];
584
585 if (msg == NULL) return 0;
586
587 h = gethostbyname(rhost);
588 if (h == NULL) return -1;
589
590 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
591 if (s <= 0) return -1;
592
593 memset(&dst, 0, sizeof(struct sockaddr_in));
594 memcpy(&(dst.sin_addr.s_addr), h->h_addr_list[0], 4);
595 dst.sin_family = AF_INET;
596 dst.sin_port = 514;
597 dst.sin_len = sizeof(struct sockaddr_in);
598
599 level = ASL_LEVEL_DEBUG;
600
601 val = asl_get(msg, ASL_KEY_LEVEL);
602 if (val != NULL) level = atoi(val);
603
604 memset(&gtime, 0, sizeof(struct tm));
605 timestr = NULL;
606
607 tick = time(NULL);
608 gmtime_r(&tick, &gtime);
609
610 /* Canonical form: YYYY.MM.DD hh:mm:ss UTC */
611 asprintf(&timestr, "%d.%02d.%02d %02d:%02d:%02d UTC", gtime.tm_year + 1900, gtime.tm_mon + 1, gtime.tm_mday, gtime.tm_hour, gtime.tm_min, gtime.tm_sec);
612
613 if (timestr != NULL)
614 {
615 asl_set(msg, ASL_KEY_TIME, timestr);
616 free(timestr);
617 }
618
619 if (gethostname(myname, MAXHOSTNAMELEN) == 0) asl_set(msg, ASL_KEY_HOST, myname);
620
621 len = 0;
622 str = asl_msg_to_string(msg, &len);
623 if (str == NULL) return -1;
624
625 asprintf(&out, "%10u %s\n", len+1, str);
626 free(str);
627 if (out == NULL) return -1;
628
629 sendto(s, out, len+12, 0, (const struct sockaddr *)&dst, sizeof(struct sockaddr_in));
630
631 free(out);
632 close(s);
633 return 0;
634 }
635
636 int
637 rlegacy(char *msg, int level, char *rhost)
638 {
639 char *out;
640 uint32_t len;
641 time_t tick;
642 char *ltime;
643 int s;
644 struct sockaddr_in dst;
645 struct hostent *h;
646 char myname[MAXHOSTNAMELEN + 1];
647
648 if (msg == NULL) return 0;
649
650 h = gethostbyname(rhost);
651 if (h == NULL) return -1;
652
653 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
654 if (s <= 0) return -1;
655
656 memset(&dst, 0, sizeof(struct sockaddr_in));
657 memcpy(&(dst.sin_addr.s_addr), h->h_addr_list[0], 4);
658 dst.sin_family = AF_INET;
659 dst.sin_port = 514;
660 dst.sin_len = sizeof(struct sockaddr_in);
661
662 tick = time(NULL);
663 ltime = ctime(&tick);
664 ltime[19] = '\0';
665
666 gethostname(myname, MAXHOSTNAMELEN);
667
668 asprintf(&out, "<%d>%s %s syslog[%d]: %s", level, ltime+4, myname, getpid(), msg);
669 len = strlen(out);
670 sendto(s, out, len, 0, (const struct sockaddr *)&dst, sizeof(struct sockaddr_in));
671
672 free(out);
673 close(s);
674 return 0;
675 }
676
677 static int
678 _isanumber(char *s)
679 {
680 int i;
681
682 if (s == NULL) return 0;
683
684 i = 0;
685 if ((s[0] == '-') || (s[0] == '+')) i = 1;
686
687 if (s[i] == '\0') return 0;
688
689 for (; s[i] != '\0'; i++)
690 {
691 if (!isdigit(s[i])) return 0;
692 }
693
694 return 1;
695 }
696
697 int
698 asl_string_to_level(const char *s)
699 {
700 if (s == NULL) return -1;
701
702 if ((s[0] >= '0') && (s[0] <= '7') && (s[1] == '\0')) return atoi(s);
703
704 if (!strncasecmp(s, "em", 2)) return ASL_LEVEL_EMERG;
705 else if (!strncasecmp(s, "p", 1)) return ASL_LEVEL_EMERG;
706 else if (!strncasecmp(s, "a", 1)) return ASL_LEVEL_ALERT;
707 else if (!strncasecmp(s, "c", 1)) return ASL_LEVEL_CRIT;
708 else if (!strncasecmp(s, "er", 2)) return ASL_LEVEL_ERR;
709 else if (!strncasecmp(s, "x", 1)) return ASL_LEVEL_ERR;
710 else if (!strncasecmp(s, "w", 1)) return ASL_LEVEL_WARNING;
711 else if (!strncasecmp(s, "n", 1)) return ASL_LEVEL_NOTICE;
712 else if (!strncasecmp(s, "i", 1)) return ASL_LEVEL_INFO;
713 else if (!strncasecmp(s, "d", 1)) return ASL_LEVEL_DEBUG;
714
715 return -1;
716 }
717
718 const char *
719 asl_string_to_char_level(const char *s)
720 {
721 if (s == NULL) return NULL;
722
723 if ((s[0] >= '0') && (s[0] <= '7') && (s[1] == '\0')) return s;
724
725 if (!strncasecmp(s, "em", 2)) return "0";
726 else if (!strncasecmp(s, "p", 1)) return "0";
727 else if (!strncasecmp(s, "a", 1)) return "1";
728 else if (!strncasecmp(s, "c", 1)) return "2";
729 else if (!strncasecmp(s, "er", 2)) return "3";
730 else if (!strncasecmp(s, "x", 1)) return "3";
731 else if (!strncasecmp(s, "w", 1)) return "4";
732 else if (!strncasecmp(s, "n", 1)) return "5";
733 else if (!strncasecmp(s, "i", 1)) return "6";
734 else if (!strncasecmp(s, "d", 1)) return "7";
735
736 return NULL;
737 }
738
739 int
740 syslog_remote_control(int argc, char *argv[])
741 {
742 int pid, uid, status, mask;
743
744 if ((argc < 3) || (argc > 4))
745 {
746 fprintf(stderr, "usage:\n");
747 fprintf(stderr, "%s -c process [mask]\n", myname);
748 fprintf(stderr, " get (set if mask is specified) syslog filter mask for process (pid or name)\n");
749 fprintf(stderr, " process may be pid or process name\n");
750 fprintf(stderr, " use \"-c 0\" to get master syslog filter mask\n");
751 fprintf(stderr, " use \"-c 0 off\" to disable master syslog filter mask\n");
752 fprintf(stderr, "\n");
753 return -1;
754 }
755
756 pid = RC_MASTER;
757 uid = -2;
758
759 status = PROC_NOT_FOUND;
760
761 if ((!strcmp(argv[2], "syslogd")) || (!strcmp(argv[2], "syslog")))
762 {
763 pid = RC_SYSLOGD;
764 uid = 0;
765 status = 0;
766 }
767 else if (_isanumber(argv[2]) != 0)
768 {
769 pid = atoi(argv[2]);
770 status = procinfo(NULL, &pid, &uid);
771 }
772 else
773 {
774 status = procinfo(argv[2], &pid, &uid);
775 }
776
777 if (status == PROC_NOT_FOUND)
778 {
779 fprintf(stderr, "%s: process not found\n", argv[2]);
780 return -1;
781 }
782
783 if (status == PROC_NOT_UNIQUE)
784 {
785 fprintf(stderr, "%s: multiple processes found\n", argv[2]);
786 fprintf(stderr, "use pid to identify a process uniquely\n");
787 return -1;
788 }
789
790 if (pid == 0) pid = RC_MASTER;
791
792 if (argc == 4)
793 {
794 if ((pid == RC_MASTER) && (!strcasecmp(argv[3], "off"))) mask = 0;
795 else if ((pid == RC_SYSLOGD) && (!strcasecmp(argv[3], "off"))) mask = 0;
796 else
797 {
798 mask = asl_string_to_filter(argv[3]);
799 if (mask < 0)
800 {
801 printf("unknown syslog mask: %s\n", argv[3]);
802 return -1;
803 }
804 }
805
806 rcontrol_set(pid, uid, mask);
807 }
808 else
809 {
810 rcontrol_get(pid, uid);
811 }
812
813 return 0;
814 }
815
816 int
817 syslog_send(int argc, char *argv[])
818 {
819 int i, start, kv, len, rfmt, rlevel, filter, status;
820 aslclient asl;
821 aslmsg m;
822 char tmp[64], *str, *rhost;
823
824 kv = 0;
825 rhost = NULL;
826 rfmt = SEND_FORMAT_LEGACY;
827 start = 1;
828 rlevel = 7;
829
830 for (i = 1; i < argc; i++)
831 {
832 if (!strcmp(argv[i], "-s")) start = i+1;
833 else if (!strcmp(argv[i], "-k"))
834 {
835 kv = 1;
836 rfmt = SEND_FORMAT_ASL;
837 }
838 else if (!strcmp(argv[i], "-r"))
839 {
840 rhost = argv[++i];
841 start = i+1;
842 }
843 else if (!strcmp(argv[i], "-l"))
844 {
845 rlevel = asl_string_to_level(argv[++i]);
846 if (rlevel < 0)
847 {
848 fprintf(stderr, "Unknown level: %s\n", argv[i]);
849 return(-1);
850 }
851 start = i+1;
852 }
853 }
854
855 asl = asl_open(myname, "syslog", 0);
856 asl_set_filter(asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
857
858 m = asl_new(ASL_TYPE_MSG);
859 asl_set(m, ASL_KEY_SENDER, myname);
860
861 sprintf(tmp, "%d", rlevel);
862 asl_set(m, ASL_KEY_LEVEL, tmp);
863
864 str = NULL;
865
866 if (kv == 0)
867 {
868 len = 0;
869 for (i = start; i < argc; i++) len += (strlen(argv[i]) + 1);
870 str = calloc(len + 1, 1);
871 if (str == NULL) return -1;
872
873 for (i = start; i < argc; i++)
874 {
875 strcat(str, argv[i]);
876 if ((i+1) < argc) strcat(str, " ");
877 }
878 asl_set(m, ASL_KEY_MSG, str);
879 }
880 else
881 {
882 for (i = start + 1; i < argc; i += 2)
883 {
884 if (!strcmp(argv[i], "-k")) i++;
885 asl_set(m, argv[i], argv[i + 1]);
886 if (!strcmp(argv[i], ASL_KEY_LEVEL)) rlevel = atoi(argv[i + 1]);
887 }
888 }
889
890 if (rhost == NULL)
891 {
892 filter = 0;
893 status = rcontrol_get_string(rcontrol_name(RC_SYSLOGD, 0), &filter);
894 if (status != 0)
895 {
896 fprintf(stderr, "Warning: Can't get current syslogd ASL filter value\n");
897 }
898 else if ((ASL_FILTER_MASK(rlevel) & filter) == 0)
899 {
900 fprintf(stderr, "Warning: The current syslogd ASL filter value (%s)\n", asl_filter_string(filter));
901 fprintf(stderr, " will exclude this message from the ASL database\n");
902 }
903
904 asl_send(asl, m);
905 }
906 else if (rfmt == SEND_FORMAT_ASL)
907 {
908 rsend(m, rhost);
909 }
910 else if ((rfmt == SEND_FORMAT_LEGACY) && (str != NULL))
911 {
912 rlegacy(str, rlevel, rhost);
913 }
914
915 asl_free(m);
916
917 if (str != NULL) free(str);
918
919 asl_close(asl);
920
921 return 0;
922 }
923
924 static void
925 print_xml_header(FILE *f)
926 {
927 if (f == NULL) return;
928
929 fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
930 fprintf(f, "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n");
931 fprintf(f, "<plist version=\"1.0\">\n");
932 fprintf(f, "<array>\n");
933 }
934
935 static void
936 print_xml_trailer(FILE *f)
937 {
938 if (f == NULL) return;
939
940 fprintf(f, "</array>\n");
941 fprintf(f, "</plist>\n");
942 }
943
944 static void
945 printmsg(FILE *f, asl_msg_t *msg, char *fmt, int pflags)
946 {
947 char *str;
948 const char *mf, *tf;
949 uint32_t encode, len, status;
950 uint64_t xid;
951
952 if (f == NULL)
953 {
954 if (export != NULL)
955 {
956 xid = 0;
957 status = asl_file_save(export, msg, &xid);
958 if (status != ASL_STATUS_OK)
959 {
960 fprintf(stderr, "export file write failed: %s\n", asl_core_error(status));
961 asl_file_close(export);
962 export = NULL;
963 }
964 }
965
966 return;
967 }
968
969 encode = pflags & 0x0000000f;
970
971 mf = ASL_MSG_FMT_RAW;
972 if (fmt != NULL) mf = (const char *)fmt;
973 else if (pflags & FORMAT_STD) mf = ASL_MSG_FMT_STD;
974 else if (pflags & FORMAT_LEGACY) mf = ASL_MSG_FMT_BSD;
975 else if (pflags & FORMAT_XML) mf = ASL_MSG_FMT_XML;
976
977 tf = ASL_TIME_FMT_SEC;
978 if (pflags & TIME_UTC) tf = ASL_TIME_FMT_UTC;
979 if (pflags & TIME_LCL) tf = ASL_TIME_FMT_LCL;
980
981 len = 0;
982 str = asl_format_message(msg, mf, tf, encode, &len);
983 if (str != NULL)
984 {
985 fprintf(f, "%s", str);
986 free(str);
987 }
988 }
989
990 asl_search_result_t *
991 store_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64_t *last)
992 {
993 uint32_t status;
994 asl_search_result_t *res;
995
996 if (store == NULL)
997 {
998 status = asl_store_open_read(NULL, &store);
999 if (status != 0) return NULL;
1000 }
1001
1002 res = NULL;
1003 status = asl_store_match(store, q, &res, last, start, count, dir);
1004 if (status != 0) return NULL;
1005
1006 return res;
1007 }
1008
1009 asl_search_result_t *
1010 file_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64_t *last)
1011 {
1012 uint32_t status;
1013 asl_search_result_t *res;
1014
1015 res = NULL;
1016 status = asl_file_list_match(db_files, q, &res, last, start, count, dir);
1017 if (status != 0) return NULL;
1018
1019 return res;
1020 }
1021
1022 asl_search_result_t *
1023 legacy_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64_t *last)
1024 {
1025 uint32_t status;
1026 asl_search_result_t *res;
1027
1028 res = NULL;
1029 status = asl_file_match(legacy, q, &res, last, start, count, dir);
1030 if (status != 0) return NULL;
1031
1032 return res;
1033 }
1034
1035 asl_search_result_t *
1036 syslogd_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64_t *last)
1037 {
1038 char *str, *res;
1039 caddr_t vmstr;
1040 uint32_t len, reslen, status;
1041 int flags;
1042 kern_return_t kstatus;
1043 security_token_t sec;
1044 asl_search_result_t *l;
1045
1046 if (asl_server_port == MACH_PORT_NULL)
1047 {
1048 kstatus = bootstrap_look_up(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port);
1049 if (kstatus != KERN_SUCCESS)
1050 {
1051 fprintf(stderr, "query failed: can't contact syslogd\n");
1052 return NULL;
1053 }
1054 }
1055
1056 len = 0;
1057 str = asl_list_to_string(q, &len);
1058
1059 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
1060 if (kstatus != KERN_SUCCESS)
1061 {
1062 free(str);
1063 return NULL;
1064 }
1065
1066 memmove(vmstr, str, len);
1067 free(str);
1068
1069 res = NULL;
1070 reslen = 0;
1071 sec.val[0] = -1;
1072 sec.val[1] = -1;
1073 status = 0;
1074 flags = 0;
1075 if (dir < 0) flags = QUERY_FLAG_SEARCH_REVERSE;
1076
1077 kstatus = _asl_server_query(asl_server_port, (caddr_t)vmstr, len, start, count, flags, (caddr_t *)&res, &reslen, last, (int *)&status, &sec);
1078
1079 if (res == NULL) return NULL;
1080 l = asl_list_from_string(res);
1081 vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
1082 return l;
1083 }
1084
1085 void
1086 search_once(FILE *f, char *pfmt, int pflags, asl_search_result_t *ql, uint64_t qmin, uint64_t *cmax, uint32_t count, uint32_t batch, int dir, uint32_t tail)
1087 {
1088 asl_search_result_t *res;
1089 int i, more, total;
1090
1091 if (pflags & FORMAT_XML) print_xml_header(f);
1092
1093 res = NULL;
1094 more = 1;
1095 total = 0;
1096
1097 while (more == 1)
1098 {
1099 if (dbselect == DB_SELECT_STORE) res = store_query(ql, qmin, batch, dir, cmax);
1100 else if (dbselect == DB_SELECT_FILES) res = file_query(ql, qmin, batch, dir, cmax);
1101 else if (dbselect == DB_SELECT_SYSLOGD) res = syslogd_query(ql, qmin, batch, dir, cmax);
1102 else if (dbselect == DB_SELECT_LEGACY) res = legacy_query(ql, qmin, batch, dir, cmax);
1103
1104 if ((dir >= 0) && (*cmax > qmin)) qmin = *cmax;
1105 else if ((dir < 0) && (*cmax < qmin)) qmin = *cmax;
1106
1107 if (res == NULL)
1108 {
1109 more = 0;
1110 }
1111 else
1112 {
1113 if ((batch > 0) && (res->count < batch)) more = 0;
1114 total += res->count;
1115 if ((count > 0) && (total >= count)) more = 0;
1116
1117 i = 0;
1118 if (tail != 0)
1119 {
1120 i = res->count - tail;
1121 tail = 0;
1122 if (i < 0) i = 0;
1123 }
1124
1125 if ((f != NULL) || (export != NULL))
1126 {
1127 for (; i < res->count; i++) printmsg(f, res->msg[i], pfmt, pflags);
1128 }
1129
1130 aslresponse_free((aslresponse)res);
1131 }
1132 }
1133
1134 if (pflags & FORMAT_XML) print_xml_trailer(f);
1135 }
1136
1137 uint32_t
1138 optype(char *o)
1139 {
1140 uint32_t op, i;
1141
1142 op = ASL_QUERY_OP_NULL;
1143
1144 if (o == NULL) return op;
1145
1146 for (i = 0; o[i] != '\0'; i++)
1147 {
1148 if (o[i] == MOD_CASE_FOLD) op |= ASL_QUERY_OP_CASEFOLD;
1149 else if (o[i] == MOD_REGEX) op |= ASL_QUERY_OP_REGEX;
1150 else if (o[i] == MOD_NUMERIC) op |= ASL_QUERY_OP_NUMERIC;
1151 else if (o[i] == MOD_SUBSTRING) op |= ASL_QUERY_OP_SUBSTRING;
1152 else if (o[i] == MOD_PREFIX) op |= ASL_QUERY_OP_PREFIX;
1153 else if (o[i] == MOD_SUFFIX) op |= ASL_QUERY_OP_SUFFIX;
1154
1155 else if (!strncasecmp(o+i, OP_EQ, sizeof(OP_EQ)))
1156 {
1157 op |= ASL_QUERY_OP_EQUAL;
1158 i += (sizeof(OP_EQ) - 2);
1159 }
1160 else if (!strncasecmp(o+i, OP_NE, sizeof(OP_NE)))
1161 {
1162 op |= ASL_QUERY_OP_NOT_EQUAL;
1163 i += (sizeof(OP_NE) - 2);
1164 }
1165 else if (!strncasecmp(o+i, OP_GT, sizeof(OP_GT)))
1166 {
1167 op |= ASL_QUERY_OP_GREATER;
1168 i += (sizeof(OP_GT) - 2);
1169 }
1170 else if (!strncasecmp(o+i, OP_GE, sizeof(OP_GE)))
1171 {
1172 op |= ASL_QUERY_OP_GREATER_EQUAL;
1173 i += (sizeof(OP_GE) - 2);
1174 }
1175 else if (!strncasecmp(o+i, OP_LT, sizeof(OP_LT)))
1176 {
1177 op |= ASL_QUERY_OP_LESS;
1178 i += (sizeof(OP_LT) - 2);
1179 }
1180 else if (!strncasecmp(o+i, OP_LE, sizeof(OP_LE)))
1181 {
1182 op |= ASL_QUERY_OP_LESS_EQUAL;
1183 i += (sizeof(OP_LE) - 2);
1184 }
1185 else
1186 {
1187 fprintf(stderr, "invalid option: %s\n", o);
1188 return 0;
1189 }
1190 }
1191
1192 /* sanity check */
1193 if (op & ASL_QUERY_OP_NUMERIC)
1194 {
1195 if (op & ASL_QUERY_OP_CASEFOLD)
1196 {
1197 fprintf(stderr, "warning: case fold modifier has no effect with numeric comparisons\n");
1198 op &= ~ASL_QUERY_OP_CASEFOLD;
1199 }
1200
1201 if (op & ASL_QUERY_OP_REGEX)
1202 {
1203 fprintf(stderr, "warning: regex modifier has no effect with numeric comparisons\n");
1204 op &= ~ASL_QUERY_OP_REGEX;
1205 }
1206
1207 if (op & ASL_QUERY_OP_SUBSTRING)
1208 {
1209 fprintf(stderr, "warning: substring modifier has no effect with numeric comparisons\n");
1210 op &= ~ASL_QUERY_OP_SUBSTRING;
1211 }
1212
1213 if (op & ASL_QUERY_OP_PREFIX)
1214 {
1215 fprintf(stderr, "warning: prefix modifier has no effect with numeric comparisons\n");
1216 op &= ~ASL_QUERY_OP_PREFIX;
1217 }
1218
1219 if (op & ASL_QUERY_OP_SUFFIX)
1220 {
1221 fprintf(stderr, "warning: suffix modifier has no effect with numeric comparisons\n");
1222 op &= ~ASL_QUERY_OP_SUFFIX;
1223 }
1224 }
1225
1226 if (op & ASL_QUERY_OP_REGEX)
1227 {
1228 if (op & ASL_QUERY_OP_SUBSTRING)
1229 {
1230 fprintf(stderr, "warning: substring modifier has no effect with regular expression comparisons\n");
1231 op &= ~ASL_QUERY_OP_SUBSTRING;
1232 }
1233
1234 if (op & ASL_QUERY_OP_PREFIX)
1235 {
1236 fprintf(stderr, "warning: prefix modifier has no effect with regular expression comparisons\n");
1237 op &= ~ASL_QUERY_OP_PREFIX;
1238 }
1239
1240 if (op & ASL_QUERY_OP_SUFFIX)
1241 {
1242 fprintf(stderr, "warning: suffix modifier has no effect with regular expression comparisons\n");
1243 op &= ~ASL_QUERY_OP_SUFFIX;
1244 }
1245 }
1246
1247 return op;
1248 }
1249
1250 int
1251 add_op(asl_msg_t *q, char *key, char *op, char *val, uint32_t flags)
1252 {
1253 uint32_t o;
1254 const char *qval;
1255
1256 if (key == NULL) return -1;
1257 if (q == NULL) return -1;
1258
1259 qval = NULL;
1260 if (strcmp(key, ASL_KEY_TIME) == 0)
1261 {
1262 qval = (const char *)val;
1263 }
1264 else if ((strcmp(key, ASL_KEY_LEVEL) == 0) && (_isanumber(val) == 0))
1265 {
1266 /* Convert level strings to numeric values */
1267 qval = asl_string_to_char_level(val);
1268 if (qval == NULL)
1269 {
1270 fprintf(stderr, "invalid value for \"Level\"key: %s\n", val);
1271 return -1;
1272 }
1273 }
1274
1275 o = ASL_QUERY_OP_NULL;
1276 if (val == NULL) o = ASL_QUERY_OP_TRUE;
1277
1278 if (op != NULL)
1279 {
1280 o = optype(op);
1281 if (o == ASL_QUERY_OP_NULL) return -1;
1282 if (val == NULL)
1283 {
1284 fprintf(stderr, "no value supplied for operator %s %s\n", key, op);
1285 return -1;
1286 }
1287
1288 if ((qval == NULL) && (o & ASL_QUERY_OP_NUMERIC) && (_isanumber(val) == 0))
1289 {
1290 fprintf(stderr, "non-numeric value supplied for numeric operator %s %s %s\n", key, op, val);
1291 return -1;
1292 }
1293 }
1294
1295 o |= flags;
1296 if (qval != NULL) asl_set_query(q, key, qval, o);
1297 else asl_set_query(q, key, val, o);
1298
1299 return 0;
1300 }
1301
1302 static uint32_t
1303 add_db_file(const char *name)
1304 {
1305 asl_file_t *s;
1306 uint32_t status;
1307
1308 if (dbselect == DB_SELECT_LEGACY)
1309 {
1310 fprintf(stderr, "syslog can only read one legacy format database\n");
1311 fprintf(stderr, "can't combine legacy and non-legacy databases in a single search\n");
1312 exit(1);
1313 }
1314
1315 /* shouldn't happen */
1316 if (name == NULL) return DB_SELECT_STORE;
1317
1318 s = NULL;
1319 status = asl_file_open_read(name, &s);
1320 if (status != ASL_STATUS_OK)
1321 {
1322 fprintf(stderr, "data store file %s open failed: %s \n", name, asl_core_error(status));
1323 exit(1);
1324 }
1325
1326 if (s == NULL)
1327 {
1328 fprintf(stderr, "data store file %s open failed\n", name);
1329 exit(1);
1330 }
1331
1332 if (s->flags & ASL_FILE_FLAG_LEGACY_STORE)
1333 {
1334 if (db_files != NULL)
1335 {
1336 fprintf(stderr, "syslog can only read a single legacy format database\n");
1337 fprintf(stderr, "can't combine legacy and non-legacy databases in a single search\n");
1338 exit(1);
1339 }
1340
1341 legacy = s;
1342 return DB_SELECT_LEGACY;
1343 }
1344
1345 db_files = asl_file_list_add(db_files, s);
1346 return DB_SELECT_FILES;
1347 }
1348
1349 static uint32_t
1350 add_db_dir(const char *name)
1351 {
1352 DIR *dp;
1353 struct dirent *dent;
1354 uint32_t status;
1355 asl_file_t *s;
1356 char *path;
1357
1358 /*
1359 * Open all readable files
1360 */
1361 dp = opendir(name);
1362 if (dp == NULL)
1363 {
1364 fprintf(stderr, "%s: %s\n", name, strerror(errno));
1365 exit(1);
1366 }
1367
1368 while ((dent = readdir(dp)) != NULL)
1369 {
1370 if (dent->d_name[0] == '.') continue;
1371
1372 path = NULL;
1373 asprintf(&path, "%s/%s", name, dent->d_name);
1374
1375 /*
1376 * asl_file_open_read will fail if path is NULL,
1377 * if the file is not an ASL store file,
1378 * or if it isn't readable.
1379 */
1380 s = NULL;
1381 status = asl_file_open_read(path, &s);
1382 if (path != NULL) free(path);
1383 if ((status != ASL_STATUS_OK) || (s == NULL)) continue;
1384
1385 db_files = asl_file_list_add(db_files, s);
1386 }
1387
1388 closedir(dp);
1389
1390 return DB_SELECT_FILES;
1391 }
1392
1393 int
1394 main(int argc, char *argv[])
1395 {
1396 FILE *outfile;
1397 int i, j, n, watch, status, pflags, tflags, iamroot, user_tflag;
1398 int notify_file, notify_token;
1399 asl_search_result_t *qlist;
1400 asl_msg_t *cq;
1401 char *pfmt;
1402 const char *exportname;
1403 uint32_t flags, tail_count, batch, encode;
1404 uint64_t qmin, cmax;
1405
1406 watch = 0;
1407 iamroot = 0;
1408 user_tflag = 0;
1409 pfmt = NULL;
1410 flags = 0;
1411 tail_count = 0;
1412 batch = FETCH_BATCH;
1413 pflags = FORMAT_STD;
1414 tflags = TIME_LCL;
1415 encode = ASL_ENCODE_ASL;
1416 cq = NULL;
1417 exportname = NULL;
1418
1419 if (getuid() == 0) iamroot = 1;
1420
1421 for (i = 1; i < argc; i++)
1422 {
1423 if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help")))
1424 {
1425 usage();
1426 exit(0);
1427 }
1428
1429 if (!strcmp(argv[i], "-time"))
1430 {
1431 qmin = time(NULL);
1432 printf("%llu\n", qmin);
1433 exit(0);
1434 }
1435
1436 if (!strcmp(argv[i], "-s"))
1437 {
1438 syslog_send(argc, argv);
1439 exit(0);
1440 }
1441
1442 if (!strcmp(argv[i], "-c"))
1443 {
1444 syslog_remote_control(argc, argv);
1445 exit(0);
1446 }
1447 }
1448
1449 qlist = (asl_search_result_t *)calloc(1, sizeof(asl_search_result_t));
1450 if (qlist == NULL) exit(1);
1451
1452 for (i = 1; i < argc; i++)
1453 {
1454 if (!strcmp(argv[i], "-f"))
1455 {
1456 if ((i + 1) < argc)
1457 {
1458 for (j = i + 1; j < argc; j++)
1459 {
1460 if (!strcmp(argv[j], "-"))
1461 {
1462 dbselect = DB_SELECT_SYSLOGD;
1463 break;
1464 }
1465 else if (argv[j][0] == '-')
1466 {
1467 break;
1468 }
1469 else
1470 {
1471 dbselect = add_db_file(argv[j]);
1472 }
1473 }
1474 }
1475 }
1476 if (!strcmp(argv[i], "-d"))
1477 {
1478 if ((i + 1) < argc)
1479 {
1480 for (j = i + 1; j < argc; j++)
1481 {
1482 if (!strcmp(argv[j], "store"))
1483 {
1484 dbselect = add_db_dir(PATH_ASL_STORE);
1485 }
1486 else if (!strcmp(argv[j], "archive"))
1487 {
1488 dbselect = add_db_dir(PATH_ASL_ARCHIVE);
1489 }
1490 else if (argv[j][0] == '-')
1491 {
1492 break;
1493 }
1494 else
1495 {
1496 dbselect = add_db_dir(argv[j]);
1497 }
1498 }
1499 }
1500 }
1501 else if (!strcmp(argv[i], "-w"))
1502 {
1503 watch = 1;
1504 tail_count = 10;
1505 if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
1506 {
1507 i++;
1508 tail_count = atoi(argv[i]);
1509 }
1510 }
1511 else if (!strcmp(argv[i], "-u"))
1512 {
1513 tflags = TIME_UTC;
1514 user_tflag = 1;
1515 }
1516 else if (!strcmp(argv[i], "-x"))
1517 {
1518 if ((i + 1) >= argc)
1519 {
1520 aslresponse_free(qlist);
1521 usage();
1522 exit(1);
1523 }
1524
1525 exportname = argv[++i];
1526 }
1527 else if (!strcmp(argv[i], "-E"))
1528 {
1529 if ((i + 1) >= argc)
1530 {
1531 aslresponse_free(qlist);
1532 usage();
1533 exit(1);
1534 }
1535
1536 i++;
1537
1538 if (!strcmp(argv[i], "vis")) encode = ASL_ENCODE_ASL;
1539 else if (!strcmp(argv[i], "safe")) encode = ASL_ENCODE_SAFE;
1540 else if (!strcmp(argv[i], "none")) encode = ASL_ENCODE_NONE;
1541 else if ((argv[i][0] >= '0') && (argv[i][0] <= '9') && (argv[i][1] == '\0')) encode = atoi(argv[i]);
1542 }
1543 else if (!strcmp(argv[i], "-F"))
1544 {
1545 if ((i + 1) >= argc)
1546 {
1547 aslresponse_free(qlist);
1548 usage();
1549 exit(1);
1550 }
1551
1552 i++;
1553
1554 if (!strcmp(argv[i], "raw"))
1555 {
1556 pflags = FORMAT_RAW;
1557 if (user_tflag == 0) tflags = TIME_SEC;
1558 }
1559 else if (!strcmp(argv[i], "std"))
1560 {
1561 pflags = FORMAT_STD;
1562 }
1563 else if (!strcmp(argv[i], "bsd"))
1564 {
1565 pflags = FORMAT_LEGACY;
1566 }
1567 else if (!strcmp(argv[i], "xml"))
1568 {
1569 pflags = FORMAT_XML;
1570 }
1571 else
1572 {
1573 pflags = 0;
1574 pfmt = argv[i];
1575 }
1576 }
1577 else if (!strcmp(argv[i], "-T"))
1578 {
1579 if ((i + 1) >= argc)
1580 {
1581 aslresponse_free(qlist);
1582 usage();
1583 exit(1);
1584 }
1585
1586 i++;
1587 user_tflag = 1;
1588
1589 if (!strcmp(argv[i], "sec")) tflags = TIME_SEC;
1590 else if (!strcmp(argv[i], "utc")) tflags = TIME_UTC;
1591 else if (!strcmp(argv[i], "local")) tflags = TIME_LCL;
1592 else if (!strcmp(argv[i], "lcl")) tflags = TIME_LCL;
1593 else tflags = TIME_LCL;
1594 }
1595 else if (!strcmp(argv[i], "-o"))
1596 {
1597 flags = 0;
1598
1599 if (qlist->count == 0)
1600 {
1601 qlist->msg = (asl_msg_t **)calloc(1, sizeof(asl_msg_t *));
1602 }
1603 else
1604 {
1605 qlist->msg = (asl_msg_t **)reallocf(qlist->msg, (qlist->count + 1) * sizeof(asl_msg_t *));
1606 }
1607
1608 if (qlist->msg == NULL) exit(1);
1609
1610 cq = asl_new(ASL_TYPE_QUERY);
1611 qlist->msg[qlist->count] = cq;
1612 qlist->count++;
1613 }
1614 else if (!strcmp(argv[i], "-n"))
1615 {
1616 flags = ASL_QUERY_OP_NOT;
1617 }
1618 else if (!strcmp(argv[i], "-C"))
1619 {
1620 if (qlist->count == 0)
1621 {
1622 qlist->msg = (asl_msg_t **)calloc(1, sizeof(asl_msg_t *));
1623 if (qlist->msg == NULL) exit(1);
1624
1625 cq = asl_new(ASL_TYPE_QUERY);
1626 qlist->msg[qlist->count] = cq;
1627 qlist->count++;
1628 }
1629
1630 status = add_op(cq, ASL_KEY_FACILITY, OP_EQ, FACILITY_CONSOLE, flags);
1631
1632 flags = 0;
1633 if (status != 0)
1634 {
1635 aslresponse_free(qlist);
1636 exit(1);
1637 }
1638 }
1639 else if (!strcmp(argv[i], "-k"))
1640 {
1641 i++;
1642 for (n = i; n < argc; n++)
1643 {
1644 if (!strcmp(argv[n], "-o")) break;
1645 if (!strcmp(argv[n], "-n")) break;
1646 if (!strcmp(argv[n], "-k")) break;
1647 if ((n - i) > 2)
1648 {
1649 fprintf(stderr, "invalid sequence: -k");
1650 for (j = i; j <= n; j++) fprintf(stderr, " %s", argv[j]);
1651 fprintf(stderr, "\n");
1652 usage();
1653 exit(1);
1654 }
1655 }
1656
1657 n -= i;
1658 if (n == 0)
1659 {
1660 i--;
1661 continue;
1662 }
1663
1664 if (qlist->count == 0)
1665 {
1666 qlist->msg = (asl_msg_t **)calloc(1, sizeof(asl_msg_t *));
1667 if (qlist->msg == NULL) exit(1);
1668
1669 cq = asl_new(ASL_TYPE_QUERY);
1670 qlist->msg[qlist->count] = cq;
1671 qlist->count++;
1672 }
1673
1674 status = 0;
1675 if (n == 1) status = add_op(cq, argv[i], NULL, NULL, flags);
1676 else if (n == 2) status = add_op(cq, argv[i], OP_EQ, argv[i+1], flags);
1677 else status = add_op(cq, argv[i], argv[i+1], argv[i+2], flags);
1678
1679 flags = 0;
1680 if (status != 0)
1681 {
1682 aslresponse_free(qlist);
1683 exit(1);
1684 }
1685 }
1686 }
1687
1688 pflags |= tflags;
1689 pflags |= encode;
1690
1691 outfile = stdout;
1692
1693 if (exportname != NULL)
1694 {
1695 if (watch == 1)
1696 {
1697 fprintf(stderr, "Warning: -w flag has no effect with -x export flag\n");
1698 watch = 0;
1699 }
1700
1701 status = asl_file_open_write(exportname, 0644, -1, -1, &export);
1702 if (status != ASL_STATUS_OK)
1703 {
1704 aslresponse_free(qlist);
1705 fprintf(stderr, "export file open failed: %s\n", asl_core_error(status));
1706 exit(1);
1707 }
1708
1709 /*
1710 * allow the string cache to be unlimited to maximize string dup compression
1711 * preserve message IDs
1712 */
1713 export->flags = ASL_FILE_FLAG_UNLIMITED_CACHE | ASL_FILE_FLAG_PRESERVE_MSG_ID;
1714
1715 outfile = NULL;
1716 pflags = EXPORT;
1717 }
1718
1719 qmin = 0;
1720 cmax = 0;
1721 notify_file = -1;
1722 notify_token = -1;
1723
1724 if (watch == 1)
1725 {
1726 if ((dbselect == DB_SELECT_STORE) || (dbselect == DB_SELECT_SYSLOGD))
1727 {
1728 status = notify_register_file_descriptor("com.apple.system.logger.message", &notify_file, 0, &notify_token);
1729 if (status != NOTIFY_STATUS_OK) notify_token = -1;
1730 }
1731 }
1732
1733 if ((qlist->count == 0) && (watch == 1))
1734 {
1735 qmin = -1;
1736 search_once(NULL, NULL, 0, NULL, qmin, &cmax, 1, 1, -1, 0);
1737 qmin = (cmax + 1) - tail_count;
1738 tail_count = 0;
1739 }
1740
1741 /* output should be line buffered */
1742 if (outfile != NULL) setlinebuf(outfile);
1743
1744 search_once(outfile, pfmt, pflags, qlist, qmin, &cmax, 0, batch, 1, tail_count);
1745
1746 if (watch == 1)
1747 {
1748 if (notify_token == -1)
1749 {
1750 forever
1751 {
1752 usleep(500000);
1753 if (cmax > qmin) qmin = cmax;
1754 search_once(outfile, pfmt, pflags, qlist, qmin + 1, &cmax, 0, batch, 1, 0);
1755 }
1756 }
1757 else
1758 {
1759 while (read(notify_file, &i, 4) == 4)
1760 {
1761 if (cmax > qmin) qmin = cmax;
1762 search_once(outfile, pfmt, pflags, qlist, qmin + 1, &cmax, 0, batch, 1, 0);
1763 }
1764 }
1765 }
1766
1767 if (db_files != NULL) asl_file_list_close(db_files);
1768 if (store != NULL) asl_store_close(store);
1769 if (export != NULL) asl_file_close(export);
1770
1771 aslresponse_free(qlist);
1772
1773 exit(0);
1774 }