]> git.saurik.com Git - apple/syslog.git/blob - util.tproj/syslog.c
syslog-13.tar.gz
[apple/syslog.git] / util.tproj / syslog.c
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 2004 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <ctype.h>
29 #include <time.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <sys/socket.h>
33 #include <sys/sysctl.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include <netdb.h>
37 #include <notify.h>
38 #include <asl.h>
39 #include <asl_private.h>
40
41 #define MOD_CASE_FOLD 'C'
42 #define MOD_REGEX 'R'
43 #define MOD_SUBSTRING 'S'
44 #define MOD_PREFIX 'A'
45 #define MOD_SUFFIX 'Z'
46 #define MOD_NUMERIC 'N'
47
48 #define OP_EQ "eq"
49 #define OP_NE "ne"
50 #define OP_GT "gt"
51 #define OP_GE "ge"
52 #define OP_LT "lt"
53 #define OP_LE "le"
54
55 #define ASL_QUERY_OP_NOT 0x1000
56
57 #define SEARCH_EOF -1
58 #define SEARCH_NULL 0
59 #define SEARCH_MATCH 1
60
61 #define PROC_NOT_FOUND -1
62 #define PROC_NOT_UNIQUE -2
63
64 #define RC_MASTER -1
65 #define RC_SYSLOGD -2
66
67 #define CHUNK 64
68 #define forever for(;;)
69
70 #define SEND_FORMAT_LEGACY 0
71 #define SEND_FORMAT_ASL 1
72
73 #define PRINT_LOCALTIME 0x00000001
74 #define PRINT_LEGACY_FMT 0x00000002
75 #define PRINT_STD_FMT 0x00000004
76
77 #define ASL_FILTER_MASK_PACEWNID 0xff
78 #define ASL_FILTER_MASK_PACEWNI 0x7f
79 #define ASL_FILTER_MASK_PACEWN 0x3f
80 #define ASL_FILTER_MASK_PACEW 0x1f
81 #define ASL_FILTER_MASK_PACE 0x0f
82 #define ASL_FILTER_MASK_PAC 0x07
83
84
85 /* BEGIN PRIVATE API */
86 #define _PATH_ASL_PRUNE "/var/run/asl_prune"
87 #define _PATH_SYSLOGD_PID "/var/run/syslog.pid"
88
89 /* notify SPI */
90 uint32_t notify_get_state(int token, int *state);
91 uint32_t notify_set_state(int token, int state);
92 uint32_t notify_register_plain(const char *name, int *out_token);
93
94 extern char *asl_msg_to_string(aslmsg msg, uint32_t *len);
95 extern asl_msg_t *asl_msg_from_string(const char *buf);
96 extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b);
97 extern time_t asl_parse_time(const char *in);
98 /* END PRIVATE API */
99
100 static const char *myname = "syslog";
101
102 void
103 usage()
104 {
105 fprintf(stderr, "usage:\n");
106 fprintf(stderr, "%s -s [-r host] [-l level] message...\n", myname);
107 fprintf(stderr, " send a message\n");
108 fprintf(stderr, "\n");
109 fprintf(stderr, "%s -s [-r host] -k key val [key val]...\n", myname);
110 fprintf(stderr, " send a message with the given keys and values\n");
111 fprintf(stderr, "\n");
112 fprintf(stderr, "%s -c process [filter]\n", myname);
113 fprintf(stderr, " get (set if filter is specified) syslog filter for process (pid or name)\n");
114 fprintf(stderr, " level may be any combination of the characters \"p a c e w n i d\"\n");
115 fprintf(stderr, " p = Emergency (\"Panic\")\n");
116 fprintf(stderr, " a = Alert\n");
117 fprintf(stderr, " c = Critical\n");
118 fprintf(stderr, " e = Error\n");
119 fprintf(stderr, " w = Warning\n");
120 fprintf(stderr, " n = Notice\n");
121 fprintf(stderr, " i = Info\n");
122 fprintf(stderr, " d = Debug\n");
123 fprintf(stderr, " a minus sign preceeding a single letter means \"up to\" that level\n");
124 fprintf(stderr, "\n");
125 fprintf(stderr, "%s -p [-k key [[op] val]]... [-o -k key [[op] val]] ...]...\n", myname);
126 fprintf(stderr, " -p prune datastore according to input expression (see below)\n");
127 fprintf(stderr, "\n");
128 fprintf(stderr, "%s [-w] [-F format] [-u] [-k key [[op] val]]... [-o -k key [[op] val]] ...]...\n", myname);
129 fprintf(stderr, " -w watch file (^C to quit)\n");
130 fprintf(stderr, " -F output format may be \"std\", \"raw\", or \"bsd\"\n");
131 fprintf(stderr, " format may also be a string containing variables of the form\n");
132 fprintf(stderr, " $Key or $(Key) - use the latter for non-whitespace delimited variables\n");
133 fprintf(stderr, " -u force printing of all timestamps using UTC\n");
134 fprintf(stderr, " -k key/value match\n");
135 fprintf(stderr, " if no operator or value is given, checks for the existance of the key\n");
136 fprintf(stderr, " if no operator is given, default is \"%s\"\n", OP_EQ);
137 fprintf(stderr, " -o begins a new query\n");
138 fprintf(stderr, " queries are \'OR\'ed together\n");
139 fprintf(stderr, "operators are zero or more modifiers followed by a comparison\n");
140 fprintf(stderr, " %s equal\n", OP_EQ);
141 fprintf(stderr, " %s not equal\n", OP_NE);
142 fprintf(stderr, " %s greater than\n", OP_GT);
143 fprintf(stderr, " %s greater or equal\n", OP_GE);
144 fprintf(stderr, " %s less than\n", OP_LT);
145 fprintf(stderr, " %s less or equal\n", OP_LE);
146 fprintf(stderr, "optional modifiers for operators\n");
147 fprintf(stderr, " %c case-fold\n", MOD_CASE_FOLD);
148 fprintf(stderr, " %c regular expression\n", MOD_REGEX);
149 fprintf(stderr, " %c substring\n", MOD_SUBSTRING);
150 fprintf(stderr, " %c prefix\n", MOD_PREFIX);
151 fprintf(stderr, " %c suffix\n", MOD_SUFFIX);
152 fprintf(stderr, " %c numeric comparison\n", MOD_NUMERIC);
153 }
154
155 const char *
156 notify_status_string(int status)
157 {
158 if (status == NOTIFY_STATUS_OK) return "OK";
159 if (status == NOTIFY_STATUS_INVALID_NAME) return "Process not registered";
160 if (status == NOTIFY_STATUS_NOT_AUTHORIZED) return "Not authorized";
161 return "Operation failed";
162 }
163
164 const char *
165 asl_level_string(int level)
166 {
167 if (level == ASL_LEVEL_EMERG) return ASL_STRING_EMERG;
168 if (level == ASL_LEVEL_ALERT) return ASL_STRING_ALERT;
169 if (level == ASL_LEVEL_CRIT) return ASL_STRING_CRIT;
170 if (level == ASL_LEVEL_ERR) return ASL_STRING_ERR;
171 if (level == ASL_LEVEL_WARNING) return ASL_STRING_WARNING;
172 if (level == ASL_LEVEL_NOTICE) return ASL_STRING_NOTICE;
173 if (level == ASL_LEVEL_INFO) return ASL_STRING_INFO;
174 if (level == ASL_LEVEL_DEBUG) return ASL_STRING_DEBUG;
175 return "Unknown";
176 }
177
178 int
179 procinfo(char *pname, int *pid, int *uid)
180 {
181 int mib[4];
182 int i, status, nprocs;
183 size_t miblen, size;
184 struct kinfo_proc *procs, *newprocs;
185
186 size = 0;
187 procs = NULL;
188
189 mib[0] = CTL_KERN;
190 mib[1] = KERN_PROC;
191 mib[2] = KERN_PROC_ALL;
192 mib[3] = 0;
193 miblen = 3;
194
195 status = sysctl(mib, miblen, NULL, &size, NULL, 0);
196 do
197 {
198 size += size / 10;
199 newprocs = realloc(procs, size);
200 if (newprocs == 0)
201 {
202 if (procs != NULL) free(procs);
203 return PROC_NOT_FOUND;
204 }
205
206 procs = newprocs;
207 status = sysctl(mib, miblen, procs, &size, NULL, 0);
208 } while ((status == -1) && (errno == ENOMEM));
209
210 if (status == -1)
211 {
212 if (procs != NULL) free(procs);
213 return PROC_NOT_FOUND;
214 }
215
216 if (size % sizeof(struct kinfo_proc) != 0)
217 {
218 if (procs != NULL) free(procs);
219 return PROC_NOT_FOUND;
220 }
221
222 if (procs == NULL) return PROC_NOT_FOUND;
223
224 nprocs = size / sizeof(struct kinfo_proc);
225
226 if (pname == NULL)
227 {
228 /* Search for a pid */
229 for (i = 0; i < nprocs; i++)
230 {
231 if (*pid == procs[i].kp_proc.p_pid)
232 {
233 *uid = procs[i].kp_eproc.e_ucred.cr_uid;
234 return 0;
235 }
236 }
237
238 return PROC_NOT_FOUND;
239 }
240
241 *pid = PROC_NOT_FOUND;
242
243 for (i = 0; i < nprocs; i++)
244 {
245 if (!strcmp(procs[i].kp_proc.p_comm, pname))
246 {
247 if (*pid != PROC_NOT_FOUND)
248 {
249 free(procs);
250 return PROC_NOT_UNIQUE;
251 }
252
253 *pid = procs[i].kp_proc.p_pid;
254 *uid = procs[i].kp_eproc.e_ucred.cr_uid;
255 }
256 }
257
258 free(procs);
259 if (*pid == PROC_NOT_FOUND) return PROC_NOT_FOUND;
260
261 return 0;
262 }
263
264 int
265 rcontrol_get_string(const char *prefix, int pid, int *val)
266 {
267 int t, x, status;
268 char *name;
269
270 status = NOTIFY_STATUS_OK;
271
272 if (pid == RC_SYSLOGD)
273 {
274 status = notify_register_plain(NOTIFY_SYSTEM_ASL_FILTER, &t);
275 }
276 else if (pid == RC_MASTER)
277 {
278 status = notify_register_plain(NOTIFY_SYSTEM_MASTER, &t);
279 }
280 else
281 {
282 name = NULL;
283 asprintf(&name, "%s.%d", prefix, pid);
284 if (name == NULL) return NOTIFY_STATUS_FAILED;
285
286 status = notify_register_plain(name, &t);
287 free(name);
288 }
289
290 if (status != NOTIFY_STATUS_OK) return status;
291
292 x = 0;
293 status = notify_get_state(t, &x);
294 notify_cancel(t);
295
296 *val = x;
297
298 return status;
299 }
300
301 int
302 rcontrol_set_string(const char *prefix, int pid, int filter)
303 {
304 int t, status;
305 char *name;
306
307 status = NOTIFY_STATUS_OK;
308
309 if (pid == RC_SYSLOGD)
310 {
311 status = notify_register_plain(NOTIFY_SYSTEM_ASL_FILTER, &t);
312 }
313 else if (pid == RC_MASTER)
314 {
315 status = notify_register_plain(NOTIFY_SYSTEM_MASTER, &t);
316 }
317 else
318 {
319 name = NULL;
320 asprintf(&name, "%s.%d", prefix, pid);
321 if (name == NULL) return NOTIFY_STATUS_FAILED;
322
323 status = notify_register_plain(name, &t);
324 free(name);
325 }
326
327 if (status != NOTIFY_STATUS_OK) return status;
328 status = notify_set_state(t, filter);
329 if ((pid == RC_SYSLOGD) && (status == NOTIFY_STATUS_OK)) status = notify_post(NOTIFY_SYSTEM_ASL_FILTER);
330 notify_cancel(t);
331 return status;
332 }
333
334 int
335 asl_string_to_filter(char *s)
336 {
337 int f, i;
338
339 if (s == NULL) return 0;
340 if (s[0] == '\0') return 0;
341
342 if ((s[0] >= '0') && (s[0] <= '9')) return ASL_FILTER_MASK(atoi(s));
343
344 if (s[0] == '-')
345 {
346 if ((s[1] == 'P') || (s[1] == 'p')) i = ASL_LEVEL_EMERG;
347 else if ((s[1] == 'A') || (s[1] == 'a')) i = ASL_LEVEL_ALERT;
348 else if ((s[1] == 'C') || (s[1] == 'c')) i = ASL_LEVEL_CRIT;
349 else if ((s[1] == 'E') || (s[1] == 'e')) i = ASL_LEVEL_ERR;
350 else if ((s[1] == 'X') || (s[1] == 'x')) i = ASL_LEVEL_ERR;
351 else if ((s[1] == 'W') || (s[1] == 'w')) i = ASL_LEVEL_WARNING;
352 else if ((s[1] == 'N') || (s[1] == 'n')) i = ASL_LEVEL_NOTICE;
353 else if ((s[1] == 'I') || (s[1] == 'i')) i = ASL_LEVEL_INFO;
354 else if ((s[1] == 'D') || (s[1] == 'd')) i = ASL_LEVEL_DEBUG;
355 else i = atoi(s + 1);
356 f = ASL_FILTER_MASK_UPTO(i);
357 return f;
358 }
359
360 f = 0;
361 for (i = 0; s[i] != '\0'; i++)
362 {
363 if ((s[i] == 'P') || (s[i] == 'p')) f |= ASL_FILTER_MASK_EMERG;
364 else if ((s[i] == 'A') || (s[i] == 'a')) f |= ASL_FILTER_MASK_ALERT;
365 else if ((s[i] == 'C') || (s[i] == 'c')) f |= ASL_FILTER_MASK_CRIT;
366 else if ((s[i] == 'E') || (s[i] == 'e')) f |= ASL_FILTER_MASK_ERR;
367 else if ((s[i] == 'X') || (s[i] == 'x')) f |= ASL_FILTER_MASK_ERR;
368 else if ((s[i] == 'W') || (s[i] == 'w')) f |= ASL_FILTER_MASK_WARNING;
369 else if ((s[i] == 'N') || (s[i] == 'n')) f |= ASL_FILTER_MASK_NOTICE;
370 else if ((s[i] == 'I') || (s[i] == 'i')) f |= ASL_FILTER_MASK_INFO;
371 else if ((s[i] == 'D') || (s[i] == 'd')) f |= ASL_FILTER_MASK_DEBUG;
372 }
373
374 return f;
375 }
376
377 char *
378 asl_filter_string(int f)
379 {
380 static char str[1024];
381 int i;
382
383 memset(str, 0, sizeof(str));
384 i = 0;
385
386 if ((f == ASL_FILTER_MASK_PACEWNID) != 0)
387 {
388 strcat(str, "Emergency - Debug");
389 return str;
390 }
391
392 if ((f == ASL_FILTER_MASK_PACEWNI) != 0)
393 {
394 strcat(str, "Emergency - Info");
395 return str;
396 }
397
398 if ((f == ASL_FILTER_MASK_PACEWN) != 0)
399 {
400 strcat(str, "Emergency - Notice");
401 return str;
402 }
403
404 if ((f == ASL_FILTER_MASK_PACEW) != 0)
405 {
406 strcat(str, "Emergency - Warning");
407 return str;
408 }
409
410 if ((f == ASL_FILTER_MASK_PACE) != 0)
411 {
412 strcat(str, "Emergency - Error");
413 return str;
414 }
415
416 if ((f == ASL_FILTER_MASK_PAC) != 0)
417 {
418 strcat(str, "Emergency - Critical");
419 return str;
420 }
421
422 if ((f & ASL_FILTER_MASK_EMERG) != 0)
423 {
424 strcat(str, "Emergency");
425 i++;
426 }
427
428 if ((f & ASL_FILTER_MASK_ALERT) != 0)
429 {
430 if (i > 0) strcat(str, ", ");
431 strcat(str, "Alert");
432 i++;
433 }
434
435 if ((f & ASL_FILTER_MASK_CRIT) != 0)
436 {
437 if (i > 0) strcat(str, ", ");
438 strcat(str, "Critical");
439 i++;
440 }
441
442 if ((f & ASL_FILTER_MASK_ERR) != 0)
443 {
444 if (i > 0) strcat(str, ", ");
445 strcat(str, "Error");
446 i++;
447 }
448
449 if ((f & ASL_FILTER_MASK_WARNING) != 0)
450 {
451 if (i > 0) strcat(str, ", ");
452 strcat(str, "Warning");
453 i++;
454 }
455
456 if ((f & ASL_FILTER_MASK_NOTICE) != 0)
457 {
458 if (i > 0) strcat(str, ", ");
459 strcat(str, "Notice");
460 i++;
461 }
462
463 if ((f & ASL_FILTER_MASK_INFO) != 0)
464 {
465 if (i > 0) strcat(str, ", ");
466 strcat(str, "Info");
467 i++;
468 }
469
470 if ((f & ASL_FILTER_MASK_DEBUG) != 0)
471 {
472 if (i > 0) strcat(str, ", ");
473 strcat(str, "Debug");
474 i++;
475 }
476
477 if (i == 0) sprintf(str, "Off");
478
479 return str;
480 }
481
482 int
483 rcontrol_get(const char *prefix, int pid)
484 {
485 int filter, status;
486 const char *name;
487
488 filter = 0;
489
490 if (pid < 0)
491 {
492 name = "Master";
493 if (pid == RC_SYSLOGD) name = "ASL Data Store";
494
495 status = rcontrol_get_string(NULL, pid, &filter);
496 if (status == NOTIFY_STATUS_OK)
497 {
498 printf("%s filter mask: %s\n", name, asl_filter_string(filter));
499 return 0;
500 }
501
502 printf("Unable to determine %s filter mask\n", name);
503 return -1;
504 }
505
506 status = rcontrol_get_string(prefix, pid, &filter);
507 if (status == NOTIFY_STATUS_OK)
508 {
509 printf("Process %d syslog filter mask: %s\n", pid, asl_filter_string(filter));
510 return 0;
511 }
512
513 printf("Unable to determine syslog filter mask for pid %d\n", pid);
514 return -1;
515 }
516
517 int
518 rcontrol_set(const char *prefix, int pid, int filter)
519 {
520 int status;
521 const char *name;
522
523 if (pid < 0)
524 {
525 name = "Master";
526 if (pid == RC_SYSLOGD) name = "ASL Data Store";
527 status = rcontrol_set_string(NULL, pid, filter);
528
529 if (status == NOTIFY_STATUS_OK)
530 {
531 printf("Set %s syslog filter mask: %s\n", name, asl_filter_string(filter));
532 return 0;
533 }
534
535 printf("Unable to set %s syslog filter mask: %s\n", name, notify_status_string(status));
536 return -1;
537 }
538
539 status = rcontrol_set_string(prefix, pid, filter);
540 if (status == NOTIFY_STATUS_OK)
541 {
542 printf("Set process %d syslog filter mask set: %s\n", pid, asl_filter_string(filter));
543 return 0;
544 }
545
546 printf("Unable to set syslog filter mask for pid %d: %s\n", pid, notify_status_string(status));
547 return -1;
548 }
549
550 int
551 rsend(aslmsg msg, char *rhost)
552 {
553 char *str, *out;
554 uint32_t len, level;
555 char *timestr;
556 const char *val;
557 time_t tick;
558 struct tm gtime;
559 int s;
560 struct sockaddr_in dst;
561 struct hostent *h;
562 char myname[MAXHOSTNAMELEN + 1];
563
564 if (msg == NULL) return 0;
565
566 h = gethostbyname(rhost);
567 if (h == NULL) return -1;
568
569 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
570 if (s <= 0) return -1;
571
572 memset(&dst, 0, sizeof(struct sockaddr_in));
573 memcpy(&(dst.sin_addr.s_addr), h->h_addr_list[0], 4);
574 dst.sin_family = AF_INET;
575 dst.sin_port = 514;
576 dst.sin_len = sizeof(struct sockaddr_in);
577
578 level = ASL_LEVEL_DEBUG;
579
580 val = asl_get(msg, ASL_KEY_LEVEL);
581 if (val != NULL) level = atoi(val);
582
583 memset(&gtime, 0, sizeof(struct tm));
584 timestr = NULL;
585
586 tick = time(NULL);
587 gmtime_r(&tick, &gtime);
588
589 /* Canonical form: YYYY.MM.DD hh:mm:ss UTC */
590 asprintf(&timestr, "%d.%02d.%02d %02d:%02d:%02d UTC", gtime.tm_year + 1900, gtime.tm_mon + 1, gtime.tm_mday, gtime.tm_hour, gtime.tm_min, gtime.tm_sec);
591
592 if (timestr != NULL)
593 {
594 asl_set(msg, ASL_KEY_TIME, timestr);
595 free(timestr);
596 }
597
598 if (gethostname(myname, MAXHOSTNAMELEN) == 0) asl_set(msg, ASL_KEY_HOST, myname);
599
600 len = 0;
601 str = asl_msg_to_string(msg, &len);
602 if (str == NULL) return -1;
603
604 asprintf(&out, "%10u %s\n", len+1, str);
605 free(str);
606 if (out == NULL) return -1;
607
608 sendto(s, out, len+12, 0, (const struct sockaddr *)&dst, sizeof(struct sockaddr_in));
609
610 free(out);
611 close(s);
612 return 0;
613 }
614
615 int
616 rlegacy(char *msg, int level, char *rhost)
617 {
618 char *out;
619 uint32_t len;
620 time_t tick;
621 char *ltime;
622 int s;
623 struct sockaddr_in dst;
624 struct hostent *h;
625 char myname[MAXHOSTNAMELEN + 1];
626
627 if (msg == NULL) return 0;
628
629 h = gethostbyname(rhost);
630 if (h == NULL) return -1;
631
632 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
633 if (s <= 0) return -1;
634
635 memset(&dst, 0, sizeof(struct sockaddr_in));
636 memcpy(&(dst.sin_addr.s_addr), h->h_addr_list[0], 4);
637 dst.sin_family = AF_INET;
638 dst.sin_port = 514;
639 dst.sin_len = sizeof(struct sockaddr_in);
640
641 tick = time(NULL);
642 ltime = ctime(&tick);
643 ltime[19] = '\0';
644
645 gethostname(myname, MAXHOSTNAMELEN);
646
647 asprintf(&out, "<%d>%s %s syslog[%d]: %s", level, ltime+4, myname, getpid(), msg);
648 len = strlen(out);
649 sendto(s, out, len, 0, (const struct sockaddr *)&dst, sizeof(struct sockaddr_in));
650
651 free(out);
652 close(s);
653 return 0;
654 }
655
656 static int
657 _isanumber(char *s)
658 {
659 int i;
660
661 if (s == NULL) return 0;
662
663 i = 0;
664 if ((s[0] == '-') || (s[0] == '+')) i = 1;
665
666 if (s[i] == '\0') return 0;
667
668 for (; s[i] != '\0'; i++)
669 {
670 if (!isdigit(s[i])) return 0;
671 }
672
673 return 1;
674 }
675
676 int
677 asl_string_to_level(const char *s)
678 {
679 if (s == NULL) return -1;
680
681 if ((s[0] >= '0') && (s[0] <= '7') && (s[1] == '\0')) return atoi(s);
682
683 if (!strncasecmp(s, "em", 2)) return ASL_LEVEL_EMERG;
684 else if (!strncasecmp(s, "p", 1)) return ASL_LEVEL_EMERG;
685 else if (!strncasecmp(s, "a", 1)) return ASL_LEVEL_ALERT;
686 else if (!strncasecmp(s, "c", 1)) return ASL_LEVEL_CRIT;
687 else if (!strncasecmp(s, "er", 2)) return ASL_LEVEL_ERR;
688 else if (!strncasecmp(s, "x", 1)) return ASL_LEVEL_ERR;
689 else if (!strncasecmp(s, "w", 1)) return ASL_LEVEL_WARNING;
690 else if (!strncasecmp(s, "n", 1)) return ASL_LEVEL_NOTICE;
691 else if (!strncasecmp(s, "i", 1)) return ASL_LEVEL_INFO;
692 else if (!strncasecmp(s, "d", 1)) return ASL_LEVEL_DEBUG;
693
694 return -1;
695 }
696
697 int
698 syslog_remote_control(int argc, char *argv[])
699 {
700 int pid, uid, status, mask;
701 const char *prefix;
702
703 if ((argc < 3) || (argc > 4))
704 {
705 fprintf(stderr, "usage:\n");
706 fprintf(stderr, "%s -c process [mask]\n", myname);
707 fprintf(stderr, " get (set if mask is specified) syslog filter mask for process (pid or name)\n");
708 fprintf(stderr, " process may be pid or process name\n");
709 fprintf(stderr, " use \"-c 0\" to get master syslog filter mask\n");
710 fprintf(stderr, " use \"-c 0 off\" to disable master syslog filter mask\n");
711 fprintf(stderr, "\n");
712 return -1;
713 }
714
715 pid = RC_MASTER;
716 uid = -2;
717
718 status = PROC_NOT_FOUND;
719
720 if ((!strcmp(argv[2], "syslogd")) || (!strcmp(argv[2], "syslog")))
721 {
722 pid = RC_SYSLOGD;
723 uid = 0;
724 status = 0;
725 }
726 else if (_isanumber(argv[2]) != 0)
727 {
728 pid = atoi(argv[2]);
729 status = procinfo(NULL, &pid, &uid);
730 }
731 else
732 {
733 status = procinfo(argv[2], &pid, &uid);
734 }
735
736 if (status == PROC_NOT_FOUND)
737 {
738 fprintf(stderr, "%s: process not found\n", argv[2]);
739 return -1;
740 }
741
742 if (status == PROC_NOT_UNIQUE)
743 {
744 fprintf(stderr, "%s: multiple processes found\n", argv[2]);
745 fprintf(stderr, "use pid to identify a process uniquely\n");
746 return -1;
747 }
748
749 if (pid == 0) pid = RC_MASTER;
750
751 prefix = NOTIFY_PREFIX_USER;
752 if (uid == 0) prefix = NOTIFY_PREFIX_SYSTEM;
753
754 if (argc == 4)
755 {
756 if ((pid == RC_MASTER) && (!strcasecmp(argv[3], "off"))) mask = 0;
757 else if ((pid == RC_SYSLOGD) && (!strcasecmp(argv[3], "off"))) mask = 0;
758 else
759 {
760 mask = asl_string_to_filter(argv[3]);
761 if (mask < 0)
762 {
763 printf("unknown syslog mask: %s\n", argv[3]);
764 return -1;
765 }
766 }
767
768 rcontrol_set(prefix, pid, mask);
769 }
770 else
771 {
772 rcontrol_get(prefix, pid);
773 }
774
775 return 0;
776 }
777
778 int
779 syslog_send(int argc, char *argv[])
780 {
781 int i, start, kv, len, rfmt, rlevel;
782 aslclient asl;
783 aslmsg m;
784 char tmp[64], *str, *rhost;
785
786 kv = 0;
787 rhost = NULL;
788 rfmt = SEND_FORMAT_ASL;
789 start = 1;
790 rlevel = 7;
791
792 for (i = 1; i < argc; i++)
793 {
794 if (!strcmp(argv[i], "-s")) start = i+1;
795 else if (!strcmp(argv[i], "-k")) kv = 1;
796 else if (!strcmp(argv[i], "-r"))
797 {
798 rhost = argv[++i];
799 start = i+1;
800 rfmt = SEND_FORMAT_LEGACY;
801 }
802 else if (!strcmp(argv[i], "-R"))
803 {
804 rhost = argv[++i];
805 start = i+1;
806 }
807 else if (!strcmp(argv[i], "-l"))
808 {
809 rlevel = asl_string_to_level(argv[++i]);
810 if (rlevel < 0)
811 {
812 fprintf(stderr, "Unknown level: %s\n", argv[i]);
813 return(-1);
814 }
815 start = i+1;
816 }
817 }
818
819 asl = asl_open(myname, "syslog", 0);
820 asl_set_filter(asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
821
822 m = asl_new(ASL_TYPE_MSG);
823 asl_set(m, ASL_KEY_SENDER, myname);
824
825 sprintf(tmp, "%d", rlevel);
826 asl_set(m, ASL_KEY_LEVEL, tmp);
827
828 str = NULL;
829
830 if (kv == 0)
831 {
832 len = 0;
833 for (i = start; i < argc; i++) len += (strlen(argv[i]) + 1);
834 str = calloc(len + 1, 1);
835 for (i = start; i < argc; i++)
836 {
837 strcat(str, argv[i]);
838 if ((i+1) < argc) strcat(str, " ");
839 }
840 asl_set(m, ASL_KEY_MSG, str);
841 }
842 else
843 {
844 for (i = start + 1; i < argc; i += 2) asl_set(m, argv[i], argv[i + 1]);
845 }
846
847 if (rhost == NULL)
848 {
849 asl_send(asl, m);
850 }
851 else if (rfmt == SEND_FORMAT_ASL)
852 {
853 rsend(m, rhost);
854 }
855 else if ((rfmt == SEND_FORMAT_LEGACY) && (str != NULL))
856 {
857 rlegacy(str, rlevel, rhost);
858 }
859
860 asl_free(m);
861
862 if (str != NULL) free(str);
863
864 asl_close(asl);
865
866 return 0;
867 }
868
869 static void
870 printmsg(FILE *f, asl_msg_t *msg, char *mstr, char *fmt, int pflags)
871 {
872 char *k, *t, c;
873 const char *v;
874 int i, j, l, paren, oval;
875 time_t tick;
876
877 if ((pflags & PRINT_STD_FMT) || (pflags & PRINT_LEGACY_FMT))
878 {
879 /* LEGACY: Mth dd hh:mm:ss host sender[pid]: message */
880 /* STD: Mth dd hh:mm:ss host sender[pid] <Level>: message */
881
882 /* Time */
883 v = asl_get(msg, ASL_KEY_TIME);
884 tick = 0;
885 if (v == NULL)
886 {
887 fprintf(f, "***Time unknown ");
888 }
889 else
890 {
891 tick = asl_parse_time(v);
892 t = ctime(&tick);
893 if (t == NULL) fprintf(f, "***Time unknown ");
894 else
895 {
896 t[19] = '\0';
897 fprintf(f, "%s ", t + 4);
898 }
899 }
900
901 /* Host */
902 v = asl_get(msg, ASL_KEY_HOST);
903 if (v != NULL) fprintf(f, "%s ", v);
904
905 /* Sender */
906 v = asl_get(msg, ASL_KEY_SENDER);
907 if (v != NULL) fprintf(f, "%s", v);
908
909 /* PID */
910 v = asl_get(msg, ASL_KEY_PID);
911 if ((v != NULL) && (v[0] != '-')) fprintf(f, "[%s]", v);
912
913 v = asl_get(msg, ASL_KEY_LEVEL);
914 i = -1;
915 if (_isanumber((char *)v)) i = atoi(v);
916 if (pflags & PRINT_STD_FMT) fprintf(f, " <%s>", asl_level_string(i));
917
918 fprintf(f, ": ");
919
920 /* Message */
921 v = asl_get(msg, ASL_KEY_MSG);
922 if (v != NULL) fprintf(f, "%s", v);
923
924 fprintf(f, "\n");
925 return;
926 }
927
928 if (fmt == NULL)
929 {
930 fprintf(f, "%s\n", mstr);
931 return;
932 }
933
934 for (i = 0; fmt[i] != '\0'; i++)
935 {
936 if (fmt[i] == '$')
937 {
938 i++;
939 paren = 0;
940
941 if (fmt[i] == '(')
942 {
943 paren = 1;
944 i++;
945 }
946
947 k = calloc(1, 1);
948 l = 0;
949
950 for (j = i; fmt[j] != '\0'; j++)
951 {
952 c = '\0';
953 if (fmt[j] == '\\') c = fmt[++j];
954 else if ((paren == 1) && (fmt[j] ==')')) break;
955 else if (fmt[j] != ' ') c = fmt[j];
956
957 if (c == '\0') break;
958
959 k = realloc(k, l + 1);
960 k[l] = c;
961 k[l + 1] = '\0';
962 l++;
963 }
964
965 if (paren == 1) j++;
966 i = j;
967 if (l > 0)
968 {
969 v = asl_get(msg, k);
970 if (v != NULL)
971 {
972 if ((pflags & PRINT_LOCALTIME) && (!strcmp(k, ASL_KEY_TIME)))
973 {
974 /* convert UTC time to localtime */
975 tick = asl_parse_time(v);
976 t = ctime(&tick);
977 if (t == NULL) fprintf(f, "%s", v);
978 else
979 {
980 t[19] = '\0';
981 fprintf(f, "%s", t + 4);
982 }
983 }
984 else
985 {
986 fprintf(f, "%s", v);
987 }
988 }
989 }
990 free(k);
991 }
992
993 if (fmt[i] == '\\')
994 {
995 i++;
996 if (fmt[i] == '$') fprintf(f, "$");
997 else if (fmt[i] == 'e') fprintf(f, "\e");
998 else if (fmt[i] == 'a') fprintf(f, "\a");
999 else if (fmt[i] == 'b') fprintf(f, "\b");
1000 else if (fmt[i] == 'f') fprintf(f, "\f");
1001 else if (fmt[i] == 'n') fprintf(f, "\n");
1002 else if (fmt[i] == 'r') fprintf(f, "\r");
1003 else if (fmt[i] == 't') fprintf(f, "\t");
1004 else if (fmt[i] == 'v') fprintf(f, "\v");
1005 else if (fmt[i] == '\'') fprintf(f, "\'");
1006 else if (fmt[i] == '\\') fprintf(f, "\\");
1007 else if (isdigit(fmt[i]))
1008 {
1009 oval = fmt[i] - '0';
1010 if (isdigit(fmt[i+1]))
1011 {
1012 i++;
1013 oval = (oval * 8) + (fmt[i] - '0');
1014 if (isdigit(fmt[i+1]))
1015 {
1016 i++;
1017 oval = (oval * 8) + (fmt[i] - '0');
1018 }
1019 }
1020 c = oval;
1021 fputc(c, stdout);
1022 }
1023 continue;
1024 }
1025
1026 if (fmt[i] == '\0') break;
1027 fputc(fmt[i], stdout);
1028 }
1029
1030 fprintf(f, "\n");
1031 }
1032
1033 static char *
1034 getnextline(FILE *fp, int watch)
1035 {
1036 char *out, c;
1037 int len, count;
1038
1039 len = CHUNK;
1040 count = 0;
1041 out = calloc(len + 1, 1);
1042
1043 forever
1044 {
1045 c = getc(fp);
1046 if (c == EOF)
1047 {
1048 if (watch == 0)
1049 {
1050 if (count == 0)
1051 {
1052 free(out);
1053 return NULL;
1054 }
1055 return out;
1056 }
1057 clearerr(fp);
1058 usleep(250000);
1059 continue;
1060 }
1061
1062 if (c == '\n') return out;
1063 if (c == '\0') return out;
1064
1065 if (count == len)
1066 {
1067 len += CHUNK;
1068 out = realloc(out, len + 1);
1069 }
1070
1071 out[count++] = c;
1072 out[count] = '\0';
1073 }
1074
1075 return NULL;
1076 }
1077
1078 int
1079 search_next(asl_msg_t **q, int nq, FILE *log, int watch, aslmsg *outmsg, char **outstr)
1080 {
1081 char *str;
1082 aslmsg m;
1083 int i, match;
1084
1085 *outmsg = NULL;
1086 *outstr = NULL;
1087
1088 if (log == NULL) return SEARCH_EOF;
1089
1090 str = getnextline(log, watch);
1091 if (str == NULL) return SEARCH_EOF;
1092
1093 m = asl_msg_from_string(str);
1094 if (m == NULL)
1095 {
1096 free(str);
1097 return SEARCH_NULL;
1098 }
1099
1100 match = 0;
1101 if (q == NULL) match = 1;
1102 for (i = 0; (i < nq) && (match == 0); i++)
1103 {
1104 match = asl_msg_cmp(q[i], m);
1105 if ((q[i]->count > 0) && (q[i]->op[0] & ASL_QUERY_OP_NOT))
1106 {
1107 match = !match;
1108 }
1109 }
1110
1111 if (match == 0)
1112 {
1113 free(str);
1114 asl_free(m);
1115 return SEARCH_NULL;
1116 }
1117
1118 *outmsg = m;
1119 *outstr = str;
1120 return SEARCH_MATCH;
1121 }
1122
1123 uint32_t
1124 optype(char *o)
1125 {
1126 uint32_t op, i;
1127
1128 op = ASL_QUERY_OP_NULL;
1129
1130 if (o == NULL) return op;
1131
1132 for (i = 0; o[i] != '\0'; i++)
1133 {
1134 if (o[i] == MOD_CASE_FOLD) op |= ASL_QUERY_OP_CASEFOLD;
1135 else if (o[i] == MOD_REGEX) op |= ASL_QUERY_OP_REGEX;
1136 else if (o[i] == MOD_NUMERIC) op |= ASL_QUERY_OP_NUMERIC;
1137 else if (o[i] == MOD_SUBSTRING) op |= ASL_QUERY_OP_SUBSTRING;
1138 else if (o[i] == MOD_PREFIX) op |= ASL_QUERY_OP_PREFIX;
1139 else if (o[i] == MOD_SUFFIX) op |= ASL_QUERY_OP_SUFFIX;
1140
1141 else if (!strncasecmp(o+i, OP_EQ, sizeof(OP_EQ)))
1142 {
1143 op |= ASL_QUERY_OP_EQUAL;
1144 i += (sizeof(OP_EQ) - 2);
1145 }
1146 else if (!strncasecmp(o+i, OP_NE, sizeof(OP_NE)))
1147 {
1148 op |= ASL_QUERY_OP_NOT_EQUAL;
1149 i += (sizeof(OP_NE) - 2);
1150 }
1151 else if (!strncasecmp(o+i, OP_GT, sizeof(OP_GT)))
1152 {
1153 op |= ASL_QUERY_OP_GREATER;
1154 i += (sizeof(OP_GT) - 2);
1155 }
1156 else if (!strncasecmp(o+i, OP_GE, sizeof(OP_GE)))
1157 {
1158 op |= ASL_QUERY_OP_GREATER_EQUAL;
1159 i += (sizeof(OP_GE) - 2);
1160 }
1161 else if (!strncasecmp(o+i, OP_LT, sizeof(OP_LT)))
1162 {
1163 op |= ASL_QUERY_OP_LESS;
1164 i += (sizeof(OP_LT) - 2);
1165 }
1166 else if (!strncasecmp(o+i, OP_LE, sizeof(OP_LE)))
1167 {
1168 op |= ASL_QUERY_OP_LESS_EQUAL;
1169 i += (sizeof(OP_LE) - 2);
1170 }
1171 else
1172 {
1173 fprintf(stderr, "invalid option: %s\n", o);
1174 return 0;
1175 }
1176 }
1177
1178 /* sanity check */
1179 if (op & ASL_QUERY_OP_NUMERIC)
1180 {
1181 if (op & ASL_QUERY_OP_CASEFOLD)
1182 {
1183 fprintf(stderr, "warning: case fold modifier has no effect with numeric comparisons\n");
1184 op &= ~ASL_QUERY_OP_CASEFOLD;
1185 }
1186
1187 if (op & ASL_QUERY_OP_REGEX)
1188 {
1189 fprintf(stderr, "warning: regex modifier has no effect with numeric comparisons\n");
1190 op &= ~ASL_QUERY_OP_REGEX;
1191 }
1192
1193 if (op & ASL_QUERY_OP_SUBSTRING)
1194 {
1195 fprintf(stderr, "warning: substring modifier has no effect with numeric comparisons\n");
1196 op &= ~ASL_QUERY_OP_SUBSTRING;
1197 }
1198
1199 if (op & ASL_QUERY_OP_PREFIX)
1200 {
1201 fprintf(stderr, "warning: prefix modifier has no effect with numeric comparisons\n");
1202 op &= ~ASL_QUERY_OP_PREFIX;
1203 }
1204
1205 if (op & ASL_QUERY_OP_SUFFIX)
1206 {
1207 fprintf(stderr, "warning: suffix modifier has no effect with numeric comparisons\n");
1208 op &= ~ASL_QUERY_OP_SUFFIX;
1209 }
1210 }
1211
1212 if (op & ASL_QUERY_OP_REGEX)
1213 {
1214 if (op & ASL_QUERY_OP_SUBSTRING)
1215 {
1216 fprintf(stderr, "warning: substring modifier has no effect with regular expression comparisons\n");
1217 op &= ~ASL_QUERY_OP_SUBSTRING;
1218 }
1219
1220 if (op & ASL_QUERY_OP_PREFIX)
1221 {
1222 fprintf(stderr, "warning: prefix modifier has no effect with regular expression comparisons\n");
1223 op &= ~ASL_QUERY_OP_PREFIX;
1224 }
1225
1226 if (op & ASL_QUERY_OP_SUFFIX)
1227 {
1228 fprintf(stderr, "warning: suffix modifier has no effect with regular expression comparisons\n");
1229 op &= ~ASL_QUERY_OP_SUFFIX;
1230 }
1231 }
1232
1233 return op;
1234 }
1235
1236 int
1237 add_op(asl_msg_t *q, char *key, char *op, char *val, uint32_t flags)
1238 {
1239 uint32_t o;
1240
1241 if (key == NULL) return -1;
1242 if (q == NULL) return -1;
1243
1244 o = ASL_QUERY_OP_NULL;
1245 if (op != NULL)
1246 {
1247 o = optype(op);
1248 if (o == ASL_QUERY_OP_NULL) return -1;
1249 if (val == NULL)
1250 {
1251 fprintf(stderr, "no value supplied for operator %s %s\n", key, op);
1252 return -1;
1253 }
1254
1255 if ((o & ASL_QUERY_OP_NUMERIC) && (_isanumber(val) == 0))
1256 {
1257 fprintf(stderr, "non-numeric value supplied for numeric operator %s %s %s\n", key, op, val);
1258 return -1;
1259 }
1260
1261 }
1262
1263 o |= flags;
1264 asl_set_query(q, key, val, o);
1265
1266 return 0;
1267 }
1268
1269 int
1270 main(int argc, char *argv[])
1271 {
1272 FILE *log, *pf, *outfile;
1273 int i, j, n, qcount, qn, watch, prune, status, pflags, tflag;
1274 asl_msg_t **qlist, *outmsg;
1275 char *logname, *outname, *pfmt, *outstr;
1276 pid_t syslogd_pid;
1277 uint32_t flags;
1278
1279 qn = 0;
1280 watch = 0;
1281 prune = 0;
1282 logname = _PATH_ASL_OUT;
1283 qlist = NULL;
1284 qcount = 0;
1285 pfmt = NULL;
1286 flags = 0;
1287 pflags = PRINT_STD_FMT;
1288 tflag = PRINT_LOCALTIME;
1289
1290 for (i = 1; i < argc; i++)
1291 {
1292 if (!strcmp(argv[i], "-s"))
1293 {
1294 syslog_send(argc, argv);
1295 exit(0);
1296 }
1297
1298 if (!strcmp(argv[i], "-c"))
1299 {
1300 syslog_remote_control(argc, argv);
1301 exit(0);
1302 }
1303 }
1304
1305 for (i = 1; i < argc; i++)
1306 {
1307 if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help")))
1308 {
1309 usage();
1310 exit(0);
1311 }
1312 else if (!strcmp(argv[i], "-w"))
1313 {
1314 watch = 1;
1315 }
1316 else if (!strcmp(argv[i], "-u"))
1317 {
1318 tflag = 0;
1319 }
1320 else if (!strcmp(argv[i], "-p"))
1321 {
1322 prune = 1;
1323 }
1324 else if (!strcmp(argv[i], "-f"))
1325 {
1326 if ((i + 1) >= argc)
1327 {
1328 usage();
1329 exit(1);
1330 }
1331
1332 logname = argv[++i];
1333 }
1334 else if (!strcmp(argv[i], "-F"))
1335 {
1336 if ((i + 1) >= argc)
1337 {
1338 usage();
1339 exit(1);
1340 }
1341
1342 i++;
1343 if (!strcmp(argv[i], "raw"))
1344 {
1345 pflags = 0;
1346 tflag = 0;
1347 }
1348 else if (!strcmp(argv[i], "std"))
1349 {
1350 pflags = PRINT_STD_FMT;
1351 }
1352 else if (!strcmp(argv[i], "bsd"))
1353 {
1354 pflags = PRINT_LEGACY_FMT;
1355 }
1356 else
1357 {
1358 pflags = 0;
1359 pfmt = argv[i];
1360 }
1361 }
1362 else if (!strcmp(argv[i], "-o"))
1363 {
1364 flags = 0;
1365
1366 if (qlist == NULL)
1367 {
1368 qlist = (asl_msg_t **)calloc(1, sizeof(asl_msg_t *));
1369 }
1370 else
1371 {
1372 qlist = (asl_msg_t **)realloc(qlist, (qcount + 1) * sizeof(asl_msg_t *));
1373 }
1374
1375 qcount++;
1376 qn = qcount - 1;
1377 qlist[qn] = asl_new(ASL_TYPE_QUERY);
1378 }
1379 else if (!strcmp(argv[i], "-n"))
1380 {
1381 flags = ASL_QUERY_OP_NOT;
1382 }
1383 else if (!strcmp(argv[i], "-k"))
1384 {
1385 i++;
1386 for (n = i; n < argc; n++)
1387 {
1388 if (!strcmp(argv[n], "-o")) break;
1389 if (!strcmp(argv[n], "-n")) break;
1390 if (!strcmp(argv[n], "-k")) break;
1391 if ((n - i) > 2)
1392 {
1393 fprintf(stderr, "invalid sequence: -k");
1394 for (j = i; j <= n; j++) fprintf(stderr, " %s", argv[j]);
1395 fprintf(stderr, "\n");
1396 usage();
1397 exit(1);
1398 }
1399 }
1400
1401 n -= i;
1402 if (n == 0)
1403 {
1404 i--;
1405 continue;
1406 }
1407
1408 if (qlist == NULL)
1409 {
1410 qlist = (asl_msg_t **)calloc(1, sizeof(asl_msg_t *));
1411 qcount = 1;
1412 qn = 0;
1413 qlist[qn] = asl_new(ASL_TYPE_QUERY);
1414 }
1415
1416 status = 0;
1417 if (n == 1) status = add_op(qlist[qn], argv[i], NULL, NULL, flags);
1418 else if (n == 2) status = add_op(qlist[qn], argv[i], OP_EQ, argv[i+1], flags);
1419 else status = add_op(qlist[qn], argv[i], argv[i+1], argv[i+2], flags);
1420
1421 flags = 0;
1422 if (status != 0) exit(1);
1423 }
1424 }
1425
1426 pflags |= tflag;
1427
1428 if (prune == 1)
1429 {
1430 if (watch == 1)
1431 {
1432 fprintf(stderr, "-w flag has no effect when pruning log file\n");
1433 }
1434
1435 if (getuid() != 0)
1436 {
1437 fprintf(stderr, "you must be root to prune the log file\n");
1438 exit(1);
1439 }
1440
1441 if (qlist == NULL)
1442 {
1443 fprintf(stderr, "no queries for pruning\n");
1444 exit(0);
1445 }
1446
1447 pf = fopen(_PATH_SYSLOGD_PID, "r");
1448 if (pf == NULL)
1449 {
1450 perror(_PATH_SYSLOGD_PID);
1451 exit(1);
1452 }
1453
1454 status = fscanf(pf, "%d", &syslogd_pid);
1455 fclose(pf);
1456 if (status != 1)
1457 {
1458 fprintf(stderr, "can't read syslogd pid from %s\n", _PATH_SYSLOGD_PID);
1459 exit(1);
1460 }
1461
1462 unlink(_PATH_ASL_PRUNE);
1463 pf = fopen(_PATH_ASL_PRUNE, "w");
1464 if (pf == NULL)
1465 {
1466 perror(_PATH_ASL_PRUNE);
1467 exit(1);
1468 }
1469
1470 for (i = 0; i < qcount; i++)
1471 {
1472 outstr = asl_msg_to_string(qlist[i], &j);
1473 fprintf(pf, "%s\n", outstr);
1474 free(outstr);
1475 }
1476
1477 fclose(pf);
1478
1479 kill(syslogd_pid, SIGWINCH);
1480
1481 exit(0);
1482 }
1483
1484 log = NULL;
1485
1486 if (!strcmp(logname, "-")) log = stdin;
1487 else log = fopen(logname, "r");
1488
1489 if (log == NULL)
1490 {
1491 perror(logname);
1492 exit(1);
1493 }
1494
1495 if (watch == 1) fseek(log, 0, SEEK_END);
1496 outname = NULL;
1497 outfile = stdout;
1498
1499 do
1500 {
1501 outmsg = NULL;
1502 outstr = NULL;
1503 status = search_next(qlist, qcount, log, watch, &outmsg, &outstr);
1504
1505 if (status == SEARCH_MATCH)
1506 {
1507 printmsg(outfile, outmsg, outstr, pfmt, pflags);
1508 }
1509
1510 if (outstr != NULL) free(outstr);
1511 if (outmsg != NULL) asl_free(outmsg);
1512 }
1513 while (status != SEARCH_EOF);
1514
1515 fclose(log);
1516
1517 for (i = 0; i < qcount; i++) asl_free(qlist[i]);
1518 if (qlist != NULL) free(qlist);
1519
1520 exit(0);
1521 }