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