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