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