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