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