]>
Commit | Line | Data |
---|---|---|
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 |
123 | static asl_file_list_t *db_files = NULL; |
124 | static asl_store_t *store = NULL; | |
125 | static asl_file_t *legacy = NULL; | |
57b0aad2 | 126 | static asl_file_t *export = NULL; |
a83ff38a A |
127 | static const char *sort_key = NULL; |
128 | static const char *sort_key_2 = NULL; | |
129 | static int sort_numeric = 0; | |
130 | static char *last_printmsg_str = NULL; | |
131 | static int last_printmsg_count = 0; | |
db78b1bd | 132 | static const char *tfmt = NULL; |
a83ff38a A |
133 | |
134 | #ifdef CONFIG_IPHONE | |
135 | static uint32_t dbselect = DB_SELECT_SYSLOGD; | |
136 | #else | |
137 | static uint32_t dbselect = DB_SELECT_ASL; | |
138 | #endif | |
1496e7d1 | 139 | |
b16a592a | 140 | /* notify SPI */ |
b16a592a A |
141 | uint32_t notify_register_plain(const char *name, int *out_token); |
142 | ||
b16a592a | 143 | extern asl_msg_t *asl_msg_from_string(const char *buf); |
5dd30d76 A |
144 | extern char *asl_list_to_string(asl_search_result_t *list, uint32_t *outlen); |
145 | extern asl_search_result_t *asl_list_from_string(const char *buf); | |
b16a592a A |
146 | extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b); |
147 | extern time_t asl_parse_time(const char *in); | |
148 | /* END PRIVATE API */ | |
149 | ||
5dd30d76 A |
150 | #define ASL_SERVICE_NAME "com.apple.system.logger" |
151 | static mach_port_t asl_server_port = MACH_PORT_NULL; | |
152 | ||
57b0aad2 A |
153 | static const char *myname = "syslog"; |
154 | ||
b16a592a A |
155 | void |
156 | usage() | |
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 | ||
221 | const char * | |
222 | notify_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 | ||
230 | const char * | |
231 | asl_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 | ||
244 | int | |
245 | procinfo(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 | ||
330 | int | |
c4fdb7d1 | 331 | rcontrol_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 | ||
348 | int | |
c4fdb7d1 | 349 | rcontrol_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 | ||
364 | int | |
365 | asl_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 | ||
407 | char * | |
408 | asl_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 |
512 | const char * |
513 | rcontrol_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 | 525 | int |
c4fdb7d1 | 526 | rcontrol_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 | ||
556 | int | |
c4fdb7d1 | 557 | rcontrol_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 | ||
589 | int | |
590 | rsend(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(×tr, "%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 | ||
648 | int | |
649 | rlegacy(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 | ||
689 | static 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 | ||
709 | int | |
710 | asl_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 |
730 | const char * |
731 | asl_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 |
751 | int |
752 | syslog_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 |
826 | int |
827 | syslog_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 |
922 | int |
923 | syslog_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 | 964 | static void |
5dd30d76 | 965 | print_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 |
975 | static void |
976 | print_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 | 984 | static void |
a83ff38a | 985 | printmsg(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 |
1059 | asl_search_result_t * |
1060 | store_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 | ||
1078 | asl_search_result_t * | |
1079 | file_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 | ||
1091 | asl_search_result_t * | |
1092 | legacy_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 | 1104 | asl_search_result_t * |
57b0aad2 | 1105 | syslogd_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 |
1154 | void |
1155 | filter_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 |
1181 | void |
1182 | syslogd_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 | |
1310 | int | |
1311 | sort_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 | ||
1340 | int | |
1341 | sort_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 | 1353 | void |
57b0aad2 | 1354 | search_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 | ||
1420 | uint32_t | |
1421 | optype(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 | ||
1533 | int | |
1534 | add_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 |
1585 | static uint32_t |
1586 | add_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 | ||
1632 | static uint32_t | |
1633 | add_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 |
1687 | int |
1688 | main(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", ¬ify_file, 0, ¬ify_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 | } |