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