1/* 2 * Copyright (c) 2007-2009 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 <stdio.h> 25#include <dirent.h> 26#include <string.h> 27#include <stdlib.h> 28#include <unistd.h> 29#include <stdint.h> 30#include <errno.h> 31#include <time.h> 32#include <sys/time.h> 33#include <sys/stat.h> 34#include <sys/param.h> 35#include <servers/bootstrap.h> 36#include <bootstrap_priv.h> 37#include <mach/mach.h> 38#include <copyfile.h> 39#include <fcntl.h> 40#include <zlib.h> 41#include <xpc/xpc.h> 42#include <xpc/private.h> 43#include <os/assumes.h> 44#include <vproc_priv.h> 45#include <asl.h> 46#include <asl_private.h> 47#include <asl_core.h> 48#include <asl_file.h> 49#include <asl_store.h> 50#include "asl_common.h" 51 52#define DEFAULT_MAX_SIZE 150000000 53#define IOBUFSIZE 4096 54 55#define DO_ASLDB 0x00000001 56#define DO_MODULE 0x00000002 57#define DO_CHECKPT 0x00000004 58 59#define DEBUG_FLAG_MASK 0xfffffff0 60#define DEBUG_LEVEL_MASK 0x0000000f 61#define DEBUG_STDERR 0x00000010 62#define DEBUG_ASL 0x00000020 63 64#define AUX_URL_MINE "file:///var/log/asl/" 65#define AUX_URL_MINE_LEN 20 66 67/* length of "file://" */ 68#define AUX_URL_PATH_OFFSET 7 69 70extern kern_return_t _asl_server_query 71( 72 mach_port_t server, 73 caddr_t request, 74 mach_msg_type_number_t requestCnt, 75 uint64_t startid, 76 int count, 77 int flags, 78 caddr_t *reply, 79 mach_msg_type_number_t *replyCnt, 80 uint64_t *lastid, 81 int *status, 82 security_token_t *token 83); 84 85/* global */ 86static time_t module_ttl; 87static uint32_t debug; 88static int dryrun; 89static int asl_aux_fd = -1; 90static aslclient aslc; 91static mach_port_t asl_server_port; 92static xpc_connection_t listener; 93static dispatch_queue_t serverq; 94 95typedef struct name_list_s 96{ 97 char *name; 98 size_t size; 99 struct name_list_s *next; 100} name_list_t; 101 102static const char * 103keep_str(uint8_t mask) 104{ 105 static char str[9]; 106 uint32_t x = 0; 107 108 memset(str, 0, sizeof(str)); 109 if (mask & 0x01) str[x++] = '0'; 110 if (mask & 0x02) str[x++] = '1'; 111 if (mask & 0x04) str[x++] = '2'; 112 if (mask & 0x08) str[x++] = '3'; 113 if (mask & 0x10) str[x++] = '4'; 114 if (mask & 0x20) str[x++] = '5'; 115 if (mask & 0x40) str[x++] = '6'; 116 if (mask & 0x80) str[x++] = '7'; 117 if (x == 0) str[x++] = '-'; 118 return str; 119} 120 121void 122set_debug(int flag, const char *str) 123{ 124 int level, x; 125 126 if (str == NULL) x = ASL_LEVEL_ERR; 127 else if (((str[0] == 'L') || (str[0] == 'l')) && ((str[1] >= '0') && (str[1] <= '7')) && (str[2] == '\0')) x = atoi(str+1); 128 else if ((str[0] >= '0') && (str[0] <= '7') && (str[1] == '\0')) x = ASL_LEVEL_CRIT + atoi(str); 129 else x = ASL_LEVEL_ERR; 130 131 if (x <= 0) x = 0; 132 else if (x > 7) x = 7; 133 134 level = debug & DEBUG_LEVEL_MASK; 135 if (x > level) level = x; 136 137 debug = debug & DEBUG_FLAG_MASK; 138 debug |= flag; 139 debug |= level; 140} 141 142void 143debug_log(int level, const char *str, ...) 144{ 145 va_list v; 146 147 if ((debug & DEBUG_STDERR) && (level <= (debug & DEBUG_LEVEL_MASK))) 148 { 149 va_start(v, str); 150 vfprintf(stderr, str, v); 151 va_end(v); 152 } 153 154 if (debug & DEBUG_ASL) 155 { 156 char *line = NULL; 157 158 if (aslc == NULL) 159 { 160 aslc = asl_open("aslmanager", "syslog", 0); 161 asl_msg_t *msg = asl_msg_new(ASL_TYPE_MSG); 162 163 asl_msg_set_key_val(msg, ASL_KEY_MSG, "Status Report"); 164 asl_msg_set_key_val(msg, ASL_KEY_LEVEL, ASL_STRING_NOTICE); 165 asl_create_auxiliary_file((asl_object_t)msg, "Status Report", "public.text", &asl_aux_fd); 166 asl_msg_release(msg); 167 } 168 169 va_start(v, str); 170 vasprintf(&line, str, v); 171 va_end(v); 172 173 if (line != NULL) write(asl_aux_fd, line, strlen(line)); 174 free(line); 175 } 176} 177 178__attribute__((noreturn)) static void 179xpc_server_exit(int status) 180{ 181 xpc_connection_cancel(listener); 182 xpc_release(listener); 183 dispatch_release(serverq); 184 exit(status); 185} 186 187name_list_t * 188add_to_name_list(name_list_t *l, const char *name, size_t size) 189{ 190 name_list_t *e, *x; 191 192 if (name == NULL) return l; 193 194 e = (name_list_t *)calloc(1, sizeof(name_list_t)); 195 if (e == NULL) return NULL; 196 197 e->name = strdup(name); 198 if (e->name == NULL) 199 { 200 free(e); 201 return NULL; 202 } 203 204 e->size = size; 205 206 /* list is sorted by name (i.e. primarily by timestamp) */ 207 if (l == NULL) return e; 208 209 if (strcmp(e->name, l->name) <= 0) 210 { 211 e->next = l; 212 return e; 213 } 214 215 for (x = l; (x->next != NULL) && (strcmp(e->name, x->next->name) > 0) ; x = x->next); 216 217 e->next = x->next; 218 x->next = e; 219 return l; 220} 221 222void 223free_name_list(name_list_t *l) 224{ 225 name_list_t *e; 226 227 while (l != NULL) 228 { 229 e = l; 230 l = l->next; 231 free(e->name); 232 free(e); 233 } 234 235 free(l); 236} 237/* 238 * Copy ASL files by reading and writing each record. 239 */ 240uint32_t 241copy_asl_file(const char *src, const char *dst, mode_t mode) 242{ 243 asl_msg_list_t *res; 244 asl_file_t *f; 245 uint32_t status, i; 246 uint64_t mid; 247 size_t rcount; 248 249 if (src == NULL) return ASL_STATUS_INVALID_ARG; 250 if (dst == NULL) return ASL_STATUS_INVALID_ARG; 251 252 f = NULL; 253 status = asl_file_open_read(src, &f); 254 if (status != ASL_STATUS_OK) return status; 255 256 res = NULL; 257 mid = 0; 258 259 res = asl_file_match(f, NULL, &mid, 0, 0, 0, 1); 260 asl_file_close(f); 261 262 if (res == NULL) return ASL_STATUS_OK; 263 rcount = asl_msg_list_count(res); 264 if (rcount == 0) 265 { 266 asl_msg_list_release(res); 267 return ASL_STATUS_OK; 268 } 269 270 f = NULL; 271 status = asl_file_open_write(dst, mode, -1, -1, &f); 272 if (status != ASL_STATUS_OK) return status; 273 if (f == ASL_STATUS_OK) return ASL_STATUS_FAILED; 274 275 f->flags = ASL_FILE_FLAG_PRESERVE_MSG_ID; 276 277 for (i = 0; i < rcount; i++) 278 { 279 mid = 0; 280 status = asl_file_save(f, asl_msg_list_get_index(res, i), &mid); 281 if (status != ASL_STATUS_OK) break; 282 } 283 284 asl_file_close(f); 285 return status; 286} 287 288int 289copy_compress_file(asl_out_dst_data_t *asldst, const char *src, const char *dst) 290{ 291 int in, out; 292 size_t n; 293 gzFile gz; 294 char buf[IOBUFSIZE]; 295 296 in = open(src, O_RDONLY, 0); 297 if (in < 0) return -1; 298 299 out = open(dst, O_WRONLY | O_CREAT, asldst->mode); 300 if (out >= 0) out = asl_out_dst_set_access(out, asldst); 301 if (out < 0) 302 { 303 close(in); 304 return -1; 305 } 306 307 gz = gzdopen(out, "w"); 308 if (gz == NULL) 309 { 310 close(in); 311 close(out); 312 return -1; 313 } 314 315 do { 316 n = read(in, buf, sizeof(buf)); 317 if (n > 0) gzwrite(gz, buf, n); 318 } while (n == IOBUFSIZE); 319 320 gzclose(gz); 321 close(in); 322 close(out); 323 324 return 0; 325} 326 327void 328filesystem_rename(const char *src, const char *dst) 329{ 330 int status = 0; 331 332 debug_log(ASL_LEVEL_NOTICE, " rename %s ---> %s\n", src, dst); 333 if (dryrun == 1) return; 334 335 status = rename(src, dst); 336 if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] rename %s ---> %s\n", status, errno, strerror(errno), src, dst); 337} 338 339void 340filesystem_unlink(const char *path) 341{ 342 int status = 0; 343 344 debug_log(ASL_LEVEL_NOTICE, " remove %s\n", path); 345 if (dryrun == 1) return; 346 347 status = unlink(path); 348 if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] unlink %s\n", status, errno, strerror(errno), path); 349} 350 351void 352filesystem_truncate(const char *path) 353{ 354 int status = 0; 355 356 debug_log(ASL_LEVEL_NOTICE, " truncate %s\n", path); 357 if (dryrun == 1) return; 358 359 status = truncate(path, 0); 360 if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] unlink %s\n", status, errno, strerror(errno), path); 361} 362 363void 364filesystem_rmdir(const char *path) 365{ 366 int status = 0; 367 368 debug_log(ASL_LEVEL_NOTICE, " remove directory %s\n", path); 369 if (dryrun == 1) return; 370 371 status = rmdir(path); 372 if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] rmdir %s\n", status, errno, strerror(errno), path); 373} 374 375int32_t 376filesystem_copy(asl_out_dst_data_t *asldst, const char *src, const char *dst, uint32_t flags) 377{ 378 char *dot; 379 380 if ((src == NULL) || (dst == NULL)) return 0; 381 382 dot = strrchr(src, '.'); 383 if ((dot != NULL) && (!strcmp(dot, ".gz"))) flags &= ~MODULE_FLAG_COMPRESS; 384 385 if (((flags & MODULE_FLAG_COMPRESS) == 0) && (!strcmp(src, dst))) return 0; 386 387 if (flags & MODULE_FLAG_TYPE_ASL) debug_log(ASL_LEVEL_NOTICE, " copy asl %s ---> %s\n", src, dst); 388 else if (flags & MODULE_FLAG_COMPRESS) debug_log(ASL_LEVEL_NOTICE, " copy compress %s ---> %s.gz\n", src, dst); 389 else debug_log(ASL_LEVEL_NOTICE, " copy %s ---> %s\n", src, dst); 390 391 if (dryrun == 1) return 0; 392 393 if (flags & MODULE_FLAG_TYPE_ASL) 394 { 395 uint32_t status = copy_asl_file(src, dst, asldst->mode); 396 if (status != 0) 397 { 398 debug_log(ASL_LEVEL_ERR, " FAILED status %u [%s] asl copy %s ---> %s\n", status, asl_core_error(status), src, dst); 399 return 0; 400 } 401 } 402 else if (flags & MODULE_FLAG_COMPRESS) 403 { 404 char gzdst[MAXPATHLEN]; 405 406 snprintf(gzdst, sizeof(gzdst), "%s.gz", dst); 407 408 int status = copy_compress_file(asldst, src, gzdst); 409 if (status != 0) 410 { 411 debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] copy & compress %s ---> %s\n", status, errno, strerror(errno), src, dst); 412 return 0; 413 } 414 } 415 else 416 { 417 int status = copyfile(src, dst, NULL, COPYFILE_ALL | COPYFILE_RECURSIVE); 418 if (status != 0) 419 { 420 debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] copy %s ---> %s\n", status, errno, strerror(errno), src, dst); 421 return 0; 422 } 423 } 424 425 return 1; 426} 427 428int 429remove_directory(const char *path) 430{ 431 DIR *dp; 432 struct dirent *dent; 433 char *str; 434 435 dp = opendir(path); 436 if (dp == NULL) return 0; 437 438 while ((dent = readdir(dp)) != NULL) 439 { 440 if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue; 441 asprintf(&str, "%s/%s", path, dent->d_name); 442 if (str != NULL) 443 { 444 filesystem_unlink(str); 445 free(str); 446 str = NULL; 447 } 448 } 449 450 closedir(dp); 451 filesystem_rmdir(path); 452 453 return 0; 454} 455 456/* 457 * Determine the age (in whole days) of a YMD file from its name. 458 * Also determines UID and GID from ".Unnn.Gnnn" part of file name. 459 */ 460uint32_t 461ymd_file_age(const char *name, time_t now, uid_t *u, gid_t *g) 462{ 463 struct tm ftime; 464 time_t created; 465 uint32_t days; 466 const char *p; 467 468 if (name == NULL) return 0; 469 470 if (now == 0) now = time(NULL); 471 472 memset(&ftime, 0, sizeof(struct tm)); 473 ftime.tm_hour = 24; 474 475 /* name is YYYY.MM.DD.<...> */ 476 477 if ((name[0] < '0') || (name[0] > '9')) return 0; 478 ftime.tm_year = 1000 * (name[0] - '0'); 479 480 if ((name[1] < '0') || (name[1] > '9')) return 0; 481 ftime.tm_year += 100 * (name[1] - '0'); 482 483 if ((name[2] < '0') || (name[2] > '9')) return 0; 484 ftime.tm_year += 10 * (name[2] - '0'); 485 486 if ((name[3] < '0') || (name[3] > '9')) return 0; 487 ftime.tm_year += name[3] - '0'; 488 ftime.tm_year -= 1900; 489 490 if (name[4] != '.') return 0; 491 492 if ((name[5] < '0') || (name[5] > '9')) return 0; 493 ftime.tm_mon = 10 * (name[5] - '0'); 494 495 if ((name[6] < '0') || (name[6] > '9')) return 0; 496 ftime.tm_mon += name[6] - '0'; 497 ftime.tm_mon -= 1; 498 499 if (name[7] != '.') return 0; 500 501 if ((name[8] < '0') || (name[8] > '9')) return 0; 502 ftime.tm_mday = 10 * (name[8] - '0'); 503 504 if ((name[9] < '0') || (name[9] > '9')) return 0; 505 ftime.tm_mday += name[9] - '0'; 506 507 if (name[10] != '.') return 0; 508 509 created = mktime(&ftime); 510 if (created > now) return 0; 511 512 days = (now - created) / 86400; 513 514 if (u != NULL) 515 { 516 *u = -1; 517 p = strchr(name+10, 'U'); 518 if (p != NULL) *u = atoi(p+1); 519 } 520 521 if (g != NULL) 522 { 523 *g = -1; 524 p = strchr(name+10, 'G'); 525 if (p != NULL) *g = atoi(p+1); 526 } 527 528 return days; 529} 530 531void 532aux_url_callback(const char *url) 533{ 534 if (url == NULL) return; 535 if (!strncmp(url, AUX_URL_MINE, AUX_URL_MINE_LEN)) filesystem_unlink(url + AUX_URL_PATH_OFFSET); 536} 537 538uint32_t 539ymd_file_filter(const char *name, const char *path, uint32_t keep_mask, mode_t ymd_mode, uid_t ymd_uid, gid_t ymd_gid) 540{ 541 asl_file_t *f = NULL; 542 uint8_t km = keep_mask; 543 uint32_t status, len, dstcount = 0; 544 char src[MAXPATHLEN]; 545 char dst[MAXPATHLEN]; 546 547 if (snprintf(src, MAXPATHLEN, "%s/%s", path, name) >= MAXPATHLEN) return ASL_STATUS_FAILED; 548 if (snprintf(dst, MAXPATHLEN, "%s/%s", path, name) >= MAXPATHLEN) return ASL_STATUS_FAILED; 549 len = strlen(src) - 3; 550 snprintf(dst + len, 4, "tmp"); 551 552 //TODO: check if src file is already filtered 553 debug_log(ASL_LEVEL_NOTICE, " filter %s %s ---> %s\n", src, keep_str(km), dst); 554 555 status = ASL_STATUS_OK; 556 557 if (dryrun == 0) 558 { 559 status = asl_file_open_read(name, &f); 560 if (status != ASL_STATUS_OK) return status; 561 562 status = asl_file_filter_level(f, dst, keep_mask, ymd_mode, ymd_uid, ymd_gid, &dstcount, aux_url_callback); 563 asl_file_close(f); 564 } 565 566 filesystem_unlink(src); 567 if ((status != ASL_STATUS_OK) || (dstcount == 0)) filesystem_unlink(dst); 568 else filesystem_rename(dst, src); 569 570 return status; 571} 572 573/* 574 * Used to set config parameters. 575 * Line format "= name value" 576 */ 577static void 578_aslmanager_set_param(asl_out_dst_data_t *dst, char *s) 579{ 580 char **l; 581 uint32_t count; 582 583 if (s == NULL) return; 584 if (s[0] == '\0') return; 585 586 /* skip '=' and whitespace */ 587 if (*s == '=') s++; 588 while ((*s == ' ') || (*s == '\t')) s++; 589 590 l = explode(s, " \t"); 591 if (l == NULL) return; 592 593 for (count = 0; l[count] != NULL; count++); 594 595 /* name is required */ 596 if (count == 0) 597 { 598 free_string_list(l); 599 return; 600 } 601 602 /* value is required */ 603 if (count == 1) 604 { 605 free_string_list(l); 606 return; 607 } 608 609 if (!strcasecmp(l[0], "aslmanager_debug")) 610 { 611 /* = debug level */ 612 set_debug(DEBUG_ASL, l[1]); 613 } 614 else if (!strcasecmp(l[0], "store_ttl")) 615 { 616 /* = store_ttl days */ 617 dst->ttl[LEVEL_ALL] = (time_t)atoll(l[1]); 618 } 619 else if (!strcasecmp(l[0], "module_ttl")) 620 { 621 /* = module_ttl days */ 622 module_ttl = (time_t)atoll(l[1]); 623 } 624 else if (!strcasecmp(l[0], "max_store_size")) 625 { 626 /* = max_file_size bytes */ 627 dst->all_max = atoi(l[1]); 628 } 629 else if (!strcasecmp(l[0], "archive")) 630 { 631 free(dst->rotate_dir); 632 dst->rotate_dir = NULL; 633 634 /* = archive {0|1} path */ 635 if (!strcmp(l[1], "1")) 636 { 637 if (l[2] == NULL) dst->rotate_dir = strdup(PATH_ASL_ARCHIVE); 638 else dst->rotate_dir = strdup(l[2]); 639 } 640 } 641 else if (!strcasecmp(l[0], "store_path")) 642 { 643 /* = archive path */ 644 free(dst->path); 645 dst->path = strdup(l[1]); 646 } 647 else if (!strcasecmp(l[0], "archive_mode")) 648 { 649 dst->mode = strtol(l[1], NULL, 0); 650 if ((dst->mode == 0) && (errno == EINVAL)) dst->mode = 0400; 651 } 652 653 free_string_list(l); 654} 655 656size_t 657directory_size(const char *path) 658{ 659 DIR *dp; 660 struct dirent *dent; 661 struct stat sb; 662 size_t size; 663 char *str; 664 665 dp = opendir(path); 666 if (dp == NULL) return 0; 667 668 size = 0; 669 while ((dent = readdir(dp)) != NULL) 670 { 671 if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue; 672 673 memset(&sb, 0, sizeof(struct stat)); 674 str = NULL; 675 asprintf(&str, "%s/%s", path, dent->d_name); 676 677 if ((str != NULL) && (stat(str, &sb) == 0) && S_ISREG(sb.st_mode)) 678 { 679 size += sb.st_size; 680 free(str); 681 } 682 } 683 684 closedir(dp); 685 return size; 686} 687 688static int 689process_asl_data_store(asl_out_dst_data_t *dst) 690{ 691 int32_t today_ymd_stringlen, expire_ymd_stringlen; 692 time_t now, ttl, ymd_expire; 693 struct tm ctm; 694 char today_ymd_string[32], expire_ymd_string[32], *str; 695 DIR *dp; 696 struct dirent *dent; 697 name_list_t *ymd_list, *bb_list, *aux_list, *bb_aux_list, *e; 698 size_t file_size, store_size; 699 struct stat sb; 700 701 ymd_list = NULL; 702 bb_list = NULL; 703 aux_list = NULL; 704 bb_aux_list = NULL; 705 store_size = 0; 706 707 if (dst == NULL) return 0; 708 if (dst->path == NULL) return 0; 709 710 debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n"); 711 debug_log(ASL_LEVEL_NOTICE, "Processing data store %s\n", dst->path); 712 713 if (dst->rotate_dir != NULL) 714 { 715 /* check archive */ 716 memset(&sb, 0, sizeof(struct stat)); 717 if (stat(dst->rotate_dir, &sb) == 0) 718 { 719 /* must be a directory */ 720 if (!S_ISDIR(sb.st_mode)) 721 { 722 debug_log(ASL_LEVEL_ERR, "aslmanager error: archive %s is not a directory", dst->rotate_dir); 723 return -1; 724 } 725 } 726 else 727 { 728 if (errno == ENOENT) 729 { 730 /* archive doesn't exist - create it */ 731 if (mkdir(dst->rotate_dir, 0755) != 0) 732 { 733 debug_log(ASL_LEVEL_ERR, "aslmanager error: can't create archive %s: %s\n", dst->rotate_dir, strerror(errno)); 734 return -1; 735 } 736 } 737 else 738 { 739 /* stat failed for some other reason */ 740 debug_log(ASL_LEVEL_ERR, "aslmanager error: can't stat archive %s: %s\n", dst->rotate_dir, strerror(errno)); 741 return -1; 742 } 743 } 744 } 745 746 chdir(dst->path); 747 748 /* determine current time */ 749 now = time(NULL); 750 751 /* ttl 0 means files never expire */ 752 ymd_expire = 0; 753 ttl = dst->ttl[LEVEL_ALL] * SECONDS_PER_DAY; 754 755 if ((ttl > 0) && (ttl <= now)) ymd_expire = now - ttl; 756 757 /* construct today's date as YYYY.MM.DD */ 758 memset(&ctm, 0, sizeof(struct tm)); 759 if (localtime_r((const time_t *)&now, &ctm) == NULL) return -1; 760 761 snprintf(today_ymd_string, sizeof(today_ymd_string), "%d.%02d.%02d.", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); 762 today_ymd_stringlen = strlen(today_ymd_string); 763 764 /* construct regular file expiry date as YYYY.MM.DD */ 765 memset(&ctm, 0, sizeof(struct tm)); 766 if (localtime_r((const time_t *)&ymd_expire, &ctm) == NULL) return -1; 767 768 snprintf(expire_ymd_string, sizeof(expire_ymd_string), "%d.%02d.%02d.", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); 769 expire_ymd_stringlen = strlen(expire_ymd_string); 770 771 debug_log(ASL_LEVEL_NOTICE, "Expiry Date %s\n", expire_ymd_string); 772 773 dp = opendir(dst->path); 774 if (dp == NULL) return -1; 775 776 /* gather a list of YMD files, AUX dirs, BB.AUX dirs, and BB files */ 777 while ((dent = readdir(dp)) != NULL) 778 { 779 memset(&sb, 0, sizeof(struct stat)); 780 file_size = 0; 781 if (stat(dent->d_name, &sb) == 0) file_size = sb.st_size; 782 783 if ((dent->d_name[0] >= '0') && (dent->d_name[0] <= '9')) 784 { 785 ymd_list = add_to_name_list(ymd_list, dent->d_name, file_size); 786 store_size += file_size; 787 } 788 else if (!strncmp(dent->d_name, "AUX.", 4) && (dent->d_name[4] >= '0') && (dent->d_name[4] <= '9') && S_ISDIR(sb.st_mode)) 789 { 790 file_size = directory_size(dent->d_name); 791 aux_list = add_to_name_list(aux_list, dent->d_name, file_size); 792 store_size += file_size; 793 } 794 else if (!strncmp(dent->d_name, "BB.AUX.", 7) && (dent->d_name[7] >= '0') && (dent->d_name[7] <= '9') && S_ISDIR(sb.st_mode)) 795 { 796 file_size = directory_size(dent->d_name); 797 bb_aux_list = add_to_name_list(bb_aux_list, dent->d_name, file_size); 798 store_size += file_size; 799 } 800 else if (!strncmp(dent->d_name, "BB.", 3) && (dent->d_name[3] >= '0') && (dent->d_name[3] <= '9')) 801 { 802 bb_list = add_to_name_list(bb_list, dent->d_name, file_size); 803 store_size += file_size; 804 } 805 else if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) 806 {} 807 else if ((!strcmp(dent->d_name, "StoreData")) || (!strcmp(dent->d_name, "SweepStore"))) 808 {} 809 else 810 { 811 debug_log(ASL_LEVEL_ERR, "aslmanager: unexpected file %s in ASL data store\n", dent->d_name); 812 } 813 } 814 815 closedir(dp); 816 817 debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size); 818 debug_log(ASL_LEVEL_NOTICE, "Data Store YMD Files\n"); 819 for (e = ymd_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, " %s %lu\n", e->name, e->size); 820 debug_log(ASL_LEVEL_NOTICE, "Data Store AUX Directories\n"); 821 for (e = aux_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, " %s %lu\n", e->name, e->size); 822 debug_log(ASL_LEVEL_NOTICE, "Data Store BB.AUX Directories\n"); 823 for (e = bb_aux_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, " %s %lu\n", e->name, e->size); 824 debug_log(ASL_LEVEL_NOTICE, "Data Store BB Files\n"); 825 for (e = bb_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, " %s %lu\n", e->name, e->size); 826 827 /* Delete/achive expired YMD files */ 828 debug_log(ASL_LEVEL_NOTICE, "Start YMD File Scan\n"); 829 830 e = ymd_list; 831 while (e != NULL) 832 { 833 if (strncmp(e->name, expire_ymd_string, expire_ymd_stringlen) <= 0) 834 { 835 /* file has expired, archive it if required, then unlink it */ 836 if (dst->rotate_dir != NULL) 837 { 838 str = NULL; 839 asprintf(&str, "%s/%s", dst->rotate_dir, e->name); 840 if (str == NULL) return -1; 841 842 filesystem_copy(dst, e->name, str, 0); 843 free(str); 844 } 845 846 filesystem_unlink(e->name); 847 store_size -= e->size; 848 e->size = 0; 849 } 850 else 851 { 852 /* check if there are any per-level TTLs and filter the file if required */ 853 uint32_t i, bit, keep_mask; 854 uid_t ymd_uid = -1; 855 gid_t ymd_gid = -1; 856 mode_t ymd_mode = 0600; 857 uint32_t age = ymd_file_age(e->name, now, &ymd_uid, &ymd_gid); 858 859 if (age > 0) 860 { 861 keep_mask = 0x000000ff; 862 bit = 1; 863 for (i = 0; i <= 7; i++) 864 { 865 if ((dst->ttl[i] > 0) && (age >= dst->ttl[i])) keep_mask &= ~bit; 866 bit *= 2; 867 } 868 869 memset(&sb, 0, sizeof(struct stat)); 870 if (stat(e->name, &sb) == 0) ymd_mode = sb.st_mode & 0777; 871 872 if (keep_mask != 0x000000ff) ymd_file_filter(e->name, dst->path, keep_mask, ymd_mode, ymd_uid, ymd_gid); 873 } 874 } 875 876 e = e->next; 877 } 878 879 debug_log(ASL_LEVEL_NOTICE, "Finished YMD File Scan\n"); 880 881 /* Delete/achive expired YMD AUX directories */ 882 debug_log(ASL_LEVEL_NOTICE, "Start AUX Directory Scan\n"); 883 884 e = aux_list; 885 while (e != NULL) 886 { 887 /* stop when a file name/date is after the expire date */ 888 if (strncmp(e->name + 4, expire_ymd_string, expire_ymd_stringlen) > 0) break; 889 890 if (dst->rotate_dir != NULL) 891 { 892 str = NULL; 893 asprintf(&str, "%s/%s", dst->rotate_dir, e->name); 894 if (str == NULL) return -1; 895 896 filesystem_copy(dst, e->name, str, 0); 897 free(str); 898 } 899 900 remove_directory(e->name); 901 store_size -= e->size; 902 e->size = 0; 903 904 e = e->next; 905 } 906 907 debug_log(ASL_LEVEL_NOTICE, "Finished AUX Directory Scan\n"); 908 909 /* Delete/achive expired BB.AUX directories */ 910 debug_log(ASL_LEVEL_NOTICE, "Start BB.AUX Directory Scan\n"); 911 912 e = bb_aux_list; 913 while (e != NULL) 914 { 915 /* stop when a file name/date is after the expire date */ 916 if (strncmp(e->name + 7, today_ymd_string, today_ymd_stringlen) > 0) break; 917 918 if (dst->rotate_dir != NULL) 919 { 920 str = NULL; 921 asprintf(&str, "%s/%s", dst->rotate_dir, e->name); 922 if (str == NULL) return -1; 923 924 filesystem_copy(dst, e->name, str, 0); 925 free(str); 926 } 927 928 remove_directory(e->name); 929 store_size -= e->size; 930 e->size = 0; 931 932 e = e->next; 933 } 934 935 debug_log(ASL_LEVEL_NOTICE, "Finished BB.AUX Directory Scan\n"); 936 937 /* Delete/achive expired BB files */ 938 debug_log(ASL_LEVEL_NOTICE, "Start BB Scan\n"); 939 940 e = bb_list; 941 while (e != NULL) 942 { 943 /* stop when a file name/date is after the expire date */ 944 if (strncmp(e->name + 3, today_ymd_string, today_ymd_stringlen) > 0) break; 945 946 if (dst->rotate_dir != NULL) 947 { 948 str = NULL; 949 asprintf(&str, "%s/%s", dst->rotate_dir, e->name); 950 if (str == NULL) return -1; 951 952 /* syslog -x [str] -f [e->name] */ 953 filesystem_copy(dst, e->name, str, 0); 954 free(str); 955 } 956 957 filesystem_unlink(e->name); 958 store_size -= e->size; 959 e->size = 0; 960 961 e = e->next; 962 } 963 964 debug_log(ASL_LEVEL_NOTICE, "Finished BB Scan\n"); 965 966 if (dst->all_max > 0) 967 { 968 /* if data store is over max_size, delete/archive more YMD files */ 969 if (store_size > dst->all_max) debug_log(ASL_LEVEL_NOTICE, "Additional YMD Scan\n"); 970 971 e = ymd_list; 972 while ((e != NULL) && (store_size > dst->all_max)) 973 { 974 if (e->size != 0) 975 { 976 if (strncmp(e->name, today_ymd_string, today_ymd_stringlen) == 0) 977 { 978 /* do not touch active file YYYY.MM.DD.asl */ 979 if (strcmp(e->name + today_ymd_stringlen, "asl") == 0) 980 { 981 e = e->next; 982 continue; 983 } 984 } 985 986 if (dst->rotate_dir != NULL) 987 { 988 str = NULL; 989 asprintf(&str, "%s/%s", dst->rotate_dir, e->name); 990 if (str == NULL) return -1; 991 992 /* syslog -x [str] -f [e->name] */ 993 filesystem_copy(dst, e->name, str, 0); 994 free(str); 995 } 996 997 filesystem_unlink(e->name); 998 store_size -= e->size; 999 e->size = 0; 1000 } 1001 1002 e = e->next; 1003 } 1004 1005 /* if data store is over dst->all_max, delete/archive more BB files */ 1006 if (store_size > dst->all_max) debug_log(ASL_LEVEL_NOTICE, "Additional BB Scan\n"); 1007 1008 e = bb_list; 1009 while ((e != NULL) && (store_size > dst->all_max)) 1010 { 1011 if (e->size != 0) 1012 { 1013 if (dst->rotate_dir != NULL) 1014 { 1015 str = NULL; 1016 asprintf(&str, "%s/%s", dst->rotate_dir, e->name); 1017 if (str == NULL) return -1; 1018 1019 /* syslog -x [str] -f [e->name] */ 1020 filesystem_copy(dst, e->name, str, 0); 1021 free(str); 1022 } 1023 1024 filesystem_unlink(e->name); 1025 store_size -= e->size; 1026 e->size = 0; 1027 } 1028 1029 e = e->next; 1030 } 1031 } 1032 1033 free_name_list(ymd_list); 1034 free_name_list(bb_list); 1035 free_name_list(aux_list); 1036 free_name_list(bb_aux_list); 1037 1038 debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size); 1039 1040 return 0; 1041} 1042 1043/* move sequenced source files to dst dir, renaming as we go */ 1044static int 1045module_copy_rename(asl_out_dst_data_t *dst) 1046{ 1047 asl_out_file_list_t *src_list, *dst_list, *f, *dst_last; 1048 char *base, *dst_dir; 1049 char fpathsrc[MAXPATHLEN], fpathdst[MAXPATHLEN]; 1050 uint32_t src_count, dst_count; 1051 int32_t x, moved; 1052 1053 if (dst == NULL) return -1; 1054 if (dst->path == NULL) return -1; 1055 1056 base = strrchr(dst->path, '/'); 1057 if (base == NULL) return -1; 1058 1059 src_list = asl_list_src_files(dst); 1060 if (src_list == 0) 1061 { 1062 debug_log(ASL_LEVEL_INFO, " no src files\n"); 1063 return 0; 1064 } 1065 1066 debug_log(ASL_LEVEL_INFO, " src files\n"); 1067 1068 src_count = 0; 1069 for (f = src_list; f != NULL; f = f->next) 1070 { 1071 debug_log(ASL_LEVEL_INFO, " %s\n", f->name); 1072 src_count++; 1073 } 1074 1075 dst_list = asl_list_dst_files(dst); 1076 1077 *base = '\0'; 1078 base++; 1079 1080 dst_dir = dst->rotate_dir; 1081 if (dst_dir == NULL) dst_dir = dst->path; 1082 1083 dst_count = 0; 1084 dst_last = dst_list; 1085 1086 if (dst_list == NULL) debug_log(ASL_LEVEL_INFO, " no dst files\n"); 1087 else debug_log(ASL_LEVEL_INFO, " dst files\n"); 1088 1089 for (f = dst_list; f != NULL; f = f->next) 1090 { 1091 debug_log(ASL_LEVEL_INFO, " %s\n", f->name); 1092 dst_last = f; 1093 dst_count++; 1094 } 1095 1096 if (dst->flags & MODULE_FLAG_STYLE_SEQ) 1097 { 1098 for (f = dst_last; f != NULL; f = f->prev) 1099 { 1100 int is_gz = 0; 1101 char *dot = strrchr(f->name, '.'); 1102 if ((dot != NULL) && (!strcmp(dot, ".gz"))) is_gz = 1; 1103 1104 snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst_dir, f->name); 1105 snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d%s", dst_dir, base, f->seq+src_count, (is_gz == 1) ? ".gz" : ""); 1106 filesystem_rename(fpathsrc, fpathdst); 1107 } 1108 1109 for (f = src_list, x = 0; f != NULL; f = f->next, x++) 1110 { 1111 snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->path, f->name); 1112 snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d", dst_dir, base, x); 1113 moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags); 1114 if (moved != 0) 1115 { 1116 if (dst->flags & MODULE_FLAG_TRUNCATE) filesystem_truncate(fpathsrc); 1117 else filesystem_unlink(fpathsrc); 1118 } 1119 } 1120 } 1121 else 1122 { 1123 for (f = src_list; f != NULL; f = f->next) 1124 { 1125 /* final / active base stamped file looks like a checkpointed file - ignore it */ 1126 if ((dst->flags & MODULE_FLAG_BASESTAMP) && (f->next == NULL)) break; 1127 1128 snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->path, f->name); 1129 1130 /* MODULE_FLAG_EXTERNAL files are not decorated with a timestamp */ 1131 if (dst->flags & MODULE_FLAG_EXTERNAL) 1132 { 1133 char tstamp[32]; 1134 1135 asl_make_timestamp(f->ftime, dst->flags, tstamp, sizeof(tstamp)); 1136 snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s", dst_dir, base, tstamp); 1137 } 1138 else 1139 { 1140 snprintf(fpathdst, sizeof(fpathdst), "%s/%s", dst_dir, f->name); 1141 } 1142 1143 moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags); 1144 if (moved != 0) 1145 { 1146 if (dst->flags & MODULE_FLAG_TRUNCATE) filesystem_truncate(fpathsrc); 1147 else filesystem_unlink(fpathsrc); 1148 } 1149 } 1150 } 1151 1152 asl_out_file_list_free(src_list); 1153 asl_out_file_list_free(dst_list); 1154 1155 if (base != NULL) *--base = '/'; 1156 1157 return 0; 1158} 1159 1160/* delete expired files */ 1161static int 1162module_expire(asl_out_dst_data_t *dst) 1163{ 1164 asl_out_file_list_t *dst_list, *f; 1165 char *base, *dst_dir, fpath[MAXPATHLEN]; 1166 time_t now, ttl, cutoff; 1167 1168 if (dst == NULL) return -1; 1169 if (dst->path == NULL) return -1; 1170 if (dst->ttl[LEVEL_ALL] == 0) return 0; 1171 1172 ttl = 0; 1173 if (module_ttl > 0) ttl = module_ttl; 1174 else ttl = dst->ttl[LEVEL_ALL]; 1175 1176 ttl *= SECONDS_PER_DAY; 1177 1178 now = time(NULL); 1179 if (ttl > now) return 0; 1180 1181 cutoff = now - ttl; 1182 1183 base = strrchr(dst->path, '/'); 1184 if (base == NULL) return -1; 1185 1186 dst_list = asl_list_dst_files(dst); 1187 1188 *base = '\0'; 1189 1190 dst_dir = dst->rotate_dir; 1191 if (dst_dir == NULL) dst_dir = dst->path; 1192 1193 if (dst_list == NULL) 1194 { 1195 debug_log(ASL_LEVEL_INFO, " no dst files\n"); 1196 } 1197 else 1198 { 1199 debug_log(ASL_LEVEL_INFO, " dst files\n"); 1200 for (f = dst_list; f != NULL; f = f->next) debug_log(ASL_LEVEL_INFO, " %s\n", f->name); 1201 } 1202 1203 for (f = dst_list; f != NULL; f = f->next) 1204 { 1205 if (f->ftime <= cutoff) 1206 { 1207 snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name); 1208 filesystem_unlink(fpath); 1209 } 1210 } 1211 1212 asl_out_file_list_free(dst_list); 1213 1214 if (base != NULL) *base = '/'; 1215 1216 return 0; 1217} 1218 1219/* check all_max size and delete files (oldest first) to stay within size limit */ 1220static int 1221module_check_size(asl_out_dst_data_t *dst) 1222{ 1223 asl_out_file_list_t *dst_list, *f, *dst_end; 1224 char *base, *dst_dir, fpath[MAXPATHLEN]; 1225 size_t total; 1226 1227 if (dst == NULL) return -1; 1228 if (dst->path == NULL) return -1; 1229 1230 if (dst->all_max == 0) return 0; 1231 1232 dst_list = asl_list_dst_files(dst); 1233 if (dst_list == NULL) 1234 { 1235 debug_log(ASL_LEVEL_INFO, " no dst files\n"); 1236 return 0; 1237 } 1238 1239 base = NULL; 1240 dst_dir = dst->rotate_dir; 1241 if (dst_dir == NULL) 1242 { 1243 dst_dir = dst->path; 1244 base = strrchr(dst->path, '/'); 1245 if (base == NULL) 1246 { 1247 asl_out_file_list_free(dst_list); 1248 return -1; 1249 } 1250 1251 *base = '\0'; 1252 } 1253 1254 debug_log(ASL_LEVEL_INFO, " dst files\n"); 1255 dst_end = dst_list; 1256 for (f = dst_list; f != NULL; f = f->next) 1257 { 1258 dst_end = f; 1259 debug_log(ASL_LEVEL_INFO, " %s size %lu\n", f->name, f->size); 1260 } 1261 1262 total = 0; 1263 for (f = dst_list; f != NULL; f = f->next) total += f->size; 1264 1265 for (f = dst_end; (total > dst->all_max) && (f != NULL); f = f->prev) 1266 { 1267 snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name); 1268 filesystem_unlink(fpath); 1269 total -= f->size; 1270 } 1271 1272 asl_out_file_list_free(dst_list); 1273 1274 if (base != NULL) *base = '/'; 1275 1276 return 0; 1277} 1278 1279 1280static int 1281process_module(asl_out_module_t *mod) 1282{ 1283 asl_out_rule_t *r; 1284 1285 if (mod == NULL) return -1; 1286 1287 debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n"); 1288 debug_log(ASL_LEVEL_NOTICE, "Processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name); 1289 1290 for (r = mod->ruleset; r != NULL; r = r->next) 1291 { 1292 if (r->action == ACTION_OUT_DEST) 1293 { 1294 if (r->dst == NULL) 1295 { 1296 debug_log(ASL_LEVEL_NOTICE, "NULL dst data for output rule - skipped\n"); 1297 } 1298 else if (r->dst->flags & MODULE_FLAG_ROTATE) 1299 { 1300 debug_log(ASL_LEVEL_NOTICE, "Checking file %s\n", r->dst->path); 1301 debug_log(ASL_LEVEL_NOTICE, "- Rename, move to destination directory, and compress as required\n"); 1302 1303 module_copy_rename(r->dst); 1304 1305 if (r->dst->ttl[LEVEL_ALL] > 0) 1306 { 1307 debug_log(ASL_LEVEL_NOTICE, "- Check for expired files - TTL = %d days\n", r->dst->ttl[LEVEL_ALL]); 1308 module_expire(r->dst); 1309 } 1310 1311 if (r->dst->all_max > 0) 1312 { 1313 debug_log(ASL_LEVEL_NOTICE, "- Check total storage used - MAX = %lu\n", r->dst->all_max); 1314 module_check_size(r->dst); 1315 } 1316 } 1317 else if ((r->dst->flags & MODULE_FLAG_TYPE_ASL_DIR) && (r->dst->ttl[LEVEL_ALL] > 0)) 1318 { 1319 process_asl_data_store(r->dst); 1320 } 1321 } 1322 } 1323 1324 debug_log(ASL_LEVEL_NOTICE, "Finished processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name); 1325 return 0; 1326} 1327 1328asl_msg_list_t * 1329control_query(asl_msg_t *a) 1330{ 1331 asl_msg_list_t *out; 1332 char *qstr, *str, *res; 1333 uint32_t len, reslen, status; 1334 uint64_t cmax, qmin; 1335 kern_return_t kstatus; 1336 caddr_t vmstr; 1337 security_token_t sec; 1338 1339 if (asl_server_port == MACH_PORT_NULL) 1340 { 1341 bootstrap_look_up2(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port, 0, BOOTSTRAP_PRIVILEGED_SERVER); 1342 if (asl_server_port == MACH_PORT_NULL) return NULL; 1343 } 1344 1345 qstr = asl_msg_to_string((asl_msg_t *)a, &len); 1346 1347 str = NULL; 1348 if (qstr == NULL) 1349 { 1350 asprintf(&str, "1\nQ [= ASLOption control]\n"); 1351 } 1352 else 1353 { 1354 asprintf(&str, "1\n%s [= ASLOption control]\n", qstr); 1355 free(qstr); 1356 } 1357 1358 if (str == NULL) return NULL; 1359 1360 /* length includes trailing nul */ 1361 len = strlen(str) + 1; 1362 out = NULL; 1363 qmin = 0; 1364 cmax = 0; 1365 sec.val[0] = -1; 1366 sec.val[1] = -1; 1367 1368 res = NULL; 1369 reslen = 0; 1370 status = ASL_STATUS_OK; 1371 1372 kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE); 1373 if (kstatus != KERN_SUCCESS) return NULL; 1374 1375 memmove(vmstr, str, len); 1376 free(str); 1377 1378 status = 0; 1379 kstatus = _asl_server_query(asl_server_port, vmstr, len, qmin, 1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status, &sec); 1380 if (kstatus != KERN_SUCCESS) return NULL; 1381 1382 if (res == NULL) return NULL; 1383 1384 out = asl_msg_list_from_string(res); 1385 vm_deallocate(mach_task_self(), (vm_address_t)res, reslen); 1386 1387 return out; 1388} 1389 1390int 1391checkpoint(const char *name) 1392{ 1393 /* send checkpoint message to syslogd */ 1394 debug_log(ASL_LEVEL_NOTICE, "Checkpoint module %s\n", (name == NULL) ? "*" : name); 1395 if (dryrun != 0) return 0; 1396 1397 asl_msg_t *qmsg = asl_msg_new(ASL_TYPE_QUERY); 1398 char *tmp = NULL; 1399 asl_msg_list_t *res; 1400 1401 asprintf(&tmp, "%s checkpoint", (name == NULL) ? "*" : name); 1402 asl_msg_set_key_val_op(qmsg, "action", tmp, ASL_QUERY_OP_EQUAL); 1403 free(tmp); 1404 1405 res = control_query(qmsg); 1406 1407 asl_msg_list_release(res); 1408 return 0; 1409} 1410 1411int 1412cli_main(int argc, char *argv[]) 1413{ 1414 int i, work; 1415 asl_out_module_t *mod, *m; 1416 asl_out_rule_t *r; 1417 asl_out_dst_data_t store, *asl_store_dst = NULL; 1418 const char *mname = NULL; 1419 1420 if (geteuid() != 0) 1421 { 1422 if (argc == 0) debug = DEBUG_ASL; 1423 else debug = DEBUG_STDERR; 1424 1425 debug_log(ASL_LEVEL_ERR, "aslmanager must be run by root\n"); 1426 exit(1); 1427 } 1428 1429 module_ttl = DEFAULT_TTL; 1430 1431 /* cobble up a dst_data with defaults and parameter settings */ 1432 memset(&store, 0, sizeof(store)); 1433 store.ttl[LEVEL_ALL] = DEFAULT_TTL; 1434 store.all_max = DEFAULT_MAX_SIZE; 1435 1436 for (i = 1; i < argc; i++) 1437 { 1438 if (!strcmp(argv[i], "-s")) 1439 { 1440 if (((i + 1) < argc) && (argv[i + 1][0] != '-')) 1441 { 1442 store.path = strdup(argv[++i]); 1443 asl_store_dst = &store; 1444 } 1445 } 1446 } 1447 1448 /* get parameters from asl.conf */ 1449 mod = asl_out_module_init(); 1450 1451 if (mod != NULL) 1452 { 1453 for (r = mod->ruleset; r != NULL; r = r->next) 1454 { 1455 if ((asl_store_dst == NULL) && (r->action == ACTION_OUT_DEST) && (!strcmp(r->dst->path, PATH_ASL_STORE))) 1456 asl_store_dst = r->dst; 1457 } 1458 1459 for (r = mod->ruleset; r != NULL; r = r->next) 1460 { 1461 if (r->action == ACTION_SET_PARAM) 1462 { 1463 if (r->query == NULL) _aslmanager_set_param(asl_store_dst, r->options); 1464 } 1465 } 1466 } 1467 1468 work = DO_ASLDB | DO_MODULE; 1469 1470 for (i = 1; i < argc; i++) 1471 { 1472 if (!strcmp(argv[i], "-a")) 1473 { 1474 if (((i + 1) < argc) && (argv[i + 1][0] != '-')) asl_store_dst->rotate_dir = strdup(argv[++i]); 1475 else asl_store_dst->rotate_dir = strdup(PATH_ASL_ARCHIVE); 1476 asl_store_dst->mode = 0400; 1477 } 1478 else if (!strcmp(argv[i], "-store_ttl")) 1479 { 1480 if (((i + 1) < argc) && (argv[i + 1][0] != '-')) asl_store_dst->ttl[LEVEL_ALL] = atoi(argv[++i]); 1481 } 1482 else if (!strcmp(argv[i], "-module_ttl")) 1483 { 1484 if (((i + 1) < argc) && (argv[i + 1][0] != '-')) module_ttl = atoi(argv[++i]); 1485 } 1486 else if (!strcmp(argv[i], "-ttl")) 1487 { 1488 if (((i + 1) < argc) && (argv[i + 1][0] != '-')) module_ttl = asl_store_dst->ttl[LEVEL_ALL] = atoi(argv[++i]); 1489 } 1490 else if (!strcmp(argv[i], "-size")) 1491 { 1492 if (((i + 1) < argc) && (argv[i + 1][0] != '-')) asl_store_dst->all_max = asl_str_to_size(argv[++i]); 1493 } 1494 else if (!strcmp(argv[i], "-checkpoint")) 1495 { 1496 work |= DO_CHECKPT; 1497 } 1498 else if (!strcmp(argv[i], "-module")) 1499 { 1500 work &= ~DO_ASLDB; 1501 1502 /* optional name follows -module */ 1503 if ((i +1) < argc) 1504 { 1505 if (argv[i + 1][0] != '-') mname = argv[++i]; 1506 } 1507 } 1508 else if (!strcmp(argv[i], "-asldb")) 1509 { 1510 work = DO_ASLDB; 1511 } 1512 else if (!strcmp(argv[i], "-d")) 1513 { 1514 if (((i + i) < argc) && (argv[i+1][0] != '-')) set_debug(DEBUG_STDERR, argv[++i]); 1515 else set_debug(DEBUG_STDERR, NULL); 1516 } 1517 else if (!strcmp(argv[i], "-dd")) 1518 { 1519 dryrun = 1; 1520 1521 if (((i + i) < argc) && (argv[i+1][0] != '-')) set_debug(DEBUG_STDERR, argv[++i]); 1522 else set_debug(DEBUG_STDERR, NULL); 1523 } 1524 } 1525 1526 if (asl_store_dst->path == NULL) asl_store_dst->path = strdup(PATH_ASL_STORE); 1527 1528 debug_log(ASL_LEVEL_ERR, "aslmanager starting%s\n", (dryrun == 1) ? " dryrun" : ""); 1529 1530 if (work & DO_ASLDB) process_asl_data_store(asl_store_dst); 1531 1532 if (work & DO_MODULE) 1533 { 1534 if (work & DO_CHECKPT) checkpoint(mname); 1535 1536 if (mod != NULL) 1537 { 1538 for (m = mod; m != NULL; m = m->next) 1539 { 1540 if ((mname == NULL) || ((m->name != NULL) && (!strcmp(m->name, mname)))) 1541 { 1542 process_module(m); 1543 } 1544 } 1545 } 1546 } 1547 1548 asl_out_module_free(mod); 1549 1550 debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n"); 1551 debug_log(ASL_LEVEL_ERR, "aslmanager finished%s\n", (dryrun == 1) ? " dryrun" : ""); 1552 if (asl_aux_fd >= 0) asl_close_auxiliary_file(asl_aux_fd); 1553 1554 return 0; 1555} 1556 1557static void 1558accept_connection(xpc_connection_t peer) 1559{ 1560 xpc_connection_set_event_handler(peer, ^(xpc_object_t request) { 1561 if (xpc_get_type(request) == XPC_TYPE_DICTIONARY) 1562 { 1563 uid_t uid = xpc_connection_get_euid(peer); 1564 1565 /* send a reply immediately */ 1566 xpc_object_t reply = xpc_dictionary_create_reply(request); 1567 xpc_connection_send_message(peer, reply); 1568 xpc_release(reply); 1569 1570 /* 1571 * Some day, we may use the dictionary to pass parameters 1572 * to aslmanager, but for now, we ignore the input. 1573 */ 1574 if (uid == 0) cli_main(0, NULL); 1575 } 1576 else if (xpc_get_type(request) == XPC_TYPE_ERROR) 1577 { 1578 /* disconnect */ 1579 } 1580 1581 dispatch_async(serverq, ^__attribute__((noreturn)) { xpc_server_exit(0); }); 1582 }); 1583 1584 xpc_connection_resume(peer); 1585} 1586 1587int 1588main(int argc, char *argv[]) 1589{ 1590 int64_t is_managed = 0; 1591 1592 vproc_swap_integer(NULL, VPROC_GSK_IS_MANAGED, NULL, &is_managed); 1593 1594 if (is_managed == 0) return cli_main(argc, argv); 1595 1596 /* XPC server */ 1597 serverq = dispatch_queue_create("aslmanager", NULL); 1598 xpc_track_activity(); 1599 1600 /* Handle incoming messages. */ 1601 listener = xpc_connection_create_mach_service("com.apple.aslmanager", serverq, XPC_CONNECTION_MACH_SERVICE_LISTENER); 1602 xpc_connection_set_event_handler(listener, ^(xpc_object_t peer) { 1603 if (xpc_get_type(peer) == XPC_TYPE_CONNECTION) accept_connection(peer); 1604 }); 1605 xpc_connection_resume(listener); 1606 1607 dispatch_main(); 1608} 1609