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