2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
32 #include <sys/socket.h>
33 #include <sys/sysctl.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
39 #include <asl_private.h>
41 #define MOD_CASE_FOLD 'C'
43 #define MOD_SUBSTRING 'S'
44 #define MOD_PREFIX 'A'
45 #define MOD_SUFFIX 'Z'
46 #define MOD_NUMERIC 'N'
55 #define ASL_QUERY_OP_NOT 0x1000
59 #define SEARCH_MATCH 1
61 #define PROC_NOT_FOUND -1
62 #define PROC_NOT_UNIQUE -2
68 #define forever for(;;)
70 #define SEND_FORMAT_LEGACY 0
71 #define SEND_FORMAT_ASL 1
73 #define PRINT_LOCALTIME 0x00000001
74 #define PRINT_LEGACY_FMT 0x00000002
75 #define PRINT_STD_FMT 0x00000004
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
85 /* BEGIN PRIVATE API */
86 #define _PATH_ASL_PRUNE "/var/run/asl_prune"
87 #define _PATH_SYSLOGD_PID "/var/run/syslog.pid"
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
);
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
);
100 static const char *myname
= "syslog";
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
);
156 notify_status_string(int status
)
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";
165 asl_level_string(int level
)
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
;
179 procinfo(char *pname
, int *pid
, int *uid
)
182 int i
, status
, nprocs
;
184 struct kinfo_proc
*procs
, *newprocs
;
191 mib
[2] = KERN_PROC_ALL
;
195 status
= sysctl(mib
, miblen
, NULL
, &size
, NULL
, 0);
199 newprocs
= realloc(procs
, size
);
202 if (procs
!= NULL
) free(procs
);
203 return PROC_NOT_FOUND
;
207 status
= sysctl(mib
, miblen
, procs
, &size
, NULL
, 0);
208 } while ((status
== -1) && (errno
== ENOMEM
));
212 if (procs
!= NULL
) free(procs
);
213 return PROC_NOT_FOUND
;
216 if (size
% sizeof(struct kinfo_proc
) != 0)
218 if (procs
!= NULL
) free(procs
);
219 return PROC_NOT_FOUND
;
222 if (procs
== NULL
) return PROC_NOT_FOUND
;
224 nprocs
= size
/ sizeof(struct kinfo_proc
);
228 /* Search for a pid */
229 for (i
= 0; i
< nprocs
; i
++)
231 if (*pid
== procs
[i
].kp_proc
.p_pid
)
233 *uid
= procs
[i
].kp_eproc
.e_ucred
.cr_uid
;
238 return PROC_NOT_FOUND
;
241 *pid
= PROC_NOT_FOUND
;
243 for (i
= 0; i
< nprocs
; i
++)
245 if (!strcmp(procs
[i
].kp_proc
.p_comm
, pname
))
247 if (*pid
!= PROC_NOT_FOUND
)
250 return PROC_NOT_UNIQUE
;
253 *pid
= procs
[i
].kp_proc
.p_pid
;
254 *uid
= procs
[i
].kp_eproc
.e_ucred
.cr_uid
;
259 if (*pid
== PROC_NOT_FOUND
) return PROC_NOT_FOUND
;
265 rcontrol_get_string(const char *prefix
, int pid
, int *val
)
270 status
= NOTIFY_STATUS_OK
;
272 if (pid
== RC_SYSLOGD
)
274 status
= notify_register_plain(NOTIFY_SYSTEM_ASL_FILTER
, &t
);
276 else if (pid
== RC_MASTER
)
278 status
= notify_register_plain(NOTIFY_SYSTEM_MASTER
, &t
);
283 asprintf(&name
, "%s.%d", prefix
, pid
);
284 if (name
== NULL
) return NOTIFY_STATUS_FAILED
;
286 status
= notify_register_plain(name
, &t
);
290 if (status
!= NOTIFY_STATUS_OK
) return status
;
293 status
= notify_get_state(t
, &x
);
302 rcontrol_set_string(const char *prefix
, int pid
, int filter
)
307 status
= NOTIFY_STATUS_OK
;
309 if (pid
== RC_SYSLOGD
)
311 status
= notify_register_plain(NOTIFY_SYSTEM_ASL_FILTER
, &t
);
313 else if (pid
== RC_MASTER
)
315 status
= notify_register_plain(NOTIFY_SYSTEM_MASTER
, &t
);
320 asprintf(&name
, "%s.%d", prefix
, pid
);
321 if (name
== NULL
) return NOTIFY_STATUS_FAILED
;
323 status
= notify_register_plain(name
, &t
);
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
);
335 asl_string_to_filter(char *s
)
339 if (s
== NULL
) return 0;
340 if (s
[0] == '\0') return 0;
342 if ((s
[0] >= '0') && (s
[0] <= '9')) return ASL_FILTER_MASK(atoi(s
));
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
);
361 for (i
= 0; s
[i
] != '\0'; i
++)
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
;
378 asl_filter_string(int f
)
380 static char str
[1024];
383 memset(str
, 0, sizeof(str
));
386 if ((f
== ASL_FILTER_MASK_PACEWNID
) != 0)
388 strcat(str
, "Emergency - Debug");
392 if ((f
== ASL_FILTER_MASK_PACEWNI
) != 0)
394 strcat(str
, "Emergency - Info");
398 if ((f
== ASL_FILTER_MASK_PACEWN
) != 0)
400 strcat(str
, "Emergency - Notice");
404 if ((f
== ASL_FILTER_MASK_PACEW
) != 0)
406 strcat(str
, "Emergency - Warning");
410 if ((f
== ASL_FILTER_MASK_PACE
) != 0)
412 strcat(str
, "Emergency - Error");
416 if ((f
== ASL_FILTER_MASK_PAC
) != 0)
418 strcat(str
, "Emergency - Critical");
422 if ((f
& ASL_FILTER_MASK_EMERG
) != 0)
424 strcat(str
, "Emergency");
428 if ((f
& ASL_FILTER_MASK_ALERT
) != 0)
430 if (i
> 0) strcat(str
, ", ");
431 strcat(str
, "Alert");
435 if ((f
& ASL_FILTER_MASK_CRIT
) != 0)
437 if (i
> 0) strcat(str
, ", ");
438 strcat(str
, "Critical");
442 if ((f
& ASL_FILTER_MASK_ERR
) != 0)
444 if (i
> 0) strcat(str
, ", ");
445 strcat(str
, "Error");
449 if ((f
& ASL_FILTER_MASK_WARNING
) != 0)
451 if (i
> 0) strcat(str
, ", ");
452 strcat(str
, "Warning");
456 if ((f
& ASL_FILTER_MASK_NOTICE
) != 0)
458 if (i
> 0) strcat(str
, ", ");
459 strcat(str
, "Notice");
463 if ((f
& ASL_FILTER_MASK_INFO
) != 0)
465 if (i
> 0) strcat(str
, ", ");
470 if ((f
& ASL_FILTER_MASK_DEBUG
) != 0)
472 if (i
> 0) strcat(str
, ", ");
473 strcat(str
, "Debug");
477 if (i
== 0) sprintf(str
, "Off");
483 rcontrol_get(const char *prefix
, int pid
)
493 if (pid
== RC_SYSLOGD
) name
= "ASL Data Store";
495 status
= rcontrol_get_string(NULL
, pid
, &filter
);
496 if (status
== NOTIFY_STATUS_OK
)
498 printf("%s filter mask: %s\n", name
, asl_filter_string(filter
));
502 printf("Unable to determine %s filter mask\n", name
);
506 status
= rcontrol_get_string(prefix
, pid
, &filter
);
507 if (status
== NOTIFY_STATUS_OK
)
509 printf("Process %d syslog filter mask: %s\n", pid
, asl_filter_string(filter
));
513 printf("Unable to determine syslog filter mask for pid %d\n", pid
);
518 rcontrol_set(const char *prefix
, int pid
, int filter
)
526 if (pid
== RC_SYSLOGD
) name
= "ASL Data Store";
527 status
= rcontrol_set_string(NULL
, pid
, filter
);
529 if (status
== NOTIFY_STATUS_OK
)
531 printf("Set %s syslog filter mask: %s\n", name
, asl_filter_string(filter
));
535 printf("Unable to set %s syslog filter mask: %s\n", name
, notify_status_string(status
));
539 status
= rcontrol_set_string(prefix
, pid
, filter
);
540 if (status
== NOTIFY_STATUS_OK
)
542 printf("Set process %d syslog filter mask set: %s\n", pid
, asl_filter_string(filter
));
546 printf("Unable to set syslog filter mask for pid %d: %s\n", pid
, notify_status_string(status
));
551 rsend(aslmsg msg
, char *rhost
)
560 struct sockaddr_in dst
;
562 char myname
[MAXHOSTNAMELEN
+ 1];
564 if (msg
== NULL
) return 0;
566 h
= gethostbyname(rhost
);
567 if (h
== NULL
) return -1;
569 s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
570 if (s
<= 0) return -1;
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
;
576 dst
.sin_len
= sizeof(struct sockaddr_in
);
578 level
= ASL_LEVEL_DEBUG
;
580 val
= asl_get(msg
, ASL_KEY_LEVEL
);
581 if (val
!= NULL
) level
= atoi(val
);
583 memset(>ime
, 0, sizeof(struct tm
));
587 gmtime_r(&tick
, >ime
);
589 /* Canonical form: YYYY.MM.DD hh:mm:ss UTC */
590 asprintf(×tr
, "%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
);
594 asl_set(msg
, ASL_KEY_TIME
, timestr
);
598 if (gethostname(myname
, MAXHOSTNAMELEN
) == 0) asl_set(msg
, ASL_KEY_HOST
, myname
);
601 str
= asl_msg_to_string(msg
, &len
);
602 if (str
== NULL
) return -1;
604 asprintf(&out
, "%10u %s\n", len
+1, str
);
606 if (out
== NULL
) return -1;
608 sendto(s
, out
, len
+12, 0, (const struct sockaddr
*)&dst
, sizeof(struct sockaddr_in
));
616 rlegacy(char *msg
, int level
, char *rhost
)
623 struct sockaddr_in dst
;
625 char myname
[MAXHOSTNAMELEN
+ 1];
627 if (msg
== NULL
) return 0;
629 h
= gethostbyname(rhost
);
630 if (h
== NULL
) return -1;
632 s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
633 if (s
<= 0) return -1;
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
;
639 dst
.sin_len
= sizeof(struct sockaddr_in
);
642 ltime
= ctime(&tick
);
645 gethostname(myname
, MAXHOSTNAMELEN
);
647 asprintf(&out
, "<%d>%s %s syslog[%d]: %s", level
, ltime
+4, myname
, getpid(), msg
);
649 sendto(s
, out
, len
, 0, (const struct sockaddr
*)&dst
, sizeof(struct sockaddr_in
));
661 if (s
== NULL
) return 0;
664 if ((s
[0] == '-') || (s
[0] == '+')) i
= 1;
666 if (s
[i
] == '\0') return 0;
668 for (; s
[i
] != '\0'; i
++)
670 if (!isdigit(s
[i
])) return 0;
677 asl_string_to_level(const char *s
)
679 if (s
== NULL
) return -1;
681 if ((s
[0] >= '0') && (s
[0] <= '7') && (s
[1] == '\0')) return atoi(s
);
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
;
698 syslog_remote_control(int argc
, char *argv
[])
700 int pid
, uid
, status
, mask
;
703 if ((argc
< 3) || (argc
> 4))
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");
718 status
= PROC_NOT_FOUND
;
720 if ((!strcmp(argv
[2], "syslogd")) || (!strcmp(argv
[2], "syslog")))
726 else if (_isanumber(argv
[2]) != 0)
729 status
= procinfo(NULL
, &pid
, &uid
);
733 status
= procinfo(argv
[2], &pid
, &uid
);
736 if (status
== PROC_NOT_FOUND
)
738 fprintf(stderr
, "%s: process not found\n", argv
[2]);
742 if (status
== PROC_NOT_UNIQUE
)
744 fprintf(stderr
, "%s: multiple processes found\n", argv
[2]);
745 fprintf(stderr
, "use pid to identify a process uniquely\n");
749 if (pid
== 0) pid
= RC_MASTER
;
751 prefix
= NOTIFY_PREFIX_USER
;
752 if (uid
== 0) prefix
= NOTIFY_PREFIX_SYSTEM
;
756 if ((pid
== RC_MASTER
) && (!strcasecmp(argv
[3], "off"))) mask
= 0;
757 else if ((pid
== RC_SYSLOGD
) && (!strcasecmp(argv
[3], "off"))) mask
= 0;
760 mask
= asl_string_to_filter(argv
[3]);
763 printf("unknown syslog mask: %s\n", argv
[3]);
768 rcontrol_set(prefix
, pid
, mask
);
772 rcontrol_get(prefix
, pid
);
779 syslog_send(int argc
, char *argv
[])
781 int i
, start
, kv
, len
, rfmt
, rlevel
;
784 char tmp
[64], *str
, *rhost
;
788 rfmt
= SEND_FORMAT_ASL
;
792 for (i
= 1; i
< argc
; i
++)
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"))
800 rfmt
= SEND_FORMAT_LEGACY
;
802 else if (!strcmp(argv
[i
], "-R"))
807 else if (!strcmp(argv
[i
], "-l"))
809 rlevel
= asl_string_to_level(argv
[++i
]);
812 fprintf(stderr
, "Unknown level: %s\n", argv
[i
]);
819 asl
= asl_open(myname
, "syslog", 0);
820 asl_set_filter(asl
, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
));
822 m
= asl_new(ASL_TYPE_MSG
);
823 asl_set(m
, ASL_KEY_SENDER
, myname
);
825 sprintf(tmp
, "%d", rlevel
);
826 asl_set(m
, ASL_KEY_LEVEL
, tmp
);
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
++)
837 strcat(str
, argv
[i
]);
838 if ((i
+1) < argc
) strcat(str
, " ");
840 asl_set(m
, ASL_KEY_MSG
, str
);
844 for (i
= start
+ 1; i
< argc
; i
+= 2) asl_set(m
, argv
[i
], argv
[i
+ 1]);
851 else if (rfmt
== SEND_FORMAT_ASL
)
855 else if ((rfmt
== SEND_FORMAT_LEGACY
) && (str
!= NULL
))
857 rlegacy(str
, rlevel
, rhost
);
862 if (str
!= NULL
) free(str
);
870 printmsg(FILE *f
, asl_msg_t
*msg
, char *mstr
, char *fmt
, int pflags
)
874 int i
, j
, l
, paren
, oval
;
877 if ((pflags
& PRINT_STD_FMT
) || (pflags
& PRINT_LEGACY_FMT
))
879 /* LEGACY: Mth dd hh:mm:ss host sender[pid]: message */
880 /* STD: Mth dd hh:mm:ss host sender[pid] <Level>: message */
883 v
= asl_get(msg
, ASL_KEY_TIME
);
887 fprintf(f
, "***Time unknown ");
891 tick
= asl_parse_time(v
);
893 if (t
== NULL
) fprintf(f
, "***Time unknown ");
897 fprintf(f
, "%s ", t
+ 4);
902 v
= asl_get(msg
, ASL_KEY_HOST
);
903 if (v
!= NULL
) fprintf(f
, "%s ", v
);
906 v
= asl_get(msg
, ASL_KEY_SENDER
);
907 if (v
!= NULL
) fprintf(f
, "%s", v
);
910 v
= asl_get(msg
, ASL_KEY_PID
);
911 if ((v
!= NULL
) && (v
[0] != '-')) fprintf(f
, "[%s]", v
);
913 v
= asl_get(msg
, ASL_KEY_LEVEL
);
915 if (_isanumber((char *)v
)) i
= atoi(v
);
916 if (pflags
& PRINT_STD_FMT
) fprintf(f
, " <%s>", asl_level_string(i
));
921 v
= asl_get(msg
, ASL_KEY_MSG
);
922 if (v
!= NULL
) fprintf(f
, "%s", v
);
930 fprintf(f
, "%s\n", mstr
);
934 for (i
= 0; fmt
[i
] != '\0'; i
++)
950 for (j
= i
; fmt
[j
] != '\0'; j
++)
953 if (fmt
[j
] == '\\') c
= fmt
[++j
];
954 else if ((paren
== 1) && (fmt
[j
] ==')')) break;
955 else if (fmt
[j
] != ' ') c
= fmt
[j
];
957 if (c
== '\0') break;
959 k
= realloc(k
, l
+ 1);
972 if ((pflags
& PRINT_LOCALTIME
) && (!strcmp(k
, ASL_KEY_TIME
)))
974 /* convert UTC time to localtime */
975 tick
= asl_parse_time(v
);
977 if (t
== NULL
) fprintf(f
, "%s", v
);
981 fprintf(f
, "%s", t
+ 4);
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
]))
1009 oval
= fmt
[i
] - '0';
1010 if (isdigit(fmt
[i
+1]))
1013 oval
= (oval
* 8) + (fmt
[i
] - '0');
1014 if (isdigit(fmt
[i
+1]))
1017 oval
= (oval
* 8) + (fmt
[i
] - '0');
1026 if (fmt
[i
] == '\0') break;
1027 fputc(fmt
[i
], stdout
);
1034 getnextline(FILE *fp
, int watch
)
1041 out
= calloc(len
+ 1, 1);
1062 if (c
== '\n') return out
;
1063 if (c
== '\0') return out
;
1068 out
= realloc(out
, len
+ 1);
1079 search_next(asl_msg_t
**q
, int nq
, FILE *log
, int watch
, aslmsg
*outmsg
, char **outstr
)
1088 if (log
== NULL
) return SEARCH_EOF
;
1090 str
= getnextline(log
, watch
);
1091 if (str
== NULL
) return SEARCH_EOF
;
1093 m
= asl_msg_from_string(str
);
1101 if (q
== NULL
) match
= 1;
1102 for (i
= 0; (i
< nq
) && (match
== 0); i
++)
1104 match
= asl_msg_cmp(q
[i
], m
);
1105 if ((q
[i
]->count
> 0) && (q
[i
]->op
[0] & ASL_QUERY_OP_NOT
))
1120 return SEARCH_MATCH
;
1128 op
= ASL_QUERY_OP_NULL
;
1130 if (o
== NULL
) return op
;
1132 for (i
= 0; o
[i
] != '\0'; i
++)
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
;
1141 else if (!strncasecmp(o
+i
, OP_EQ
, sizeof(OP_EQ
)))
1143 op
|= ASL_QUERY_OP_EQUAL
;
1144 i
+= (sizeof(OP_EQ
) - 2);
1146 else if (!strncasecmp(o
+i
, OP_NE
, sizeof(OP_NE
)))
1148 op
|= ASL_QUERY_OP_NOT_EQUAL
;
1149 i
+= (sizeof(OP_NE
) - 2);
1151 else if (!strncasecmp(o
+i
, OP_GT
, sizeof(OP_GT
)))
1153 op
|= ASL_QUERY_OP_GREATER
;
1154 i
+= (sizeof(OP_GT
) - 2);
1156 else if (!strncasecmp(o
+i
, OP_GE
, sizeof(OP_GE
)))
1158 op
|= ASL_QUERY_OP_GREATER_EQUAL
;
1159 i
+= (sizeof(OP_GE
) - 2);
1161 else if (!strncasecmp(o
+i
, OP_LT
, sizeof(OP_LT
)))
1163 op
|= ASL_QUERY_OP_LESS
;
1164 i
+= (sizeof(OP_LT
) - 2);
1166 else if (!strncasecmp(o
+i
, OP_LE
, sizeof(OP_LE
)))
1168 op
|= ASL_QUERY_OP_LESS_EQUAL
;
1169 i
+= (sizeof(OP_LE
) - 2);
1173 fprintf(stderr
, "invalid option: %s\n", o
);
1179 if (op
& ASL_QUERY_OP_NUMERIC
)
1181 if (op
& ASL_QUERY_OP_CASEFOLD
)
1183 fprintf(stderr
, "warning: case fold modifier has no effect with numeric comparisons\n");
1184 op
&= ~ASL_QUERY_OP_CASEFOLD
;
1187 if (op
& ASL_QUERY_OP_REGEX
)
1189 fprintf(stderr
, "warning: regex modifier has no effect with numeric comparisons\n");
1190 op
&= ~ASL_QUERY_OP_REGEX
;
1193 if (op
& ASL_QUERY_OP_SUBSTRING
)
1195 fprintf(stderr
, "warning: substring modifier has no effect with numeric comparisons\n");
1196 op
&= ~ASL_QUERY_OP_SUBSTRING
;
1199 if (op
& ASL_QUERY_OP_PREFIX
)
1201 fprintf(stderr
, "warning: prefix modifier has no effect with numeric comparisons\n");
1202 op
&= ~ASL_QUERY_OP_PREFIX
;
1205 if (op
& ASL_QUERY_OP_SUFFIX
)
1207 fprintf(stderr
, "warning: suffix modifier has no effect with numeric comparisons\n");
1208 op
&= ~ASL_QUERY_OP_SUFFIX
;
1212 if (op
& ASL_QUERY_OP_REGEX
)
1214 if (op
& ASL_QUERY_OP_SUBSTRING
)
1216 fprintf(stderr
, "warning: substring modifier has no effect with regular expression comparisons\n");
1217 op
&= ~ASL_QUERY_OP_SUBSTRING
;
1220 if (op
& ASL_QUERY_OP_PREFIX
)
1222 fprintf(stderr
, "warning: prefix modifier has no effect with regular expression comparisons\n");
1223 op
&= ~ASL_QUERY_OP_PREFIX
;
1226 if (op
& ASL_QUERY_OP_SUFFIX
)
1228 fprintf(stderr
, "warning: suffix modifier has no effect with regular expression comparisons\n");
1229 op
&= ~ASL_QUERY_OP_SUFFIX
;
1237 add_op(asl_msg_t
*q
, char *key
, char *op
, char *val
, uint32_t flags
)
1241 if (key
== NULL
) return -1;
1242 if (q
== NULL
) return -1;
1244 o
= ASL_QUERY_OP_NULL
;
1248 if (o
== ASL_QUERY_OP_NULL
) return -1;
1251 fprintf(stderr
, "no value supplied for operator %s %s\n", key
, op
);
1255 if ((o
& ASL_QUERY_OP_NUMERIC
) && (_isanumber(val
) == 0))
1257 fprintf(stderr
, "non-numeric value supplied for numeric operator %s %s %s\n", key
, op
, val
);
1264 asl_set_query(q
, key
, val
, o
);
1270 main(int argc
, char *argv
[])
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
;
1282 logname
= _PATH_ASL_OUT
;
1287 pflags
= PRINT_STD_FMT
;
1288 tflag
= PRINT_LOCALTIME
;
1290 for (i
= 1; i
< argc
; i
++)
1292 if (!strcmp(argv
[i
], "-s"))
1294 syslog_send(argc
, argv
);
1298 if (!strcmp(argv
[i
], "-c"))
1300 syslog_remote_control(argc
, argv
);
1305 for (i
= 1; i
< argc
; i
++)
1307 if ((!strcmp(argv
[i
], "-help")) || (!strcmp(argv
[i
], "--help")))
1312 else if (!strcmp(argv
[i
], "-w"))
1316 else if (!strcmp(argv
[i
], "-u"))
1320 else if (!strcmp(argv
[i
], "-p"))
1324 else if (!strcmp(argv
[i
], "-f"))
1326 if ((i
+ 1) >= argc
)
1332 logname
= argv
[++i
];
1334 else if (!strcmp(argv
[i
], "-F"))
1336 if ((i
+ 1) >= argc
)
1343 if (!strcmp(argv
[i
], "raw"))
1348 else if (!strcmp(argv
[i
], "std"))
1350 pflags
= PRINT_STD_FMT
;
1352 else if (!strcmp(argv
[i
], "bsd"))
1354 pflags
= PRINT_LEGACY_FMT
;
1362 else if (!strcmp(argv
[i
], "-o"))
1368 qlist
= (asl_msg_t
**)calloc(1, sizeof(asl_msg_t
*));
1372 qlist
= (asl_msg_t
**)realloc(qlist
, (qcount
+ 1) * sizeof(asl_msg_t
*));
1377 qlist
[qn
] = asl_new(ASL_TYPE_QUERY
);
1379 else if (!strcmp(argv
[i
], "-n"))
1381 flags
= ASL_QUERY_OP_NOT
;
1383 else if (!strcmp(argv
[i
], "-k"))
1386 for (n
= i
; n
< argc
; n
++)
1388 if (!strcmp(argv
[n
], "-o")) break;
1389 if (!strcmp(argv
[n
], "-n")) break;
1390 if (!strcmp(argv
[n
], "-k")) break;
1393 fprintf(stderr
, "invalid sequence: -k");
1394 for (j
= i
; j
<= n
; j
++) fprintf(stderr
, " %s", argv
[j
]);
1395 fprintf(stderr
, "\n");
1410 qlist
= (asl_msg_t
**)calloc(1, sizeof(asl_msg_t
*));
1413 qlist
[qn
] = asl_new(ASL_TYPE_QUERY
);
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
);
1422 if (status
!= 0) exit(1);
1432 fprintf(stderr
, "-w flag has no effect when pruning log file\n");
1437 fprintf(stderr
, "you must be root to prune the log file\n");
1443 fprintf(stderr
, "no queries for pruning\n");
1447 pf
= fopen(_PATH_SYSLOGD_PID
, "r");
1450 perror(_PATH_SYSLOGD_PID
);
1454 status
= fscanf(pf
, "%d", &syslogd_pid
);
1458 fprintf(stderr
, "can't read syslogd pid from %s\n", _PATH_SYSLOGD_PID
);
1462 unlink(_PATH_ASL_PRUNE
);
1463 pf
= fopen(_PATH_ASL_PRUNE
, "w");
1466 perror(_PATH_ASL_PRUNE
);
1470 for (i
= 0; i
< qcount
; i
++)
1472 outstr
= asl_msg_to_string(qlist
[i
], &j
);
1473 fprintf(pf
, "%s\n", outstr
);
1479 kill(syslogd_pid
, SIGWINCH
);
1486 if (!strcmp(logname
, "-")) log
= stdin
;
1487 else log
= fopen(logname
, "r");
1495 if (watch
== 1) fseek(log
, 0, SEEK_END
);
1503 status
= search_next(qlist
, qcount
, log
, watch
, &outmsg
, &outstr
);
1505 if (status
== SEARCH_MATCH
)
1507 printmsg(outfile
, outmsg
, outstr
, pfmt
, pflags
);
1510 if (outstr
!= NULL
) free(outstr
);
1511 if (outmsg
!= NULL
) asl_free(outmsg
);
1513 while (status
!= SEARCH_EOF
);
1517 for (i
= 0; i
< qcount
; i
++) asl_free(qlist
[i
]);
1518 if (qlist
!= NULL
) free(qlist
);