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