X-Git-Url: https://git.saurik.com/apple/syslog.git/blobdiff_plain/e125da38929cd700d1ef4f2d364c6fbcbb2247cc..3cdd567c187c10b7decc42c9d15b29749836a2a9:/util.tproj/syslog.c?ds=sidebyside diff --git a/util.tproj/syslog.c b/util.tproj/syslog.c index 383be59..baa90f4 100644 --- a/util.tproj/syslog.c +++ b/util.tproj/syslog.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2009 Apple Inc. All rights reserved. + * Copyright (c) 2007-2015 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,6 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ +#include #include #include #include @@ -36,14 +37,19 @@ #include #include #include +#include #include #include #include +#include +#include #include -#include +#include "asl_ipc.h" #include #include #include +#include +#include "asl_common.h" #define MOD_CASE_FOLD 'C' #define MOD_REGEX 'R' @@ -65,9 +71,6 @@ #define FACILITY_CONSOLE "com.apple.console" -/* Shared with Libc */ -#define NOTIFY_RC "com.apple.asl.remote" - #define SEARCH_EOF -1 #define SEARCH_NULL 0 #define SEARCH_MATCH 1 @@ -76,7 +79,6 @@ #define PROC_NOT_UNIQUE -2 #define RC_MASTER -1 -#define RC_SYSLOGD -2 #define CHUNK 64 #define forever for(;;) @@ -84,14 +86,11 @@ #define SEND_FORMAT_LEGACY 0 #define SEND_FORMAT_ASL 1 -#define TIME_SEC 0x00000010 -#define TIME_UTC 0x00000020 -#define TIME_LCL 0x00000040 - #define FORMAT_RAW 0x00000100 #define FORMAT_LEGACY 0x00000200 #define FORMAT_STD 0x00000400 #define FORMAT_XML 0x00000800 +#define COMPRESS_DUPS 0x00010000 #define EXPORT 0x00000100 @@ -103,91 +102,198 @@ #define ASL_FILTER_MASK_PAC 0x07 #define FETCH_BATCH 1024 +#define MAX_RANDOM 8192 + +#define DB_SELECT_ASL 0 +#define DB_SELECT_STORE 1 +#define DB_SELECT_FILES 2 +#define DB_SELECT_SYSLOGD 3 +#define DB_SELECT_LEGACY 4 -#define DB_SELECT_STORE 0 -#define DB_SELECT_FILES 1 -#define DB_SELECT_SYSLOGD 2 -#define DB_SELECT_LEGACY 3 +/* STD and BSD format messages start with 'DAY MMM DD HH:MM:SS ' timestamp */ +#define STD_BSD_DATE_LEN 20 + +/* Max message size for direct watch */ +#define MAX_DIRECT_SIZE 16384 + +/* Buffer for direct watch data */ +#define DIRECT_BUF_SIZE 1024 static asl_file_list_t *db_files = NULL; static asl_store_t *store = NULL; static asl_file_t *legacy = NULL; static asl_file_t *export = NULL; - -static uint32_t dbselect = DB_SELECT_STORE; +static const char *sort_key = NULL; +static const char *sort_key_2 = NULL; +static int sort_numeric = 0; +static char *last_printmsg_str = NULL; +static int last_printmsg_count = 0; +static const char *tfmt = NULL; + +#if TARGET_OS_EMBEDDED +static uint32_t dbselect = DB_SELECT_SYSLOGD; +#else +static uint32_t dbselect = DB_SELECT_ASL; +#endif + +typedef struct +{ + char *name; + uint32_t count; + uint32_t total_messages; + size_t total_size; + uint32_t *messages; + size_t *size; +} sender_stat_t; + +#define ASL_IOS_STATS_DIR "/var/log/asl/Logs/ASLStatistics" +static uint32_t stats_sender_count; +static sender_stat_t **stats_sender; +static uint32_t stats_total_all_messages; /* notify SPI */ uint32_t notify_register_plain(const char *name, int *out_token); -extern char *asl_msg_to_string(aslmsg msg, uint32_t *len); -extern asl_msg_t *asl_msg_from_string(const char *buf); -extern char *asl_list_to_string(asl_search_result_t *list, uint32_t *outlen); -extern asl_search_result_t *asl_list_from_string(const char *buf); -extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b); +asl_msg_t *_asl_server_control_query(void); extern time_t asl_parse_time(const char *in); +asl_msg_t * asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const char *sstr, const char *fstr, const char *mstr); /* END PRIVATE API */ -#define ASL_SERVICE_NAME "com.apple.system.logger" static mach_port_t asl_server_port = MACH_PORT_NULL; static const char *myname = "syslog"; +/* forward */ +asl_msg_list_t *syslogd_query(asl_msg_list_t *q, uint64_t start, int count, int dir, uint64_t *last); +static void printmsg(FILE *f, asl_msg_t *msg, char *fmt, int pflags); + +#define HELP_UNAVAILABLE -1 +#define HELP_CONTROL HELP_UNAVAILABLE /* undocumented */ +#define HELP_ALL 0 +#define HELP_SEND 1 +#define HELP_REMOTE_CONTROL 2 +#define HELP_CONFIG 3 +#define HELP_MODULE 4 +#define HELP_SEARCH 5 +#define HELP_STATS 6 + void -usage() +usage(uint32_t section) { + if (section == HELP_UNAVAILABLE) + { + fprintf(stderr, "help is not available for this command\n"); + return; + } + fprintf(stderr, "usage:\n"); - fprintf(stderr, "%s -s [-r host] [-l level] message...\n", myname); - fprintf(stderr, " send a message\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "%s -s [-r host] -k key val [key val]...\n", myname); - fprintf(stderr, " send a message with the given keys and values\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "%s -c process [filter]\n", myname); - fprintf(stderr, " get (set if filter is specified) syslog filter for process (pid or name)\n"); - fprintf(stderr, " level may be any combination of the characters \"p a c e w n i d\"\n"); - fprintf(stderr, " p = Emergency (\"Panic\")\n"); - fprintf(stderr, " a = Alert\n"); - fprintf(stderr, " c = Critical\n"); - fprintf(stderr, " e = Error\n"); - fprintf(stderr, " w = Warning\n"); - fprintf(stderr, " n = Notice\n"); - fprintf(stderr, " i = Info\n"); - fprintf(stderr, " d = Debug\n"); - fprintf(stderr, " a minus sign preceeding a single letter means \"up to\" that level\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "%s [-f file...] [-d path...] [-x file] [-w [N]] [-F format] [-u] [-k key [[op] val]]... [-o -k key [[op] val]] ...]...\n", myname); - fprintf(stderr, " -f read named file[s], rather than standard log message store.\n"); - fprintf(stderr, " -d read all file in named directory path, rather than standard log message store.\n"); - fprintf(stderr, " -x export to named ASL format file, rather than printing\n"); - fprintf(stderr, " -w watch data store (^C to quit)\n"); - fprintf(stderr, " prints the last N matching lines (default 10) before waiting\n"); - fprintf(stderr, " \"-w 0\" prints all matching lines before waiting\n"); - fprintf(stderr, " -F output format may be \"std\", \"raw\", \"bsd\", or \"xml\"\n"); - fprintf(stderr, " format may also be a string containing variables of the form\n"); - fprintf(stderr, " $Key or $(Key) - use the latter for non-whitespace delimited variables\n"); - fprintf(stderr, " -T timestamp format may be \"sec\" (seconds), \"utc\" (UTC), or \"local\" (local timezone)\n"); - fprintf(stderr, " -E text encoding may be \"vis\", \"safe\", or \"none\"\n"); - fprintf(stderr, " -u print timestamps using UTC (equivalent to \"-T utc\")\n"); - fprintf(stderr, " -k key/value match\n"); - fprintf(stderr, " if no operator or value is given, checks for the existance of the key\n"); - fprintf(stderr, " if no operator is given, default is \"%s\"\n", OP_EQ); - fprintf(stderr, " -C alias for \"-k Facility com.apple.console\"\n"); - fprintf(stderr, " -o begins a new query\n"); - fprintf(stderr, " queries are \'OR\'ed together\n"); - fprintf(stderr, "operators are zero or more modifiers followed by a comparison\n"); - fprintf(stderr, " %s equal\n", OP_EQ); - fprintf(stderr, " %s not equal\n", OP_NE); - fprintf(stderr, " %s greater than\n", OP_GT); - fprintf(stderr, " %s greater or equal\n", OP_GE); - fprintf(stderr, " %s less than\n", OP_LT); - fprintf(stderr, " %s less or equal\n", OP_LE); - fprintf(stderr, "optional modifiers for operators\n"); - fprintf(stderr, " %c case-fold\n", MOD_CASE_FOLD); - fprintf(stderr, " %c regular expression\n", MOD_REGEX); - fprintf(stderr, " %c substring\n", MOD_SUBSTRING); - fprintf(stderr, " %c prefix\n", MOD_PREFIX); - fprintf(stderr, " %c suffix\n", MOD_SUFFIX); - fprintf(stderr, " %c numeric comparison\n", MOD_NUMERIC); + + if ((section == HELP_ALL) || (section == HELP_SEND)) + { + fprintf(stderr, "%s -s [-r host] [-l level] message...\n", myname); + fprintf(stderr, " send a message\n"); + fprintf(stderr, "\n"); + + fprintf(stderr, "%s -s [-r host] -k key val [key val]...\n", myname); + fprintf(stderr, " send a message with the given keys and values\n"); + fprintf(stderr, "\n"); + } + + if ((section == HELP_ALL) || (section == HELP_REMOTE_CONTROL)) + { + fprintf(stderr, "%s -c process [mask] [-s [on|off]] [-t [on|off]]\n", myname); + fprintf(stderr, " get (set if mask or actions are specified) syslog filter mask and actions for process (pid or name)\n"); + fprintf(stderr, " mask may be any combination of the characters \"p a c e w n i d\"\n"); + fprintf(stderr, " p = Emergency (\"Panic\")\n"); + fprintf(stderr, " a = Alert\n"); + fprintf(stderr, " c = Critical\n"); + fprintf(stderr, " e = Error\n"); + fprintf(stderr, " w = Warning\n"); + fprintf(stderr, " n = Notice\n"); + fprintf(stderr, " i = Info\n"); + fprintf(stderr, " d = Debug\n"); + fprintf(stderr, " a minus sign preceding a single letter means \"up to\" that level\n"); + fprintf(stderr, " use \"0\" for process to get or set master syslog flags\n"); + fprintf(stderr, " use \"-c process off\" to deactivate current settings\n"); + fprintf(stderr, " -s controls sending ASL mesages (to syslogd)\n"); + fprintf(stderr, " -t controls sending Activity Tracing mesages\n"); + fprintf(stderr, "\n"); + } + + if ((section == HELP_ALL) || (section == HELP_CONFIG)) + { + fprintf(stderr, "%s -config [params...]\n", myname); + fprintf(stderr, " without params, fetch and print syslogd parameters and statistics\n"); + fprintf(stderr, " otherwise, set or reset syslogd configuration parameters\n"); + fprintf(stderr, "\n"); + } + + if ((section == HELP_ALL) || (section == HELP_MODULE)) + { + fprintf(stderr, "%s -module [name [action]]\n", myname); + fprintf(stderr, " with no name, prints configuration for all ASL output modules\n"); + fprintf(stderr, " with name and no action, prints configuration for named ASL output module\n"); + fprintf(stderr, " supported actions - module name required, use '*' (with single quotes) for all modules:\n"); + fprintf(stderr, " enable [01] enables (or disables with 0) named module\n"); + fprintf(stderr, " does not apply to com.apple.asl when '*' is used\n"); + fprintf(stderr, " checkpoint [file] checkpoints all files or specified file for named module\n"); + fprintf(stderr, "\n"); + } + + if ((section == HELP_ALL) || (section == HELP_SEARCH)) + { + 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); + fprintf(stderr, " -f read named file[s], rather than standard log message store.\n"); + fprintf(stderr, " -d read all file in named directory path, rather than standard log message store.\n"); + fprintf(stderr, " -x export to named ASL format file, rather than printing\n"); + fprintf(stderr, " -w watch data store (^C to quit)\n"); + fprintf(stderr, " prints the last N matching lines (default 10) before waiting\n"); + fprintf(stderr, " \"-w all\" prints all matching lines before waiting\n"); + fprintf(stderr, " \"-w boot\" prints all matching lines since last system boot before waiting\n"); + fprintf(stderr, " -F output format may be \"std\", \"raw\", \"bsd\", or \"xml\"\n"); + fprintf(stderr, " format may also be a string containing variables of the form\n"); + fprintf(stderr, " $Key or $(Key) - use the latter for non-whitespace delimited variables\n"); + fprintf(stderr, " -T timestamp format may be \"sec\" (seconds), \"utc\" (UTC), or \"local\" (local timezone)\n"); + fprintf(stderr, " -E text encoding may be \"vis\", \"safe\", or \"none\"\n"); + fprintf(stderr, " -nodc no duplicate message compression\n"); + fprintf(stderr, " -u print timestamps using UTC (equivalent to \"-T utc\")\n"); + fprintf(stderr, " -sort sort messages using value for specified key1 (secondary sort by key2 if provided)\n"); + fprintf(stderr, " -nsort numeric sort messages using value for specified key1 (secondary sort by key2 if provided)\n"); + fprintf(stderr, " -k key/value match\n"); + fprintf(stderr, " if no operator or value is given, checks for the existence of the key\n"); + fprintf(stderr, " if no operator is given, default is \"%s\"\n", OP_EQ); + fprintf(stderr, " -B only process log messages since last system boot\n"); + fprintf(stderr, " -C alias for \"-k Facility com.apple.console\"\n"); + fprintf(stderr, " -o begins a new query\n"); + fprintf(stderr, " queries are \'OR\'ed together\n"); + fprintf(stderr, "operators are zero or more modifiers followed by a comparison\n"); + fprintf(stderr, " %s equal\n", OP_EQ); + fprintf(stderr, " %s not equal\n", OP_NE); + fprintf(stderr, " %s greater than\n", OP_GT); + fprintf(stderr, " %s greater or equal\n", OP_GE); + fprintf(stderr, " %s less than\n", OP_LT); + fprintf(stderr, " %s less or equal\n", OP_LE); + fprintf(stderr, "optional modifiers for operators\n"); + fprintf(stderr, " %c case-fold\n", MOD_CASE_FOLD); + fprintf(stderr, " %c regular expression\n", MOD_REGEX); + fprintf(stderr, " %c substring\n", MOD_SUBSTRING); + fprintf(stderr, " %c prefix\n", MOD_PREFIX); + fprintf(stderr, " %c suffix\n", MOD_SUFFIX); + fprintf(stderr, " %c numeric comparison\n", MOD_NUMERIC); + fprintf(stderr, "\n"); + } + + if ((section == HELP_ALL) || (section == HELP_STATS)) + { + fprintf(stderr, "%s -stats [-n n] [-d path] [-v]\n", myname); + fprintf(stderr, " compiles and prints syslogd usage statistics\n"); + fprintf(stderr, " -n n prints stats for just the top n (e.g. top 10) senders\n"); + fprintf(stderr, " -d path reads the ASL database at the given path for statistics\n"); + fprintf(stderr, " -v verbose ([message_count total_data data_average] for 10 minute intervals)\n"); + fprintf(stderr, "\n"); + } + + fprintf(stderr, "NOTE: Most system logs have moved to a new logging system. See log(1) for more information.\n"); } const char * @@ -213,6 +319,170 @@ asl_level_string(int level) return "Unknown"; } +int +module_control(int argc, char *argv[]) +{ + const char *val = NULL; + uint64_t last; + char *str; + int i; + + for (i = 2; i < argc; i++) + { + if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help"))) + { + usage(HELP_MODULE); + return 0; + } + } + + asl_msg_t *ctl = _asl_server_control_query(); + if (ctl == NULL) + { + fprintf(stderr, "can't get status information from syslogd\n"); + return -1; + } + + argc -= 2; + argv += 2; + + if (argc < 2) + { + int first = 1; + + /* print config */ + asl_out_module_t *m = asl_out_module_init(); + asl_out_module_t *x = m; + + while (x != NULL) + { + if ((argc == 0) || (!strcmp(argv[0], x->name))) + { + asl_msg_lookup(ctl, x->name, &val, NULL); + + if (first == 0) printf("\n"); + first = 0; + + if (x->name == NULL) printf("ASL out module has no name\n"); + else printf("ASL out module: %s %s[current status: %s]\n", x->name, (x->flags & MODULE_FLAG_LOCAL) ? "local " : "", (val == NULL) ? "unknown" : val ); + + asl_out_module_print(stdout, x); + } + + x = x->next; + } + + asl_msg_release(ctl); + asl_out_module_free(m); + return 0; + } + + /* name enable [val] */ + /* name disable [val] */ + if ((!strcmp(argv[1], "enable")) || (!strcmp(argv[1], "disable"))) + { + int want = -1; + int status = -1; + asl_msg_t *cm; + asl_client_t *ac; + + if (!strcmp(argv[1], "enable")) + { + if (argc < 3) want = 1; + else if (!strcmp(argv[2], "1")) want = 1; + else if (!strcmp(argv[2], "0")) want = 0; + else + { + printf("invalid value %s for %s %s - expecting 0 or 1\n", argv[2], argv[0], argv[1]); + exit(-1); + } + } + else + { + if (argc < 3) want = 0; + else if (!strcmp(argv[2], "1")) want = 0; + else if (!strcmp(argv[2], "0")) want = 1; + else + { + printf("invalid value %s for %s %s - expecting 0 or 1\n", argv[2], argv[0], argv[1]); + exit(-1); + } + } + + asl_msg_lookup(ctl, argv[0], &val, NULL); + if (val != NULL) + { + if (!strcmp(val, "enabled")) status = 1; + else status = 0; + } + + asl_msg_release(ctl); + + if (want < 0) + { + printf("internal error: want = -1\n"); + exit(-1); + } + + if (want == status) + { + printf("module %s is already %s\n", argv[0], val); + return 0; + } + + cm = asl_msg_new(ASL_TYPE_MSG); + asprintf(&str, "@ %s enable %d", argv[0], want); + + if ((cm == NULL) || (str == NULL)) + { + fprintf(stderr, "can't allocate memory - exiting\n"); + exit(-1); + } + + ac = asl_client_open(NULL, NULL, 0); + asl_client_set_filter(ac, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); + asl_msg_set_key_val(cm, ASL_KEY_LEVEL, "7"); + asl_msg_set_key_val(cm, ASL_KEY_OPTION, "control"); + asl_msg_set_key_val(cm, ASL_KEY_MSG, str); + asl_client_send(ac, cm); + + asl_client_release(ac); + asl_msg_release(cm); + free(str); + return 0; + } + + asl_msg_release(ctl); + + /* name checkpoint [file] */ + if (!strcmp(argv[1], "checkpoint")) + { + asl_msg_list_t *q = asl_msg_list_new(); + asl_msg_t *qm = asl_msg_new(ASL_TYPE_QUERY); + + if ((q == NULL) || (qm == NULL)) + { + fprintf(stderr, "can't allocate memory - exiting\n"); + exit(-1); + } + + asl_msg_list_append(q, qm); + asl_msg_release(qm); + + asl_msg_set_key_val_op(qm, ASL_KEY_OPTION, "control", ASL_QUERY_OP_EQUAL); + asprintf(&str, "%s checkpoint%s%s", argv[0], (argc > 2) ? " " : "", (argc > 2) ? argv[2] : ""); + asl_msg_set_key_val_op(qm, "action", str, ASL_QUERY_OP_EQUAL); + + asl_msg_list_t *res = syslogd_query((asl_msg_list_t *)q, 0, 0, 1, &last); + free(q); + asl_msg_list_release(res); + return 0; + } + + printf("unknown module control: %s\n", argv[1]); + exit(-1); +} + int procinfo(char *pname, int *pid, int *uid) { @@ -318,7 +588,7 @@ rcontrol_get_string(const char *name, int *val) } int -rcontrol_set_string(const char *name, int filter) +rcontrol_set_string(const char *name, uint32_t bits) { int t, status; uint64_t x; @@ -326,7 +596,7 @@ rcontrol_set_string(const char *name, int filter) status = notify_register_plain(name, &t); if (status != NOTIFY_STATUS_OK) return status; - x = filter; + x = bits; status = notify_set_state(t, x); notify_post(NOTIFY_RC); notify_cancel(t); @@ -486,7 +756,6 @@ rcontrol_name(pid_t pid, uid_t uid) { static char str[1024]; - if (pid == RC_SYSLOGD) return NOTIFY_SYSTEM_ASL_FILTER; if (pid == RC_MASTER) return NOTIFY_SYSTEM_MASTER; memset(str, 0, sizeof(str)); @@ -495,68 +764,77 @@ rcontrol_name(pid_t pid, uid_t uid) return str; } +void +print_eval_bits(uint32_t eval) +{ + printf("0x%08x O%s ", eval, (eval & EVAL_ACTIVE) ? "N " : "FF"); + if (eval & EVAL_SEND_ASL) printf("ASL "); + if (eval & EVAL_SEND_TRACE) printf("TRACE "); + if (eval & EVAL_TEXT_FILE) printf("TEXT "); + if (eval & EVAL_ASL_FILE) printf("FILE "); + if (eval & EVAL_TUNNEL) printf("TUNNEL "); + printf("/ 0x%02x %s\n", eval & EVAL_LEVEL_MASK, asl_filter_string(eval & EVAL_LEVEL_MASK)); +} + int rcontrol_get(pid_t pid, uid_t uid) { int filter, status; - const char *name; filter = 0; if (pid < 0) { - name = "Master"; - if (pid == RC_SYSLOGD) name = "ASL Data Store"; - status = rcontrol_get_string(rcontrol_name(pid, uid), &filter); if (status == NOTIFY_STATUS_OK) { - printf("%s filter mask: %s\n", name, asl_filter_string(filter)); + printf("Master settings: "); + print_eval_bits(filter); return 0; } - printf("Unable to determine %s filter mask\n", name); + printf("Unable to determine master settings\n"); return -1; } status = rcontrol_get_string(rcontrol_name(pid, uid), &filter); if (status == NOTIFY_STATUS_OK) { - printf("Process %d syslog filter mask: %s\n", pid, asl_filter_string(filter)); + printf("Process %d syslog settings: ", pid); + print_eval_bits(filter); return 0; } - printf("Unable to determine syslog filter mask for pid %d\n", pid); + printf("Unable to determine syslog settings for pid %d\n", pid); return -1; } int -rcontrol_set(pid_t pid, uid_t uid, int filter) +rcontrol_set(pid_t pid, uid_t uid, uint32_t bits) { int status; - const char *name; + const char *rcname; + + rcname = rcontrol_name(pid, uid); if (pid < 0) { - name = "Master"; - if (pid == RC_SYSLOGD) name = "ASL Data Store"; - status = rcontrol_set_string(rcontrol_name(pid, uid), filter); + status = rcontrol_set_string(rcname, bits); if (status == NOTIFY_STATUS_OK) { - printf("Set %s syslog filter mask: %s\n", name, asl_filter_string(filter)); + if (pid == RC_MASTER) status = notify_post(NOTIFY_SYSTEM_MASTER); return 0; } - printf("Unable to set %s syslog filter mask: %s\n", name, notify_status_string(status)); + printf("Unable to set master syslog filter mask: %s\n", notify_status_string(status)); return -1; } - status = rcontrol_set_string(rcontrol_name(pid, uid), filter); + status = rcontrol_set_string(rcname, bits); if (status == NOTIFY_STATUS_OK) { - if (pid == RC_SYSLOGD) status = notify_post(NOTIFY_SYSTEM_ASL_FILTER); - printf("Set process %d syslog filter mask set: %s\n", pid, asl_filter_string(filter)); + status = notify_post(rcname); return 0; } @@ -565,18 +843,17 @@ rcontrol_set(pid_t pid, uid_t uid, int filter) } int -rsend(aslmsg msg, char *rhost) +rsend(asl_msg_t *msg, char *rhost) { char *str, *out; uint32_t len, level; char *timestr; const char *val; time_t tick; - struct tm gtime; int s; struct sockaddr_in dst; struct hostent *h; - char myname[MAXHOSTNAMELEN + 1]; + char host_name[MAXHOSTNAMELEN + 1]; if (msg == NULL) return 0; @@ -594,28 +871,23 @@ rsend(aslmsg msg, char *rhost) level = ASL_LEVEL_DEBUG; - val = asl_get(msg, ASL_KEY_LEVEL); + val = asl_msg_get_val_for_key(msg, ASL_KEY_LEVEL); if (val != NULL) level = atoi(val); - memset(>ime, 0, sizeof(struct tm)); - timestr = NULL; tick = time(NULL); - gmtime_r(&tick, >ime); - - /* Canonical form: YYYY.MM.DD hh:mm:ss UTC */ - asprintf(×tr, "%d.%02d.%02d %02d:%02d:%02d UTC", gtime.tm_year + 1900, gtime.tm_mon + 1, gtime.tm_mday, gtime.tm_hour, gtime.tm_min, gtime.tm_sec); - + timestr = NULL; + asprintf(×tr, "%llu", (unsigned long long)tick); if (timestr != NULL) { - asl_set(msg, ASL_KEY_TIME, timestr); + asl_msg_set_key_val(msg, ASL_KEY_TIME, timestr); free(timestr); } - if (gethostname(myname, MAXHOSTNAMELEN) == 0) asl_set(msg, ASL_KEY_HOST, myname); + if (gethostname(host_name, MAXHOSTNAMELEN) == 0) asl_msg_set_key_val(msg, ASL_KEY_HOST, host_name); len = 0; - str = asl_msg_to_string(msg, &len); + str = asl_msg_to_string((asl_msg_t *)msg, &len); if (str == NULL) return -1; asprintf(&out, "%10u %s\n", len+1, str); @@ -639,7 +911,7 @@ rlegacy(char *msg, int level, char *rhost) int s; struct sockaddr_in dst; struct hostent *h; - char myname[MAXHOSTNAMELEN + 1]; + char host_name[MAXHOSTNAMELEN + 1]; if (msg == NULL) return 0; @@ -659,9 +931,9 @@ rlegacy(char *msg, int level, char *rhost) ltime = ctime(&tick); ltime[19] = '\0'; - gethostname(myname, MAXHOSTNAMELEN); + gethostname(host_name, MAXHOSTNAMELEN); - asprintf(&out, "<%d>%s %s syslog[%d]: %s", level, ltime+4, myname, getpid(), msg); + asprintf(&out, "<%d>%s %s syslog[%d]: %s", level, ltime+4, host_name, getpid(), msg); len = strlen(out); sendto(s, out, len, 0, (const struct sockaddr *)&dst, sizeof(struct sockaddr_in)); @@ -670,6 +942,230 @@ rlegacy(char *msg, int level, char *rhost) return 0; } +void +stats_print_sender_stats(sender_stat_t *s, uint32_t interval, bool print_samples) +{ + uint32_t i; + uint32_t p10000 = (s->total_messages * 10000) / stats_total_all_messages; + + if (strcmp(s->name, "*")) printf("%s: %u (%u.%02u%%) %lu\n", s->name, s->total_messages, p10000 / 100, p10000 % 100, s->total_size); + else printf("TOTAL: %u (100.00%%) %lu\n", s->total_messages, s->total_size); + + if (print_samples) + { + int k = 0; + printf("[message_count data_size data_average]\n"); + + for (i = 0, k = 0; i < s->count; i++) + { + size_t avg = 0; + + if (s->messages[i] > 0) avg = s->size[i] / s->messages[i]; + printf("[%u %lu %lu]", s->messages[i], s->size[i], avg); + if (++k == 6) + { + printf("\n"); + k = 0; + } + else + { + printf(" "); + } + } + + for (; i < interval; i++) + { + printf("[0 0 0]"); + if ((++k == 6) || ((i + 1) == interval)) + { + printf("\n"); + k = 0; + } + else + { + printf(" "); + } + } + + printf("\n"); + } +} + +int +stats_n_comp(const void *x, const void *y) +{ + int pn, qn; + sender_stat_t **p = (sender_stat_t **)x; + sender_stat_t **q = (sender_stat_t **)y; + pn = (*p)->total_messages; + qn = (*q)->total_messages; + return qn - pn; +} + +void +stats_sender_set_stat_numbers(const char *name, sender_stat_t *s, uint32_t interval, uint32_t nmsgs, size_t msize) +{ + s->messages = (uint32_t *)reallocf(s->messages, interval * sizeof(uint32_t)); + s->size = (size_t *)reallocf(s->size, interval * sizeof(size_t)); + + for (; s->count < interval; s->count++) + { + s->messages[s->count] = 0; + s->size[s->count] = 0; + } + + s->messages[interval - 1] = nmsgs; + s->size[interval - 1] = msize; + + s->total_messages += nmsgs; + s->total_size += msize; + + if (strcmp(name, "*")) stats_total_all_messages += nmsgs; +} + +void +stats_sender_set_stats(uint32_t interval, const char *name, uint32_t nmsgs, size_t msize) +{ + uint32_t i; + for (i = 0; i < stats_sender_count; i++) + { + if (strcmp(stats_sender[i]->name, name) == 0) + { + stats_sender_set_stat_numbers(name, stats_sender[i], interval, nmsgs, msize); + return; + } + } + + stats_sender = (sender_stat_t **)realloc(stats_sender, (stats_sender_count + 1) * sizeof(sender_stat_t *)); + stats_sender[stats_sender_count] = (sender_stat_t *)calloc(1, sizeof(sender_stat_t)); + stats_sender[stats_sender_count]->name = strdup(name); + + stats_sender_set_stat_numbers(name, stats_sender[stats_sender_count], interval, nmsgs, msize); + stats_sender_count++; +} + +void +stats_process_stat_msg(uint32_t interval, asl_object_t msg) +{ + uint32_t i, n; + + n = asl_count(msg); + + for (i = 0; i < n; i++) + { + const char *key = NULL; + const char *val = NULL; + uint32_t s_n = 0; + size_t s_size = 0; + if (asl_fetch_key_val_op(msg, i, &key, &val, NULL) != 0) break; + if (key[0] == '*') + { + if (2 == sscanf(val, "%u %lu", &s_n, &s_size)) + { + stats_sender_set_stats(interval, key + 1, s_n, s_size); + } + } + } +} + + +int +asl_stats(int argc, char *argv[]) +{ + asl_object_t msg; + uint32_t i, interval, top = UINT32_MAX; + bool print_samples = false; + asl_object_t store = NULL; + + for (i = 2; i < argc; i++) + { + if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help"))) + { + usage(HELP_STATS); + return 0; + } + else if (!strcmp(argv[i], "-n")) + { + i++; + if (i >= argc) + { + fprintf(stderr, "error: expected an integer value following \"-n\"\n"); + usage(HELP_STATS); + return -1; + } + + top = 1 + atoi(argv[i]); + } + else if (!strcmp(argv[i], "-v")) + { + print_samples = true; + } + else if (!strcmp(argv[i], "-d")) + { + i++; + if (i >= argc) + { + fprintf(stderr, "error: expected a directory path following \"-d\"\n"); + usage(HELP_STATS); + return -1; + } + store = asl_open_path(argv[i], 0); + if (store == NULL) + { + fprintf(stderr, "error: failed to open ASL directory %s\n", argv[i]); + return -1; + } + } + } + +#if TARGET_OS_EMBEDDED + if (store == NULL) store = asl_open_path(ASL_IOS_STATS_DIR, 0); + if (store == NULL) + { + fprintf(stderr, "error: failed to open ASL directory %s\n", ASL_IOS_STATS_DIR); + return -1; + } +#endif + + asl_object_t stats_query = asl_new(ASL_TYPE_QUERY); + if (stats_query == NULL) + { + fprintf(stderr, "error: failed to create stats_query\n"); + return -1; + } + + asl_set_query(stats_query, ASL_KEY_FACILITY, "com.apple.asl.statistics", ASL_QUERY_OP_EQUAL); + + asl_object_t stats = asl_search(store, stats_query); + asl_release(stats_query); + asl_release(store); + + if (stats == NULL) + { + printf("no statistics records in the ASL database\n"); + return 0; + } + + for (interval = 1, msg = asl_next(stats); msg != NULL; interval++, msg = asl_next(stats)) + { + stats_process_stat_msg(interval, msg); + } + + asl_release(stats); + + qsort(stats_sender, stats_sender_count, sizeof(sender_stat_t *), stats_n_comp); + + printf("sender: message_count (%% of total) data_size\n"); + + for (i = 0; (i < stats_sender_count) && (i < top); i++) + { + stats_print_sender_stats(stats_sender[i], interval - 1, print_samples); + } + + /* NB sender stats are not freed since we exit after this */ + return 0; +} + static int _isanumber(char *s) { @@ -735,20 +1231,24 @@ asl_string_to_char_level(const char *s) int syslog_remote_control(int argc, char *argv[]) { - int pid, uid, status, mask; + int i, pid, uid, status, mask; + uint32_t bits; - if ((argc < 3) || (argc > 4)) + if (argc < 3) { - fprintf(stderr, "usage:\n"); - fprintf(stderr, "%s -c process [mask]\n", myname); - fprintf(stderr, " get (set if mask is specified) syslog filter mask for process (pid or name)\n"); - fprintf(stderr, " process may be pid or process name\n"); - fprintf(stderr, " use \"-c 0\" to get master syslog filter mask\n"); - fprintf(stderr, " use \"-c 0 off\" to disable master syslog filter mask\n"); - fprintf(stderr, "\n"); + usage(HELP_REMOTE_CONTROL); return -1; } + for (i = 2; i < argc; i++) + { + if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help"))) + { + usage(HELP_REMOTE_CONTROL); + return 0; + } + } + pid = RC_MASTER; uid = -2; @@ -756,9 +1256,8 @@ syslog_remote_control(int argc, char *argv[]) if ((!strcmp(argv[2], "syslogd")) || (!strcmp(argv[2], "syslog"))) { - pid = RC_SYSLOGD; - uid = 0; - status = 0; + fprintf(stderr, "%s: does not have a filter mask\n", argv[2]); + return -1; } else if (_isanumber(argv[2]) != 0) { @@ -785,37 +1284,78 @@ syslog_remote_control(int argc, char *argv[]) if (pid == 0) pid = RC_MASTER; - if (argc == 4) + if (argc == 3) + { + rcontrol_get(pid, uid); + return 0; + } + + bits = EVAL_ACTIVE | EVAL_SEND_ASL | EVAL_SEND_TRACE; + + for (i = 3; i < argc; i++) { - if ((pid == RC_MASTER) && (!strcasecmp(argv[3], "off"))) mask = 0; - else if ((pid == RC_SYSLOGD) && (!strcasecmp(argv[3], "off"))) mask = 0; + if ((!strcasecmp(argv[i], "off")) || (!strcmp(argv[i], "0"))) + { + bits = 0; + } + else if (!strcmp(argv[i], "-s")) + { + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) + { + i++; + if (!strcasecmp(argv[i], "off") || !strcmp(argv[i], "0")) bits &= ~EVAL_SEND_ASL; + } + } + else if (!strcmp(argv[i], "-t")) + { + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) + { + i++; + if (!strcasecmp(argv[i], "off") || !strcmp(argv[i], "0")) bits &= ~EVAL_SEND_TRACE; + } + } else { - mask = asl_string_to_filter(argv[3]); + mask = asl_string_to_filter(argv[i]); if (mask < 0) { - printf("unknown syslog mask: %s\n", argv[3]); + printf("can't understand mask: %s\n", argv[i]); return -1; } + bits = (bits & EVAL_ACTION_MASK) | mask; } - - rcontrol_set(pid, uid, mask); - } - else - { - rcontrol_get(pid, uid); } + rcontrol_set(pid, uid, bits); return 0; } int syslog_send(int argc, char *argv[]) { - int i, start, kv, len, rfmt, rlevel, filter, status; - aslclient asl; - aslmsg m; + int status, i, start, kv, len, rfmt, rlevel; + asl_object_t asl = NULL; + asl_msg_t *m; char tmp[64], *str, *rhost; + struct timeval tval = {0, 0}; + char host_name[MAXHOSTNAMELEN + 1]; + + for (i = 2; i < argc; i++) + { + if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help"))) + { + usage(HELP_SEND); + return 0; + } + } + + status = gettimeofday(&tval, NULL); + if (status != 0) + { + time_t tick = time(NULL); + tval.tv_sec = tick; + tval.tv_usec = 0; + } kv = 0; rhost = NULL; @@ -846,16 +1386,42 @@ syslog_send(int argc, char *argv[]) } start = i+1; } + else if (!strcmp(argv[i], "-x")) + { + i++; + if (i >= argc) + { + fprintf(stderr, "expected a path following -x\n"); + return -1; + } + + asl = asl_open_path(argv[i], ASL_OPT_OPEN_WRITE); + if (asl == NULL) + { + fprintf(stderr, "Could not open %s for write\n", argv[i]); + return -1; + } + } } - asl = asl_open(myname, "syslog", 0); + + if (asl == NULL) asl = asl_open(myname, "syslog", 0); asl_set_filter(asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); - m = asl_new(ASL_TYPE_MSG); - asl_set(m, ASL_KEY_SENDER, myname); + m = asl_base_msg(NULL, rlevel, &tval, myname, "syslog", NULL); + if (m == NULL) + { + fprintf(stderr, "Could not create message\n"); + return -1; + } + + if (gethostname(host_name, MAXHOSTNAMELEN) == 0) asl_msg_set_key_val(m, ASL_KEY_HOST, host_name); - sprintf(tmp, "%d", rlevel); - asl_set(m, ASL_KEY_LEVEL, tmp); + snprintf(tmp, sizeof(tmp), "%d", getuid()); + asl_msg_set_key_val(m, ASL_KEY_UID, tmp); + + snprintf(tmp, sizeof(tmp), "%d", getgid()); + asl_msg_set_key_val(m, ASL_KEY_GID, tmp); str = NULL; @@ -871,33 +1437,21 @@ syslog_send(int argc, char *argv[]) strcat(str, argv[i]); if ((i+1) < argc) strcat(str, " "); } - asl_set(m, ASL_KEY_MSG, str); + asl_msg_set_key_val(m, ASL_KEY_MSG, str); } else { for (i = start + 1; i < argc; i += 2) { if (!strcmp(argv[i], "-k")) i++; - asl_set(m, argv[i], argv[i + 1]); + asl_msg_set_key_val(m, argv[i], argv[i + 1]); if (!strcmp(argv[i], ASL_KEY_LEVEL)) rlevel = atoi(argv[i + 1]); } } if (rhost == NULL) { - filter = 0; - status = rcontrol_get_string(rcontrol_name(RC_SYSLOGD, 0), &filter); - if (status != 0) - { - fprintf(stderr, "Warning: Can't get current syslogd ASL filter value\n"); - } - else if ((ASL_FILTER_MASK(rlevel) & filter) == 0) - { - fprintf(stderr, "Warning: The current syslogd ASL filter value (%s)\n", asl_filter_string(filter)); - fprintf(stderr, " will exclude this message from the ASL database\n"); - } - - asl_send(asl, m); + asl_send(asl, (asl_object_t)m); } else if (rfmt == SEND_FORMAT_ASL) { @@ -908,11 +1462,133 @@ syslog_send(int argc, char *argv[]) rlegacy(str, rlevel, rhost); } - asl_free(m); + asl_msg_release(m); if (str != NULL) free(str); - asl_close(asl); + asl_release(asl); + + return 0; +} + +int +syslog_config(int argc, char *argv[]) +{ + int i; + uint32_t x; + uid_t uid; + asl_client_t *asl; + asl_msg_t *m; + asl_string_t *str; + const char *key, *val; + + for (i = 2; i < argc; i++) + { + if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help"))) + { + usage(HELP_CONFIG); + return 0; + } + } + + if (argc == 2) + { + asl_msg_t *ctl = _asl_server_control_query(); + if (ctl == NULL) + { + fprintf(stderr, "can't get status information from syslogd\n"); + return -1; + } + + for (x = asl_msg_fetch(ctl, 0, &key, &val, NULL); x != IndexNull; x = asl_msg_fetch(ctl, x, &key, &val, NULL)) + { + printf("%s %s\n", key, val); + } + + asl_msg_release(ctl); + return 0; + } + + uid = geteuid(); + if (uid != 0) + { + fprintf(stderr, "syslogd parameters may only be set by the superuser\n"); + return -1; + } + + str = asl_string_new(0); + asl_string_append(str, "= "); + + for (i = 2; i < argc; i++) + { + asl_string_append(str, argv[i]); + if ((i + 1) < argc) asl_string_append(str, " "); + } + + asl = asl_client_open(myname, "syslog", 0); + + m = asl_msg_new(ASL_TYPE_MSG); + asl_msg_set_key_val(m, ASL_KEY_LEVEL, ASL_STRING_NOTICE); + asl_msg_set_key_val(m, ASL_KEY_OPTION, ASL_OPT_CONTROL); + asl_msg_set_key_val(m, ASL_KEY_SENDER, myname); + asl_msg_set_key_val(m, ASL_KEY_MSG, asl_string_bytes(str)); + + asl_client_send(asl, m); + + asl_string_release(str); + asl_msg_release(m); + asl_client_release(asl); + + return 0; +} + +int +syslog_control(int argc, char *argv[]) +{ + int i; + uid_t uid; + asl_client_t *asl; + asl_msg_t *m; + asl_string_t *str; + + for (i = 2; i < argc; i++) + { + if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help"))) + { + usage(HELP_CONTROL); + return 0; + } + } + + uid = geteuid(); + if (uid != 0) + { + fprintf(stderr, "syslog control limited to use by superuser\n"); + return -1; + } + + str = asl_string_new(0); + asl_string_append(str, "@ "); + + for (i = 2; i < argc; i++) + { + asl_string_append(str, argv[i]); + if ((i + 1) < argc) asl_string_append(str, " "); + } + + asl = asl_client_open(myname, "syslog", 0); + + m = asl_msg_new(ASL_TYPE_MSG); + asl_msg_set_key_val(m, ASL_KEY_LEVEL, ASL_STRING_NOTICE); + asl_msg_set_key_val(m, ASL_KEY_OPTION, ASL_OPT_CONTROL); + asl_msg_set_key_val(m, ASL_KEY_SENDER, myname); + asl_msg_set_key_val(m, ASL_KEY_MSG, asl_string_bytes(str)); + + asl_client_send(asl, m); + + asl_string_release(str); + asl_msg_release(m); + asl_client_release(asl); return 0; } @@ -941,7 +1617,7 @@ static void printmsg(FILE *f, asl_msg_t *msg, char *fmt, int pflags) { char *str; - const char *mf, *tf; + const char *mf; uint32_t encode, len, status; uint64_t xid; @@ -970,78 +1646,85 @@ printmsg(FILE *f, asl_msg_t *msg, char *fmt, int pflags) else if (pflags & FORMAT_LEGACY) mf = ASL_MSG_FMT_BSD; else if (pflags & FORMAT_XML) mf = ASL_MSG_FMT_XML; - tf = ASL_TIME_FMT_SEC; - if (pflags & TIME_UTC) tf = ASL_TIME_FMT_UTC; - if (pflags & TIME_LCL) tf = ASL_TIME_FMT_LCL; + len = 0; + str = asl_format_message((asl_msg_t *)msg, mf, tfmt, encode, &len); + if (str == NULL) return; + + if (pflags & COMPRESS_DUPS) + { + if (last_printmsg_str != NULL) + { + if (!strcmp(str + STD_BSD_DATE_LEN, last_printmsg_str + STD_BSD_DATE_LEN)) + { + last_printmsg_count++; + free(str); + } + else + { + if (last_printmsg_count > 0) + { + fprintf(f, "--- last message repeated %d time%s ---\n", last_printmsg_count, (last_printmsg_count == 1) ? "" : "s"); + } + + free(last_printmsg_str); + last_printmsg_str = str; + last_printmsg_count = 0; - len = 0; - str = asl_format_message(msg, mf, tf, encode, &len); - if (str != NULL) + fprintf(f, "%s", str); + } + } + else + { + last_printmsg_str = str; + last_printmsg_count = 0; + + fprintf(f, "%s", str); + } + } + else { fprintf(f, "%s", str); free(str); } } -asl_search_result_t * -store_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64_t *last) +asl_msg_list_t * +store_query(asl_msg_list_t *q, uint64_t start, int count, int dir, uint64_t *last) { - uint32_t status; - asl_search_result_t *res; - if (store == NULL) { - status = asl_store_open_read(NULL, &store); + uint32_t status = asl_store_open_read(NULL, &store); if (status != 0) return NULL; } - res = NULL; - status = asl_store_match(store, q, &res, last, start, count, dir); - if (status != 0) return NULL; - - return res; + return asl_store_match(store, q, last, start, count, 0, dir); } -asl_search_result_t * -file_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64_t *last) +asl_msg_list_t * +file_query(asl_msg_list_t *q, uint64_t start, int count, int dir, uint64_t *last) { - uint32_t status; - asl_search_result_t *res; - - res = NULL; - status = asl_file_list_match(db_files, q, &res, last, start, count, dir); - if (status != 0) return NULL; - - return res; + return asl_file_list_match(db_files, q, last, start, count, 0, dir);; } -asl_search_result_t * -legacy_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64_t *last) +asl_msg_list_t * +legacy_query(asl_msg_list_t *q, uint64_t start, int count, int dir, uint64_t *last) { - uint32_t status; - asl_search_result_t *res; - - res = NULL; - status = asl_file_match(legacy, q, &res, last, start, count, dir); - if (status != 0) return NULL; - - return res; + return asl_file_match(legacy, q, last, start, count, 0, dir); } -asl_search_result_t * -syslogd_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64_t *last) +asl_msg_list_t * +syslogd_query(asl_msg_list_t *q, uint64_t start, int count, int dir, uint64_t *last) { char *str, *res; caddr_t vmstr; uint32_t len, reslen, status; int flags; kern_return_t kstatus; - security_token_t sec; - asl_search_result_t *l; + asl_msg_list_t *l; if (asl_server_port == MACH_PORT_NULL) { - kstatus = bootstrap_look_up(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port); + kstatus = bootstrap_look_up2(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port, 0, BOOTSTRAP_PRIVILEGED_SERVER); if (kstatus != KERN_SUCCESS) { fprintf(stderr, "query failed: can't contact syslogd\n"); @@ -1050,9 +1733,9 @@ syslogd_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64 } len = 0; - str = asl_list_to_string(q, &len); + str = asl_msg_list_to_string(q, &len); - kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE); + kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL)); if (kstatus != KERN_SUCCESS) { free(str); @@ -1064,24 +1747,221 @@ syslogd_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64 res = NULL; reslen = 0; - sec.val[0] = -1; - sec.val[1] = -1; status = 0; flags = 0; if (dir < 0) flags = QUERY_FLAG_SEARCH_REVERSE; - kstatus = _asl_server_query(asl_server_port, (caddr_t)vmstr, len, start, count, flags, (caddr_t *)&res, &reslen, last, (int *)&status, &sec); + kstatus = _asl_server_query_2(asl_server_port, (caddr_t)vmstr, len, start, count, flags, (caddr_t *)&res, &reslen, last, (int *)&status); if (res == NULL) return NULL; - l = asl_list_from_string(res); + l = asl_msg_list_from_string(res); vm_deallocate(mach_task_self(), (vm_address_t)res, reslen); return l; } void -search_once(FILE *f, char *pfmt, int pflags, asl_search_result_t *ql, uint64_t qmin, uint64_t *cmax, uint32_t count, uint32_t batch, int dir, uint32_t tail) +filter_and_print(asl_msg_t *msg, asl_msg_list_t *ql, FILE *f, char *pfmt, int pflags) +{ + int i, do_match, did_match; + + if (msg == NULL) return; + + do_match = 1; + if (ql == NULL) do_match = 0; + else if (ql->count == 0) do_match = 0; + + did_match = 1; + + if (do_match != 0) + { + did_match = 0; + + for (i = 0; (i < ql->count) && (did_match == 0); i++) + { + did_match = asl_msg_cmp(ql->msg[i], (asl_msg_t *)msg); + } + } + + if (did_match != 0) printmsg(f, msg, pfmt, pflags); +} + +#if TARGET_OS_EMBEDDED +void +syslogd_direct_watch(FILE *f, char *pfmt, int pflags, asl_msg_list_t *ql) +{ + struct sockaddr_in address; + int i, bytes, sock, stream, status; + uint32_t n, inlen; + uint16_t port; + socklen_t addresslength; + char *str, buf[DIRECT_BUF_SIZE]; + asl_msg_t *msg; + + if (asl_server_port == MACH_PORT_NULL) + { + status = bootstrap_look_up(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port); + if (status != KERN_SUCCESS) + { + fprintf(stderr, "query failed: can't contact syslogd\n"); + exit(1); + } + } + + addresslength = sizeof(address); + sock = socket(AF_INET, SOCK_STREAM, 0); + port = (arc4random() % (IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO)) + IPPORT_HIFIRSTAUTO; + + memset(&address, 0, addresslength); + address.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + address.sin_family = AF_INET; + address.sin_port = htons(port); + + status = bind(sock, (struct sockaddr *)&address, sizeof(address)); + + for (i = 0; (i < MAX_RANDOM) && (status < 0); i++) + { + port = (arc4random() % (IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO)) + IPPORT_HIFIRSTAUTO; + address.sin_port = htons(port); + + status = bind(sock, (struct sockaddr *)&address, sizeof(address)); + } + + if (status < 0) + { + fprintf(stderr, "query failed: can't find a port to connect to syslogd\n"); + exit(1); + } + + bytes = 0; + + if (listen(sock, 1) == -1) + { + perror("listen"); + exit(1); + } + + i = htons(port); + _asl_server_register_direct_watch(asl_server_port, i); + + stream = accept(sock, (struct sockaddr*)&address, &addresslength); + if (stream == -1) + { + perror("accept"); + exit(1); + } + + forever + { + inlen = 0; + errno = 0; + bytes = recvfrom(stream, &n, sizeof(n), 0, NULL, NULL); + if (bytes <= 0) + { + fprintf(stderr, "\nrecvfrom (message length) returned %d (errno %d) - exiting\n", bytes, errno); + break; + } + else inlen = ntohl(n); + + if (inlen == 0) continue; + + str = NULL; + if (inlen <= DIRECT_BUF_SIZE) + { + str = buf; + } + else + { + str = calloc(1, inlen + 1); + if (str == NULL) + { + fprintf(stderr, "\ncan't allocate memory - exiting\n"); + close(stream); + close(sock); + exit(1); + } + } + + n = 0; + while (n < inlen) + { + errno = 0; + bytes = recvfrom(stream, str + n, inlen - n, 0, NULL, NULL); + if (bytes <= 0) + { + fprintf(stderr, "\nrecvfrom (message body) returned %d (errno %d) at length %d of %d - exiting\n", bytes, errno, n, inlen); + break; + } + else n += bytes; + } + + if (n < inlen) + { + fprintf(stderr, "\ntruncated message: expected %d bytes received %d bytes\n", inlen, n); + close(stream); + close(sock); + exit(1); + } + + msg = asl_msg_from_string(str); + if (str != buf) free(str); + filter_and_print(msg, ql, f, pfmt, pflags); + asl_msg_release(msg); + } + + close(stream); + close(sock); + + address.sin_addr.s_addr = 0; +} +#endif + +int +sort_compare_key(asl_msg_t *a, asl_msg_t *b, const char *key) +{ + const char *va, *vb; + uint64_t na, nb; + + if (key == NULL) return 0; + + va = asl_msg_get_val_for_key(a, key); + vb = asl_msg_get_val_for_key(b, key); + + if (va == NULL) return -1; + if (vb == NULL) return 1; + + if (sort_numeric == 1) + { + na = atoll(va); + nb = atoll(vb); + if (na < nb) return -1; + if (na > nb) return 1; + return 0; + } + + return strcmp(va, vb); +} + +int +sort_compare(const void **ap, const void **bp) +{ + int cmp; + asl_msg_t *a, *b; + + if (sort_key == NULL) return 0; + + a = (asl_msg_t *)*ap; + b = (asl_msg_t *)*bp; + + cmp = sort_compare_key(a, b, sort_key); + if ((cmp == 0) && (sort_key_2 != NULL)) cmp = sort_compare_key(a, b, sort_key_2); + + return cmp; +} + +void +search_once(FILE *f, char *pfmt, int pflags, asl_msg_list_t *ql, uint64_t qmin, uint64_t *cmax, uint32_t count, uint32_t batch, int dir, uint32_t tail) { - asl_search_result_t *res; + asl_msg_list_t *res; int i, more, total; if (pflags & FORMAT_XML) print_xml_header(f); @@ -1092,13 +1972,15 @@ search_once(FILE *f, char *pfmt, int pflags, asl_search_result_t *ql, uint64_t q while (more == 1) { - if (dbselect == DB_SELECT_STORE) res = store_query(ql, qmin, batch, dir, cmax); + if (batch == 0) more = 0; + + if ((dbselect == DB_SELECT_ASL) || (dbselect == DB_SELECT_STORE)) res = store_query(ql, qmin, batch, dir, cmax); else if (dbselect == DB_SELECT_FILES) res = file_query(ql, qmin, batch, dir, cmax); else if (dbselect == DB_SELECT_SYSLOGD) res = syslogd_query(ql, qmin, batch, dir, cmax); else if (dbselect == DB_SELECT_LEGACY) res = legacy_query(ql, qmin, batch, dir, cmax); - if ((dir >= 0) && (*cmax > qmin)) qmin = *cmax; - else if ((dir < 0) && (*cmax < qmin)) qmin = *cmax; + if ((dir >= 0) && (*cmax > qmin)) qmin = *cmax + 1; + else if ((dir < 0) && (*cmax < qmin)) qmin = *cmax - 1; if (res == NULL) { @@ -1118,15 +2000,28 @@ search_once(FILE *f, char *pfmt, int pflags, asl_search_result_t *ql, uint64_t q if (i < 0) i = 0; } + if (sort_key != NULL) + { + qsort(res->msg, res->count, sizeof(asl_msg_t *), sort_compare); + } + if ((f != NULL) || (export != NULL)) { for (; i < res->count; i++) printmsg(f, res->msg[i], pfmt, pflags); } - aslresponse_free((aslresponse)res); + asl_msg_list_release(res); } } + if ((pflags & COMPRESS_DUPS) && (last_printmsg_count > 0)) + { + fprintf(f, "--- last message repeated %d time%s ---\n", last_printmsg_count, (last_printmsg_count == 1) ? "" : "s"); + free(last_printmsg_str); + last_printmsg_str = NULL; + last_printmsg_count = 0; + } + if (pflags & FORMAT_XML) print_xml_trailer(f); } @@ -1289,8 +2184,8 @@ add_op(asl_msg_t *q, char *key, char *op, char *val, uint32_t flags) } o |= flags; - if (qval != NULL) asl_set_query(q, key, qval, o); - else asl_set_query(q, key, val, o); + if (qval != NULL) asl_msg_set_key_val_op(q, key, qval, o); + else asl_msg_set_key_val_op(q, key, val, o); return 0; } @@ -1309,7 +2204,7 @@ add_db_file(const char *name) } /* shouldn't happen */ - if (name == NULL) return DB_SELECT_STORE; + if (name == NULL) return DB_SELECT_ASL; s = NULL; status = asl_file_open_read(name, &s); @@ -1351,6 +2246,17 @@ add_db_dir(const char *name) asl_file_t *s; char *path; + /* + * Try opening as a data store + */ + status = asl_store_open_read(name, &store); + if (status == 0) + { + if (name == NULL) return DB_SELECT_ASL; + if (!strcmp(name, PATH_ASL_STORE)) return DB_SELECT_ASL; + return DB_SELECT_STORE; + } + /* * Open all readable files */ @@ -1390,9 +2296,9 @@ int main(int argc, char *argv[]) { FILE *outfile; - int i, j, n, watch, status, pflags, tflags, iamroot, user_tflag; + int i, j, n, watch, status, pflags, iamroot, user_tflag, export_preserve_id, saw_dash_d, since_boot; int notify_file, notify_token; - asl_search_result_t *qlist; + asl_msg_list_t *qlist; asl_msg_t *cq; char *pfmt; const char *exportname; @@ -1406,29 +2312,56 @@ main(int argc, char *argv[]) flags = 0; tail_count = 0; batch = FETCH_BATCH; - pflags = FORMAT_STD; - tflags = TIME_LCL; - encode = ASL_ENCODE_ASL; + pflags = FORMAT_STD | COMPRESS_DUPS; + encode = ASL_ENCODE_SAFE; cq = NULL; exportname = NULL; + export_preserve_id = 0; + saw_dash_d = 0; + since_boot = 0; i = asl_store_location(); if (i == ASL_STORE_LOCATION_MEMORY) dbselect = DB_SELECT_SYSLOGD; if (getuid() == 0) iamroot = 1; + if ((argc > 1) && ((!strcmp(argv[1], "-help")) || (!strcmp(argv[1], "--help")))) + { + usage(HELP_ALL); + exit(0); + } + for (i = 1; i < argc; i++) { - if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help"))) + + if ((!strcmp(argv[i], "-time")) || (!strcmp(argv[i], "--time"))) + { + qmin = time(NULL); + printf("%llu\n", qmin); + exit(0); + } + + if ((!strcmp(argv[i], "-stats")) || (!strcmp(argv[i], "--stats"))) { - usage(); + asl_stats(argc, argv); exit(0); } - if (!strcmp(argv[i], "-time")) + if ((!strcmp(argv[i], "-config")) || (!strcmp(argv[i], "--config"))) { - qmin = time(NULL); - printf("%llu\n", qmin); + syslog_config(argc, argv); + exit(0); + } + + if ((!strcmp(argv[i], "-control")) || (!strcmp(argv[i], "--control"))) + { + syslog_control(argc, argv); + exit(0); + } + + if ((!strcmp(argv[i], "-module")) || (!strcmp(argv[i], "--module"))) + { + module_control(argc, argv); exit(0); } @@ -1445,9 +2378,11 @@ main(int argc, char *argv[]) } } - qlist = (asl_search_result_t *)calloc(1, sizeof(asl_search_result_t)); + qlist = asl_msg_list_new(); if (qlist == NULL) exit(1); + cq = NULL; + for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-f")) @@ -1459,6 +2394,7 @@ main(int argc, char *argv[]) if (!strcmp(argv[j], "-")) { dbselect = DB_SELECT_SYSLOGD; + i++; break; } else if (argv[j][0] == '-') @@ -1468,23 +2404,28 @@ main(int argc, char *argv[]) else { dbselect = add_db_file(argv[j]); + i++; } } } } - if (!strcmp(argv[i], "-d")) + else if (!strcmp(argv[i], "-d")) { - if ((i + 1) < argc) + saw_dash_d = i + 1; + + if (saw_dash_d < argc) { - for (j = i + 1; j < argc; j++) + for (j = saw_dash_d; j < argc; j++) { if (!strcmp(argv[j], "store")) { dbselect = add_db_dir(PATH_ASL_STORE); + i++; } else if (!strcmp(argv[j], "archive")) { dbselect = add_db_dir(PATH_ASL_ARCHIVE); + i++; } else if (argv[j][0] == '-') { @@ -1493,9 +2434,23 @@ main(int argc, char *argv[]) else { dbselect = add_db_dir(argv[j]); + i++; } } } + else + { + fprintf(stderr, "missing directory name following -d flag\n"); + return -1; + } + } + else if (!strcmp(argv[i], "-b")) + { + batch = atoi(argv[++i]); + } + else if (!strcmp(argv[i], "-B")) + { + since_boot = 1; } else if (!strcmp(argv[i], "-w")) { @@ -1504,31 +2459,85 @@ main(int argc, char *argv[]) if (((i + 1) < argc) && (argv[i + 1][0] != '-')) { i++; - tail_count = atoi(argv[i]); + if (!strcmp(argv[i], "all")) + { + tail_count = (uint32_t)-1; + } + else if (!strcmp(argv[i], "boot")) + { + since_boot = 1; + } + else + { + tail_count = atoi(argv[i]); + } + } + } + else if (!strcmp(argv[i], "-sort")) + { + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) + { + i++; + sort_key = argv[i]; + + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) + { + i++; + sort_key_2 = argv[i]; + } + } + else + { + sort_key = ASL_KEY_MSG_ID; + } + + batch = 0; + } + else if (!strcmp(argv[i], "-nsort")) + { + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) + { + i++; + sort_key = argv[i]; + + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) + { + i++; + sort_key_2 = argv[i]; + } + } + else + { + sort_key = ASL_KEY_MSG_ID; } + + sort_numeric = 1; + batch = 0; } else if (!strcmp(argv[i], "-u")) { - tflags = TIME_UTC; + tfmt = "Z"; user_tflag = 1; } - else if (!strcmp(argv[i], "-x")) + else if ((!strcmp(argv[i], "-x")) || (!strcmp(argv[i], "-X"))) { if ((i + 1) >= argc) { - aslresponse_free(qlist); - usage(); + asl_msg_list_release(qlist); + usage(HELP_SEARCH); exit(1); } + if (!strcmp(argv[i], "-x")) export_preserve_id = 1; + exportname = argv[++i]; } else if (!strcmp(argv[i], "-E")) { if ((i + 1) >= argc) { - aslresponse_free(qlist); - usage(); + asl_msg_list_release(qlist); + usage(HELP_SEARCH); exit(1); } @@ -1536,6 +2545,7 @@ main(int argc, char *argv[]) if (!strcmp(argv[i], "vis")) encode = ASL_ENCODE_ASL; else if (!strcmp(argv[i], "safe")) encode = ASL_ENCODE_SAFE; + else if (!strcmp(argv[i], "xml")) encode = ASL_ENCODE_XML; else if (!strcmp(argv[i], "none")) encode = ASL_ENCODE_NONE; else if ((argv[i][0] >= '0') && (argv[i][0] <= '9') && (argv[i][1] == '\0')) encode = atoi(argv[i]); } @@ -1543,8 +2553,8 @@ main(int argc, char *argv[]) { if ((i + 1) >= argc) { - aslresponse_free(qlist); - usage(); + asl_msg_list_release(qlist); + usage(HELP_SEARCH); exit(1); } @@ -1553,19 +2563,20 @@ main(int argc, char *argv[]) if (!strcmp(argv[i], "raw")) { pflags = FORMAT_RAW; - if (user_tflag == 0) tflags = TIME_SEC; + if (user_tflag == 0) tfmt = "sec"; } else if (!strcmp(argv[i], "std")) { - pflags = FORMAT_STD; + pflags = FORMAT_STD | COMPRESS_DUPS; } else if (!strcmp(argv[i], "bsd")) { - pflags = FORMAT_LEGACY; + pflags = FORMAT_LEGACY | COMPRESS_DUPS; } else if (!strcmp(argv[i], "xml")) { pflags = FORMAT_XML; + encode = ASL_ENCODE_XML; } else { @@ -1577,38 +2588,29 @@ main(int argc, char *argv[]) { if ((i + 1) >= argc) { - aslresponse_free(qlist); - usage(); + asl_msg_list_release(qlist); + usage(HELP_SEARCH); exit(1); } i++; + tfmt = argv[i]; user_tflag = 1; - - if (!strcmp(argv[i], "sec")) tflags = TIME_SEC; - else if (!strcmp(argv[i], "utc")) tflags = TIME_UTC; - else if (!strcmp(argv[i], "local")) tflags = TIME_LCL; - else if (!strcmp(argv[i], "lcl")) tflags = TIME_LCL; - else tflags = TIME_LCL; + } + else if (!strcmp(argv[i], "-nodc")) + { + pflags = pflags & ~COMPRESS_DUPS; } else if (!strcmp(argv[i], "-o")) { flags = 0; - if (qlist->count == 0) - { - qlist->msg = (asl_msg_t **)calloc(1, sizeof(asl_msg_t *)); - } - else + if (cq != NULL) { - qlist->msg = (asl_msg_t **)reallocf(qlist->msg, (qlist->count + 1) * sizeof(asl_msg_t *)); + asl_msg_list_append(qlist, cq); + asl_msg_release(cq); + cq = NULL; } - - if (qlist->msg == NULL) exit(1); - - cq = asl_new(ASL_TYPE_QUERY); - qlist->msg[qlist->count] = cq; - qlist->count++; } else if (!strcmp(argv[i], "-n")) { @@ -1616,22 +2618,23 @@ main(int argc, char *argv[]) } else if (!strcmp(argv[i], "-C")) { - if (qlist->count == 0) + if (cq != NULL) { - qlist->msg = (asl_msg_t **)calloc(1, sizeof(asl_msg_t *)); - if (qlist->msg == NULL) exit(1); - - cq = asl_new(ASL_TYPE_QUERY); - qlist->msg[qlist->count] = cq; - qlist->count++; + asl_msg_list_append(qlist, cq); + asl_msg_release(cq); + cq = NULL; } + flags = 0; + cq = asl_msg_new(ASL_TYPE_QUERY); status = add_op(cq, ASL_KEY_FACILITY, OP_EQ, FACILITY_CONSOLE, flags); + asl_msg_list_append(qlist, cq); + asl_msg_release(cq); + cq = NULL; - flags = 0; if (status != 0) { - aslresponse_free(qlist); + asl_msg_list_release(qlist); exit(1); } } @@ -1648,7 +2651,7 @@ main(int argc, char *argv[]) fprintf(stderr, "invalid sequence: -k"); for (j = i; j <= n; j++) fprintf(stderr, " %s", argv[j]); fprintf(stderr, "\n"); - usage(); + usage(HELP_SEARCH); exit(1); } } @@ -1660,15 +2663,7 @@ main(int argc, char *argv[]) continue; } - if (qlist->count == 0) - { - qlist->msg = (asl_msg_t **)calloc(1, sizeof(asl_msg_t *)); - if (qlist->msg == NULL) exit(1); - - cq = asl_new(ASL_TYPE_QUERY); - qlist->msg[qlist->count] = cq; - qlist->count++; - } + if (cq == NULL) cq = asl_msg_new(ASL_TYPE_QUERY); status = 0; if (n == 1) status = add_op(cq, argv[i], NULL, NULL, flags); @@ -1678,17 +2673,58 @@ main(int argc, char *argv[]) flags = 0; if (status != 0) { - aslresponse_free(qlist); + asl_msg_list_release(qlist); exit(1); } + + i += (n - 1); + } + else + { + fprintf(stderr, "syslog: unknown option \"%s\"\n", argv[i]); + fprintf(stderr, "run \"syslog -help\" for usage\n"); + exit(1); } } - pflags |= tflags; + if (cq != NULL) + { + asl_msg_list_append(qlist, cq); + asl_msg_release(cq); + cq = NULL; + } + pflags |= encode; outfile = stdout; + /* + * Catch and report some cases where watch (-w) doesn't work + */ + if (watch == 1) + { + if (sort_key != NULL) + { + fprintf(stderr, "Warning: -w flag has no effect with -sort flag\n"); + watch = 0; + } + + if (dbselect == DB_SELECT_FILES) + { + if (saw_dash_d == 0) + { + fprintf(stderr, "Warning: -w flag not supported for a set of one or more files\n"); + } + else + { + fprintf(stderr, "Warning: directory \"%s\" is not an ASL data store\n", argv[saw_dash_d]); + fprintf(stderr, " -w flag not supported for a set of one or more files\n"); + } + + watch = 0; + } + } + if (exportname != NULL) { if (watch == 1) @@ -1700,7 +2736,7 @@ main(int argc, char *argv[]) status = asl_file_open_write(exportname, 0644, -1, -1, &export); if (status != ASL_STATUS_OK) { - aslresponse_free(qlist); + asl_msg_list_release(qlist); fprintf(stderr, "export file open failed: %s\n", asl_core_error(status)); exit(1); } @@ -1709,7 +2745,8 @@ main(int argc, char *argv[]) * allow the string cache to be unlimited to maximize string dup compression * preserve message IDs */ - export->flags = ASL_FILE_FLAG_UNLIMITED_CACHE | ASL_FILE_FLAG_PRESERVE_MSG_ID; + export->flags = ASL_FILE_FLAG_UNLIMITED_CACHE; + if (export_preserve_id != 0) export->flags |= ASL_FILE_FLAG_PRESERVE_MSG_ID; outfile = NULL; pflags = EXPORT; @@ -1720,31 +2757,75 @@ main(int argc, char *argv[]) notify_file = -1; notify_token = -1; - if (watch == 1) + fprintf(stderr, "NOTE: Most system logs have moved to a new logging system. See log(1) for more information.\n"); + + /* set starting point */ + if (since_boot == 1) { - if ((dbselect == DB_SELECT_STORE) || (dbselect == DB_SELECT_SYSLOGD)) + /* search back for last "BOOT_TIME (ut_type == 2) record */ + asl_msg_list_t *bt; + asl_msg_t *bq; + + bt = asl_msg_list_new(); + if (bt == NULL) { - status = notify_register_file_descriptor("com.apple.system.logger.message", ¬ify_file, 0, ¬ify_token); - if (status != NOTIFY_STATUS_OK) notify_token = -1; + fprintf(stderr, "\ncan't allocate memory - exiting\n"); + exit(1); } - } - if ((qlist->count == 0) && (watch == 1)) + bq = asl_msg_new(ASL_TYPE_QUERY); + if (bq == NULL) + { + fprintf(stderr, "\ncan't allocate memory - exiting\n"); + exit(1); + } + + asl_msg_list_append(bt, bq); + asl_msg_release(bq); + + asl_msg_set_key_val_op(bq, "ut_type", "2", ASL_QUERY_OP_EQUAL); + + search_once(NULL, NULL, 0, (asl_msg_list_t *)bt, -1, &qmin, 1, 1, -1, 0); + asl_msg_list_release(bt); + + if (qmin > 0) qmin--; + tail_count = 0; + } + else if (watch == 1) { + /* go back tail_count records from last record */ qmin = -1; - search_once(NULL, NULL, 0, NULL, qmin, &cmax, 1, 1, -1, 0); - qmin = (cmax + 1) - tail_count; + search_once(NULL, NULL, 0, qlist, qmin, &cmax, 1, 1, -1, 0); + + if (cmax >= tail_count) qmin = cmax - tail_count; + else qmin = 0; + tail_count = 0; } + if ((watch == 1) && (dbselect == DB_SELECT_ASL)) + { + status = notify_register_file_descriptor("com.apple.system.logger.message", ¬ify_file, 0, ¬ify_token); + if (status != NOTIFY_STATUS_OK) notify_token = -1; + } + /* output should be line buffered */ if (outfile != NULL) setlinebuf(outfile); - search_once(outfile, pfmt, pflags, qlist, qmin, &cmax, 0, batch, 1, tail_count); + search_once(outfile, pfmt, pflags, qlist, qmin + 1, &cmax, 0, 0, 1, tail_count); if (watch == 1) { - if (notify_token == -1) + if (dbselect == DB_SELECT_SYSLOGD) + { +#if TARGET_OS_EMBEDDED + syslogd_direct_watch(outfile, pfmt, pflags, qlist); +#else + fprintf(stderr, "Warning: -w flag cannot be used when querying syslogd directly\n"); + exit(1); +#endif + } + else if (notify_token == -1) { forever { @@ -1764,10 +2845,10 @@ main(int argc, char *argv[]) } if (db_files != NULL) asl_file_list_close(db_files); - if (store != NULL) asl_store_close(store); - if (export != NULL) asl_file_close(export); + if (store != NULL) asl_store_release(store); + if (export != NULL) asl_file_release(export); - aslresponse_free(qlist); + asl_msg_list_release(qlist); exit(0); }