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