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