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