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