From 5222c21d179b0b291b379bab771199072df3ea35 Mon Sep 17 00:00:00 2001 From: Apple Date: Wed, 15 Jul 2015 22:30:37 +0000 Subject: [PATCH] syslog-322.tar.gz --- aslcommon/asl_common.c | 979 +++++++--- aslcommon/asl_common.h | 71 +- aslcommon/asl_memory.c | 321 ++-- aslcommon/asl_memory.h | 36 +- aslmanager.tproj/aslmanager.c | 1659 +++------------- aslmanager.tproj/cache_delete.c | 145 ++ aslmanager.tproj/cache_delete.h | 24 + ...m.apple.activity_tracing.CacheDelete.plist | 12 + aslmanager.tproj/com.apple.aslmanager.plist | 6 +- aslmanager.tproj/daemon.c | 1695 +++++++++++++++++ aslmanager.tproj/daemon.h | 102 + libsystem_asl.tproj/include/asl.h | 6 +- libsystem_asl.tproj/include/asl_client.h | 3 + libsystem_asl.tproj/include/asl_core.h | 21 + libsystem_asl.tproj/include/asl_file.h | 9 +- libsystem_asl.tproj/include/asl_msg.h | 20 +- libsystem_asl.tproj/include/asl_private.h | 39 +- libsystem_asl.tproj/man/asl.3 | 2 +- libsystem_asl.tproj/src/asl.c | 391 ++-- libsystem_asl.tproj/src/asl_client.c | 43 +- libsystem_asl.tproj/src/asl_core.c | 279 ++- libsystem_asl.tproj/src/asl_file.c | 291 ++- libsystem_asl.tproj/src/asl_msg.c | 501 +++-- libsystem_asl.tproj/src/asl_object.c | 2 +- libsystem_asl.tproj/src/asl_store.c | 123 +- libsystem_asl.tproj/src/asl_string.c | 321 +++- libsystem_asl.tproj/src/asl_util.c | 1 + libsystem_asl.tproj/src/syslog.c | 163 +- syslog.xcodeproj/project.pbxproj | 79 +- syslogd.tproj/after_install.sh | 41 +- syslogd.tproj/asl.conf.5 | 194 +- syslogd.tproj/asl.conf.ios | 30 + .../{asl_sim.conf => asl.conf.ios_sim} | 3 - syslogd.tproj/asl.conf.osx | 34 + syslogd.tproj/asl_action.c | 100 +- syslogd.tproj/bsd_out.c | 6 +- syslogd.tproj/com.apple.system.log | 8 + syslogd.tproj/daemon.c | 305 ++- syslogd.tproj/daemon.h | 33 +- syslogd.tproj/dbserver.c | 322 ++-- syslogd.tproj/remote.c | 6 + syslogd.tproj/syslog.conf | 3 + syslogd.tproj/syslogd.c | 8 +- syslogd.tproj/udp_in.c | 2 +- util.tproj/syslog.1 | 18 +- util.tproj/syslog.c | 687 +++++-- xcodeconfig/aslmanager.xcconfig | 2 +- xcodeconfig/base.xcconfig | 4 - xcodeconfig/libasl.xcconfig | 14 +- xcodeconfig/syslogd.xcconfig | 2 +- xcodeconfig/util.xcconfig | 2 +- 51 files changed, 6178 insertions(+), 2990 deletions(-) create mode 100644 aslmanager.tproj/cache_delete.c create mode 100644 aslmanager.tproj/cache_delete.h create mode 100644 aslmanager.tproj/com.apple.activity_tracing.CacheDelete.plist create mode 100644 aslmanager.tproj/daemon.c create mode 100644 aslmanager.tproj/daemon.h create mode 100644 syslogd.tproj/asl.conf.ios rename syslogd.tproj/{asl_sim.conf => asl.conf.ios_sim} (95%) create mode 100644 syslogd.tproj/asl.conf.osx create mode 100644 syslogd.tproj/com.apple.system.log create mode 100644 syslogd.tproj/syslog.conf diff --git a/aslcommon/asl_common.c b/aslcommon/asl_common.c index fea5e91..ebe75c4 100644 --- a/aslcommon/asl_common.c +++ b/aslcommon/asl_common.c @@ -2,14 +2,14 @@ * Copyright (c) 2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -17,11 +17,10 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_LICENSE_HEADER_END@ */ -#include #include #include #include @@ -56,6 +55,8 @@ #define _PATH_ASL_CONF_LOCAL_DIR "/usr/local/etc/asl" #endif +//#define DEBUG_LIST_FILES 1 + static const char *asl_out_action_name[] = { "none ", @@ -83,12 +84,6 @@ static const char *asl_out_action_name[] = #define forever for(;;) #define KEYMATCH(S,K) ((strncasecmp(S, K, strlen(K)) == 0)) -#define STAMP_STYLE_INVALID -1 -#define STAMP_STYLE_NULL 0 -#define STAMP_STYLE_SEC 1 -#define STAMP_STYLE_SEQ 2 -#define STAMP_STYLE_UTC_OR_LCL 3 - asl_msg_t * xpc_object_to_asl_msg(xpc_object_t xobj) { @@ -231,7 +226,7 @@ _insert_string(char *s, char **l, uint32_t x) int i, len; if (s == NULL) return l; - if (l == NULL) + if (l == NULL) { l = (char **)malloc(2 * sizeof(char *)); if (l == NULL) return NULL; @@ -249,7 +244,7 @@ _insert_string(char *s, char **l, uint32_t x) for (i = 0; l[i] != NULL; i++); - /* len includes the NULL at the end of the list */ + /* len includes the NULL at the end of the list */ len = i + 1; l = (char **)reallocf(l, (len + 1) * sizeof(char *)); @@ -443,8 +438,8 @@ next_word_from_string(char **s) return out; } -static asl_out_dst_data_t * -_asl_out_dest_for_path(asl_out_module_t *m, const char *path) +asl_out_dst_data_t * +asl_out_dest_for_path(asl_out_module_t *m, const char *path) { if (m == NULL) return NULL; if (path == NULL) return NULL; @@ -454,7 +449,7 @@ _asl_out_dest_for_path(asl_out_module_t *m, const char *path) asl_out_rule_t *r = m->ruleset; while (r != NULL) { - if ((r->action == ACTION_OUT_DEST) && (r->dst != NULL) && (r->dst->path != NULL) && (!strcmp(r->dst->path, path))) return r->dst; + if ((r->action == ACTION_OUT_DEST) && (r->dst != NULL) && (r->dst->path != NULL) && (streq(r->dst->path, path))) return r->dst; r = r->next; } @@ -538,7 +533,7 @@ _asl_common_make_dir_path(asl_out_module_t *mlist, uint32_t flags, const char *p return -1; } - dst = _asl_out_dest_for_path(mlist, tmp); + dst = asl_out_dest_for_path(mlist, tmp); if ((dst == NULL) && (flags & MODULE_FLAG_NONSTD_DIR)) { /* no rule to create a non-standard path component! */ @@ -616,6 +611,70 @@ asl_out_mkpath(asl_out_module_t *mlist, asl_out_rule_t *r) return -1; } +int +asl_make_database_dir(const char *dir, char **out) +{ + const char *asldir, *path; + char *str = NULL; + struct stat sb; + int status; + mode_t mask; + + if (out != NULL) *out = NULL; + + asldir = asl_filesystem_path(ASL_PLACE_DATABASE); + if (asldir == NULL) return -1; + + if (dir == NULL) + { + /* create the database directory itself */ + path = asldir; + } + else + { + if (strchr(dir, '/') != NULL) return -1; + + asprintf(&str, "%s/%s", asldir, dir); + if (str == NULL) return -1; + path = str; + } + + memset(&sb, 0, sizeof(struct stat)); + + status = stat(path, &sb); + if (status == 0) + { + if (S_ISDIR(sb.st_mode)) + { + if (out == NULL) free(str); + else *out = str; + return 0; + } + + free(str); + return -1; + } + + if (errno != ENOENT) + { + free(str); + return -1; + } + + mask = umask(0); + status = mkdir(path, 0755); + umask(mask); + + if (status == 0) + { + if (out == NULL) free(str); + else *out = str; + } + else free(str); + + return status; +} + void asl_make_timestamp(time_t stamp, uint32_t flags, char *buf, size_t len) { @@ -624,19 +683,19 @@ asl_make_timestamp(time_t stamp, uint32_t flags, char *buf, size_t len) if (buf == NULL) return; - if (flags & MODULE_FLAG_STYLE_UTC) + if (flags & MODULE_NAME_STYLE_STAMP_UTC) { memset(&t, 0, sizeof(t)); gmtime_r(&stamp, &t); snprintf(buf, len, "%d-%02d-%02dT%02d:%02d:%02dZ", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); } - else if (flags & MODULE_FLAG_STYLE_UTC_B) + else if (flags & MODULE_NAME_STYLE_STAMP_UTC_B) { memset(&t, 0, sizeof(t)); gmtime_r(&stamp, &t); snprintf(buf, len, "%d%02d%02dT%02d%02d%02dZ", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); } - else if (flags & MODULE_FLAG_STYLE_LCL) + else if (flags & MODULE_NAME_STYLE_STAMP_LCL) { bool neg = false; memset(&t, 0, sizeof(t)); @@ -654,7 +713,7 @@ asl_make_timestamp(time_t stamp, uint32_t flags, char *buf, size_t len) else if (m > 0) snprintf(buf, len, "%d-%02d-%02dT%02d:%02d:%02d%c%u:%02u", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, neg ? '-' : '+', h, m); else snprintf(buf, len, "%d-%02d-%02dT%02d:%02d:%02d%c%u", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, neg ? '-' : '+', h); } - else if (flags & MODULE_FLAG_STYLE_LCL_B) + else if (flags & MODULE_NAME_STYLE_STAMP_LCL_B) { bool neg = false; memset(&t, 0, sizeof(t)); @@ -674,26 +733,37 @@ asl_make_timestamp(time_t stamp, uint32_t flags, char *buf, size_t len) } else { - snprintf(buf, len, "%c%lu", STYLE_SEC_PREFIX_CHAR, stamp); + snprintf(buf, len, "%c%llu", STYLE_SEC_PREFIX_CHAR, (unsigned long long)stamp); } } void -asl_make_dst_filename(asl_out_dst_data_t *dst, char *buf, size_t len) +asl_dst_make_current_name(asl_out_dst_data_t *dst, uint32_t xflags, char *buf, size_t len) { + char tstamp[32]; + if (dst == NULL) return; if (buf == NULL) return; - if (dst->flags & (MODULE_FLAG_BASESTAMP | MODULE_FLAG_TYPE_ASL_DIR)) - { - char tstamp[32]; - const char *name = dst->path; + xflags |= dst->flags; - if (dst->flags & MODULE_FLAG_TYPE_ASL_DIR) name = dst->fname; + if (dst->timestamp == 0) dst->timestamp = time(NULL); + asl_make_timestamp(dst->timestamp, dst->style_flags, tstamp, sizeof(tstamp)); - if (dst->stamp == 0) dst->stamp = time(NULL); - asl_make_timestamp(dst->stamp, dst->flags, tstamp, sizeof(tstamp)); - snprintf(buf, len, "%s.%s", name, tstamp); + if (xflags & MODULE_FLAG_TYPE_ASL_DIR) + { + snprintf(buf, len, "%s.%s", dst->current_name, tstamp); + } + else if (xflags & MODULE_FLAG_BASESTAMP) + { + if ((dst->dir != NULL) && (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BSE)) + { + snprintf(buf, len, "%s/%s.%s.%s", dst->dir, dst->base, tstamp, dst->ext); + } + else + { + snprintf(buf, len, "%s.%s", dst->path, tstamp); + } } else { @@ -741,8 +811,11 @@ asl_out_dst_data_release(asl_out_dst_data_t *dst) if (dst->refcount > 0) dst->refcount--; if (dst->refcount > 0) return; + free(dst->dir); free(dst->path); - free(dst->fname); + free(dst->current_name); + free(dst->base); + free(dst->ext); free(dst->rotate_dir); free(dst->fmt); #if !TARGET_IPHONE_SIMULATOR @@ -886,11 +959,11 @@ asl_out_dst_file_create_open(asl_out_dst_data_t *dst, char **pathp) if (dst == NULL) return -1; if (dst->path == NULL) return -1; - asl_make_dst_filename(dst, outpath, sizeof(outpath)); - if (dst->fname != NULL) free(dst->fname); + asl_dst_make_current_name(dst, 0, outpath, sizeof(outpath)); + free(dst->current_name); - dst->fname = strdup(outpath); - if (dst->fname == NULL) return -1; + dst->current_name = strdup(outpath); + if (dst->current_name == NULL) return -1; if (pathp != NULL) *pathp = strdup(outpath); @@ -904,10 +977,11 @@ asl_out_dst_file_create_open(asl_out_dst_data_t *dst, char **pathp) /* file exists */ fd = open(outpath, O_RDWR | O_APPEND | O_EXCL, 0); - if (dst->stamp == 0) dst->stamp = sb.st_birthtimespec.tv_sec; - if (dst->stamp == 0) dst->stamp = sb.st_mtimespec.tv_sec; + if (dst->timestamp == 0) dst->timestamp = sb.st_birthtimespec.tv_sec; + if (dst->timestamp == 0) dst->timestamp = sb.st_mtimespec.tv_sec; dst->size = sb.st_size; + if ((dst->flags & MODULE_FLAG_BASESTAMP) && (dst->flags & MODULE_FLAG_SYMLINK)) symlink(outpath, dst->path); return fd; } else if (errno != ENOENT) @@ -919,11 +993,18 @@ asl_out_dst_file_create_open(asl_out_dst_data_t *dst, char **pathp) fd = open(outpath, O_RDWR | O_CREAT | O_EXCL, (dst->mode & 00666)); if (fd < 0) return -1; - dst->stamp = time(NULL); + dst->timestamp = time(NULL); fd = asl_out_dst_set_access(fd, dst); if (fd < 0) unlink(outpath); + if ((dst->flags & MODULE_FLAG_BASESTAMP) && (dst->flags & MODULE_FLAG_SYMLINK)) + { + /* remove old symlink, make a new link to the "current" file */ + unlink(dst->path); + symlink(outpath, dst->path); + } + return fd; } @@ -1091,9 +1172,9 @@ _asl_out_module_parse_set_param(asl_out_module_t *m, char *s) else { /* = param [query] */ - if ((!strncmp(p, "[File ", 6)) || (!strncmp(p, "[File\t", 6))) out->action = ACTION_SET_FILE; - else if ((!strncmp(p, "[Plist ", 7)) || (!strncmp(p, "[Plist\t", 7))) out->action = ACTION_SET_PLIST; - else if ((!strncmp(p, "[Profile ", 9)) || (!strncmp(p, "[Profile\t", 9))) out->action = ACTION_SET_PROF; + if (streq_len(p, "[File ", 6) || streq_len(p, "[File\t", 6)) out->action = ACTION_SET_FILE; + else if (streq_len(p, "[Plist ", 7) || streq_len(p, "[Plist\t", 7)) out->action = ACTION_SET_PLIST; + else if (streq_len(p, "[Profile ", 9) || streq_len(p, "[Profile\t", 9)) out->action = ACTION_SET_PROF; p--; *p = '\0'; @@ -1204,28 +1285,6 @@ _dst_format_string(char *s) return fmt; } -size_t -asl_str_to_size(char *s) -{ - size_t len, n, max; - char x; - - if (s == NULL) return 0; - - len = strlen(s); - if (len == 0) return 0; - - n = 1; - x = s[len - 1]; - if (x > 90) x -= 32; - if (x == 'K') n = 1ll << 10; - else if (x == 'M') n = 1ll << 20; - else if (x == 'G') n = 1ll << 30; - - max = atoll(s) * n; - return max; -} - static bool _dst_path_match(const char *newpath, const char *existingpath) { @@ -1239,12 +1298,135 @@ _dst_path_match(const char *newpath, const char *existingpath) return (strcmp(newpath, trailing) == 0); } +static uint32_t +_parse_stamp_string(const char *in) +{ + char buf[16]; + uint32_t x; + + if (in == NULL) return 0; + + for (x = 0; (((in[x] >= 'a') && (in[x] <= 'z')) || (in[x] == '-')) && (x < 11); x++) buf[x] = in[x]; + buf[x] = '\0'; + + if (streq(buf, "sec") || streq(buf, "seconds")) return MODULE_NAME_STYLE_STAMP_SEC; + if (streq(buf, "zulu") || streq(buf, "utc")) return MODULE_NAME_STYLE_STAMP_UTC; + if (streq(buf, "utc-b") || streq(buf, "utc-basic")) return MODULE_NAME_STYLE_STAMP_UTC_B; + if (streq(buf, "local") || streq(buf, "lcl")) return MODULE_NAME_STYLE_STAMP_LCL; + if (streq(buf, "local-b") || streq(buf, "lcl-b") || streq(buf, "local-basic") || streq(buf, "lcl-basic")) return MODULE_NAME_STYLE_STAMP_LCL_B; + if (streq(buf, "#") || streq(buf, "seq") || streq(buf, "sequence"))return MODULE_NAME_STYLE_STAMP_SEQ; + + return 0; +} + +/* + * Parse a file-rotation naming style. + * + * Legacy: sec / seconds, utc / date / zulu [-b], local / lcl [-b], # / seq / sequence + * We scan the whole line and match to one of these. + * + * New scheme: 2 or 3 components: base and style, or base, style, and extension. + * these define a name format. base is the file name without a leading directory path + * and with no extension (e.g. "foo"). style is one of the styles above. extension is + * the file name extension (e.g. "log", "txt", etc). + * + * Examples: + * foo.utc.log + * foo.log.lcl + * foo.seq + * + * The leading base name may be ommitted (E.G. ".lcl.log", ".log.seq") + * If the leading base name AND extension are omitted, it is taken from the path. E.G. ".lcl", ".seq" + * + * If we get input without a stamp spec, we default to "sec". + */ +static int +_parse_dst_style(asl_out_dst_data_t *dst, const char *in) +{ + const char *p, *q; + size_t len; + + if ((dst == NULL) || (in == NULL)) return -1; + + /* check for base. or just . for shorthand */ + p = NULL; + if (in[0] == '.') + { + p = in + 1; + } + else + { + if (dst->base == NULL) return -1; + + len = strlen(dst->base); + if (streq_len(in, dst->base, len) && (in[len] == '.')) p = in + len + 1; + } + + if (p == NULL) + { + /* input does not start with '.' or base, so this is legacy style */ + dst->style_flags = _parse_stamp_string(in); + if (dst->style_flags == 0) return -1; + + if (dst->ext == NULL) dst->style_flags |= MODULE_NAME_STYLE_FORMAT_BS; + else dst->style_flags |= MODULE_NAME_STYLE_FORMAT_BES; + + return 0; + } + + /* look for another dot in the name */ + for (q = p; (*q != '.') && (*q != ' ') && (*q != '\t') && (*q != '\0'); q++); + if (*q != '.') q = NULL; + + if (q == NULL) + { + /* we require a stamp spec, so we are expecting base.stamp */ + dst->style_flags = _parse_stamp_string(p); + + if (dst->style_flags == 0) return -1; + + /* + * We got a valid stamp style ("base.stamp"). + * Note that we might have skipped the extention if the file name was "foo.log". + * That's OK - syslogd writes "foo.log", but the rotated files are e.g. foo.20141018T1745Z. + */ + dst->style_flags |= MODULE_NAME_STYLE_FORMAT_BS; + return 0; + } + + /* set q to the char past the dot */ + q++; + + /* either base.stamp.ext or base.ext.stamp */ + if (dst->ext == NULL) return -1; + + len = strlen(dst->ext); + if (streq_len(p, dst->ext, len) && (p[len] == '.')) + { + /* got base.ext.stamp */ + dst->style_flags = _parse_stamp_string(q); + if (dst->style_flags == 0) return -1; + + dst->style_flags |= MODULE_NAME_STYLE_FORMAT_BES; + return 0; + } + + /* must be base.stamp.ext */ + if (strneq_len(q, dst->ext, len)) return -1; + + dst->style_flags = _parse_stamp_string(p); + if (dst->style_flags == 0) return -1; + + dst->style_flags |= MODULE_NAME_STYLE_FORMAT_BSE; + return 0; +} + static asl_out_dst_data_t * _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) { asl_out_rule_t *out, *rule; asl_out_dst_data_t *dst; - char *p, *opts, *path; + char *p, *dot, *opts, *path; char **path_parts; int has_dotdot, recursion_limit; uint32_t i, flags = 0; @@ -1275,7 +1457,7 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) for (i = 0; path_parts[i] != NULL; i++) { - if (!strncmp(path_parts[i], "$ENV(", 5)) + if (streq_len(path_parts[i], "$ENV(", 5)) { char *p = strchr(path_parts[i], ')'); if (p != NULL) *p = '\0'; @@ -1301,7 +1483,7 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) } } - if ((has_dotdot == 0) && (!strcmp(path_parts[i], ".."))) has_dotdot = 1; + if ((has_dotdot == 0) && streq(path_parts[i], "..")) has_dotdot = 1; } free_string_list(path_parts); @@ -1357,7 +1539,7 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) if (log_root == NULL) log_root = "/tmp/log"; #endif - if (!strcmp(m->name, ASL_MODULE_NAME)) + if (streq(m->name, ASL_MODULE_NAME)) { asprintf(&path, "%s/%s", log_root, t); } @@ -1375,8 +1557,8 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) * Standard log directories get marked so that syslogd * will create them without explicit rules. */ - if (!strncmp(path, PATH_VAR_LOG, PATH_VAR_LOG_LEN)) flags &= ~MODULE_FLAG_NONSTD_DIR; - else if (!strncmp(path, PATH_LIBRARY_LOGS, PATH_LIBRARY_LOGS_LEN)) flags &= ~MODULE_FLAG_NONSTD_DIR; + if (streq_len(path, PATH_VAR_LOG, PATH_VAR_LOG_LEN)) flags &= ~MODULE_FLAG_NONSTD_DIR; + else if (streq_len(path, PATH_LIBRARY_LOGS, PATH_LIBRARY_LOGS_LEN)) flags &= ~MODULE_FLAG_NONSTD_DIR; } out = (asl_out_rule_t *)calloc(1, sizeof(asl_out_rule_t)); @@ -1391,10 +1573,37 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) dst->refcount = 1; dst->path = path; + + p = strrchr(dst->path, '/'); + if (p != NULL) + { + *p = '\0'; + dst->dir = strdup(dst->path); + *p = '/'; + } + dst->mode = def_mode; dst->ttl[LEVEL_ALL] = DEFAULT_TTL; dst->flags = flags | MODULE_FLAG_COALESCE; + /* + * Break out base and extension (if present) from path. + * Note this only supports a '.' as a separator. + */ + p = strrchr(path, '/'); + if (p == NULL) p = path; + else p++; + + dot = strrchr(path, '.'); + if (dot != NULL) + { + *dot = '\0'; + dst->ext = strdup(dot + 1); + } + + dst->base = strdup(p); + if (dot != NULL) *dot = '.'; + while (NULL != (p = next_word_from_string(&opts))) { if (KEYMATCH(p, "mode=")) dst->mode = strtol(p+5, NULL, 0); @@ -1413,46 +1622,27 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) else if (KEYMATCH(p+9, "false")) dst->flags &= ~MODULE_FLAG_COALESCE; } else if (KEYMATCH(p, "compress")) dst->flags |= MODULE_FLAG_COMPRESS; + else if (KEYMATCH(p, "activity")) dst->flags |= MODULE_FLAG_ACTIVITY; else if (KEYMATCH(p, "extern")) dst->flags |= MODULE_FLAG_EXTERNAL; else if (KEYMATCH(p, "truncate")) dst->flags |= MODULE_FLAG_TRUNCATE; else if (KEYMATCH(p, "dir")) dst->flags |= MODULE_FLAG_TYPE_ASL_DIR; else if (KEYMATCH(p, "soft")) dst->flags |= MODULE_FLAG_SOFT_WRITE; - else if (KEYMATCH(p, "file_max=")) dst->file_max = asl_str_to_size(p+9); - else if (KEYMATCH(p, "all_max=")) dst->all_max = asl_str_to_size(p+8); + else if (KEYMATCH(p, "file_max=")) dst->file_max = asl_core_str_to_size(p+9); + else if (KEYMATCH(p, "all_max=")) dst->all_max = asl_core_str_to_size(p+8); else if (KEYMATCH(p, "style=") || KEYMATCH(p, "rotate=")) { const char *x = p + 6; - if (KEYMATCH(p, "rotate=")) x++; + if (*p == 'r') x++; + if (_parse_dst_style(dst, x) == 0) dst->flags |= MODULE_FLAG_ROTATE; + } + else if (KEYMATCH(p, "rotate")) + { + if (dst->ext == NULL) dst->style_flags = MODULE_NAME_STYLE_FORMAT_BS | MODULE_NAME_STYLE_STAMP_SEC; + else dst->style_flags = MODULE_NAME_STYLE_FORMAT_BES | MODULE_NAME_STYLE_STAMP_SEC; dst->flags |= MODULE_FLAG_ROTATE; - - if (KEYMATCH(x, "sec") || KEYMATCH(x, "seconds")) - { - dst->flags |= MODULE_FLAG_STYLE_SEC; - } - else if (KEYMATCH(x, "utc") || KEYMATCH(x, "date") || KEYMATCH(x, "zulu")) - { - const char *dash = strchr(x, '-'); - if ((dash != NULL) && (*(dash + 1) == 'b')) dst->flags |= MODULE_FLAG_STYLE_UTC_B; - else dst->flags |= MODULE_FLAG_STYLE_UTC; - } - else if (KEYMATCH(x, "local") || KEYMATCH(x, "lcl")) - { - const char *dash = strchr(x, '-'); - if ((dash != NULL) && (*(dash + 1) == 'b')) dst->flags |= MODULE_FLAG_STYLE_LCL_B; - else dst->flags |= MODULE_FLAG_STYLE_LCL; - } - else if (KEYMATCH(x, "#") || KEYMATCH(x, "seq") || KEYMATCH(x, "sequence")) - { - dst->flags |= MODULE_FLAG_STYLE_SEQ; - } - else - { - dst->flags |= MODULE_FLAG_STYLE_SEC; - } } - else if (KEYMATCH(p, "rotate")) dst->flags |= MODULE_FLAG_ROTATE; else if (KEYMATCH(p, "crashlog")) { /* crashlog implies rotation */ @@ -1465,17 +1655,21 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) { dst->flags |= MODULE_FLAG_BASESTAMP; } + else if (KEYMATCH(p, "link") || KEYMATCH(p, "symlink")) + { + dst->flags |= MODULE_FLAG_SYMLINK; + } else if (KEYMATCH(p, "ttl")) { char *q = p + 3; if (*q == '=') { - dst->ttl[LEVEL_ALL] = strtol(p+4, NULL, 0); + dst->ttl[LEVEL_ALL] = asl_core_str_to_time(p+4, SECONDS_PER_DAY); } else if ((*q >= '0') && (*q <= '7') && (*(q+1) == '=')) { uint32_t x = *q - '0'; - dst->ttl[x] = strtol(p+5, NULL, 0); + dst->ttl[x] = asl_core_str_to_time(p+5, SECONDS_PER_DAY); } } @@ -1485,7 +1679,7 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) #if TARGET_OS_EMBEDDED /* check for crashreporter files */ - if ((KEYMATCH(dst->path, _PATH_CRASHREPORTER)) || (KEYMATCH(dst->path, _PATH_CRASHREPORTER_MOBILE))) + if ((KEYMATCH(dst->path, _PATH_CRASHREPORTER)) || (KEYMATCH(dst->path, _PATH_CRASHREPORTER_MOBILE_1)) || (KEYMATCH(dst->path, _PATH_CRASHREPORTER_MOBILE_2))) { dst->flags |= MODULE_FLAG_ROTATE; dst->flags |= MODULE_FLAG_CRASHLOG; @@ -1504,24 +1698,27 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) if (strcmp(dst->fmt, "std") && strcmp(dst->fmt, "bsd")) dst->flags &= ~MODULE_FLAG_COALESCE; /* note if format is one of std, bsd, or msg */ - if (!strcmp(dst->fmt, "std") || !strcmp(dst->fmt, "bsd") || !strcmp(dst->fmt, "msg")) dst->flags |= MODULE_FLAG_STD_BSD_MSG; + if (streq(dst->fmt, "std") || streq(dst->fmt, "bsd") || streq(dst->fmt, "msg")) dst->flags |= MODULE_FLAG_STD_BSD_MSG; - /* MODULE_FLAG_STYLE_SEQ can not be used with MODULE_FLAG_BASESTAMP */ - if ((dst->flags & MODULE_FLAG_BASESTAMP) && (dst->flags & MODULE_FLAG_STYLE_SEQ)) + /* MODULE_NAME_STYLE_STAMP_SEQ can not be used with MODULE_FLAG_BASESTAMP */ + if ((dst->flags & MODULE_FLAG_BASESTAMP) && (dst->flags & MODULE_NAME_STYLE_STAMP_SEQ)) { - dst->flags &= ~MODULE_FLAG_STYLE_SEQ; - dst->flags |= MODULE_FLAG_STYLE_SEC; + dst->flags &= ~MODULE_NAME_STYLE_STAMP_SEQ; + dst->flags |= MODULE_NAME_STYLE_STAMP_SEC; } /* set time format for raw output */ - if (!strcmp(dst->fmt, "raw")) dst->tfmt = "sec"; + if (streq(dst->fmt, "raw")) dst->tfmt = "sec"; /* check for ASL_PLACE_DATABASE_DEFAULT */ - if (!strcmp(dst->path, ASL_PLACE_DATABASE_DEFAULT)) + if (streq(dst->path, ASL_PLACE_DATABASE_DEFAULT)) { dst->flags = MODULE_FLAG_TYPE_ASL_DIR; } + /* set file_max to all_max if it is zero */ + if (dst->file_max == 0) dst->file_max = dst->all_max; + out->action = ACTION_OUT_DEST; out->dst = dst; @@ -1551,29 +1748,29 @@ _asl_out_module_parse_query_action(asl_out_module_t *m, char *s) if (p == NULL) p = strchr(act, '\t'); if (p != NULL) *p = '\0'; - if (!strcasecmp(act, "ignore")) out->action = ACTION_IGNORE; - else if (!strcasecmp(act, "skip")) out->action = ACTION_SKIP; - else if (!strcasecmp(act, "claim")) out->action = ACTION_CLAIM; - else if (!strcasecmp(act, "notify")) out->action = ACTION_NOTIFY; - else if (!strcasecmp(act, "file")) out->action = ACTION_FILE; - else if (!strcasecmp(act, "asl_file")) out->action = ACTION_ASL_FILE; - else if (!strcasecmp(act, "directory")) out->action = ACTION_ASL_DIR; - else if (!strcasecmp(act, "dir")) out->action = ACTION_ASL_DIR; - else if (!strcasecmp(act, "asl_directory")) out->action = ACTION_ASL_DIR; - else if (!strcasecmp(act, "asl_dir")) out->action = ACTION_ASL_DIR; - else if (!strcasecmp(act, "store_dir")) out->action = ACTION_ASL_DIR; - else if (!strcasecmp(act, "store_directory")) out->action = ACTION_ASL_DIR; - else if (!strcasecmp(act, "control")) out->action = ACTION_CONTROL; - else if (!strcasecmp(act, "save")) out->action = ACTION_ASL_STORE; - else if (!strcasecmp(act, "store")) out->action = ACTION_ASL_STORE; - else if (!strcasecmp(act, "access")) out->action = ACTION_ACCESS; - else if (!strcasecmp(act, "set")) out->action = ACTION_SET_KEY; - else if (!strcasecmp(act, "unset")) out->action = ACTION_UNSET_KEY; - else if (!strcmp(m->name, ASL_MODULE_NAME)) + if (strcaseeq(act, "ignore")) out->action = ACTION_IGNORE; + else if (strcaseeq(act, "skip")) out->action = ACTION_SKIP; + else if (strcaseeq(act, "claim")) out->action = ACTION_CLAIM; + else if (strcaseeq(act, "notify")) out->action = ACTION_NOTIFY; + else if (strcaseeq(act, "file")) out->action = ACTION_FILE; + else if (strcaseeq(act, "asl_file")) out->action = ACTION_ASL_FILE; + else if (strcaseeq(act, "directory")) out->action = ACTION_ASL_DIR; + else if (strcaseeq(act, "dir")) out->action = ACTION_ASL_DIR; + else if (strcaseeq(act, "asl_directory")) out->action = ACTION_ASL_DIR; + else if (strcaseeq(act, "asl_dir")) out->action = ACTION_ASL_DIR; + else if (strcaseeq(act, "store_dir")) out->action = ACTION_ASL_DIR; + else if (strcaseeq(act, "store_directory")) out->action = ACTION_ASL_DIR; + else if (strcaseeq(act, "control")) out->action = ACTION_CONTROL; + else if (strcaseeq(act, "save")) out->action = ACTION_ASL_STORE; + else if (strcaseeq(act, "store")) out->action = ACTION_ASL_STORE; + else if (strcaseeq(act, "access")) out->action = ACTION_ACCESS; + else if (strcaseeq(act, "set")) out->action = ACTION_SET_KEY; + else if (strcaseeq(act, "unset")) out->action = ACTION_UNSET_KEY; + else if (streq(m->name, ASL_MODULE_NAME)) { /* actions only allowed in com.apple.asl */ - if (!strcasecmp(act, "broadcast")) out->action = ACTION_BROADCAST; - else if (!strcasecmp(act, "forward")) out->action = ACTION_FORWARD; + if (strcaseeq(act, "broadcast")) out->action = ACTION_BROADCAST; + else if (strcaseeq(act, "forward")) out->action = ACTION_FORWARD; } if (out->action == ACTION_NONE) @@ -1622,7 +1819,7 @@ _asl_out_module_parse_query_action(asl_out_module_t *m, char *s) if (out->action == ACTION_ASL_STORE) { if (out->options == NULL) out->dst = asl_out_dst_data_retain(_asl_out_module_parse_dst(m, ASL_PLACE_DATABASE_DEFAULT, 0755)); - else if (!strncmp(out->options, ASL_PLACE_DATABASE_DEFAULT, strlen(ASL_PLACE_DATABASE_DEFAULT))) out->dst = asl_out_dst_data_retain(_asl_out_module_parse_dst(m, out->options, 0755)); + else if (streq_len(out->options, ASL_PLACE_DATABASE_DEFAULT, strlen(ASL_PLACE_DATABASE_DEFAULT))) out->dst = asl_out_dst_data_retain(_asl_out_module_parse_dst(m, out->options, 0755)); else if (out->options != NULL) out->action = ACTION_ASL_FILE; } @@ -1644,7 +1841,7 @@ _asl_out_module_parse_query_action(asl_out_module_t *m, char *s) */ if (out->dst->mode == 010000) out->dst->mode = def_mode; - if ((out->action == ACTION_FILE) && (out->dst != NULL) && (out->dst->fmt != NULL) && (!strcasecmp(out->dst->fmt, "asl"))) + if ((out->action == ACTION_FILE) && (out->dst != NULL) && (out->dst->fmt != NULL) && (strcaseeq(out->dst->fmt, "asl"))) { out->action = ACTION_ASL_FILE; } @@ -1659,13 +1856,10 @@ _asl_out_module_parse_query_action(asl_out_module_t *m, char *s) /* coalesce is meaningless for ASL directories */ out->dst->flags &= ~MODULE_FLAG_COALESCE; - /* no compression at this point */ - out->dst->flags &= ~MODULE_FLAG_COMPRESS; - out->dst->flags |= MODULE_FLAG_TYPE_ASL_DIR; /* set style bits for basestamp asl_dirs */ - if (((out->dst->flags & MODULE_FLAG_STYLE_BITS) == 0) && (out->dst->flags & MODULE_FLAG_BASESTAMP)) out->dst->flags |= MODULE_FLAG_STYLE_LCL_B; + if (((out->dst->style_flags & MODULE_NAME_STYLE_STAMP_MASK) == 0) && (out->dst->flags & MODULE_FLAG_BASESTAMP)) out->dst->style_flags |= MODULE_NAME_STYLE_STAMP_LCL_B; } /* only ACTION_FILE and ACTION_ASL_FILE may rotate */ @@ -1703,7 +1897,7 @@ asl_out_module_parse_line(asl_out_module_t *m, char *s) { return _asl_out_module_parse_set_param(m, s); } - else if (*s == '>') + else if (*s == '>') { _asl_out_module_parse_dst(m, s + 1, 010000); } @@ -1742,7 +1936,7 @@ _asl_out_module_find(asl_out_module_t *list, const char *name) for (x = list; x != NULL; x = x->next) { - if ((x->name != NULL) && (!strcmp(x->name, name))) return x; + if ((x->name != NULL) && (streq(x->name, name))) return x; } return NULL; @@ -1770,7 +1964,7 @@ _asl_out_module_read_and_merge_dir(asl_out_module_t **list, const char *path, ui { while (NULL != (ent = readdir(d))) { - if ((ent->d_name != NULL) && (ent->d_name[0] != '.')) + if (ent->d_name[0] != '.') { /* merge: skip this file if we already have a module with this name */ if (_asl_out_module_find(*list, ent->d_name) != NULL) continue; @@ -1787,7 +1981,7 @@ _asl_out_module_read_and_merge_dir(asl_out_module_t **list, const char *path, ui { x->flags |= flags; - if (!strcmp(ent->d_name, ASL_MODULE_NAME)) + if (streq(ent->d_name, ASL_MODULE_NAME)) { /* com.apple.asl goes at the head of the list */ x->next = *list; @@ -1823,10 +2017,10 @@ asl_out_module_init(void) char *asl_conf, *asl_conf_dir, *asl_conf_local_dir; sim_root_path = getenv("IPHONE_SIMULATOR_ROOT"); - assert(sim_root_path); + if (sim_root_path == NULL) return NULL; sim_resources_path = getenv("IPHONE_SHARED_RESOURCES_DIRECTORY"); - assert(sim_resources_path); + if (sim_resources_path == NULL) return NULL; asprintf(&asl_conf, "%s%s", sim_root_path, _PATH_ASL_CONF); asprintf(&asl_conf_dir, "%s%s", sim_root_path, _PATH_ASL_CONF_DIR); @@ -1885,15 +2079,27 @@ asl_out_module_rule_to_string(asl_out_rule_t *r) asprintf(&out, " %s%s%s%s%s", asl_out_action_name[r->action], - (r->query == NULL) ? "" : " ", + (r->query == NULL) ? "" : " ", (r->query == NULL) ? "" : str, - (r->options == NULL) ? "" : " ", + (r->options == NULL) ? "" : " ", (r->options == NULL) ? "" : r->options); free(str); return out; } +static const char * +_stamp_style_name(uint32_t flags) +{ + if (flags & MODULE_NAME_STYLE_STAMP_SEC) return ""; + if (flags & MODULE_NAME_STYLE_STAMP_SEQ) return ""; + if (flags & MODULE_NAME_STYLE_STAMP_UTC) return ""; + if (flags & MODULE_NAME_STYLE_STAMP_UTC_B) return ""; + if (flags & MODULE_NAME_STYLE_STAMP_LCL) return ""; + if (flags & MODULE_NAME_STYLE_STAMP_LCL_B) return ""; + return ""; +} + /* * Print module */ @@ -1903,6 +2109,7 @@ asl_out_module_print(FILE *f, asl_out_module_t *m) asl_out_rule_t *r, *n; asl_out_dst_data_t *o; uint32_t i, ttlnset; + char tstr[150]; n = NULL; for (r = m->ruleset; r != NULL; r = n) @@ -1957,39 +2164,14 @@ asl_out_module_print(FILE *f, asl_out_module_t *m) fprintf(f, "%ccompress", c); c = ' '; } - if (o->flags & MODULE_FLAG_STYLE_SEC) - { - fprintf(f, "%cseconds", c); - c = ' '; - } - if (o->flags & MODULE_FLAG_STYLE_SEQ) - { - fprintf(f, "%csequence", c); - c = ' '; - } - if (o->flags & MODULE_FLAG_STYLE_UTC) - { - fprintf(f, "%cutc", c); - c = ' '; - } - if (o->flags & MODULE_FLAG_STYLE_UTC_B) - { - fprintf(f, "%cutc-basic", c); - c = ' '; - } - if (o->flags & MODULE_FLAG_STYLE_LCL) - { - fprintf(f, "%clocal", c); - c = ' '; - } - if (o->flags & MODULE_FLAG_STYLE_LCL_B) + if (o->flags & MODULE_FLAG_BASESTAMP) { - fprintf(f, "%clocal-basic", c); + fprintf(f, "%cbasestamp", c); c = ' '; } - if (o->flags & MODULE_FLAG_BASESTAMP) + if (o->flags & MODULE_FLAG_SYMLINK) { - fprintf(f, "%cbasestamp", c); + fprintf(f, "%csymlink", c); c = ' '; } if (o->flags & MODULE_FLAG_NONSTD_DIR) @@ -2002,6 +2184,11 @@ asl_out_module_print(FILE *f, asl_out_module_t *m) fprintf(f, "%cexternal", c); c = ' '; } + if (o->flags & MODULE_FLAG_ACTIVITY) + { + fprintf(f, "%cactivity", c); + c = ' '; + } if (o->flags & MODULE_FLAG_CRASHLOG) { fprintf(f, "%ccrashlog", c); @@ -2021,11 +2208,45 @@ asl_out_module_print(FILE *f, asl_out_module_t *m) } fprintf(f, "\n"); - fprintf(f, " ttl: %u", o->ttl[LEVEL_ALL]); + if (o->flags & MODULE_FLAG_ROTATE) + { + fprintf(f, " rotatation style: "); + if (o->style_flags & MODULE_NAME_STYLE_FORMAT_BS) + { + fprintf(f, "[base=%s].%s\n", o->base, _stamp_style_name(o->style_flags)); + } + else if (o->style_flags & MODULE_NAME_STYLE_FORMAT_BES) + { + fprintf(f, "[base=%s].[ext=%s].%s\n", o->base, o->ext, _stamp_style_name(o->style_flags)); + } + else if (o->style_flags & MODULE_NAME_STYLE_FORMAT_BSE) + { + fprintf(f, "[base=%s].%s.[ext=%s]\n", o->base, _stamp_style_name(o->style_flags), o->ext); + } + else + { + fprintf(f, "0x%08x\n", o->style_flags); + } + } + + asl_core_time_to_str(o->ttl[LEVEL_ALL], tstr, sizeof(tstr)); + fprintf(f, " ttl: %s\n", tstr); + ttlnset = 0; for (i = 0; (i <= 7) & (ttlnset == 0); i++) if (o->ttl[i] != 0) ttlnset = 1; - if (ttlnset != 0) for (i = 0; i <= 7; i++) printf(" [%d %d]", i, (o->ttl[i] == 0) ? o->ttl[LEVEL_ALL] : o->ttl[i]); - fprintf(f, "\n"); + if (ttlnset != 0) + { + for (i = 0; i <= 7; i++) + { + time_t x = o->ttl[i]; + if (x == 0) x = o->ttl[LEVEL_ALL]; + asl_core_time_to_str(x, tstr, sizeof(tstr)); + + fprintf(f, " [%d %s]", i, tstr); + } + + fprintf(f, "\n"); + } fprintf(f, " mode: 0%o\n", o->mode); fprintf(f, " file_max: %lu\n", o->file_max); @@ -2064,100 +2285,262 @@ asl_out_file_list_free(asl_out_file_list_t *l) } /* - * Checks input name for the form base[.stamp][.gz] - * name == base is allowed if src is true. + * Checks input name for one of the forms: + * MODULE_NAME_STYLE_FORMAT_BS base (src only) or base.stamp[.gz] + * MODULE_NAME_STYLE_FORMAT_BES base.ext (src only) or base.ext.stamp[.gz] + * MODULE_NAME_STYLE_FORMAT_BSE base.ext (src only) or base.stamp.ext[.gz] + * + * name == base[.ext] is allowed if src is true. * base.gz is not allowed. * Output parameter stamp must be freed by caller. */ bool -_check_file_name(const char *name, const char *base, bool src, char **stamp) +_check_file_name(const char *name, const char *base, const char *ext, uint32_t flags, bool src, char **stamp) { - size_t baselen, nparts; - const char *p, *q, *part[2]; + size_t baselen, extlen; + const char *p, *z; bool isgz = false; +#ifdef DEBUG_LIST_FILES + fprintf(stderr, "_check_file_name name=%s base=%s ext=%s flags=0x%08x %s\n", name, base, (ext == NULL) ? "(NULL)" : ext, flags, src ? "src" : "dst"); +#endif + if (name == NULL) return false; if (base == NULL) return false; baselen = strlen(base); if (baselen == 0) return false; + extlen = 0; + if (ext != NULL) extlen = strlen(ext); + if (stamp != NULL) *stamp = NULL; - if (strncmp(name, base, baselen)) return false; + if (strneq_len(name, base, baselen)) + { +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " base match failed [%u]\n", __LINE__); +#endif + return false; + } - p = name + baselen; + z = strrchr(name, '.'); + if ((z != NULL) && streq(z, ".gz")) isgz = true; - /* name == base not allowed (it's the "active" file) */ - if (*p == '\0') return false; +#ifdef DEBUG_LIST_FILES + fprintf(stderr, "z=%s isgz=%s\n", (z == NULL) ? "NULL" : z, isgz ? "true" : "false"); +#endif - /* name must be base.something */ - if (*p != '.') return false; + p = name + baselen; - /* maximum of 2 parts (stamp and gz) */ - nparts = 0; - for (q = p; *q != '\0'; q++) + if (flags & MODULE_NAME_STYLE_FORMAT_BS) { - if (*q == '.') +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " MODULE_NAME_STYLE_FORMAT_BS\n"); +#endif + if (*p == '\0') { - if (nparts == 2) return false; - part[nparts++] = q + 1; + /* name == base OK if src is true */ +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " name == base %s [%u]\n", src ? "OK" : "failed", __LINE__); +#endif + return src; } - } - if (nparts == 0) return false; + /* expecting p == .stamp[.gz] */ + if (*p != '.') + { +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " expecting dot - failed [%u]\n", __LINE__); +#endif + return false; + } - isgz = strcmp(part[nparts - 1], "gz") == 0; + p++; - /* no compressed files in src */ - if (src && isgz) return false; + if (p == z) + { + /* base.gz is not allowed */ +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " got base.gz - failed [%u]\n", __LINE__); +#endif + return false; + } - /* expecting base.stamp or base.stamp.gz */ + /* got base.stamp[.gz] */ + if (stamp != NULL) + { + *stamp = strdup(p); + char *x = strchr(*stamp, '.'); + if (x != NULL) *x = '\0'; + } - if (nparts == 1) +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " got base.stamp%s - OK\n", isgz ? ".gz" : ""); +#endif + return true; + } + else if (flags & MODULE_NAME_STYLE_FORMAT_BES) { - /* compressed files must have a stamp (base.gz is not allowed) */ - if (isgz) return false; +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " MODULE_NAME_STYLE_FORMAT_BES\n"); +#endif + if (*p != '.') + { +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " expecting dot - failed [%u]\n", __LINE__); +#endif + return false; + } + + p++; + + if (strneq_len(p, ext, extlen)) + { +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " ext match failed [%u]\n", __LINE__); +#endif + return false; + } - /* got base.stamp */ - if (stamp != NULL) *stamp = strdup(part[0]); + /* expecting p == .ext[.stamp][.gz] */ + p += extlen; + + if (*p == '\0') + { + /* name == base.ext OK if src is true */ +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " name == base.ext %s [%u]\n", src ? "OK" : "failed", __LINE__); +#endif + return src; + } + + /* expecting p == .stamp[.gz] */ + if (*p != '.') + { +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " expecting dot - failed [%u]\n", __LINE__); +#endif + return false; + } + + p++; + + if (p == z) + { + /* base.ext.gz is not allowed */ +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " got base.ext.gz - failed [%u]\n", __LINE__); +#endif + return false; + } + + /* got base.ext.stamp[.gz] */ + if (stamp != NULL) + { + *stamp = strdup(p); + char *x = strchr(*stamp, '.'); + if (x != NULL) *x = '\0'; + } + +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " got base.ext.stamp%s - OK\n", isgz ? ".gz" : ""); +#endif return true; } + else if (flags & MODULE_NAME_STYLE_FORMAT_BSE) + { +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " MODULE_NAME_STYLE_FORMAT_BSE name=%s base=%s ext=%s flags=0x%08x %s\n", name, base, (ext == NULL) ? "(NULL)" : ext, flags, src ? "src" : "dst"); +#endif - /* expecting base.stamp.gz */ - if (!isgz) return false; + if (*p != '.') + { +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " expecting dot - failed [%u]\n", __LINE__); +#endif + return false; + } - /* got base.stamp.gz */ - if (stamp != NULL) - { - *stamp = strdup(part[0]); - char *x = strchr(*stamp, '.'); - if (x != NULL) *x = '\0'; + p++; + + if (streq_len(p, ext, extlen)) + { + p += extlen; + if (*p == '\0') + { + /* name == base.ext OK if src is true */ +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " name == base.ext %s [%u]\n", src ? "OK" : "failed", __LINE__); +#endif + return src; + } + } + + /* expecting p == stamp.ext[.gz] */ + + if (isgz) + { + if (strneq_len(z - extlen, ext, extlen)) + { +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " ext match (%s) isgz failed [%u]\n", z-extlen, __LINE__); +#endif + return false; + } + } + else + { + if (strneq_len(z + 1, ext, extlen)) + { +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " ext match (%s) failed [%u]\n", z, __LINE__); +#endif + return false; + } + } + + /* got base.stamp.ext[.gz] */ + if (stamp != NULL) + { + *stamp = strdup(p); + char *x = strchr(*stamp, '.'); + if (x != NULL) *x = '\0'; + } + +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " got base.stamp.ext%s - OK\n", isgz ? ".gz" : ""); +#endif + return true; } - return true; +#ifdef DEBUG_LIST_FILES + fprintf(stderr, " unknown format - failed\n"); +#endif + + return false; } /* * Find files in a directory (dir) that all have a common prefix (base). * Bits in flags further control the search. * - * MODULE_FLAG_STYLE_SEQ means a numeric sequence number is expected, although not required. + * MODULE_NAME_STYLE_STAMP_SEQ means a numeric sequence number is expected, although not required. * E.g. foo.log foo.log.0 * - * MODULE_FLAG_STYLE_SEC also means a numeric sequence number is required following an 'T' character. + * MODULE_NAME_STYLE_STAMP_SEC also means a numeric sequence number is required following an 'T' character. * The numeric value is the file's timestamp in seconds. E.g foo.log.T1335200452 * - * MODULE_FLAG_STYLE_UTC requires a date/time component as the file's timestamp. + * MODULE_NAME_STYLE_STAMP_UTC requires a date/time component as the file's timestamp. * E.g. foo.2012-04-06T15:30:00Z * - * MODULE_FLAG_STYLE_UTC_B requires a date/time component as the file's timestamp. + * MODULE_NAME_STYLE_STAMP_UTC_B requires a date/time component as the file's timestamp. * E.g. foo.20120406T153000Z * - * MODULE_FLAG_STYLE_LCL requires a date/time component as the file's timestamp. + * MODULE_NAME_STYLE_STAMP_LCL requires a date/time component as the file's timestamp. * E.g. foo.2012-04-06T15:30:00-7 * - * MODULE_FLAG_STYLE_LCL_B requires a date/time component as the file's timestamp. + * MODULE_NAME_STYLE_STAMP_LCL_B requires a date/time component as the file's timestamp. * E.g. foo.20120406T153000-07 */ int @@ -2174,7 +2557,7 @@ _parse_stamp_style(char *stamp, uint32_t flags, uint32_t *sp, time_t *tp) /* check for NULL (no stamp) */ if (stamp == NULL) return STAMP_STYLE_NULL; - /* check for MODULE_FLAG_STYLE_SEC (foo.T12345678) */ + /* check for MODULE_NAME_STYLE_STAMP_SEC (foo.T12345678) */ if (stamp[0] == 'T') { n = atoi(stamp + 1); @@ -2184,11 +2567,11 @@ _parse_stamp_style(char *stamp, uint32_t flags, uint32_t *sp, time_t *tp) return STAMP_STYLE_SEC; } - /* check for MODULE_FLAG_STYLE_SEQ (foo.0 or foo.2.gz) */ + /* check for MODULE_NAME_STYLE_STAMP_SEQ (foo.0 or foo.2.gz) */ digits = true; for (i = 0; digits && (stamp[i] != '\0'); i++) digits = (stamp[i] >= '0') && (stamp[i] <= '9'); - if (!digits && (!strcmp(stamp + i, ".gz"))) digits = true; + if (!digits && (streq(stamp + i, ".gz"))) digits = true; if (digits) { @@ -2197,25 +2580,34 @@ _parse_stamp_style(char *stamp, uint32_t flags, uint32_t *sp, time_t *tp) return STAMP_STYLE_SEQ; } - /* check for MODULE_FLAG_STYLE_UTC, UTC_B, LCL, or LCL_B */ + /* check for MODULE_NAME_STYLE_STAMP_UTC, UTC_B, LCL, or LCL_B */ memset(&t, 0, sizeof(t)); h = m = s = 0; n = 0; - if ((flags & MODULE_FLAG_STYLE_UTC) || (flags & MODULE_FLAG_STYLE_LCL)) + if ((flags & MODULE_NAME_STYLE_STAMP_UTC) || (flags & MODULE_NAME_STYLE_STAMP_LCL)) { n = sscanf(stamp, "%d-%d-%dT%d:%d:%d%c%u:%u:%u", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &zone, &h, &m, &s); } - else if ((flags & MODULE_FLAG_STYLE_UTC_B) || (flags & MODULE_FLAG_STYLE_LCL_B)) + else if ((flags & MODULE_NAME_STYLE_STAMP_UTC_B) || (flags & MODULE_NAME_STYLE_STAMP_LCL_B)) { n = sscanf(stamp, "%4d%2d%2dT%2d%2d%2d%c%2u%2u%2u", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &zone, &h, &m, &s); } else { +#ifdef DEBUG_LIST_FILES + fprintf(stderr, "_parse_stamp_style fail %u\n", __LINE__); +#endif return STAMP_STYLE_INVALID; } - if (n < 6) return STAMP_STYLE_INVALID; + if (n < 6) + { +#ifdef DEBUG_LIST_FILES + fprintf(stderr, "_parse_stamp_style fail %u\n", __LINE__); +#endif + return STAMP_STYLE_INVALID; + } if (n == 6) { @@ -2226,7 +2618,7 @@ _parse_stamp_style(char *stamp, uint32_t flags, uint32_t *sp, time_t *tp) if (n >= 8) utc_offset += (3600 * h); if (n >= 9) utc_offset += (60 * m); if (n == 10) utc_offset += s; - if (zone == '-') utc_offset *= -1; + if (zone == '+') utc_offset *= -1; } else if ((zone >= 'A') && (zone <= 'Z')) { @@ -2242,6 +2634,9 @@ _parse_stamp_style(char *stamp, uint32_t flags, uint32_t *sp, time_t *tp) } else { +#ifdef DEBUG_LIST_FILES + fprintf(stderr, "_parse_stamp_style fail %u\n", __LINE__); +#endif return STAMP_STYLE_INVALID; } @@ -2255,11 +2650,11 @@ _parse_stamp_style(char *stamp, uint32_t flags, uint32_t *sp, time_t *tp) if (tp != NULL) *tp = ftime; - return STAMP_STYLE_UTC_OR_LCL; + return STAMP_STYLE_ISO8601; } asl_out_file_list_t * -asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) +asl_list_log_files(const char *dir, const char *base, const char *ext, uint32_t flags, bool src) { DIR *d; struct dirent *ent; @@ -2270,6 +2665,10 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) int pstyle, fstyle; asl_out_file_list_t *out, *x, *y; +#ifdef DEBUG_LIST_FILES + fprintf(stderr, "asl_list_log_files dir=%s base=%s ext=%s flags=0x%08x %s\n", dir, base, (ext == NULL) ? "(NULL)" : ext, flags, src ? "src" : "dst"); +#endif + if (dir == NULL) return NULL; if (base == NULL) return NULL; @@ -2282,10 +2681,9 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) { char *stamp = NULL; bool check; + bool stat_ok = false; - if (ent->d_name == NULL) continue; - - check = _check_file_name(ent->d_name, base, src, &stamp); + check = _check_file_name(ent->d_name, base, ext, flags, src, &stamp); if (!check) continue; seq = IndexNull; @@ -2296,11 +2694,24 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) if (pstyle == STAMP_STYLE_INVALID) continue; + snprintf(path, sizeof(path), "%s/%s", dir, ent->d_name); + memset(&sb, 0, sizeof(sb)); + if (lstat(path, &sb) == 0) + { + /* ignore symlinks (created for basestamp / symlink files) */ + stat_ok = true; + if ((sb.st_mode & S_IFMT) == S_IFLNK) continue; + } + fstyle = STAMP_STYLE_NULL; - if (flags & MODULE_FLAG_STYLE_SEC) fstyle = STAMP_STYLE_SEC; - else if (flags & MODULE_FLAG_STYLE_SEQ) fstyle = STAMP_STYLE_SEQ; - else if ((flags & MODULE_FLAG_STYLE_UTC) || (flags & MODULE_FLAG_STYLE_LCL)) fstyle = STAMP_STYLE_UTC_OR_LCL; - else if ((flags & MODULE_FLAG_STYLE_UTC_B) || (flags & MODULE_FLAG_STYLE_LCL_B)) fstyle = STAMP_STYLE_UTC_OR_LCL; + if (flags & MODULE_NAME_STYLE_STAMP_SEC) fstyle = STAMP_STYLE_SEC; + else if (flags & MODULE_NAME_STYLE_STAMP_SEQ) fstyle = STAMP_STYLE_SEQ; + else if ((flags & MODULE_NAME_STYLE_STAMP_UTC) || (flags & MODULE_NAME_STYLE_STAMP_LCL)) fstyle = STAMP_STYLE_ISO8601; + else if ((flags & MODULE_NAME_STYLE_STAMP_UTC_B) || (flags & MODULE_NAME_STYLE_STAMP_LCL_B)) fstyle = STAMP_STYLE_ISO8601; + +#ifdef DEBUG_LIST_FILES + fprintf(stderr, "%s %s %u fstyle %u pstyle %u\n", __func__, path, __LINE__, fstyle, pstyle); +#endif /* * accept the file if: @@ -2314,8 +2725,14 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) if ((pstyle == STAMP_STYLE_SEC) && src) check = true; if (pstyle == fstyle) check = true; - if (!check) continue; - + if (!check) + { +#ifdef DEBUG_LIST_FILES + fprintf(stderr, "%s reject %s at line %u\n", __func__, path, __LINE__); +#endif + continue; + } + x = (asl_out_file_list_t *)calloc(1, sizeof(asl_out_file_list_t)); if (x == NULL) { @@ -2324,12 +2741,11 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) } x->name = strdup(ent->d_name); + x->stamp = pstyle; x->ftime = ftime; x->seq = seq; - memset(&sb, 0, sizeof(sb)); - snprintf(path, sizeof(path), "%s/%s", dir, ent->d_name); - if (stat(path, &sb) == 0) + if (stat_ok) { x->size = sb.st_size; if (pstyle == STAMP_STYLE_SEQ) @@ -2341,11 +2757,14 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) if (pstyle == STAMP_STYLE_SEQ) { +#ifdef DEBUG_LIST_FILES + fprintf(stderr, "asl_list_log_files SEQ %s %u %ld\n", path, x->seq, x->ftime); +#endif if (out == NULL) { out = x; } - else if ((x->seq == IndexNull) || ((x->seq < out->seq) && (out->seq != IndexNull))) + else if ((x->seq == IndexNull) || ((x->seq > out->seq) && (out->seq != IndexNull))) { x->next = out; out->prev = x; @@ -2361,7 +2780,7 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) x->prev = y; break; } - else if ((x->seq < y->next->seq) && (y->next->seq != IndexNull)) + else if ((x->seq > y->next->seq) && (y->next->seq != IndexNull)) { x->next = y->next; y->next = x; @@ -2374,6 +2793,9 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) } else { +#ifdef DEBUG_LIST_FILES + fprintf(stderr, "asl_list_log_files TIME %s %ld\n", path, x->ftime); +#endif if (out == NULL) { out = x; @@ -2417,12 +2839,14 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) asl_out_file_list_t * asl_list_src_files(asl_out_dst_data_t *dst) { - char *base; - uint32_t flags = MODULE_FLAG_STYLE_SEC; - asl_out_file_list_t *out; + uint32_t flags; +#ifdef DEBUG_LIST_FILES + fprintf(stderr, "asl_list_src_files\n"); +#endif if (dst == NULL) return NULL; if (dst->path == NULL) return NULL; + if (dst->base == NULL) return NULL; /* * MODULE_FLAG_EXTERNAL means some process other than syslogd writes the file. @@ -2438,7 +2862,7 @@ asl_list_src_files(asl_out_dst_data_t *dst) { if (S_ISREG(sb.st_mode) && (sb.st_size != 0)) { - out = (asl_out_file_list_t *)calloc(1, sizeof(asl_out_file_list_t)); + asl_out_file_list_t *out = (asl_out_file_list_t *)calloc(1, sizeof(asl_out_file_list_t)); if (out != NULL) { char *p = strrchr(dst->path, '/'); @@ -2455,40 +2879,24 @@ asl_list_src_files(asl_out_dst_data_t *dst) return NULL; } - /* - * Checkpoint / source format may be one of: - * MODULE_FLAG_STYLE_SEC (foo.T12345678.log), - * MODULE_FLAG_STYLE_UTC (foo.20120-06-24T12:34:56Z.log) - * MODULE_FLAG_STYLE_UTC_B (foo.201200624T123456Z.log) - * MODULE_FLAG_STYLE_LCL (foo.20120-06-24T12:34:56-7.log) - * MODULE_FLAG_STYLE_LCL_B (foo.201200624T123456-07.log) - * - * MODULE_FLAG_STYLE_SEC format is used for sequenced (MODULE_FLAG_STYLE_SEQ) files. - * aslmanager converts the file names. - */ - - if (dst->flags & MODULE_FLAG_STYLE_UTC) flags = MODULE_FLAG_STYLE_UTC; - else if (dst->flags & MODULE_FLAG_STYLE_UTC_B) flags = MODULE_FLAG_STYLE_UTC_B; - else if (dst->flags & MODULE_FLAG_STYLE_LCL) flags = MODULE_FLAG_STYLE_LCL; - else if (dst->flags & MODULE_FLAG_STYLE_LCL_B) flags = MODULE_FLAG_STYLE_LCL_B; - - if ((dst->rotate_dir == NULL) && ((dst->flags & MODULE_FLAG_STYLE_SEQ) == 0) && ((dst->flags & MODULE_FLAG_COMPRESS) == 0)) + if ((dst->rotate_dir == NULL) && (dst->flags & MODULE_FLAG_BASESTAMP) && ((dst->flags & MODULE_FLAG_COMPRESS) == 0)) { /* files do not move to a dest dir, get renamed, or get compressed - nothing to do */ return NULL; } - base = strrchr(dst->path, '/'); - if (base == NULL) return NULL; - - *base = '\0'; - base++; - - out = asl_list_log_files(dst->path, base, true, flags); - - if (base != NULL) *--base = '/'; + /* + * MODULE_NAME_STYLE_STAMP_SEC format is used for sequenced (MODULE_NAME_STYLE_STAMP_SEQ) files. + * aslmanager converts the file names. + */ + flags = dst->style_flags; + if (flags & MODULE_NAME_STYLE_STAMP_SEQ) + { + flags &= ~MODULE_NAME_STYLE_STAMP_SEQ; + flags |= MODULE_NAME_STYLE_STAMP_SEC; + } - return out; + return asl_list_log_files(dst->dir, dst->base, dst->ext, flags, true); } /* @@ -2497,26 +2905,19 @@ asl_list_src_files(asl_out_dst_data_t *dst) asl_out_file_list_t * asl_list_dst_files(asl_out_dst_data_t *dst) { - char *base, *dst_dir; - asl_out_file_list_t *out; + char *dst_dir; +#ifdef DEBUG_LIST_FILES + fprintf(stderr, "asl_list_dst_files\n"); +#endif if (dst == NULL) return NULL; if (dst->path == NULL) return NULL; - - base = strrchr(dst->path, '/'); - if (base == NULL) return NULL; - - *base = '\0'; - base++; + if (dst->base == NULL) return NULL; dst_dir = dst->rotate_dir; - if (dst_dir == NULL) dst_dir = dst->path; - - out = asl_list_log_files(dst_dir, base, false, dst->flags); - - if (base != NULL) *--base = '/'; + if (dst_dir == NULL) dst_dir = dst->dir; - return out; + return asl_list_log_files(dst_dir, dst->base, dst->ext, dst->style_flags, false); } static int @@ -2576,7 +2977,7 @@ int asl_secure_chown_chmod_dir(const char *path, uid_t uid, gid_t gid, mode_t mode) { int fd, status; - + fd = asl_secure_open_dir(path); if (fd < 0) return fd; diff --git a/aslcommon/asl_common.h b/aslcommon/asl_common.h index 7802887..5f92393 100644 --- a/aslcommon/asl_common.h +++ b/aslcommon/asl_common.h @@ -2,14 +2,14 @@ * Copyright (c) 2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -17,7 +17,7 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_LICENSE_HEADER_END@ */ @@ -26,17 +26,20 @@ #include #include +#include #define ASL_MODULE_NAME "com.apple.asl" #define _PATH_CRASHREPORTER "/Library/Logs/CrashReporter" -#define _PATH_CRASHREPORTER_MOBILE "/var/mobile/Library/Logs/CrashReporter" +#define _PATH_CRASHREPORTER_MOBILE_1 "/var/mobile/Library/Logs/CrashReporter" +#define _PATH_CRASHREPORTER_MOBILE_2 "/private/var/mobile/Library/Logs/CrashReporter" +#define ASL_INTERNAL_LOGS_DIR "Logs" #define ASL_SERVICE_NAME "com.apple.system.logger" #define CRASH_MOVER_WILL_START_NOTIFICATION "CrashMoverWillStart" -#define DEFAULT_TTL 7 /* days */ #define SECONDS_PER_DAY 86400 +#define DEFAULT_TTL (7 * SECONDS_PER_DAY) #define ACTION_NONE 0 #define ACTION_SET_PARAM 1 @@ -71,20 +74,33 @@ #define MODULE_FLAG_NONSTD_DIR 0x00000020 #define MODULE_FLAG_EXTERNAL 0x00000040 #define MODULE_FLAG_TRUNCATE 0x00000080 -#define MODULE_FLAG_STYLE_SEC 0x00000100 /* foo.T1332799722 (note STYLE_SEC_PREFIX_CHAR) */ -#define MODULE_FLAG_STYLE_SEQ 0x00000200 /* foo.0 */ -#define MODULE_FLAG_STYLE_UTC 0x00000400 /* foo.2012-04-06T13:45:00Z */ -#define MODULE_FLAG_STYLE_UTC_B 0x00000800 /* ("basic utc") foo.20120406T134500Z */ -#define MODULE_FLAG_STYLE_LCL 0x00001000 /* foo.2012-04-06T13:45:00-7 */ -#define MODULE_FLAG_STYLE_LCL_B 0x00002000 /* ("basic local") foo.20120406T134500-7 */ -#define MODULE_FLAG_BASESTAMP 0x00004000 /* base file has timestamp */ -#define MODULE_FLAG_CRASHLOG 0x00008000 /* checkpoint on CrashMoverWillStart notification */ -#define MODULE_FLAG_SOFT_WRITE 0x00010000 /* ignore write failures */ -#define MODULE_FLAG_TYPE_ASL 0x00020000 /* asl format file */ -#define MODULE_FLAG_TYPE_ASL_DIR 0x00040000 /* asl format directory */ -#define MODULE_FLAG_STD_BSD_MSG 0x00080000 /* print format is std, bsd, or msg */ - -#define MODULE_FLAG_STYLE_BITS (MODULE_FLAG_STYLE_SEC | MODULE_FLAG_STYLE_SEQ | MODULE_FLAG_STYLE_UTC | MODULE_FLAG_STYLE_UTC_B | MODULE_FLAG_STYLE_LCL | MODULE_FLAG_STYLE_LCL_B) +#define MODULE_FLAG_BASESTAMP 0x00000100 /* base file has timestamp */ +#define MODULE_FLAG_SYMLINK 0x00000200 /* link to basestamp name */ +#define MODULE_FLAG_CRASHLOG 0x00000400 /* checkpoint on CrashMoverWillStart notification */ +#define MODULE_FLAG_SOFT_WRITE 0x00000800 /* ignore write failures */ +#define MODULE_FLAG_TYPE_ASL 0x00001000 /* asl format file */ +#define MODULE_FLAG_TYPE_ASL_DIR 0x00002000 /* asl format directory */ +#define MODULE_FLAG_STD_BSD_MSG 0x00004000 /* print format is std, bsd, or msg */ +#define MODULE_FLAG_ACTIVITY 0x00008000 + +#define MODULE_NAME_STYLE_FORMAT_MASK 0xf0000000 +#define MODULE_NAME_STYLE_FORMAT_BS 0x10000000 /* base.stamp */ +#define MODULE_NAME_STYLE_FORMAT_BES 0x20000000 /* base.ext.stamp */ +#define MODULE_NAME_STYLE_FORMAT_BSE 0x40000000 /* base.stamp.ext */ +#define MODULE_NAME_STYLE_STAMP_MASK 0x000000ff +#define MODULE_NAME_STYLE_STAMP_SEC 0x00000001 /* foo.T1332799722 (note STYLE_SEC_PREFIX_CHAR) */ +#define MODULE_NAME_STYLE_STAMP_SEQ 0x00000002 /* foo.0 */ +#define MODULE_NAME_STYLE_STAMP_UTC 0x00000004 /* foo.2012-04-06T13:45:00Z */ +#define MODULE_NAME_STYLE_STAMP_UTC_B 0x00000008 /* ("basic utc") foo.20120406T134500Z */ +#define MODULE_NAME_STYLE_STAMP_LCL 0x00000010 /* foo.2012-04-06T13:45:00-7 */ +#define MODULE_NAME_STYLE_STAMP_LCL_B 0x00000020 /* ("basic local") foo.20120406T134500-7 */ + +#define STAMP_STYLE_INVALID -1 +#define STAMP_STYLE_NULL 0 +#define STAMP_STYLE_SEC 1 +#define STAMP_STYLE_SEQ 2 +#define STAMP_STYLE_ISO8601 3 + #define CHECKPOINT_TEST 0x00000000 #define CHECKPOINT_FORCE 0x00000001 #define CHECKPOINT_CRASH 0x00000002 @@ -93,11 +109,15 @@ typedef struct { + char *dir; char *path; - char *fname; + char *current_name; char *fmt; - const char *tfmt; char *rotate_dir; + char *base; + char *ext; + const char *tfmt; + uint32_t style_flags; uint32_t pvt_flags; uint32_t flags; uint32_t fails; @@ -112,7 +132,7 @@ typedef struct size_t file_max; size_t all_max; uint32_t refcount; - time_t stamp; + time_t timestamp; size_t size; void *private; } asl_out_dst_data_t; @@ -138,6 +158,7 @@ typedef struct asl_out_module_s typedef struct asl_out_file_list_s { char *name; + uint32_t stamp; time_t ftime; uint32_t seq; size_t size; @@ -165,20 +186,22 @@ void asl_out_module_print(FILE *f, asl_out_module_t *m); char *asl_out_module_rule_to_string(asl_out_rule_t *r); int asl_out_mkpath(asl_out_module_t *mlist, asl_out_rule_t *r); +int asl_make_database_dir(const char *dir, char **out); int asl_out_dst_checkpoint(asl_out_dst_data_t *dst, uint32_t force); int asl_out_dst_file_create_open(asl_out_dst_data_t *dst, char **pathp); int asl_out_dst_set_access(int fd, asl_out_dst_data_t *dst); void asl_make_timestamp(time_t stamp, uint32_t flags, char *buf, size_t len); -void asl_make_dst_filename(asl_out_dst_data_t *dst, char *buf, size_t len); +void asl_dst_make_current_name(asl_out_dst_data_t *dst, uint32_t xflags, char *buf, size_t len); asl_out_dst_data_t *asl_out_dst_data_retain(asl_out_dst_data_t *dst); void asl_out_dst_data_release(asl_out_dst_data_t *dst); /* rotated log files */ -asl_out_file_list_t *asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags); +asl_out_file_list_t *asl_list_log_files(const char *dir, const char *base, const char *ext, uint32_t flags, bool src); asl_out_file_list_t * asl_list_src_files(asl_out_dst_data_t *dst); asl_out_file_list_t * asl_list_dst_files(asl_out_dst_data_t *dst); void asl_out_file_list_free(asl_out_file_list_t *l); +asl_out_dst_data_t *asl_out_dest_for_path(asl_out_module_t *m, const char *path); asl_msg_t *configuration_profile_to_asl_msg(const char *ident); diff --git a/aslcommon/asl_memory.c b/aslcommon/asl_memory.c index 5bd090c..1dcfab1 100644 --- a/aslcommon/asl_memory.c +++ b/aslcommon/asl_memory.c @@ -36,7 +36,6 @@ #define DEFAULT_MAX_RECORDS 2000 #define DEFAULT_MAX_STRING_MEMORY 4096000 -#define MEM_STRING_HEADER_SIZE 8 #define forever for(;;) @@ -59,8 +58,8 @@ asl_memory_statistics(asl_memory_t *s, asl_msg_t **msg) for (i = 0; i < s->string_count; i++) { - size += MEM_STRING_HEADER_SIZE; - if (((mem_string_t *)s->string_cache[i])->str != NULL) size += (strlen(((mem_string_t *)s->string_cache[i])->str) + 1); + size += sizeof(mem_string_t); + if (s->string_cache[i]->str != NULL) size += (strlen(s->string_cache[i]->str) + 1); } snprintf(str, sizeof(str), "%llu", size); @@ -78,10 +77,10 @@ asl_memory_statistics(asl_memory_t *s, asl_msg_t **msg) snprintf(str, sizeof(str), "%u", s->string_count); asl_msg_set_key_val(out, "StringCount", str); - snprintf(str, sizeof(str), "%u", s->curr_string_mem); + snprintf(str, sizeof(str), "%lu", s->curr_string_mem); asl_msg_set_key_val(out, "StringMemory", str); - snprintf(str, sizeof(str), "%u", s->max_string_mem); + snprintf(str, sizeof(str), "%lu", s->max_string_mem); asl_msg_set_key_val(out, "MaxStringMemory", str); *msg = out; @@ -91,35 +90,45 @@ asl_memory_statistics(asl_memory_t *s, asl_msg_t **msg) uint32_t asl_memory_close(asl_memory_t *s) { - uint32_t i; - if (s == NULL) return ASL_STATUS_OK; + + dispatch_sync(s->queue, ^{ + uint32_t i; - if (s->record != NULL) - { - for (i = 0; i < s->record_count; i++) + if (s->record != NULL) { - if (s->record[i] != NULL) free(s->record[i]); - s->record[i] = NULL; - } + for (i = 0; i < s->record_count; i++) + { + free(s->record[i]); + s->record[i] = NULL; + } - free(s->record); - s->record = NULL; - } + free(s->record); + s->record = NULL; + } - if (s->buffer_record != NULL) free(s->buffer_record); + free(s->buffer_record); + s->buffer_record = NULL; - if (s->string_cache != NULL) - { - for (i = 0; i < s->string_count; i++) + if (s->string_cache != NULL) { - if (s->string_cache[i] != NULL) free(s->string_cache[i]); - s->string_cache[i] = NULL; + for (i = 0; i < s->string_count; i++) + { + if (s->string_cache[i] != NULL) + { + free(s->string_cache[i]->str); + free(s->string_cache[i]); + } + + s->string_cache[i] = NULL; + } + + free(s->string_cache); + s->string_cache = NULL; } + }); - free(s->string_cache); - s->string_cache = NULL; - } + dispatch_release(s->queue); free(s); @@ -140,12 +149,20 @@ asl_memory_open(uint32_t max_records, size_t max_str_mem, asl_memory_t **s) out = calloc(1, sizeof(asl_memory_t)); if (out == NULL) return ASL_STATUS_NO_MEMORY; + out->queue = dispatch_queue_create("ASL Memory Queue", NULL); + if (out->queue == NULL) + { + free(out); + return ASL_STATUS_NO_MEMORY; + } + out->max_string_mem = max_str_mem; out->record_count = max_records; out->record = (mem_record_t **)calloc(max_records, sizeof(mem_record_t *)); if (out->record == NULL) { + dispatch_release(out->queue); free(out); return ASL_STATUS_NO_MEMORY; } @@ -171,28 +188,67 @@ asl_memory_open(uint32_t max_records, size_t max_str_mem, asl_memory_t **s) return ASL_STATUS_OK; } +static void +asl_memory_reset(asl_memory_t *s) +{ + uint32_t i; + if (s == NULL) return; + + /* clear all message records */ + for (i = 0; i < s->record_count; i++) + { + memset(s->record[i], 0, sizeof(mem_record_t)); + } + + /* reset the string cache */ + if (s->string_cache != NULL) + { + for (i = 0; i < s->string_count; i++) + { + if (s->string_cache[i] != NULL) + { + free(s->string_cache[i]->str); + free(s->string_cache[i]); + } + + s->string_cache[i] = NULL; + } + + free(s->string_cache); + s->string_cache = NULL; + } + + s->string_count = 0; +} + static mem_string_t * -mem_string_new(const char *str, uint32_t len, uint32_t hash) +asl_memory_string_new(const char *str, uint32_t len, uint32_t hash) { mem_string_t *out; - size_t ss; if (str == NULL) return NULL; - ss = MEM_STRING_HEADER_SIZE + len + 1; - out = (mem_string_t *)calloc(1, ss); + out = (mem_string_t *)calloc(1, sizeof(mem_string_t)); if (out == NULL) return NULL; out->hash = hash; out->refcount = 1; + out->str = malloc(len + 1); + if (out->str == NULL) + { + free(out); + return NULL; + } + memcpy(out->str, str, len); + out->str[len] = 0; return out; } /* * Find the first hash greater than or equal to a given hash in the string cache. - * Return s->string_count if hash is greater that or equal to last hash in the string cache. + * Return s->string_count if hash is greater than last hash in the string cache. * Caller must check if the hashes match or not. * * This routine is used both to find strings in the cache and to determine where to insert @@ -207,7 +263,7 @@ asl_memory_string_cache_search_hash(asl_memory_t *s, uint32_t hash) if (s->string_count == 0) return 0; if (s->string_count == 1) { - ms = (mem_string_t *)s->string_cache[0]; + ms = s->string_cache[0]; if (hash < ms->hash) return 0; return 1; } @@ -218,13 +274,13 @@ asl_memory_string_cache_search_hash(asl_memory_t *s, uint32_t hash) while (range > 1) { - ms = (mem_string_t *)s->string_cache[mid]; + ms = s->string_cache[mid]; if (hash == ms->hash) { while (mid > 0) { - ms = (mem_string_t *)s->string_cache[mid - 1]; + ms = s->string_cache[mid - 1]; if (hash != ms->hash) break; mid--; } @@ -233,7 +289,7 @@ asl_memory_string_cache_search_hash(asl_memory_t *s, uint32_t hash) } else { - ms = (mem_string_t *)s->string_cache[mid]; + ms = s->string_cache[mid]; if (hash < ms->hash) top = mid; else bot = mid; } @@ -242,10 +298,10 @@ asl_memory_string_cache_search_hash(asl_memory_t *s, uint32_t hash) mid = bot + (range / 2); } - ms = (mem_string_t *)s->string_cache[bot]; + ms = s->string_cache[bot]; if (hash <= ms->hash) return bot; - ms = (mem_string_t *)s->string_cache[top]; + ms = s->string_cache[top]; if (hash <= ms->hash) return top; return s->string_count; @@ -274,11 +330,11 @@ asl_memory_string_retain(asl_memory_t *s, const char *str, int create) /* asl_memory_string_cache_search_hash just tells us where to look */ if (where < s->string_count) { - while (((mem_string_t *)(s->string_cache[where]))->hash == hash) + while (s->string_cache[where]->hash == hash) { - if (!strcmp(str, ((mem_string_t *)(s->string_cache[where]))->str)) + if (!strcmp(str, s->string_cache[where]->str)) { - ((mem_string_t *)(s->string_cache[where]))->refcount++; + s->string_cache[where]->refcount++; return s->string_cache[where]; } @@ -290,26 +346,20 @@ asl_memory_string_retain(asl_memory_t *s, const char *str, int create) if (create == 0) return NULL; /* create a new mem_string_t and insert into the cache at index 'where' */ - if (s->string_count == 0) - { - s->string_cache = (void **)calloc(1, sizeof(void *)); - } - else - { - s->string_cache = (void **)reallocf(s->string_cache, (s->string_count + 1) * sizeof(void *)); - for (i = s->string_count; i > where; i--) s->string_cache[i] = s->string_cache[i - 1]; - } - + new = asl_memory_string_new(str, len, hash); + if (new == NULL) return NULL; + + s->string_cache = (mem_string_t **)reallocf(s->string_cache, (s->string_count + 1) * sizeof(void *)); if (s->string_cache == NULL) { s->string_count = 0; + free(new); return NULL; } - new = mem_string_new(str, len, hash); - if (new == NULL) return NULL; + for (i = s->string_count; i > where; i--) s->string_cache[i] = s->string_cache[i - 1]; - s->curr_string_mem += (MEM_STRING_HEADER_SIZE + len + 1); + s->curr_string_mem += (sizeof(mem_string_t) + len + 1); s->string_cache[where] = new; s->string_count++; @@ -328,11 +378,11 @@ asl_memory_string_release(asl_memory_t *s, mem_string_t *m) if (m->refcount > 0) return ASL_STATUS_OK; where = asl_memory_string_cache_search_hash(s, m->hash); - if (((mem_string_t *)(s->string_cache[where]))->hash != m->hash) return ASL_STATUS_OK; + if (s->string_cache[where]->hash != m->hash) return ASL_STATUS_OK; while (s->string_cache[where] != m) { - if (((mem_string_t *)(s->string_cache[where]))->hash != m->hash) return ASL_STATUS_OK; + if (s->string_cache[where]->hash != m->hash) return ASL_STATUS_OK; where++; if (where >= s->string_count) return ASL_STATUS_OK; @@ -340,9 +390,12 @@ asl_memory_string_release(asl_memory_t *s, mem_string_t *m) for (i = where + 1; i < s->string_count; i++) s->string_cache[i - 1] = s->string_cache[i]; - s->curr_string_mem -= (MEM_STRING_HEADER_SIZE + strlen(m->str) + 1); + if (m->str == NULL) s->curr_string_mem -= sizeof(mem_string_t); + else s->curr_string_mem -= (sizeof(mem_string_t) + strlen(m->str) + 1); + free(m->str); free(m); + s->string_count--; if (s->string_count == 0) @@ -352,7 +405,7 @@ asl_memory_string_release(asl_memory_t *s, mem_string_t *m) return ASL_STATUS_OK; } - s->string_cache = (void **)reallocf(s->string_cache, s->string_count * sizeof(void *)); + s->string_cache = (mem_string_t **)reallocf(s->string_cache, s->string_count * sizeof(void *)); if (s->string_cache == NULL) { s->string_count = 0; @@ -520,15 +573,7 @@ asl_memory_message_encode(asl_memory_t *s, asl_msg_t *msg) v = NULL; if (val != NULL) v = asl_memory_string_retain(s, val, 1); - if (r->kvcount == 0) - { - r->kvlist = (mem_string_t **)calloc(2, sizeof(mem_string_t *)); - } - else - { - r->kvlist = (mem_string_t **)reallocf(r->kvlist, (r->kvcount + 2) * sizeof(mem_string_t *)); - } - + r->kvlist = (mem_string_t **)reallocf(r->kvlist, (r->kvcount + 2) * sizeof(mem_string_t *)); if (r->kvlist == NULL) { asl_memory_record_clear(s, r); @@ -546,45 +591,58 @@ asl_memory_message_encode(asl_memory_t *s, asl_msg_t *msg) uint32_t asl_memory_save(asl_memory_t *s, asl_msg_t *msg, uint64_t *mid) { - uint32_t status; - mem_record_t *t; + __block uint32_t status; if (s == NULL) return ASL_STATUS_INVALID_STORE; if (s->buffer_record == NULL) return ASL_STATUS_INVALID_STORE; - /* asl_memory_message_encode creates and caches strings */ - status = asl_memory_message_encode(s, msg); - if (status != ASL_STATUS_OK) return status; - - if (*mid != 0) - { - s->buffer_record->mid = *mid; - } - else - { - s->buffer_record->mid = asl_core_new_msg_id(0); - *mid = s->buffer_record->mid; - } - - /* clear the first record */ - t = s->record[s->record_first]; - asl_memory_record_clear(s, t); - - /* add the new record to the record list (swap in the buffer record) */ - s->record[s->record_first] = s->buffer_record; - s->buffer_record = t; - - /* record list is a circular queue */ - s->record_first++; - if (s->record_first >= s->record_count) s->record_first = 0; + dispatch_sync(s->queue, ^{ + mem_record_t *t; - /* delete records if too much memory is in use */ - while (s->curr_string_mem > s->max_string_mem) - { - asl_memory_record_clear(s, s->record[s->record_first]); - s->record_first++; - if (s->record_first >= s->record_count) s->record_first = 0; - } + /* asl_memory_message_encode creates and caches strings */ + status = asl_memory_message_encode(s, msg); + if (status == ASL_STATUS_OK) + { + uint32_t loop_start_index = s->record_first; + + if (*mid != 0) + { + s->buffer_record->mid = *mid; + } + else + { + s->buffer_record->mid = asl_core_new_msg_id(0); + *mid = s->buffer_record->mid; + } + + /* clear the first record */ + t = s->record[s->record_first]; + asl_memory_record_clear(s, t); + + /* add the new record to the record list (swap in the buffer record) */ + s->record[s->record_first] = s->buffer_record; + s->buffer_record = t; + + /* record list is a circular queue */ + s->record_first++; + if (s->record_first >= s->record_count) s->record_first = 0; + + /* delete records if too much memory is in use */ + while (s->curr_string_mem > s->max_string_mem) + { + asl_memory_record_clear(s, s->record[s->record_first]); + s->record_first++; + if (s->record_first >= s->record_count) s->record_first = 0; + if (s->record_first == loop_start_index) + { + /* The entire ring has been cleared. This should never happen. */ + asl_memory_reset(s); + status = ASL_STATUS_FAILED; + break; + } + } + } + }); return status; } @@ -728,9 +786,9 @@ asl_memory_message_decode(asl_memory_t *s, mem_record_t *r, asl_msg_t **out) key = NULL; val = NULL; - if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) key = r->kvlist[i]->str; + if (r->kvlist[i] != NULL) key = r->kvlist[i]->str; i++; - if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) val = r->kvlist[i]->str; + if (r->kvlist[i] != NULL) val = r->kvlist[i]->str; if (key != NULL) asl_msg_set_key_val(msg, key, val); } @@ -742,24 +800,32 @@ asl_memory_message_decode(asl_memory_t *s, mem_record_t *r, asl_msg_t **out) uint32_t asl_memory_fetch(asl_memory_t *s, uint64_t mid, asl_msg_t **msg, int32_t ruid, int32_t rgid) { - uint32_t i, status; + __block uint32_t status; if (s == NULL) return ASL_STATUS_INVALID_STORE; if (msg == NULL) return ASL_STATUS_INVALID_ARG; - for (i = 0; i < s->record_count; i++) - { - if (s->record[i]->mid == 0) break; + status = ASL_STATUS_INVALID_ID; - if (s->record[i]->mid == mid) + dispatch_sync(s->queue, ^{ + uint32_t i; + + for (i = 0; i < s->record_count; i++) { - status = asl_core_check_access(s->record[i]->ruid, s->record[i]->rgid, ruid, rgid, s->record[i]->flags); - if (status != ASL_STATUS_OK) return status; - return asl_memory_message_decode(s, s->record[i], msg); + if (s->record[i]->mid == 0) break; + + if (s->record[i]->mid == mid) + { + status = asl_core_check_access(s->record[i]->ruid, s->record[i]->rgid, ruid, rgid, s->record[i]->flags); + if (status != ASL_STATUS_OK) break; + + status = asl_memory_message_decode(s, s->record[i], msg); + break; + } } - } + }); - return ASL_STATUS_INVALID_ID; + return status; } static mem_record_t * @@ -1190,8 +1256,8 @@ asl_memory_slow_match(asl_memory_t *s, mem_record_t *r, asl_msg_t *rawq) return status; } -uint32_t -asl_memory_match_restricted_uuid(asl_memory_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t start_id, uint32_t count, uint32_t duration, int32_t direction, int32_t ruid, int32_t rgid, const char *uuid_str) +static uint32_t +asl_memory_match_restricted_uuid_internal(asl_memory_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t start_id, uint32_t count, uint32_t duration, int32_t direction, int32_t ruid, int32_t rgid, const char *uuid_str) { uint32_t status, i, where, start, j, do_match, did_match, rescount, *qtype; mem_record_t **qp; @@ -1199,9 +1265,6 @@ asl_memory_match_restricted_uuid(asl_memory_t *s, asl_msg_list_t *query, asl_msg size_t qcount; struct timeval now, finish; - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (res == NULL) return ASL_STATUS_INVALID_ARG; - qp = NULL; qtype = NULL; rescount = 0; @@ -1430,8 +1493,32 @@ asl_memory_match_restricted_uuid(asl_memory_t *s, asl_msg_list_t *query, asl_msg return ASL_STATUS_OK; } +uint32_t +asl_memory_match_restricted_uuid(asl_memory_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t start_id, uint32_t count, uint32_t duration, int32_t direction, int32_t ruid, int32_t rgid, const char *uuid_str) +{ + __block uint32_t status; + + if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (res == NULL) return ASL_STATUS_INVALID_ARG; + + dispatch_sync(s->queue, ^{ + status = asl_memory_match_restricted_uuid_internal(s, query, res, last_id, start_id, count, duration, direction, ruid, rgid, uuid_str); + }); + + return status; +} + uint32_t asl_memory_match(asl_memory_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, int32_t ruid, int32_t rgid) { - return asl_memory_match_restricted_uuid(s, query, res, last_id, start_id, count, 0, direction, ruid, rgid, NULL); + __block uint32_t status; + + if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (res == NULL) return ASL_STATUS_INVALID_ARG; + + dispatch_sync(s->queue, ^{ + status = asl_memory_match_restricted_uuid_internal(s, query, res, last_id, start_id, count, 0, direction, ruid, rgid, NULL); + }); + + return status; } diff --git a/aslcommon/asl_memory.h b/aslcommon/asl_memory.h index 3a1a30a..846dc57 100644 --- a/aslcommon/asl_memory.h +++ b/aslcommon/asl_memory.h @@ -25,30 +25,20 @@ #define __ASL_MEMORY_H__ #include #include +#include typedef struct { uint32_t hash; uint32_t refcount; - char str[]; + char *str; } mem_string_t; typedef struct { uint64_t mid; uint64_t time; - uint32_t nano; - uint8_t unused_0; - uint8_t level; - uint16_t flags; - uint32_t pid; - uint32_t uid; - uint32_t gid; - uint32_t ruid; - uint32_t rgid; - uint32_t refpid; uint64_t os_activity_id; - uint32_t kvcount; mem_string_t *host; mem_string_t *sender; mem_string_t *sender_mach_uuid; @@ -57,18 +47,30 @@ typedef struct mem_string_t *refproc; mem_string_t *session; mem_string_t **kvlist; + uint32_t nano; + uint32_t pid; + uint32_t uid; + uint32_t gid; + uint32_t ruid; + uint32_t rgid; + uint32_t refpid; + uint32_t kvcount; + uint16_t flags; + uint8_t level; + uint8_t unused_0; } mem_record_t; typedef struct { + mem_string_t **string_cache; + mem_record_t **record; + mem_record_t *buffer_record; uint32_t string_count; - void **string_cache; uint32_t record_count; uint32_t record_first; - mem_record_t **record; - mem_record_t *buffer_record; - uint32_t max_string_mem; - uint32_t curr_string_mem; + size_t max_string_mem; + size_t curr_string_mem; + dispatch_queue_t queue; } asl_memory_t; uint32_t asl_memory_open(uint32_t max_records, size_t max_str_mem, asl_memory_t **s); diff --git a/aslmanager.tproj/aslmanager.c b/aslmanager.tproj/aslmanager.c index 02eb7e0..ace8232 100644 --- a/aslmanager.tproj/aslmanager.c +++ b/aslmanager.tproj/aslmanager.c @@ -1,1411 +1,134 @@ /* - * Copyright (c) 2007-2009 Apple Inc. All rights reserved. + * Copyright (c) 2007-2015 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "asl_common.h" - -#define DEFAULT_MAX_SIZE 150000000 -#define IOBUFSIZE 4096 - -#define DO_ASLDB 0x00000001 -#define DO_MODULE 0x00000002 -#define DO_CHECKPT 0x00000004 - -#define DEBUG_FLAG_MASK 0xfffffff0 -#define DEBUG_LEVEL_MASK 0x0000000f -#define DEBUG_STDERR 0x00000010 -#define DEBUG_ASL 0x00000020 - -#define AUX_URL_MINE "file:///var/log/asl/" -#define AUX_URL_MINE_LEN 20 - -/* length of "file://" */ -#define AUX_URL_PATH_OFFSET 7 - -extern kern_return_t _asl_server_query -( - mach_port_t server, - caddr_t request, - mach_msg_type_number_t requestCnt, - uint64_t startid, - int count, - int flags, - caddr_t *reply, - mach_msg_type_number_t *replyCnt, - uint64_t *lastid, - int *status, - security_token_t *token -); - -/* global */ -static time_t module_ttl; -static uint32_t debug; -static int dryrun; -static int asl_aux_fd = -1; -static aslclient aslc; -static mach_port_t asl_server_port; -static xpc_connection_t listener; -static dispatch_queue_t serverq; - -typedef struct name_list_s -{ - char *name; - size_t size; - struct name_list_s *next; -} name_list_t; - -static const char * -keep_str(uint8_t mask) -{ - static char str[9]; - uint32_t x = 0; - - memset(str, 0, sizeof(str)); - if (mask & 0x01) str[x++] = '0'; - if (mask & 0x02) str[x++] = '1'; - if (mask & 0x04) str[x++] = '2'; - if (mask & 0x08) str[x++] = '3'; - if (mask & 0x10) str[x++] = '4'; - if (mask & 0x20) str[x++] = '5'; - if (mask & 0x40) str[x++] = '6'; - if (mask & 0x80) str[x++] = '7'; - if (x == 0) str[x++] = '-'; - return str; -} - -void -set_debug(int flag, const char *str) -{ - int level, x; - - if (str == NULL) x = ASL_LEVEL_ERR; - else if (((str[0] == 'L') || (str[0] == 'l')) && ((str[1] >= '0') && (str[1] <= '7')) && (str[2] == '\0')) x = atoi(str+1); - else if ((str[0] >= '0') && (str[0] <= '7') && (str[1] == '\0')) x = ASL_LEVEL_CRIT + atoi(str); - else x = ASL_LEVEL_ERR; - - if (x <= 0) x = 0; - else if (x > 7) x = 7; - - level = debug & DEBUG_LEVEL_MASK; - if (x > level) level = x; - - debug = debug & DEBUG_FLAG_MASK; - debug |= flag; - debug |= level; -} - -void -debug_log(int level, const char *str, ...) -{ - va_list v; - - if ((debug & DEBUG_STDERR) && (level <= (debug & DEBUG_LEVEL_MASK))) - { - va_start(v, str); - vfprintf(stderr, str, v); - va_end(v); - } - - if (debug & DEBUG_ASL) - { - char *line = NULL; - - if (aslc == NULL) - { - aslc = asl_open("aslmanager", "syslog", 0); - asl_msg_t *msg = asl_msg_new(ASL_TYPE_MSG); - - asl_msg_set_key_val(msg, ASL_KEY_MSG, "Status Report"); - asl_msg_set_key_val(msg, ASL_KEY_LEVEL, ASL_STRING_NOTICE); - asl_create_auxiliary_file((asl_object_t)msg, "Status Report", "public.text", &asl_aux_fd); - asl_msg_release(msg); - } - - va_start(v, str); - vasprintf(&line, str, v); - va_end(v); - - if (line != NULL) write(asl_aux_fd, line, strlen(line)); - free(line); - } -} - -__attribute__((noreturn)) static void -xpc_server_exit(int status) -{ - xpc_connection_cancel(listener); - xpc_release(listener); - dispatch_release(serverq); - exit(status); -} - -name_list_t * -add_to_name_list(name_list_t *l, const char *name, size_t size) -{ - name_list_t *e, *x; - - if (name == NULL) return l; - - e = (name_list_t *)calloc(1, sizeof(name_list_t)); - if (e == NULL) return NULL; - - e->name = strdup(name); - if (e->name == NULL) - { - free(e); - return NULL; - } - - e->size = size; - - /* list is sorted by name (i.e. primarily by timestamp) */ - if (l == NULL) return e; - - if (strcmp(e->name, l->name) <= 0) - { - e->next = l; - return e; - } - - for (x = l; (x->next != NULL) && (strcmp(e->name, x->next->name) > 0) ; x = x->next); - - e->next = x->next; - x->next = e; - return l; -} - -void -free_name_list(name_list_t *l) -{ - name_list_t *e; - - while (l != NULL) - { - e = l; - l = l->next; - free(e->name); - free(e); - } - - free(l); -} -/* - * Copy ASL files by reading and writing each record. - */ -uint32_t -copy_asl_file(const char *src, const char *dst, mode_t mode) -{ - asl_msg_list_t *res; - asl_file_t *f; - uint32_t status, i; - uint64_t mid; - size_t rcount; - - if (src == NULL) return ASL_STATUS_INVALID_ARG; - if (dst == NULL) return ASL_STATUS_INVALID_ARG; - - f = NULL; - status = asl_file_open_read(src, &f); - if (status != ASL_STATUS_OK) return status; - - res = NULL; - mid = 0; - - res = asl_file_match(f, NULL, &mid, 0, 0, 0, 1); - asl_file_close(f); - - if (res == NULL) return ASL_STATUS_OK; - rcount = asl_msg_list_count(res); - if (rcount == 0) - { - asl_msg_list_release(res); - return ASL_STATUS_OK; - } - - f = NULL; - status = asl_file_open_write(dst, mode, -1, -1, &f); - if (status != ASL_STATUS_OK) return status; - if (f == ASL_STATUS_OK) return ASL_STATUS_FAILED; - - f->flags = ASL_FILE_FLAG_PRESERVE_MSG_ID; - - for (i = 0; i < rcount; i++) - { - mid = 0; - status = asl_file_save(f, asl_msg_list_get_index(res, i), &mid); - if (status != ASL_STATUS_OK) break; - } - - asl_file_close(f); - return status; -} - -int -copy_compress_file(asl_out_dst_data_t *asldst, const char *src, const char *dst) -{ - int in, out; - size_t n; - gzFile gz; - char buf[IOBUFSIZE]; - - in = open(src, O_RDONLY, 0); - if (in < 0) return -1; - - out = open(dst, O_WRONLY | O_CREAT, asldst->mode); - if (out >= 0) out = asl_out_dst_set_access(out, asldst); - if (out < 0) - { - close(in); - return -1; - } - - gz = gzdopen(out, "w"); - if (gz == NULL) - { - close(in); - close(out); - return -1; - } - - do { - n = read(in, buf, sizeof(buf)); - if (n > 0) gzwrite(gz, buf, n); - } while (n == IOBUFSIZE); - - gzclose(gz); - close(in); - close(out); - - return 0; -} - -void -filesystem_rename(const char *src, const char *dst) -{ - int status = 0; - - debug_log(ASL_LEVEL_NOTICE, " rename %s ---> %s\n", src, dst); - if (dryrun == 1) return; - - status = rename(src, dst); - if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] rename %s ---> %s\n", status, errno, strerror(errno), src, dst); -} - -void -filesystem_unlink(const char *path) -{ - int status = 0; - - debug_log(ASL_LEVEL_NOTICE, " remove %s\n", path); - if (dryrun == 1) return; - - status = unlink(path); - if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] unlink %s\n", status, errno, strerror(errno), path); -} - -void -filesystem_truncate(const char *path) -{ - int status = 0; - - debug_log(ASL_LEVEL_NOTICE, " truncate %s\n", path); - if (dryrun == 1) return; - - status = truncate(path, 0); - if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] unlink %s\n", status, errno, strerror(errno), path); -} - -void -filesystem_rmdir(const char *path) -{ - int status = 0; - - debug_log(ASL_LEVEL_NOTICE, " remove directory %s\n", path); - if (dryrun == 1) return; - - status = rmdir(path); - if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] rmdir %s\n", status, errno, strerror(errno), path); -} - -int32_t -filesystem_copy(asl_out_dst_data_t *asldst, const char *src, const char *dst, uint32_t flags) -{ - char *dot; - - if ((src == NULL) || (dst == NULL)) return 0; - - dot = strrchr(src, '.'); - if ((dot != NULL) && (!strcmp(dot, ".gz"))) flags &= ~MODULE_FLAG_COMPRESS; - - if (((flags & MODULE_FLAG_COMPRESS) == 0) && (!strcmp(src, dst))) return 0; - - if (flags & MODULE_FLAG_TYPE_ASL) debug_log(ASL_LEVEL_NOTICE, " copy asl %s ---> %s\n", src, dst); - else if (flags & MODULE_FLAG_COMPRESS) debug_log(ASL_LEVEL_NOTICE, " copy compress %s ---> %s.gz\n", src, dst); - else debug_log(ASL_LEVEL_NOTICE, " copy %s ---> %s\n", src, dst); - - if (dryrun == 1) return 0; - - if (flags & MODULE_FLAG_TYPE_ASL) - { - uint32_t status = copy_asl_file(src, dst, asldst->mode); - if (status != 0) - { - debug_log(ASL_LEVEL_ERR, " FAILED status %u [%s] asl copy %s ---> %s\n", status, asl_core_error(status), src, dst); - return 0; - } - } - else if (flags & MODULE_FLAG_COMPRESS) - { - char gzdst[MAXPATHLEN]; - - snprintf(gzdst, sizeof(gzdst), "%s.gz", dst); - - int status = copy_compress_file(asldst, src, gzdst); - if (status != 0) - { - debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] copy & compress %s ---> %s\n", status, errno, strerror(errno), src, dst); - return 0; - } - } - else - { - int status = copyfile(src, dst, NULL, COPYFILE_ALL | COPYFILE_RECURSIVE); - if (status != 0) - { - debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] copy %s ---> %s\n", status, errno, strerror(errno), src, dst); - return 0; - } - } - - return 1; -} - -int -remove_directory(const char *path) -{ - DIR *dp; - struct dirent *dent; - char *str; - - dp = opendir(path); - if (dp == NULL) return 0; - - while ((dent = readdir(dp)) != NULL) - { - if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue; - asprintf(&str, "%s/%s", path, dent->d_name); - if (str != NULL) - { - filesystem_unlink(str); - free(str); - str = NULL; - } - } - - closedir(dp); - filesystem_rmdir(path); - - return 0; -} - -/* - * Determine the age (in whole days) of a YMD file from its name. - * Also determines UID and GID from ".Unnn.Gnnn" part of file name. - */ -uint32_t -ymd_file_age(const char *name, time_t now, uid_t *u, gid_t *g) -{ - struct tm ftime; - time_t created; - uint32_t days; - const char *p; - - if (name == NULL) return 0; - - if (now == 0) now = time(NULL); - - memset(&ftime, 0, sizeof(struct tm)); - ftime.tm_hour = 24; - - /* name is YYYY.MM.DD.<...> */ - - if ((name[0] < '0') || (name[0] > '9')) return 0; - ftime.tm_year = 1000 * (name[0] - '0'); - - if ((name[1] < '0') || (name[1] > '9')) return 0; - ftime.tm_year += 100 * (name[1] - '0'); - - if ((name[2] < '0') || (name[2] > '9')) return 0; - ftime.tm_year += 10 * (name[2] - '0'); - - if ((name[3] < '0') || (name[3] > '9')) return 0; - ftime.tm_year += name[3] - '0'; - ftime.tm_year -= 1900; - - if (name[4] != '.') return 0; - - if ((name[5] < '0') || (name[5] > '9')) return 0; - ftime.tm_mon = 10 * (name[5] - '0'); - - if ((name[6] < '0') || (name[6] > '9')) return 0; - ftime.tm_mon += name[6] - '0'; - ftime.tm_mon -= 1; - - if (name[7] != '.') return 0; - - if ((name[8] < '0') || (name[8] > '9')) return 0; - ftime.tm_mday = 10 * (name[8] - '0'); - - if ((name[9] < '0') || (name[9] > '9')) return 0; - ftime.tm_mday += name[9] - '0'; - - if (name[10] != '.') return 0; - - created = mktime(&ftime); - if (created > now) return 0; - - days = (now - created) / 86400; - - if (u != NULL) - { - *u = -1; - p = strchr(name+10, 'U'); - if (p != NULL) *u = atoi(p+1); - } - - if (g != NULL) - { - *g = -1; - p = strchr(name+10, 'G'); - if (p != NULL) *g = atoi(p+1); - } - - return days; -} - -void -aux_url_callback(const char *url) -{ - if (url == NULL) return; - if (!strncmp(url, AUX_URL_MINE, AUX_URL_MINE_LEN)) filesystem_unlink(url + AUX_URL_PATH_OFFSET); -} - -uint32_t -ymd_file_filter(const char *name, const char *path, uint32_t keep_mask, mode_t ymd_mode, uid_t ymd_uid, gid_t ymd_gid) -{ - asl_file_t *f = NULL; - uint8_t km = keep_mask; - uint32_t status, len, dstcount = 0; - char src[MAXPATHLEN]; - char dst[MAXPATHLEN]; - - if (snprintf(src, MAXPATHLEN, "%s/%s", path, name) >= MAXPATHLEN) return ASL_STATUS_FAILED; - if (snprintf(dst, MAXPATHLEN, "%s/%s", path, name) >= MAXPATHLEN) return ASL_STATUS_FAILED; - len = strlen(src) - 3; - snprintf(dst + len, 4, "tmp"); - - //TODO: check if src file is already filtered - debug_log(ASL_LEVEL_NOTICE, " filter %s %s ---> %s\n", src, keep_str(km), dst); - - status = ASL_STATUS_OK; - - if (dryrun == 0) - { - status = asl_file_open_read(name, &f); - if (status != ASL_STATUS_OK) return status; - - status = asl_file_filter_level(f, dst, keep_mask, ymd_mode, ymd_uid, ymd_gid, &dstcount, aux_url_callback); - asl_file_close(f); - } - - filesystem_unlink(src); - if ((status != ASL_STATUS_OK) || (dstcount == 0)) filesystem_unlink(dst); - else filesystem_rename(dst, src); - - return status; -} - -/* - * Used to set config parameters. - * Line format "= name value" - */ -static void -_aslmanager_set_param(asl_out_dst_data_t *dst, char *s) -{ - char **l; - uint32_t count; - - if (s == NULL) return; - if (s[0] == '\0') return; - - /* skip '=' and whitespace */ - if (*s == '=') s++; - while ((*s == ' ') || (*s == '\t')) s++; - - l = explode(s, " \t"); - if (l == NULL) return; - - for (count = 0; l[count] != NULL; count++); - - /* name is required */ - if (count == 0) - { - free_string_list(l); - return; - } - - /* value is required */ - if (count == 1) - { - free_string_list(l); - return; - } - - if (!strcasecmp(l[0], "aslmanager_debug")) - { - /* = debug level */ - set_debug(DEBUG_ASL, l[1]); - } - else if (!strcasecmp(l[0], "store_ttl")) - { - /* = store_ttl days */ - dst->ttl[LEVEL_ALL] = (time_t)atoll(l[1]); - } - else if (!strcasecmp(l[0], "module_ttl")) - { - /* = module_ttl days */ - module_ttl = (time_t)atoll(l[1]); - } - else if (!strcasecmp(l[0], "max_store_size")) - { - /* = max_file_size bytes */ - dst->all_max = atoi(l[1]); - } - else if (!strcasecmp(l[0], "archive")) - { - free(dst->rotate_dir); - dst->rotate_dir = NULL; - - /* = archive {0|1} path */ - if (!strcmp(l[1], "1")) - { - if (l[2] == NULL) dst->rotate_dir = strdup(PATH_ASL_ARCHIVE); - else dst->rotate_dir = strdup(l[2]); - } - } - else if (!strcasecmp(l[0], "store_path")) - { - /* = archive path */ - free(dst->path); - dst->path = strdup(l[1]); - } - else if (!strcasecmp(l[0], "archive_mode")) - { - dst->mode = strtol(l[1], NULL, 0); - if ((dst->mode == 0) && (errno == EINVAL)) dst->mode = 0400; - } - - free_string_list(l); -} - -size_t -directory_size(const char *path) -{ - DIR *dp; - struct dirent *dent; - struct stat sb; - size_t size; - char *str; - - dp = opendir(path); - if (dp == NULL) return 0; - - size = 0; - while ((dent = readdir(dp)) != NULL) - { - if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue; - - memset(&sb, 0, sizeof(struct stat)); - str = NULL; - asprintf(&str, "%s/%s", path, dent->d_name); - - if ((str != NULL) && (stat(str, &sb) == 0) && S_ISREG(sb.st_mode)) - { - size += sb.st_size; - free(str); - } - } - - closedir(dp); - return size; -} - -static int -process_asl_data_store(asl_out_dst_data_t *dst) -{ - int32_t today_ymd_stringlen, expire_ymd_stringlen; - time_t now, ttl, ymd_expire; - struct tm ctm; - char today_ymd_string[32], expire_ymd_string[32], *str; - DIR *dp; - struct dirent *dent; - name_list_t *ymd_list, *bb_list, *aux_list, *bb_aux_list, *e; - size_t file_size, store_size; - struct stat sb; - - ymd_list = NULL; - bb_list = NULL; - aux_list = NULL; - bb_aux_list = NULL; - store_size = 0; - - if (dst == NULL) return 0; - if (dst->path == NULL) return 0; - - debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n"); - debug_log(ASL_LEVEL_NOTICE, "Processing data store %s\n", dst->path); - - if (dst->rotate_dir != NULL) - { - /* check archive */ - memset(&sb, 0, sizeof(struct stat)); - if (stat(dst->rotate_dir, &sb) == 0) - { - /* must be a directory */ - if (!S_ISDIR(sb.st_mode)) - { - debug_log(ASL_LEVEL_ERR, "aslmanager error: archive %s is not a directory", dst->rotate_dir); - return -1; - } - } - else - { - if (errno == ENOENT) - { - /* archive doesn't exist - create it */ - if (mkdir(dst->rotate_dir, 0755) != 0) - { - debug_log(ASL_LEVEL_ERR, "aslmanager error: can't create archive %s: %s\n", dst->rotate_dir, strerror(errno)); - return -1; - } - } - else - { - /* stat failed for some other reason */ - debug_log(ASL_LEVEL_ERR, "aslmanager error: can't stat archive %s: %s\n", dst->rotate_dir, strerror(errno)); - return -1; - } - } - } - - chdir(dst->path); - - /* determine current time */ - now = time(NULL); - - /* ttl 0 means files never expire */ - ymd_expire = 0; - ttl = dst->ttl[LEVEL_ALL] * SECONDS_PER_DAY; - - if ((ttl > 0) && (ttl <= now)) ymd_expire = now - ttl; - - /* construct today's date as YYYY.MM.DD */ - memset(&ctm, 0, sizeof(struct tm)); - if (localtime_r((const time_t *)&now, &ctm) == NULL) return -1; - - snprintf(today_ymd_string, sizeof(today_ymd_string), "%d.%02d.%02d.", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); - today_ymd_stringlen = strlen(today_ymd_string); - - /* construct regular file expiry date as YYYY.MM.DD */ - memset(&ctm, 0, sizeof(struct tm)); - if (localtime_r((const time_t *)&ymd_expire, &ctm) == NULL) return -1; - - snprintf(expire_ymd_string, sizeof(expire_ymd_string), "%d.%02d.%02d.", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); - expire_ymd_stringlen = strlen(expire_ymd_string); - - debug_log(ASL_LEVEL_NOTICE, "Expiry Date %s\n", expire_ymd_string); - - dp = opendir(dst->path); - if (dp == NULL) return -1; - - /* gather a list of YMD files, AUX dirs, BB.AUX dirs, and BB files */ - while ((dent = readdir(dp)) != NULL) - { - memset(&sb, 0, sizeof(struct stat)); - file_size = 0; - if (stat(dent->d_name, &sb) == 0) file_size = sb.st_size; - - if ((dent->d_name[0] >= '0') && (dent->d_name[0] <= '9')) - { - ymd_list = add_to_name_list(ymd_list, dent->d_name, file_size); - store_size += file_size; - } - else if (!strncmp(dent->d_name, "AUX.", 4) && (dent->d_name[4] >= '0') && (dent->d_name[4] <= '9') && S_ISDIR(sb.st_mode)) - { - file_size = directory_size(dent->d_name); - aux_list = add_to_name_list(aux_list, dent->d_name, file_size); - store_size += file_size; - } - else if (!strncmp(dent->d_name, "BB.AUX.", 7) && (dent->d_name[7] >= '0') && (dent->d_name[7] <= '9') && S_ISDIR(sb.st_mode)) - { - file_size = directory_size(dent->d_name); - bb_aux_list = add_to_name_list(bb_aux_list, dent->d_name, file_size); - store_size += file_size; - } - else if (!strncmp(dent->d_name, "BB.", 3) && (dent->d_name[3] >= '0') && (dent->d_name[3] <= '9')) - { - bb_list = add_to_name_list(bb_list, dent->d_name, file_size); - store_size += file_size; - } - else if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) - {} - else if ((!strcmp(dent->d_name, "StoreData")) || (!strcmp(dent->d_name, "SweepStore"))) - {} - else - { - debug_log(ASL_LEVEL_ERR, "aslmanager: unexpected file %s in ASL data store\n", dent->d_name); - } - } - - closedir(dp); - - debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size); - debug_log(ASL_LEVEL_NOTICE, "Data Store YMD Files\n"); - for (e = ymd_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, " %s %lu\n", e->name, e->size); - debug_log(ASL_LEVEL_NOTICE, "Data Store AUX Directories\n"); - for (e = aux_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, " %s %lu\n", e->name, e->size); - debug_log(ASL_LEVEL_NOTICE, "Data Store BB.AUX Directories\n"); - for (e = bb_aux_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, " %s %lu\n", e->name, e->size); - debug_log(ASL_LEVEL_NOTICE, "Data Store BB Files\n"); - for (e = bb_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, " %s %lu\n", e->name, e->size); - - /* Delete/achive expired YMD files */ - debug_log(ASL_LEVEL_NOTICE, "Start YMD File Scan\n"); - - e = ymd_list; - while (e != NULL) - { - if (strncmp(e->name, expire_ymd_string, expire_ymd_stringlen) <= 0) - { - /* file has expired, archive it if required, then unlink it */ - if (dst->rotate_dir != NULL) - { - str = NULL; - asprintf(&str, "%s/%s", dst->rotate_dir, e->name); - if (str == NULL) return -1; - - filesystem_copy(dst, e->name, str, 0); - free(str); - } - - filesystem_unlink(e->name); - store_size -= e->size; - e->size = 0; - } - else - { - /* check if there are any per-level TTLs and filter the file if required */ - uint32_t i, bit, keep_mask; - uid_t ymd_uid = -1; - gid_t ymd_gid = -1; - mode_t ymd_mode = 0600; - uint32_t age = ymd_file_age(e->name, now, &ymd_uid, &ymd_gid); - - if (age > 0) - { - keep_mask = 0x000000ff; - bit = 1; - for (i = 0; i <= 7; i++) - { - if ((dst->ttl[i] > 0) && (age >= dst->ttl[i])) keep_mask &= ~bit; - bit *= 2; - } - - memset(&sb, 0, sizeof(struct stat)); - if (stat(e->name, &sb) == 0) ymd_mode = sb.st_mode & 0777; - - if (keep_mask != 0x000000ff) ymd_file_filter(e->name, dst->path, keep_mask, ymd_mode, ymd_uid, ymd_gid); - } - } - - e = e->next; - } - - debug_log(ASL_LEVEL_NOTICE, "Finished YMD File Scan\n"); - - /* Delete/achive expired YMD AUX directories */ - debug_log(ASL_LEVEL_NOTICE, "Start AUX Directory Scan\n"); - - e = aux_list; - while (e != NULL) - { - /* stop when a file name/date is after the expire date */ - if (strncmp(e->name + 4, expire_ymd_string, expire_ymd_stringlen) > 0) break; - - if (dst->rotate_dir != NULL) - { - str = NULL; - asprintf(&str, "%s/%s", dst->rotate_dir, e->name); - if (str == NULL) return -1; - - filesystem_copy(dst, e->name, str, 0); - free(str); - } - - remove_directory(e->name); - store_size -= e->size; - e->size = 0; - - e = e->next; - } - - debug_log(ASL_LEVEL_NOTICE, "Finished AUX Directory Scan\n"); - - /* Delete/achive expired BB.AUX directories */ - debug_log(ASL_LEVEL_NOTICE, "Start BB.AUX Directory Scan\n"); - - e = bb_aux_list; - while (e != NULL) - { - /* stop when a file name/date is after the expire date */ - if (strncmp(e->name + 7, today_ymd_string, today_ymd_stringlen) > 0) break; - - if (dst->rotate_dir != NULL) - { - str = NULL; - asprintf(&str, "%s/%s", dst->rotate_dir, e->name); - if (str == NULL) return -1; - - filesystem_copy(dst, e->name, str, 0); - free(str); - } - - remove_directory(e->name); - store_size -= e->size; - e->size = 0; - - e = e->next; - } - - debug_log(ASL_LEVEL_NOTICE, "Finished BB.AUX Directory Scan\n"); - - /* Delete/achive expired BB files */ - debug_log(ASL_LEVEL_NOTICE, "Start BB Scan\n"); - - e = bb_list; - while (e != NULL) - { - /* stop when a file name/date is after the expire date */ - if (strncmp(e->name + 3, today_ymd_string, today_ymd_stringlen) > 0) break; - - if (dst->rotate_dir != NULL) - { - str = NULL; - asprintf(&str, "%s/%s", dst->rotate_dir, e->name); - if (str == NULL) return -1; - - /* syslog -x [str] -f [e->name] */ - filesystem_copy(dst, e->name, str, 0); - free(str); - } - - filesystem_unlink(e->name); - store_size -= e->size; - e->size = 0; - - e = e->next; - } - - debug_log(ASL_LEVEL_NOTICE, "Finished BB Scan\n"); - - if (dst->all_max > 0) - { - /* if data store is over max_size, delete/archive more YMD files */ - if (store_size > dst->all_max) debug_log(ASL_LEVEL_NOTICE, "Additional YMD Scan\n"); - - e = ymd_list; - while ((e != NULL) && (store_size > dst->all_max)) - { - if (e->size != 0) - { - if (strncmp(e->name, today_ymd_string, today_ymd_stringlen) == 0) - { - /* do not touch active file YYYY.MM.DD.asl */ - if (strcmp(e->name + today_ymd_stringlen, "asl") == 0) - { - e = e->next; - continue; - } - } - - if (dst->rotate_dir != NULL) - { - str = NULL; - asprintf(&str, "%s/%s", dst->rotate_dir, e->name); - if (str == NULL) return -1; - - /* syslog -x [str] -f [e->name] */ - filesystem_copy(dst, e->name, str, 0); - free(str); - } - - filesystem_unlink(e->name); - store_size -= e->size; - e->size = 0; - } - - e = e->next; - } - - /* if data store is over dst->all_max, delete/archive more BB files */ - if (store_size > dst->all_max) debug_log(ASL_LEVEL_NOTICE, "Additional BB Scan\n"); - - e = bb_list; - while ((e != NULL) && (store_size > dst->all_max)) - { - if (e->size != 0) - { - if (dst->rotate_dir != NULL) - { - str = NULL; - asprintf(&str, "%s/%s", dst->rotate_dir, e->name); - if (str == NULL) return -1; - - /* syslog -x [str] -f [e->name] */ - filesystem_copy(dst, e->name, str, 0); - free(str); - } - - filesystem_unlink(e->name); - store_size -= e->size; - e->size = 0; - } - - e = e->next; - } - } - - free_name_list(ymd_list); - free_name_list(bb_list); - free_name_list(aux_list); - free_name_list(bb_aux_list); - - debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size); - - return 0; -} - -/* move sequenced source files to dst dir, renaming as we go */ -static int -module_copy_rename(asl_out_dst_data_t *dst) -{ - asl_out_file_list_t *src_list, *dst_list, *f, *dst_last; - char *base, *dst_dir; - char fpathsrc[MAXPATHLEN], fpathdst[MAXPATHLEN]; - uint32_t src_count, dst_count; - int32_t x, moved; - - if (dst == NULL) return -1; - if (dst->path == NULL) return -1; - - base = strrchr(dst->path, '/'); - if (base == NULL) return -1; - - src_list = asl_list_src_files(dst); - if (src_list == 0) - { - debug_log(ASL_LEVEL_INFO, " no src files\n"); - return 0; - } - - debug_log(ASL_LEVEL_INFO, " src files\n"); - - src_count = 0; - for (f = src_list; f != NULL; f = f->next) - { - debug_log(ASL_LEVEL_INFO, " %s\n", f->name); - src_count++; - } - - dst_list = asl_list_dst_files(dst); - - *base = '\0'; - base++; - - dst_dir = dst->rotate_dir; - if (dst_dir == NULL) dst_dir = dst->path; - - dst_count = 0; - dst_last = dst_list; - - if (dst_list == NULL) debug_log(ASL_LEVEL_INFO, " no dst files\n"); - else debug_log(ASL_LEVEL_INFO, " dst files\n"); - - for (f = dst_list; f != NULL; f = f->next) - { - debug_log(ASL_LEVEL_INFO, " %s\n", f->name); - dst_last = f; - dst_count++; - } - - if (dst->flags & MODULE_FLAG_STYLE_SEQ) - { - for (f = dst_last; f != NULL; f = f->prev) - { - int is_gz = 0; - char *dot = strrchr(f->name, '.'); - if ((dot != NULL) && (!strcmp(dot, ".gz"))) is_gz = 1; - - snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst_dir, f->name); - snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d%s", dst_dir, base, f->seq+src_count, (is_gz == 1) ? ".gz" : ""); - filesystem_rename(fpathsrc, fpathdst); - } - - for (f = src_list, x = 0; f != NULL; f = f->next, x++) - { - snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->path, f->name); - snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d", dst_dir, base, x); - moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags); - if (moved != 0) - { - if (dst->flags & MODULE_FLAG_TRUNCATE) filesystem_truncate(fpathsrc); - else filesystem_unlink(fpathsrc); - } - } - } - else - { - for (f = src_list; f != NULL; f = f->next) - { - /* final / active base stamped file looks like a checkpointed file - ignore it */ - if ((dst->flags & MODULE_FLAG_BASESTAMP) && (f->next == NULL)) break; - - snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->path, f->name); - - /* MODULE_FLAG_EXTERNAL files are not decorated with a timestamp */ - if (dst->flags & MODULE_FLAG_EXTERNAL) - { - char tstamp[32]; + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ - asl_make_timestamp(f->ftime, dst->flags, tstamp, sizeof(tstamp)); - snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s", dst_dir, base, tstamp); - } - else - { - snprintf(fpathdst, sizeof(fpathdst), "%s/%s", dst_dir, f->name); - } +#include +#include +#include +#include +#include +#include - moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags); - if (moved != 0) - { - if (dst->flags & MODULE_FLAG_TRUNCATE) filesystem_truncate(fpathsrc); - else filesystem_unlink(fpathsrc); - } - } - } +#include "asl_common.h" +#include "daemon.h" +#include "cache_delete.h" - asl_out_file_list_free(src_list); - asl_out_file_list_free(dst_list); +/* global */ +bool dryrun; +uint32_t debug; +FILE *debugfp; +dispatch_queue_t work_queue; - if (base != NULL) *--base = '/'; +static dispatch_queue_t server_queue; +static time_t module_ttl; +static xpc_connection_t listener; +static bool main_task_enqueued; +static bool initial_main_task = true; +static dispatch_source_t sig_term_src; - return 0; -} +/* wait 5 minutes to run main task after being invoked by XPC */ +#define MAIN_TASK_INITIAL_DELAY 300 -/* delete expired files */ -static int -module_expire(asl_out_dst_data_t *dst) +/* + * Used to set config parameters. + * Line format "= name value" + */ +static void +_aslmanager_set_param(asl_out_dst_data_t *dst, char *s) { - asl_out_file_list_t *dst_list, *f; - char *base, *dst_dir, fpath[MAXPATHLEN]; - time_t now, ttl, cutoff; - - if (dst == NULL) return -1; - if (dst->path == NULL) return -1; - if (dst->ttl[LEVEL_ALL] == 0) return 0; - - ttl = 0; - if (module_ttl > 0) ttl = module_ttl; - else ttl = dst->ttl[LEVEL_ALL]; - - ttl *= SECONDS_PER_DAY; - - now = time(NULL); - if (ttl > now) return 0; - - cutoff = now - ttl; + char **l; + uint32_t count; - base = strrchr(dst->path, '/'); - if (base == NULL) return -1; + if (s == NULL) return; + if (s[0] == '\0') return; - dst_list = asl_list_dst_files(dst); + /* skip '=' and whitespace */ + if (*s == '=') s++; + while ((*s == ' ') || (*s == '\t')) s++; - *base = '\0'; + l = explode(s, " \t"); + if (l == NULL) return; - dst_dir = dst->rotate_dir; - if (dst_dir == NULL) dst_dir = dst->path; + for (count = 0; l[count] != NULL; count++); - if (dst_list == NULL) - { - debug_log(ASL_LEVEL_INFO, " no dst files\n"); - } - else + /* name is required */ + if (count == 0) { - debug_log(ASL_LEVEL_INFO, " dst files\n"); - for (f = dst_list; f != NULL; f = f->next) debug_log(ASL_LEVEL_INFO, " %s\n", f->name); + free_string_list(l); + return; } - for (f = dst_list; f != NULL; f = f->next) + /* value is required */ + if (count == 1) { - if (f->ftime <= cutoff) - { - snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name); - filesystem_unlink(fpath); - } + free_string_list(l); + return; } - asl_out_file_list_free(dst_list); - - if (base != NULL) *base = '/'; - - return 0; -} - -/* check all_max size and delete files (oldest first) to stay within size limit */ -static int -module_check_size(asl_out_dst_data_t *dst) -{ - asl_out_file_list_t *dst_list, *f, *dst_end; - char *base, *dst_dir, fpath[MAXPATHLEN]; - size_t total; - - if (dst == NULL) return -1; - if (dst->path == NULL) return -1; - - if (dst->all_max == 0) return 0; - - dst_list = asl_list_dst_files(dst); - if (dst_list == NULL) + if (!strcasecmp(l[0], "aslmanager_debug")) { - debug_log(ASL_LEVEL_INFO, " no dst files\n"); - return 0; + /* = debug level */ + set_debug(DEBUG_ASL, l[1]); } - - base = NULL; - dst_dir = dst->rotate_dir; - if (dst_dir == NULL) + else if (!strcasecmp(l[0], "store_ttl")) { - dst_dir = dst->path; - base = strrchr(dst->path, '/'); - if (base == NULL) - { - asl_out_file_list_free(dst_list); - return -1; - } - - *base = '\0'; + /* = store_ttl days */ + dst->ttl[LEVEL_ALL] = asl_core_str_to_time(l[1], SECONDS_PER_DAY); } - - debug_log(ASL_LEVEL_INFO, " dst files\n"); - dst_end = dst_list; - for (f = dst_list; f != NULL; f = f->next) + else if (!strcasecmp(l[0], "module_ttl")) { - dst_end = f; - debug_log(ASL_LEVEL_INFO, " %s size %lu\n", f->name, f->size); + /* = module_ttl days */ + module_ttl = asl_core_str_to_time(l[1], SECONDS_PER_DAY); } - - total = 0; - for (f = dst_list; f != NULL; f = f->next) total += f->size; - - for (f = dst_end; (total > dst->all_max) && (f != NULL); f = f->prev) + else if (!strcasecmp(l[0], "max_store_size")) { - snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name); - filesystem_unlink(fpath); - total -= f->size; + /* = max_file_size bytes */ + dst->all_max = asl_core_str_to_size(l[1]); } - - asl_out_file_list_free(dst_list); - - if (base != NULL) *base = '/'; - - return 0; -} - - -static int -process_module(asl_out_module_t *mod) -{ - asl_out_rule_t *r; - - if (mod == NULL) return -1; - - debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n"); - debug_log(ASL_LEVEL_NOTICE, "Processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name); - - for (r = mod->ruleset; r != NULL; r = r->next) + else if (!strcasecmp(l[0], "archive")) { - if (r->action == ACTION_OUT_DEST) - { - if (r->dst == NULL) - { - debug_log(ASL_LEVEL_NOTICE, "NULL dst data for output rule - skipped\n"); - } - else if (r->dst->flags & MODULE_FLAG_ROTATE) - { - debug_log(ASL_LEVEL_NOTICE, "Checking file %s\n", r->dst->path); - debug_log(ASL_LEVEL_NOTICE, "- Rename, move to destination directory, and compress as required\n"); - - module_copy_rename(r->dst); - - if (r->dst->ttl[LEVEL_ALL] > 0) - { - debug_log(ASL_LEVEL_NOTICE, "- Check for expired files - TTL = %d days\n", r->dst->ttl[LEVEL_ALL]); - module_expire(r->dst); - } + free(dst->rotate_dir); + dst->rotate_dir = NULL; - if (r->dst->all_max > 0) - { - debug_log(ASL_LEVEL_NOTICE, "- Check total storage used - MAX = %lu\n", r->dst->all_max); - module_check_size(r->dst); - } - } - else if ((r->dst->flags & MODULE_FLAG_TYPE_ASL_DIR) && (r->dst->ttl[LEVEL_ALL] > 0)) - { - process_asl_data_store(r->dst); - } + /* = archive {0|1} path */ + if (!strcmp(l[1], "1")) + { + if (l[2] == NULL) dst->rotate_dir = strdup(PATH_ASL_ARCHIVE); + else dst->rotate_dir = strdup(l[2]); } } - - debug_log(ASL_LEVEL_NOTICE, "Finished processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name); - return 0; -} - -asl_msg_list_t * -control_query(asl_msg_t *a) -{ - asl_msg_list_t *out; - char *qstr, *str, *res; - uint32_t len, reslen, status; - uint64_t cmax, qmin; - kern_return_t kstatus; - caddr_t vmstr; - security_token_t sec; - - if (asl_server_port == MACH_PORT_NULL) - { - bootstrap_look_up2(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port, 0, BOOTSTRAP_PRIVILEGED_SERVER); - if (asl_server_port == MACH_PORT_NULL) return NULL; - } - - qstr = asl_msg_to_string((asl_msg_t *)a, &len); - - str = NULL; - if (qstr == NULL) + else if (!strcasecmp(l[0], "store_path")) { - asprintf(&str, "1\nQ [= ASLOption control]\n"); + /* = archive path */ + free(dst->path); + dst->path = strdup(l[1]); } - else + else if (!strcasecmp(l[0], "archive_mode")) { - asprintf(&str, "1\n%s [= ASLOption control]\n", qstr); - free(qstr); + dst->mode = strtol(l[1], NULL, 0); + if ((dst->mode == 0) && (errno == EINVAL)) dst->mode = 0400; } - if (str == NULL) return NULL; - - /* length includes trailing nul */ - len = strlen(str) + 1; - out = NULL; - qmin = 0; - cmax = 0; - sec.val[0] = -1; - sec.val[1] = -1; - - res = NULL; - reslen = 0; - status = ASL_STATUS_OK; - - kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE); - if (kstatus != KERN_SUCCESS) return NULL; - - memmove(vmstr, str, len); - free(str); - - status = 0; - kstatus = _asl_server_query(asl_server_port, vmstr, len, qmin, 1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status, &sec); - if (kstatus != KERN_SUCCESS) return NULL; - - if (res == NULL) return NULL; - - out = asl_msg_list_from_string(res); - vm_deallocate(mach_task_self(), (vm_address_t)res, reslen); - - return out; -} - -int -checkpoint(const char *name) -{ - /* send checkpoint message to syslogd */ - debug_log(ASL_LEVEL_NOTICE, "Checkpoint module %s\n", (name == NULL) ? "*" : name); - if (dryrun != 0) return 0; - - asl_msg_t *qmsg = asl_msg_new(ASL_TYPE_QUERY); - char *tmp = NULL; - asl_msg_list_t *res; - - asprintf(&tmp, "%s checkpoint", (name == NULL) ? "*" : name); - asl_msg_set_key_val_op(qmsg, "action", tmp, ASL_QUERY_OP_EQUAL); - free(tmp); - - res = control_query(qmsg); - - asl_msg_list_release(res); - return 0; + free_string_list(l); } int @@ -1414,9 +137,14 @@ cli_main(int argc, char *argv[]) int i, work; asl_out_module_t *mod, *m; asl_out_rule_t *r; - asl_out_dst_data_t store, *asl_store_dst = NULL; + asl_out_dst_data_t store, opts, *asl_store_dst = NULL; const char *mname = NULL; + char *path = NULL; + bool quiet = false; + bool cache_delete = false; + bool cache_delete_query = false; +#if !TARGET_OS_SIMULATOR if (geteuid() != 0) { if (argc == 0) debug = DEBUG_ASL; @@ -1425,6 +153,7 @@ cli_main(int argc, char *argv[]) debug_log(ASL_LEVEL_ERR, "aslmanager must be run by root\n"); exit(1); } +#endif module_ttl = DEFAULT_TTL; @@ -1433,9 +162,21 @@ cli_main(int argc, char *argv[]) store.ttl[LEVEL_ALL] = DEFAULT_TTL; store.all_max = DEFAULT_MAX_SIZE; + memset(&opts, 0, sizeof(opts)); + opts.ttl[LEVEL_ALL] = DEFAULT_TTL; + opts.all_max = DEFAULT_MAX_SIZE; + for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "-s")) + if (!strcmp(argv[i], "-q")) + { + quiet = true; + } + else if (!strcmp(argv[i], "-dd")) + { + quiet = true; + } + else if (!strcmp(argv[i], "-s")) { if (((i + 1) < argc) && (argv[i + 1][0] != '-')) { @@ -1445,14 +186,34 @@ cli_main(int argc, char *argv[]) } } + if (!quiet) + { + int status = asl_make_database_dir(NULL, NULL); + if (status == 0) status = asl_make_database_dir(ASL_INTERNAL_LOGS_DIR, &path); + if (status == 0) + { + char tstamp[32], *str = NULL; + + asl_make_timestamp(time(NULL), MODULE_NAME_STYLE_STAMP_LCL_B, tstamp, sizeof(tstamp)); + asprintf(&str, "%s/aslmanager.%s", path, tstamp); + + if (str != NULL) + { + if (status == 0) debugfp = fopen(str, "w"); + if (debugfp != NULL) debug |= DEBUG_FILE; + free(str); + } + } + } + /* get parameters from asl.conf */ mod = asl_out_module_init(); if (mod != NULL) { - for (r = mod->ruleset; r != NULL; r = r->next) + for (r = mod->ruleset; (r != NULL) && (asl_store_dst == NULL); r = r->next) { - if ((asl_store_dst == NULL) && (r->action == ACTION_OUT_DEST) && (!strcmp(r->dst->path, PATH_ASL_STORE))) + if ((r->dst != NULL) && (r->action == ACTION_OUT_DEST) && (!strcmp(r->dst->path, PATH_ASL_STORE))) asl_store_dst = r->dst; } @@ -1471,30 +232,55 @@ cli_main(int argc, char *argv[]) { if (!strcmp(argv[i], "-a")) { + if (asl_store_dst == NULL) asl_store_dst = &store; + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) asl_store_dst->rotate_dir = strdup(argv[++i]); else asl_store_dst->rotate_dir = strdup(PATH_ASL_ARCHIVE); asl_store_dst->mode = 0400; } else if (!strcmp(argv[i], "-store_ttl")) { - if (((i + 1) < argc) && (argv[i + 1][0] != '-')) asl_store_dst->ttl[LEVEL_ALL] = atoi(argv[++i]); + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) + { + if (asl_store_dst == NULL) asl_store_dst = &store; + asl_store_dst->ttl[LEVEL_ALL] = asl_core_str_to_time(argv[++i], SECONDS_PER_DAY); + } } else if (!strcmp(argv[i], "-module_ttl")) { - if (((i + 1) < argc) && (argv[i + 1][0] != '-')) module_ttl = atoi(argv[++i]); + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) module_ttl = asl_core_str_to_time(argv[++i], SECONDS_PER_DAY); } else if (!strcmp(argv[i], "-ttl")) { - if (((i + 1) < argc) && (argv[i + 1][0] != '-')) module_ttl = asl_store_dst->ttl[LEVEL_ALL] = atoi(argv[++i]); + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) + { + opts.ttl[LEVEL_ALL] = asl_core_str_to_time(argv[++i], SECONDS_PER_DAY); + + if (asl_store_dst == NULL) asl_store_dst = &store; + asl_store_dst->ttl[LEVEL_ALL] = opts.ttl[LEVEL_ALL]; + + module_ttl = opts.ttl[LEVEL_ALL]; + } } else if (!strcmp(argv[i], "-size")) { - if (((i + 1) < argc) && (argv[i + 1][0] != '-')) asl_store_dst->all_max = asl_str_to_size(argv[++i]); + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) + { + opts.all_max = asl_core_str_to_size(argv[++i]); + + if (asl_store_dst == NULL) asl_store_dst = &store; + asl_store_dst->all_max = opts.all_max; + } } else if (!strcmp(argv[i], "-checkpoint")) { work |= DO_CHECKPT; } + else if (!strcmp(argv[i], "-cache_delete")) + { + cache_delete = true; + if (((i + 1) < argc) && (argv[i + 1][0] == 'q')) cache_delete_query = true; + } else if (!strcmp(argv[i], "-module")) { work &= ~DO_ASLDB; @@ -1516,18 +302,54 @@ cli_main(int argc, char *argv[]) } else if (!strcmp(argv[i], "-dd")) { - dryrun = 1; + dryrun = true; if (((i + i) < argc) && (argv[i+1][0] != '-')) set_debug(DEBUG_STDERR, argv[++i]); - else set_debug(DEBUG_STDERR, NULL); + else set_debug(DEBUG_STDERR, "l7"); } } if (asl_store_dst->path == NULL) asl_store_dst->path = strdup(PATH_ASL_STORE); - debug_log(ASL_LEVEL_ERR, "aslmanager starting%s\n", (dryrun == 1) ? " dryrun" : ""); + debug_log(ASL_LEVEL_ERR, "aslmanager starting%s\n", dryrun ? " dryrun" : ""); + + if (cache_delete) + { + size_t curr_size = 0; + + if (cache_delete_task(true, &curr_size) != 0) + { + debug_log(ASL_LEVEL_NOTICE, "cache_delete_process failed - can't determine current size\n"); + } + else + { + debug_log(ASL_LEVEL_NOTICE, "cache delete current size = %lu\n", curr_size); + + if (!cache_delete_query) + { + size_t new_size = curr_size - opts.all_max; + + if (cache_delete_task(false, &new_size) != 0) + { + debug_log(ASL_LEVEL_NOTICE, "cache_delete_process failed - delete failed\n"); + } + else + { + debug_log(ASL_LEVEL_NOTICE, "cache delete new size = %lu\n", new_size); + } + } + } + + asl_out_module_free(mod); + + debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n"); + debug_log(ASL_LEVEL_ERR, "aslmanager finished%s\n", dryrun ? " dryrun" : ""); + debug_close(); + + return 0; + } - if (work & DO_ASLDB) process_asl_data_store(asl_store_dst); + if (work & DO_ASLDB) process_asl_data_store(asl_store_dst, &opts); if (work & DO_MODULE) { @@ -1537,9 +359,13 @@ cli_main(int argc, char *argv[]) { for (m = mod; m != NULL; m = m->next) { - if ((mname == NULL) || ((m->name != NULL) && (!strcmp(m->name, mname)))) + if (mname == NULL) { - process_module(m); + process_module(m, NULL); + } + else if ((m->name != NULL) && (!strcmp(m->name, mname))) + { + process_module(m, &opts); } } } @@ -1548,12 +374,43 @@ cli_main(int argc, char *argv[]) asl_out_module_free(mod); debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n"); - debug_log(ASL_LEVEL_ERR, "aslmanager finished%s\n", (dryrun == 1) ? " dryrun" : ""); - if (asl_aux_fd >= 0) asl_close_auxiliary_file(asl_aux_fd); + debug_log(ASL_LEVEL_ERR, "aslmanager finished%s\n", dryrun ? " dryrun" : ""); + debug_close(); return 0; } +/* dispatched on server_queue, dispatches to work_queue */ +void +main_task(void) +{ + /* if main task is already running or queued, do nothing */ + if (main_task_enqueued) return; + + main_task_enqueued = true; + xpc_transaction_begin(); + + if (initial_main_task) + { + initial_main_task = false; + dispatch_time_t delay = dispatch_walltime(NULL, MAIN_TASK_INITIAL_DELAY * NSEC_PER_SEC); + + dispatch_after(delay, work_queue, ^{ + cli_main(0, NULL); + main_task_enqueued = false; + xpc_transaction_end(); + }); + } + else + { + dispatch_async(work_queue, ^{ + cli_main(0, NULL); + main_task_enqueued = false; + xpc_transaction_end(); + }); + } +} + static void accept_connection(xpc_connection_t peer) { @@ -1571,14 +428,16 @@ accept_connection(xpc_connection_t peer) * Some day, we may use the dictionary to pass parameters * to aslmanager, but for now, we ignore the input. */ - if (uid == 0) cli_main(0, NULL); + + if (uid == geteuid()) + { + main_task(); + } } else if (xpc_get_type(request) == XPC_TYPE_ERROR) { /* disconnect */ } - - dispatch_async(serverq, ^__attribute__((noreturn)) { xpc_server_exit(0); }); }); xpc_connection_resume(peer); @@ -1593,16 +452,32 @@ main(int argc, char *argv[]) if (is_managed == 0) return cli_main(argc, argv); + /* Set I/O policy */ + setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE); + /* XPC server */ - serverq = dispatch_queue_create("aslmanager", NULL); - xpc_track_activity(); + server_queue = dispatch_queue_create("aslmanager", NULL); + + work_queue = dispatch_queue_create("work queue", NULL); + + /* Exit on SIGTERM */ + signal(SIGTERM, SIG_IGN); + sig_term_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, (uintptr_t)SIGTERM, 0, dispatch_get_main_queue()); + dispatch_source_set_event_handler(sig_term_src, ^{ + debug_log(ASL_LEVEL_NOTICE, "SIGTERM exit\n"); + exit(0); + }); + + dispatch_resume(sig_term_src); /* Handle incoming messages. */ - listener = xpc_connection_create_mach_service("com.apple.aslmanager", serverq, XPC_CONNECTION_MACH_SERVICE_LISTENER); + listener = xpc_connection_create_mach_service("com.apple.aslmanager", server_queue, XPC_CONNECTION_MACH_SERVICE_LISTENER); xpc_connection_set_event_handler(listener, ^(xpc_object_t peer) { if (xpc_get_type(peer) == XPC_TYPE_CONNECTION) accept_connection(peer); }); xpc_connection_resume(listener); + cache_delete_register(); + dispatch_main(); } diff --git a/aslmanager.tproj/cache_delete.c b/aslmanager.tproj/cache_delete.c new file mode 100644 index 0000000..1184fc2 --- /dev/null +++ b/aslmanager.tproj/cache_delete.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2015 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include "daemon.h" + +/* CacheDelete ID (stored in cache delete plist). Must match suggested CacheDelete id naming conventions. */ +#define CACHE_DELETE_ID "com.apple.activity_tracing.cache-delete" + +#define CFSTR_FROM_DICT(dict, key) ({ \ + void *strRef = NULL; \ + if (dict != NULL) { \ + strRef = (void *)CFDictionaryGetValue(dict, key); \ + if ((strRef == NULL) || (CFStringGetTypeID() != CFGetTypeID(strRef))) strRef = NULL; \ + } \ + (CFStringRef)strRef; \ +}) + +#define INT64_FROM_DICT(dict, key) ({ \ + int64_t value = 0; \ + if (dict != NULL) { \ + void *numRef = (void *)CFDictionaryGetValue(dict, key); \ + if (numRef && (CFNumberGetTypeID() == CFGetTypeID(numRef))) {\ + if (!CFNumberGetValue(numRef, kCFNumberSInt64Type, &value)) value = 0; \ + } \ + } \ + value; \ +}) + +static int64_t +_purgeable(void) +{ + size_t psize = 0; + int status = cache_delete_task(true, &psize); + if (status == 0) return (uint64_t)psize; + return 0; +} + +static int64_t +_purge(int64_t purge_amount_bytes, CacheDeleteUrgency urgency) +{ + size_t curr_size, new_size; + curr_size = 0; + + int status = cache_delete_task(true, &curr_size); + if (status != 0) return 0; + + new_size = curr_size - purge_amount_bytes; + + status = cache_delete_task(false, &new_size); + if (status == 0) return new_size; + + return 0; +} + +static bool +_volume_contains_cached_data(CFStringRef volume) +{ + return true; +} + + +static CFDictionaryRef +_handle_cache_delete_with_urgency(CFDictionaryRef info, CacheDeleteUrgency urgency, bool purge) +{ + xpc_transaction_begin(); + + uint64_t amount_requested = INT64_FROM_DICT(info, CFSTR(CACHE_DELETE_AMOUNT_KEY)); + CFStringRef volume_requested = CFSTR_FROM_DICT(info, CFSTR(CACHE_DELETE_VOLUME_KEY)); + + CFMutableDictionaryRef result = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (result == NULL) + { + goto bail; + } + else if (volume_requested == NULL) + { + goto bail; + } + + /* TODO: CFStringGetCStringPtr can return NULL */ +// debug_log(ASL_LEVEL_DEBUG, "CacheDelete request (purge=%d, urgency=%d, volume=%s, amount=%llu).", (int)urgency, CFStringGetCStringPtr(volume_requested, kCFStringEncodingUTF8), amount_requested); + + int64_t amount_purged = 0; + + if (_volume_contains_cached_data(volume_requested)) + { + if (purge) + { + amount_purged = _purge(amount_requested, urgency); +// debug_log(ASL_LEVEL_WARNING, "Purged %lld bytes.", amount_purged); + } + else + { + amount_purged = _purgeable(); +// debug_log(ASL_LEVEL_WARNING, "%lld bytes of purgeable space.", amount_purged); + } + } + + CFNumberRef amount_purged_obj = CFNumberCreate(NULL, kCFNumberSInt64Type, &amount_purged); + if (amount_purged_obj != NULL) + { + CFDictionaryAddValue(result, CFSTR(CACHE_DELETE_AMOUNT_KEY), amount_purged_obj); + CFRelease(amount_purged_obj); + } + +bail: + + xpc_transaction_end(); + return result; +} + +bool +cache_delete_register(void) +{ + return CacheDeleteRegisterInfoCallbacks(CFSTR(CACHE_DELETE_ID), ^CFDictionaryRef(CacheDeleteUrgency urgency, CFDictionaryRef info) { + /* Purgeable Space Request */ + return _handle_cache_delete_with_urgency(info, urgency, false); + }, ^CFDictionaryRef(CacheDeleteUrgency urgency, CFDictionaryRef info) { + /* Purge Request */ + return _handle_cache_delete_with_urgency(info, urgency, true); + }, NULL, NULL) == 0; +} diff --git a/aslmanager.tproj/cache_delete.h b/aslmanager.tproj/cache_delete.h new file mode 100644 index 0000000..22d3b12 --- /dev/null +++ b/aslmanager.tproj/cache_delete.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2015 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +bool cache_delete_register(void); diff --git a/aslmanager.tproj/com.apple.activity_tracing.CacheDelete.plist b/aslmanager.tproj/com.apple.activity_tracing.CacheDelete.plist new file mode 100644 index 0000000..35633de --- /dev/null +++ b/aslmanager.tproj/com.apple.activity_tracing.CacheDelete.plist @@ -0,0 +1,12 @@ + + + + + CACHE_DELETE_ID + com.apple.activity_tracing.cache-delete + CACHE_DELETE_SERVICES + + PURGE + + + diff --git a/aslmanager.tproj/com.apple.aslmanager.plist b/aslmanager.tproj/com.apple.aslmanager.plist index 05586a1..3e1429c 100644 --- a/aslmanager.tproj/com.apple.aslmanager.plist +++ b/aslmanager.tproj/com.apple.aslmanager.plist @@ -14,9 +14,13 @@ com.apple.aslmanager + com.apple.activity_tracing.cache-delete + EnableTransactions - + + EnablePressuredExit + POSIXSpawnType Interactive diff --git a/aslmanager.tproj/daemon.c b/aslmanager.tproj/daemon.c new file mode 100644 index 0000000..ea05d27 --- /dev/null +++ b/aslmanager.tproj/daemon.c @@ -0,0 +1,1695 @@ +/* + * Copyright (c) 2015 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "daemon.h" + +/* global */ +extern bool dryrun; +extern uint32_t debug; +extern FILE *debugfp; +extern dispatch_queue_t work_queue; + +static mach_port_t asl_server_port; +static aslclient aslc; +static int asl_aux_fd = -1; + +extern kern_return_t _asl_server_query +( + mach_port_t server, + caddr_t request, + mach_msg_type_number_t requestCnt, + uint64_t startid, + int count, + int flags, + caddr_t *reply, + mach_msg_type_number_t *replyCnt, + uint64_t *lastid, + int *status, + security_token_t *token + ); + +const char * +keep_str(uint8_t mask) +{ + static char str[9]; + uint32_t x = 0; + + memset(str, 0, sizeof(str)); + if (mask & 0x01) str[x++] = '0'; + if (mask & 0x02) str[x++] = '1'; + if (mask & 0x04) str[x++] = '2'; + if (mask & 0x08) str[x++] = '3'; + if (mask & 0x10) str[x++] = '4'; + if (mask & 0x20) str[x++] = '5'; + if (mask & 0x40) str[x++] = '6'; + if (mask & 0x80) str[x++] = '7'; + if (x == 0) str[x++] = '-'; + return str; +} + +void +set_debug(int flag, const char *str) +{ + int level, x; + + if (str == NULL) x = ASL_LEVEL_ERR; + else if (((str[0] == 'L') || (str[0] == 'l')) && ((str[1] >= '0') && (str[1] <= '7')) && (str[2] == '\0')) x = atoi(str+1); + else if ((str[0] >= '0') && (str[0] <= '7') && (str[1] == '\0')) x = ASL_LEVEL_CRIT + atoi(str); + else x = ASL_LEVEL_ERR; + + if (x <= 0) x = 0; + else if (x > 7) x = 7; + + level = debug & DEBUG_LEVEL_MASK; + if (x > level) level = x; + + debug = debug & DEBUG_FLAG_MASK; + debug |= flag; + debug |= level; +} + +void +debug_log(int level, char *str, ...) +{ + va_list v; + char ts[32]; + + time_t now = time(NULL); + memset(ts, 0, sizeof(ts)); + strftime(ts, sizeof(ts), "%b %e %T", localtime(&now)); + + if ((debug & DEBUG_STDERR) && (level <= (debug & DEBUG_LEVEL_MASK))) + { + fprintf(stderr, "%s: ", ts); + va_start(v, str); + vfprintf(stderr, str, v); + va_end(v); + } + + if ((debug & DEBUG_FILE) && (debugfp != NULL)) + { + fprintf(debugfp, "%s: ", ts); + va_start(v, str); + vfprintf(debugfp, str, v); + va_end(v); + } + + if (debug & DEBUG_ASL) + { + char *line = NULL; + + if (aslc == NULL) + { + aslc = asl_open("aslmanager", "syslog", 0); + asl_msg_t *msg = asl_msg_new(ASL_TYPE_MSG); + + asl_msg_set_key_val(msg, ASL_KEY_MSG, "Status Report"); + asl_msg_set_key_val(msg, ASL_KEY_LEVEL, ASL_STRING_NOTICE); + asl_create_auxiliary_file((asl_object_t)msg, "Status Report", "public.text", &asl_aux_fd); + asl_msg_release(msg); + } + + va_start(v, str); + vasprintf(&line, str, v); + va_end(v); + + if (line != NULL) + { + write(asl_aux_fd, ts, strlen(ts)); + write(asl_aux_fd, line, strlen(line)); + } + + free(line); + } +} + +void +debug_close() +{ + if (asl_aux_fd >= 0) asl_close_auxiliary_file(asl_aux_fd); + if (debugfp != NULL) fclose(debugfp); +} + +name_list_t * +add_to_name_list(name_list_t *l, const char *name, size_t size, uint32_t flags) +{ + name_list_t *e, *x; + + if (name == NULL) return l; + + e = (name_list_t *)calloc(1, sizeof(name_list_t)); + if (e == NULL) return NULL; + + e->name = strdup(name); + if (e->name == NULL) + { + free(e); + return NULL; + } + + e->size = size; + e->flags = flags; + + /* list is sorted by name (i.e. primarily by timestamp) */ + if (l == NULL) return e; + + if (strcmp(e->name, l->name) <= 0) + { + e->next = l; + return e; + } + + for (x = l; (x->next != NULL) && (strcmp(e->name, x->next->name) > 0) ; x = x->next); + + e->next = x->next; + x->next = e; + return l; +} + +void +free_name_list(name_list_t *l) +{ + name_list_t *e; + + while (l != NULL) + { + e = l; + l = l->next; + free(e->name); + free(e); + } + + free(l); +} + +int +copy_compress_file(asl_out_dst_data_t *asldst, const char *src, const char *dst) +{ + int in, out; + size_t n; + gzFile gz; + char buf[IOBUFSIZE]; + + in = open(src, O_RDONLY, 0); + if (in < 0) return -1; + + out = open(dst, O_WRONLY | O_CREAT, asldst->mode & 0666); + if (out >= 0) out = asl_out_dst_set_access(out, asldst); + if (out < 0) + { + close(in); + return -1; + } + + gz = gzdopen(out, "w"); + if (gz == NULL) + { + close(in); + close(out); + return -1; + } + + do { + n = read(in, buf, sizeof(buf)); + if (n > 0) gzwrite(gz, buf, n); + } while (n == IOBUFSIZE); + + gzclose(gz); + close(in); + close(out); + + return 0; +} + +void +filesystem_rename(const char *src, const char *dst) +{ + int status = 0; + + debug_log(ASL_LEVEL_NOTICE, " rename %s ---> %s\n", src, dst); + if (dryrun) return; + + status = rename(src, dst); + if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] rename %s ---> %s\n", status, errno, strerror(errno), src, dst); +} + +void +filesystem_unlink(const char *path) +{ + int status = 0; + + debug_log(ASL_LEVEL_NOTICE, " remove %s\n", path); + if (dryrun) return; + + status = unlink(path); + if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] unlink %s\n", status, errno, strerror(errno), path); +} + +void +filesystem_truncate(const char *path) +{ + int status = 0; + + debug_log(ASL_LEVEL_NOTICE, " truncate %s\n", path); + if (dryrun) return; + + status = truncate(path, 0); + if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] unlink %s\n", status, errno, strerror(errno), path); +} + +void +filesystem_rmdir(const char *path) +{ + int status = 0; + + debug_log(ASL_LEVEL_NOTICE, " remove directory %s\n", path); + if (dryrun) return; + + status = rmdir(path); + if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] rmdir %s\n", status, errno, strerror(errno), path); +} + +/* + * Copy ASL files by reading and writing each record. + */ +static uint32_t +copy_asl_file(const char *src, const char *dst, mode_t mode) +{ + asl_file_t *fin, *fout; + uint32_t status; + + if (src == NULL) return ASL_STATUS_INVALID_ARG; + if (dst == NULL) return ASL_STATUS_INVALID_ARG; + + fin = NULL; + status = asl_file_open_read(src, &fin); + if (status != ASL_STATUS_OK) return status; + + fout = NULL; + status = asl_file_open_write(dst, mode, -1, -1, &fout); + if (status != ASL_STATUS_OK) + { + asl_file_close(fin); + return status; + } + + if (fout == NULL) + { + asl_file_close(fin); + return ASL_STATUS_FAILED; + } + + fout->flags = ASL_FILE_FLAG_PRESERVE_MSG_ID; + + status = asl_file_read_set_position(fin, ASL_FILE_POSITION_FIRST); + if (status != ASL_STATUS_OK) + { + asl_file_close(fin); + asl_file_close(fout); + return ASL_STATUS_READ_FAILED; + } + + while (status == ASL_STATUS_OK) + { + uint64_t mid = 0; + asl_msg_t *msg = NULL; + + status = asl_file_fetch_next(fin, &msg); + if (msg == NULL) + { + status = ASL_STATUS_OK; + break; + } + + if (status != ASL_STATUS_OK) break; + + status = asl_file_save(fout, msg, &mid); + asl_msg_release(msg); + } + + asl_file_close(fin); + asl_file_close(fout); + + return status; +} + +int32_t +filesystem_copy(asl_out_dst_data_t *asldst, const char *src, const char *dst, uint32_t flags) +{ + char *dot; + + if ((src == NULL) || (dst == NULL)) return 0; + + dot = strrchr(src, '.'); + if ((dot != NULL) && (!strcmp(dot, ".gz"))) flags &= ~MODULE_FLAG_COMPRESS; + + if (((flags & MODULE_FLAG_COMPRESS) == 0) && (!strcmp(src, dst))) return 0; + + if (flags & MODULE_FLAG_TYPE_ASL) debug_log(ASL_LEVEL_NOTICE, " copy asl %s ---> %s\n", src, dst); + else if (flags & MODULE_FLAG_COMPRESS) debug_log(ASL_LEVEL_NOTICE, " copy compress %s ---> %s.gz\n", src, dst); + else debug_log(ASL_LEVEL_NOTICE, " copy %s ---> %s\n", src, dst); + + if (dryrun) return 0; + + if (flags & MODULE_FLAG_TYPE_ASL) + { + uint32_t status = copy_asl_file(src, dst, asldst->mode); + if (status != 0) + { + debug_log(ASL_LEVEL_ERR, " FAILED status %u [%s] asl copy %s ---> %s\n", status, asl_core_error(status), src, dst); + return 0; + } + } + else if (flags & MODULE_FLAG_COMPRESS) + { + char gzdst[MAXPATHLEN]; + + snprintf(gzdst, sizeof(gzdst), "%s.gz", dst); + + int status = copy_compress_file(asldst, src, gzdst); + if (status != 0) + { + debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] copy & compress %s ---> %s\n", status, errno, strerror(errno), src, dst); + return 0; + } + } + else + { + int status = copyfile(src, dst, NULL, COPYFILE_ALL | COPYFILE_RECURSIVE); + if (status != 0) + { + debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] copy %s ---> %s\n", status, errno, strerror(errno), src, dst); + return 0; + } + } + + return 1; +} + +int32_t +filesystem_reset_ctime(const char *path) +{ + struct attrlist attr_list; + struct timespec now; + + debug_log(ASL_LEVEL_NOTICE, " reset ctime %s\n", path); + + memset(&attr_list, 0, sizeof(attr_list)); + attr_list.bitmapcount = ATTR_BIT_MAP_COUNT; + attr_list.commonattr = ATTR_CMN_CRTIME; + + memset(&now, 0, sizeof(now)); + now.tv_sec = time(NULL); + + return setattrlist(path, &attr_list, &now, sizeof(now), 0); +} + +int +remove_directory(const char *path) +{ + DIR *dp; + struct dirent *dent; + char *str; + + dp = opendir(path); + if (dp == NULL) return 0; + + while ((dent = readdir(dp)) != NULL) + { + if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue; + asprintf(&str, "%s/%s", path, dent->d_name); + if (str != NULL) + { + filesystem_unlink(str); + free(str); + str = NULL; + } + } + + closedir(dp); + filesystem_rmdir(path); + + return 0; +} + +size_t +directory_size(const char *path) +{ + DIR *dp; + struct dirent *dent; + struct stat sb; + size_t size; + char *str; + + dp = opendir(path); + if (dp == NULL) return 0; + + size = 0; + while ((dent = readdir(dp)) != NULL) + { + if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue; + + memset(&sb, 0, sizeof(struct stat)); + str = NULL; + asprintf(&str, "%s/%s", path, dent->d_name); + + if ((str != NULL) && (stat(str, &sb) == 0) && S_ISREG(sb.st_mode)) + { + size += sb.st_size; + free(str); + } + } + + closedir(dp); + return size; +} + +time_t +parse_ymd_name(const char *name) +{ + struct tm ftime; + time_t created; + int32_t tzh, tzm, sign = -1; + const char *x; + bool legacy = false; + + if (name == NULL) return -1; + + x = name; + + if ((*x == 'T') || (*x == 't')) + { + x++; + created = atol(x); + if ((created == 0) && (*x != '0')) return -1; + + x = strchr(x, '.'); + if (x == NULL) return -1; + + return created; + } + + memset(&ftime, 0, sizeof(ftime)); + + if ((*x < '0') || (*x > '9')) return 1; + ftime.tm_year = 1000 * (*x++ - '0'); + + if ((*x < '0') || (*x > '9')) return 1; + ftime.tm_year += 100 * (*x++ - '0'); + + if ((*x < '0') || (*x > '9')) return 1; + ftime.tm_year += 10 * (*x++ - '0'); + + if ((*x < '0') || (*x > '9')) return 1; + ftime.tm_year += *x++ - '0'; + ftime.tm_year -= 1900; + + if (*x == '-') x++; + else if (*x == '.') + { + x++; + legacy = true; + } + + if ((*x < '0') || (*x > '9')) return 1; + ftime.tm_mon = 10 * (*x++ - '0'); + + if ((*x < '0') || (*x > '9')) return 1; + ftime.tm_mon += *x++ - '0'; + ftime.tm_mon -= 1; + + if ((*x == '-') || (*x == '.')) x++; + + if ((*x < '0') || (*x > '9')) return 1; + ftime.tm_mday = 10 * (*x++ - '0'); + + if ((*x < '0') || (*x > '9')) return 1; + ftime.tm_mday += *x++ - '0'; + + if (legacy) + { + if ((*x != '.') && (*x != '\0')) return -1; + + /* assume the file was created at midnight */ + ftime.tm_hour = 24; + ftime.tm_min = 0; + ftime.tm_sec = 0; + ftime.tm_isdst = -1; + + created = mktime(&ftime); + return created; + } + + if ((*x != 'T') && (*x != 't')) return 1; + x++; + + if ((*x < '0') || (*x > '9')) return 1; + ftime.tm_hour = 10 * (*x++ - '0'); + + if ((*x < '0') || (*x > '9')) return 1; + ftime.tm_hour += *x++ - '0'; + + if (*x == ':') x++; + + if ((*x < '0') || (*x > '9')) return 1; + ftime.tm_min = 10 * (*x++ - '0'); + + if ((*x < '0') || (*x > '9')) return 1; + ftime.tm_min += *x++ - '0'; + + if (*x == ':') x++; + + if ((*x < '0') || (*x > '9')) return 1; + ftime.tm_sec = 10 * (*x++ - '0'); + + if ((*x < '0') || (*x > '9')) return 1; + ftime.tm_sec += *x++ - '0'; + + if ((*x == 'Z') || (*x == 'z')) + { + created = timegm(&ftime); + return created; + } + + if ((*x != '+') && (*x != '-')) return 1; + + if (*x == '-') sign = 1; + x++; + + if ((*x < '0') || (*x > '9')) return 1; + tzh = 10 * (*x++ - '0'); + + if ((*x < '0') || (*x > '9')) tzh /= 10; + else tzh += *x++ - '0'; + + if (tzh > 23) return 1; + + tzm = 0; + if ((*x == ':') || ((*x >= '0') && (*x <= '9'))) + { + if (*x != ':') tzm = 10 * (*x - '0'); + x++; + + if ((*x < '0') || (*x > '9'))return -1; + tzm += *x++ - '0'; + + if (tzm > 59) return -1; + } + + ftime.tm_sec += (sign * (tzh * SECONDS_PER_HOUR) + (tzm * SECONDS_PER_MINUTE)); + + if ((*x != '.') && (*x != '\0')) return -1; + + created = timegm(&ftime); + return created; +} + + +/* + * Determine the age (in seconds) of a YMD file from its name. + * Also determines UID and GID from ".Unnn.Gnnn" part of file name. + */ +uint32_t +ymd_file_age(const char *name, time_t now, uid_t *u, gid_t *g) +{ + struct tm ftime; + time_t created; + uint32_t seconds; + const char *p; + + if (name == NULL) return 0; + + if (now == 0) now = time(NULL); + + memset(&ftime, 0, sizeof(struct tm)); + + created = parse_ymd_name(name); + if (created < 0) return 0; + if (created > now) return 0; + seconds = now - created; + + if (u != NULL) + { + *u = -1; + p = strchr(name, 'U'); + if (p != NULL) *u = atoi(p+1); + } + + if (g != NULL) + { + *g = -1; + p = strchr(name, 'G'); + if (p != NULL) *g = atoi(p+1); + } + + return seconds; +} + + +static void +aux_url_callback(const char *url) +{ + if (url == NULL) return; + if (!strncmp(url, AUX_URL_MINE, AUX_URL_MINE_LEN)) filesystem_unlink(url + AUX_URL_PATH_OFFSET); +} + +uint32_t +ymd_file_filter(const char *name, const char *path, uint32_t keep_mask, mode_t ymd_mode, uid_t ymd_uid, gid_t ymd_gid) +{ + asl_file_t *f = NULL; + uint8_t km = keep_mask; + uint32_t status, len, dstcount = 0; + char src[MAXPATHLEN]; + char dst[MAXPATHLEN]; + + if (snprintf(src, MAXPATHLEN, "%s/%s", path, name) >= MAXPATHLEN) return ASL_STATUS_FAILED; + if (snprintf(dst, MAXPATHLEN, "%s/%s", path, name) >= MAXPATHLEN) return ASL_STATUS_FAILED; + len = strlen(src) - 3; + snprintf(dst + len, 4, "tmp"); + + //TODO: check if src file is already filtered + debug_log(ASL_LEVEL_NOTICE, " filter %s %s ---> %s\n", src, keep_str(km), dst); + + status = ASL_STATUS_OK; + + if (!dryrun) + { + status = asl_file_open_read(name, &f); + if (status != ASL_STATUS_OK) return status; + + status = asl_file_filter_level(f, dst, keep_mask, ymd_mode, ymd_uid, ymd_gid, &dstcount, aux_url_callback); + asl_file_close(f); + } + + filesystem_unlink(src); + if ((status != ASL_STATUS_OK) || (dstcount == 0)) filesystem_unlink(dst); + else filesystem_rename(dst, src); + + return status; +} + +int +process_asl_data_store(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts) +{ + time_t now, midnight, since_midnight; + char *str; + DIR *dp; + struct dirent *dent; + name_list_t *ymd_list, *bb_list, *aux_list, *bb_aux_list, *e; + size_t file_size, store_size; + struct stat sb; + char tstr[128]; + struct tm t_tmp; + uint32_t ttl = 0; + + ymd_list = NULL; + bb_list = NULL; + aux_list = NULL; + bb_aux_list = NULL; + store_size = 0; + + if (dst == NULL) return 0; + if (dst->path == NULL) return 0; + + ttl = dst->ttl[LEVEL_ALL]; + if ((opts != NULL) && (opts->ttl[LEVEL_ALL] > 0)) ttl = opts->ttl[LEVEL_ALL]; + + size_t all_max = dst->all_max; + if ((opts != NULL) && (opts->all_max > 0)) all_max = opts->all_max; + + debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n"); + debug_log(ASL_LEVEL_NOTICE, "Processing data store %s\n", dst->path); + + if (dst->rotate_dir != NULL) + { + /* check archive */ + memset(&sb, 0, sizeof(struct stat)); + if (stat(dst->rotate_dir, &sb) == 0) + { + /* must be a directory */ + if (!S_ISDIR(sb.st_mode)) + { + debug_log(ASL_LEVEL_ERR, "aslmanager error: archive %s is not a directory", dst->rotate_dir); + return -1; + } + } + else + { + if (errno == ENOENT) + { + /* archive doesn't exist - create it */ + if (mkdir(dst->rotate_dir, 0755) != 0) + { + debug_log(ASL_LEVEL_ERR, "aslmanager error: can't create archive %s: %s\n", dst->rotate_dir, strerror(errno)); + return -1; + } + } + else + { + /* stat failed for some other reason */ + debug_log(ASL_LEVEL_ERR, "aslmanager error: can't stat archive %s: %s\n", dst->rotate_dir, strerror(errno)); + return -1; + } + } + } + + chdir(dst->path); + + /* determine current time */ + now = time(NULL); + + localtime_r(&now, &t_tmp); + + t_tmp.tm_sec = 0; + t_tmp.tm_min = 0; + t_tmp.tm_hour = 0; + + midnight = mktime(&t_tmp); + since_midnight = now - midnight; + + dp = opendir(dst->path); + if (dp == NULL) return -1; + + /* gather a list of YMD files, AUX dirs, BB.AUX dirs, and BB files */ + while ((dent = readdir(dp)) != NULL) + { + uint32_t file_flags = 0; + char *dot = NULL; + + memset(&sb, 0, sizeof(struct stat)); + file_size = 0; + if (stat(dent->d_name, &sb) == 0) file_size = sb.st_size; + + dot = strrchr(dent->d_name, '.'); + if ((dot != NULL) && !strcmp(dot, ".gz")) file_flags |= NAME_LIST_FLAG_COMPRESSED; + + if ((dent->d_name[0] >= '0') && (dent->d_name[0] <= '9')) + { + ymd_list = add_to_name_list(ymd_list, dent->d_name, file_size, file_flags); + store_size += file_size; + } + else if (((dent->d_name[0] == 'T') || (dent->d_name[0] == 't')) && (dent->d_name[1] >= '0') && (dent->d_name[1] <= '9')) + { + ymd_list = add_to_name_list(ymd_list, dent->d_name, file_size, file_flags); + store_size += file_size; + } + else if (!strncmp(dent->d_name, "AUX.", 4) && (dent->d_name[4] >= '0') && (dent->d_name[4] <= '9') && S_ISDIR(sb.st_mode)) + { + file_size = directory_size(dent->d_name); + aux_list = add_to_name_list(aux_list, dent->d_name, file_size, file_flags); + store_size += file_size; + } + else if (!strncmp(dent->d_name, "BB.AUX.", 7) && (dent->d_name[7] >= '0') && (dent->d_name[7] <= '9') && S_ISDIR(sb.st_mode)) + { + file_size = directory_size(dent->d_name); + bb_aux_list = add_to_name_list(bb_aux_list, dent->d_name, file_size, file_flags); + store_size += file_size; + } + else if (!strncmp(dent->d_name, "BB.", 3) && (dent->d_name[3] >= '0') && (dent->d_name[3] <= '9')) + { + bb_list = add_to_name_list(bb_list, dent->d_name, file_size, file_flags); + store_size += file_size; + } + else if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) + {} + else if ((!strcmp(dent->d_name, "StoreData")) || (!strcmp(dent->d_name, "SweepStore"))) + {} + else if (!strcmp(dent->d_name, ASL_INTERNAL_LOGS_DIR)) + {} + else + { + debug_log(ASL_LEVEL_ERR, "aslmanager: unexpected file %s in ASL data store\n", dent->d_name); + } + } + + closedir(dp); + + debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size); + asl_core_time_to_str(ttl, tstr, sizeof(tstr)); + debug_log(ASL_LEVEL_NOTICE, "Data Store YMD Files (TTL = %s)\n", tstr); + for (e = ymd_list; e != NULL; e = e->next) + { + uint32_t age = ymd_file_age(e->name, now, NULL, NULL); + asl_core_time_to_str(age, tstr, sizeof(tstr)); + debug_log(ASL_LEVEL_NOTICE, " %s %lu (age %s%s)\n", e->name, e->size, tstr, (age > ttl) ? " - expired" : ""); + } + + debug_log(ASL_LEVEL_NOTICE, "Data Store AUX Directories\n"); + for (e = aux_list; e != NULL; e = e->next) + { + uint32_t age = ymd_file_age(e->name + 4, now, NULL, NULL) / SECONDS_PER_DAY; + asl_core_time_to_str(age, tstr, sizeof(tstr)); + debug_log(ASL_LEVEL_NOTICE, " %s %lu (age %s)\n", e->name, e->size, tstr, (age > ttl) ? " - expired" : ""); + } + + debug_log(ASL_LEVEL_NOTICE, "Data Store BB.AUX Directories\n"); + for (e = bb_aux_list; e != NULL; e = e->next) + { + uint32_t age = ymd_file_age(e->name + 7, now, NULL, NULL); + asl_core_time_to_str(age, tstr, sizeof(tstr)); + debug_log(ASL_LEVEL_NOTICE, " %s %lu (age %s)\n", e->name, e->size, tstr, ((age / SECONDS_PER_DAY) > 0) ? " - expired" : ""); + } + + debug_log(ASL_LEVEL_NOTICE, "Data Store BB Files\n"); + for (e = bb_list; e != NULL; e = e->next) + { + uint32_t age = ymd_file_age(e->name + 3, now, NULL, NULL) / SECONDS_PER_DAY; + asl_core_time_to_str(age, tstr, sizeof(tstr)); + debug_log(ASL_LEVEL_NOTICE, " %s %lu (age %s)\n", e->name, e->size, tstr, ((age / SECONDS_PER_DAY) > 0) ? " - expired" : ""); + } + + /* Delete/achive expired YMD files */ + debug_log(ASL_LEVEL_NOTICE, "Start YMD File Scan\n"); + + e = ymd_list; + while (e != NULL) + { + uid_t ymd_uid = -1; + gid_t ymd_gid = -1; + uint32_t age = ymd_file_age(e->name, now, &ymd_uid, &ymd_gid); + + if (age > ttl) + { + /* file has expired, archive it if required, then unlink it */ + if (dst->rotate_dir != NULL) + { + str = NULL; + asprintf(&str, "%s/%s", dst->rotate_dir, e->name); + if (str == NULL) return -1; + + filesystem_copy(dst, e->name, str, 0); + free(str); + } + + filesystem_unlink(e->name); + store_size -= e->size; + e->size = 0; + } + else if ((e->flags & NAME_LIST_FLAG_COMPRESSED) == 0) + { + uint32_t i, bit, keep_mask; + mode_t ymd_mode = 0600; + + /* check if there are any per-level TTLs and filter the file if required */ + if (age > 0) + { + keep_mask = 0x000000ff; + bit = 1; + for (i = 0; i <= 7; i++) + { + if ((dst->ttl[i] > 0) && (age >= dst->ttl[i])) keep_mask &= ~bit; + bit *= 2; + } + + memset(&sb, 0, sizeof(struct stat)); + if (stat(e->name, &sb) == 0) ymd_mode = sb.st_mode & 0777; + + if (keep_mask != 0x000000ff) ymd_file_filter(e->name, dst->path, keep_mask, ymd_mode, ymd_uid, ymd_gid); + } + + if ((age > since_midnight) && (dst->flags & MODULE_FLAG_COMPRESS)) + { + char gzdst[MAXPATHLEN]; + + snprintf(gzdst, sizeof(gzdst), "%s.gz", e->name); + debug_log(ASL_LEVEL_NOTICE, " compress %s ---> %s\n", e->name, gzdst); + + if (!dryrun) + { + int status = copy_compress_file(dst, e->name, gzdst); + if (status == 0) + { + filesystem_unlink(e->name); + } + else + { + debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] compress %s ---> %s\n", status, errno, strerror(errno), e->name, gzdst); + return 0; + } + } + } + } + + e = e->next; + } + + debug_log(ASL_LEVEL_NOTICE, "Finished YMD File Scan\n"); + + /* Delete/achive expired YMD AUX directories */ + debug_log(ASL_LEVEL_NOTICE, "Start AUX Directory Scan\n"); + + e = aux_list; + while (e != NULL) + { + uint32_t age = ymd_file_age(e->name + 4, now, NULL, NULL); + + if (age > ttl) + { + if (dst->rotate_dir != NULL) + { + str = NULL; + asprintf(&str, "%s/%s", dst->rotate_dir, e->name); + if (str == NULL) return -1; + + filesystem_copy(dst, e->name, str, 0); + free(str); + } + + remove_directory(e->name); + store_size -= e->size; + e->size = 0; + } + + e = e->next; + } + + debug_log(ASL_LEVEL_NOTICE, "Finished AUX Directory Scan\n"); + + /* Delete/achive expired BB.AUX directories */ + debug_log(ASL_LEVEL_NOTICE, "Start BB.AUX Directory Scan\n"); + + e = bb_aux_list; + while (e != NULL) + { + uint32_t age = ymd_file_age(e->name + 7, now, NULL, NULL); + + if (age > 0) + { + if (dst->rotate_dir != NULL) + { + str = NULL; + asprintf(&str, "%s/%s", dst->rotate_dir, e->name); + if (str == NULL) return -1; + + filesystem_copy(dst, e->name, str, 0); + free(str); + } + + remove_directory(e->name); + store_size -= e->size; + e->size = 0; + } + + e = e->next; + } + + debug_log(ASL_LEVEL_NOTICE, "Finished BB.AUX Directory Scan\n"); + + /* Delete/achive expired BB files */ + debug_log(ASL_LEVEL_NOTICE, "Start BB Scan\n"); + + e = bb_list; + while (e != NULL) + { + uint32_t age = ymd_file_age(e->name + 3, now, NULL, NULL); + + if (age > 0) + { + if (dst->rotate_dir != NULL) + { + str = NULL; + asprintf(&str, "%s/%s", dst->rotate_dir, e->name); + if (str == NULL) return -1; + + /* syslog -x [str] -f [e->name] */ + filesystem_copy(dst, e->name, str, 0); + free(str); + } + + filesystem_unlink(e->name); + store_size -= e->size; + e->size = 0; + } + + e = e->next; + } + + debug_log(ASL_LEVEL_NOTICE, "Finished BB Scan\n"); + + if (all_max > 0) + { + /* if data store is over max_size, delete/archive more YMD files */ + if (store_size > all_max) debug_log(ASL_LEVEL_NOTICE, "Additional YMD Scan\n"); + + e = ymd_list; + while ((e != NULL) && (store_size > all_max)) + { + if (e->size != 0) + { + uint32_t age = ymd_file_age(e->name, now, NULL, NULL); + if (age == 0) + { + /* do not touch active file YYYY.MM.DD.asl */ + e = e->next; + continue; + } + + if (dst->rotate_dir != NULL) + { + str = NULL; + asprintf(&str, "%s/%s", dst->rotate_dir, e->name); + if (str == NULL) return -1; + + /* syslog -x [str] -f [e->name] */ + filesystem_copy(dst, e->name, str, 0); + free(str); + } + + filesystem_unlink(e->name); + store_size -= e->size; + e->size = 0; + } + + e = e->next; + } + + /* if data store is over all_max, delete/archive more BB files */ + if (store_size > all_max) debug_log(ASL_LEVEL_NOTICE, "Additional BB Scan\n"); + + e = bb_list; + while ((e != NULL) && (store_size > all_max)) + { + if (e->size != 0) + { + if (dst->rotate_dir != NULL) + { + str = NULL; + asprintf(&str, "%s/%s", dst->rotate_dir, e->name); + if (str == NULL) return -1; + + /* syslog -x [str] -f [e->name] */ + filesystem_copy(dst, e->name, str, 0); + free(str); + } + + filesystem_unlink(e->name); + store_size -= e->size; + e->size = 0; + } + + e = e->next; + } + } + + free_name_list(ymd_list); + free_name_list(bb_list); + free_name_list(aux_list); + free_name_list(bb_aux_list); + + debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size); + + return 0; +} + +static asl_out_file_list_t * +_remove_youngest_activity_tracing_file(asl_out_file_list_t *l) +{ + asl_out_file_list_t *f; + + /* ignore youngest activity tracing file - it is the active file */ + if (l->next == NULL) + { + debug_log(ASL_LEVEL_INFO, " ignore youngest (only) activity tracing file %s\n", l->name); + asl_out_file_list_free(l); + return NULL; + } + + for (f = l; f->next->next != NULL; f = f->next); + debug_log(ASL_LEVEL_INFO, " ignore youngest activity tracing file %s\n", f->next->name); + asl_out_file_list_free(f->next); + f->next = NULL; + return l; +} + +/* move sequenced source files to dst dir, renaming as we go */ +int +module_copy_rename(asl_out_dst_data_t *dst) +{ + asl_out_file_list_t *src_list, *dst_list, *f; + char *dst_dir; + char fpathsrc[MAXPATHLEN], fpathdst[MAXPATHLEN]; + uint32_t src_count, dst_count; + int32_t x, moved; + + if (dst == NULL) return -1; + if (dst->path == NULL) return -1; + + src_list = asl_list_src_files(dst); + + /* + * Note: the unmarked file (e.g. system.log) is included in src_list. + * If it is from a MODULE_FLAG_EXTERNAL dst and it is less than 24 hours old, + * we ignore it. If it is not external, we also ignore it since syslogd will + * checkpoint it to create system.log.Tnnnnnnnnnn. + */ + if ((src_list != NULL) && (src_list->stamp == STAMP_STYLE_NULL)) + { + bool ignore_it = false; + + if (dst->flags & MODULE_FLAG_EXTERNAL) + { + if ((time(NULL) - src_list->ftime) < SECONDS_PER_DAY) + { + debug_log(ASL_LEVEL_INFO, " ignore src file %s since it is external and less than a day old\n", src_list->name); + ignore_it = true; + } + } + else + { + debug_log(ASL_LEVEL_INFO, " ignore src file %s since it is internal and syslogd will checkpoint it when it needs to be renamed\n", src_list->name); + ignore_it = true; + } + + if (ignore_it) + { + asl_out_file_list_t *first = src_list; + src_list = src_list->next; + first->next = NULL; + asl_out_file_list_free(first); + } + } + + if (src_list == NULL) + { + debug_log(ASL_LEVEL_INFO, " no src files\n"); + return 0; + } + + debug_log(ASL_LEVEL_INFO, " src files\n"); + + src_count = 0; + for (f = src_list; f != NULL; f = f->next) + { + debug_log(ASL_LEVEL_INFO, " %s\n", f->name); + src_count++; + } + + dst_list = asl_list_dst_files(dst); + + if ((dst_list != NULL) && (dst->flags & MODULE_FLAG_ACTIVITY)) + { + dst_list = _remove_youngest_activity_tracing_file(dst_list); + } + + dst_dir = dst->rotate_dir; + if (dst_dir == NULL) dst_dir = dst->dir; + + dst_count = 0; + + if (dst_list == NULL) debug_log(ASL_LEVEL_INFO, " no dst files\n"); + else debug_log(ASL_LEVEL_INFO, " dst files\n"); + + for (f = dst_list; f != NULL; f = f->next) + { + debug_log(ASL_LEVEL_INFO, " %s\n", f->name); + dst_count++; + } + + if (dst->style_flags & MODULE_NAME_STYLE_STAMP_SEQ) + { + for (f = dst_list; f != NULL; f = f->next) + { + int is_gz = 0; + char *dot = strrchr(f->name, '.'); + if ((dot != NULL) && (!strcmp(dot, ".gz"))) is_gz = 1; + + snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst_dir, f->name); + + if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BS) + { + snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d%s", dst_dir, dst->base, f->seq+src_count, (is_gz == 1) ? ".gz" : ""); + } + else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BES) + { + snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s.%d%s", dst_dir, dst->base, dst->ext, f->seq+src_count, (is_gz == 1) ? ".gz" : ""); + } + else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BSE) + { + snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d.%s%s", dst_dir, dst->base, f->seq+src_count, dst->ext, (is_gz == 1) ? ".gz" : ""); + } + + filesystem_rename(fpathsrc, fpathdst); + } + + for (f = src_list, x = 0; f != NULL; f = f->next, x++) + { + snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->dir, f->name); + + if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BS) + { + snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d", dst_dir, dst->base, x); + } + else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BES) + { + snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s.%d", dst_dir, dst->base, dst->ext, x); + } + else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BSE) + { + snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d.%s", dst_dir, dst->base, x, dst->ext); + } + + moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags); + if (moved != 0) + { + if (dst->flags & MODULE_FLAG_TRUNCATE) + { + filesystem_truncate(fpathsrc); + filesystem_reset_ctime(fpathsrc); + } + else + { + filesystem_unlink(fpathsrc); + } + } + } + } + else + { + for (f = src_list; f != NULL; f = f->next) + { + /* final / active base stamped file looks like a checkpointed file - ignore it */ + if ((dst->flags & MODULE_FLAG_BASESTAMP) && (f->next == NULL)) break; + + snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->dir, f->name); + + /* MODULE_FLAG_EXTERNAL files are not decorated with a timestamp */ + if (dst->flags & MODULE_FLAG_EXTERNAL) + { + char tstamp[32]; + + asl_make_timestamp(f->ftime, dst->style_flags, tstamp, sizeof(tstamp)); + + if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BS) + { + snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s", dst_dir, dst->base, tstamp); + } + else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BES) + { + snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s.%s", dst_dir, dst->base, dst->ext, tstamp); + } + else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BSE) + { + snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s.%s", dst_dir, dst->base, tstamp, dst->ext); + } + + } + else + { + snprintf(fpathdst, sizeof(fpathdst), "%s/%s", dst_dir, f->name); + } + + moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags); + if (moved != 0) + { + if (dst->flags & MODULE_FLAG_TRUNCATE) filesystem_truncate(fpathsrc); + else filesystem_unlink(fpathsrc); + } + } + } + + asl_out_file_list_free(src_list); + asl_out_file_list_free(dst_list); + + return 0; +} + +/* delete expired files */ +int +module_expire(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts) +{ + asl_out_file_list_t *dst_list, *f; + char *base, *dst_dir, fpath[MAXPATHLEN]; + time_t now, ttl, age; + + if (dst == NULL) return -1; + if (dst->path == NULL) return -1; + if (dst->ttl[LEVEL_ALL] == 0) return 0; + + ttl = dst->ttl[LEVEL_ALL]; + if ((opts != NULL) && (opts->ttl[LEVEL_ALL] > 0)) ttl = opts->ttl[LEVEL_ALL]; + + now = time(NULL); + if (ttl > now) return 0; + + base = strrchr(dst->path, '/'); + if (base == NULL) return -1; + + dst_list = asl_list_dst_files(dst); + + if ((dst_list != NULL) && (dst->flags & MODULE_FLAG_ACTIVITY)) + { + dst_list = _remove_youngest_activity_tracing_file(dst_list); + } + + *base = '\0'; + + dst_dir = dst->rotate_dir; + if (dst_dir == NULL) dst_dir = dst->dir; + + if (dst_list == NULL) + { + debug_log(ASL_LEVEL_INFO, " no dst files\n"); + } + else + { + debug_log(ASL_LEVEL_INFO, " dst files\n"); + for (f = dst_list; f != NULL; f = f->next) + { + char tstr[150]; + age = now - f->ftime; + + asl_core_time_to_str(age, tstr, sizeof(tstr)); + debug_log(ASL_LEVEL_INFO, " %s (age %s%s)\n", f->name, tstr, (age > ttl) ? " - expired" : ""); + } + } + + for (f = dst_list; f != NULL; f = f->next) + { + age = now - f->ftime; + if (age > ttl) + { + snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name); + filesystem_unlink(fpath); + } + } + + asl_out_file_list_free(dst_list); + + if (base != NULL) *base = '/'; + + return 0; +} + +/* + * Check all_max size and delete files (oldest first) to stay within size limit. + * If query is true, then just report total size. + */ +int +module_check_size(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts, bool query, size_t *msize) +{ + asl_out_file_list_t *dst_list, *f, *dst_end; + char *dst_dir, fpath[MAXPATHLEN]; + size_t total; + + size_t all_max = dst->all_max; + if ((opts != NULL) && (opts->all_max > 0)) all_max = opts->all_max; + + if (dst == NULL) return -1; + if (dst->path == NULL) return -1; + + if (all_max == 0) return 0; + + dst_list = asl_list_dst_files(dst); + + if ((dst_list != NULL) && (dst->flags & MODULE_FLAG_ACTIVITY)) + { + dst_list = _remove_youngest_activity_tracing_file(dst_list); + } + + if (dst_list == NULL) + { + debug_log(ASL_LEVEL_INFO, " no dst files\n"); + return 0; + } + + dst_dir = dst->rotate_dir; + if (dst_dir == NULL) dst_dir = dst->dir; + + debug_log(ASL_LEVEL_INFO, " dst files\n"); + dst_end = dst_list; + for (f = dst_list; f != NULL; f = f->next) + { + dst_end = f; + debug_log(ASL_LEVEL_INFO, " %s size %lu\n", f->name, f->size); + } + + total = 0; + for (f = dst_list; f != NULL; f = f->next) total += f->size; + + if (!query) + { + for (f = dst_list; (total > all_max) && (f != NULL); f = f->next) + { + snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name); + filesystem_unlink(fpath); + total -= f->size; + } + } + + if (msize != NULL) *msize = total; + + asl_out_file_list_free(dst_list); + + return 0; +} + +int +process_dst(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts) +{ + uint32_t ttl = dst->ttl[LEVEL_ALL]; + if ((opts != NULL) && (opts->ttl[LEVEL_ALL] > 0)) ttl = opts->ttl[LEVEL_ALL]; + + size_t all_max = dst->all_max; + if ((opts != NULL) && (opts->all_max > 0)) all_max = opts->all_max; + + if (dst == NULL) + { + debug_log(ASL_LEVEL_NOTICE, "NULL dst data for output rule - skipped\n"); + } + else if (dst->flags & MODULE_FLAG_ROTATE) + { + debug_log(ASL_LEVEL_NOTICE, "Checking file %s\n", dst->path); + debug_log(ASL_LEVEL_NOTICE, "- Rename, move to destination directory, and compress as required\n"); + + module_copy_rename(dst); + + if (ttl > 0) + { + char tstr[150]; + + asl_core_time_to_str(ttl, tstr, sizeof(tstr)); + debug_log(ASL_LEVEL_NOTICE, "- Check for expired files - TTL = %s\n", tstr); + module_expire(dst, opts); + } + + if (all_max > 0) + { + debug_log(ASL_LEVEL_NOTICE, "- Check total storage used - MAX = %lu\n", all_max); + module_check_size(dst, opts, false, NULL); + } + } + else if ((dst->flags & MODULE_FLAG_TYPE_ASL_DIR) && (ttl > 0)) + { + process_asl_data_store(dst, opts); + } + + return 0; +} + +int +process_module(asl_out_module_t *mod, asl_out_dst_data_t *opts) +{ + asl_out_rule_t *r; + uint32_t flags = 0; + + if (mod == NULL) return -1; + + if (opts != NULL) flags = opts->flags; + + debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n"); + debug_log(ASL_LEVEL_NOTICE, "Processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name); + + for (r = mod->ruleset; r != NULL; r = r->next) + { + if (r->action == ACTION_OUT_DEST) + { + if ((flags == 0) || ((flags & r->dst->flags) != 0)) process_dst(r->dst, opts); + } + } + + debug_log(ASL_LEVEL_NOTICE, "Finished processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name); + return 0; +} + +int +cache_delete_task(bool query, size_t *size) +{ + dispatch_sync(work_queue, ^{ + asl_out_module_t *mod, *m; + asl_out_dst_data_t opts; + size_t total_size = 0; + + memset(&opts, 0, sizeof(opts)); + if ((!query) && (size != NULL)) opts.all_max = *size; + + debug_log(ASL_LEVEL_NOTICE, "cache_delete_process%s size %lu\n", query ? " query" : "", opts.all_max); + + mod = asl_out_module_init(); + + for (m = mod; m != NULL; m = m->next) + { + bool logged = false; + asl_out_rule_t *r; + + for (r = m->ruleset; r != NULL; r = r->next) + { + if (r->action == ACTION_OUT_DEST) + { + if (r->dst->flags & MODULE_FLAG_ACTIVITY) + { + if (!logged) + { + debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n"); + debug_log(ASL_LEVEL_NOTICE, "Processing activity module %s\n", (m->name == NULL) ? "asl.conf" : m->name); + logged = true; + } + + size_t dsize = 0; + module_check_size(r->dst, &opts, false, &dsize); + total_size += dsize; + } + } + } + + if (logged) debug_log(ASL_LEVEL_NOTICE, "Finished processing activity module %s\n", (m->name == NULL) ? "asl.conf" : m->name); + } + + asl_out_module_free(mod); + + if (size != NULL) *size = total_size; + }); + + return 0; +} + +asl_msg_list_t * +control_query(asl_msg_t *a) +{ + asl_msg_list_t *out; + char *qstr, *str, *res; + uint32_t len, reslen, status; + uint64_t cmax, qmin; + kern_return_t kstatus; + caddr_t vmstr; + security_token_t sec; + + if (asl_server_port == MACH_PORT_NULL) + { + kstatus = bootstrap_look_up2(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port, 0, BOOTSTRAP_PRIVILEGED_SERVER); + if (asl_server_port == MACH_PORT_NULL) return NULL; + } + + qstr = asl_msg_to_string((asl_msg_t *)a, &len); + + str = NULL; + if (qstr == NULL) + { + asprintf(&str, "1\nQ [= ASLOption control]\n"); + } + else + { + asprintf(&str, "1\n%s [= ASLOption control]\n", qstr); + free(qstr); + } + + if (str == NULL) return NULL; + + /* length includes trailing nul */ + len = strlen(str) + 1; + out = NULL; + qmin = 0; + cmax = 0; + sec.val[0] = -1; + sec.val[1] = -1; + + res = NULL; + reslen = 0; + status = ASL_STATUS_OK; + + kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL)); + if (kstatus != KERN_SUCCESS) return NULL; + + memmove(vmstr, str, len); + free(str); + + status = 0; + kstatus = _asl_server_query(asl_server_port, vmstr, len, qmin, 1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status, &sec); + if (kstatus != KERN_SUCCESS) return NULL; + + if (res == NULL) return NULL; + + out = asl_msg_list_from_string(res); + vm_deallocate(mach_task_self(), (vm_address_t)res, reslen); + + return out; +} + +int +checkpoint(const char *name) +{ + /* send checkpoint message to syslogd */ + debug_log(ASL_LEVEL_NOTICE, "Checkpoint module %s\n", (name == NULL) ? "*" : name); + if (dryrun) return 0; + + asl_msg_t *qmsg = asl_msg_new(ASL_TYPE_QUERY); + char *tmp = NULL; + asl_msg_list_t *res; + + asprintf(&tmp, "%s checkpoint", (name == NULL) ? "*" : name); + asl_msg_set_key_val_op(qmsg, "action", tmp, ASL_QUERY_OP_EQUAL); + free(tmp); + + res = control_query(qmsg); + + asl_msg_list_release(res); + return 0; +} diff --git a/aslmanager.tproj/daemon.h b/aslmanager.tproj/daemon.h new file mode 100644 index 0000000..ed05961 --- /dev/null +++ b/aslmanager.tproj/daemon.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include "asl_common.h" + +#define DEFAULT_MAX_SIZE 150000000 +#define IOBUFSIZE 4096 + +#define DO_ASLDB 0x00000001 +#define DO_MODULE 0x00000002 +#define DO_CHECKPT 0x00000004 + +#define DEBUG_FLAG_MASK 0xfffffff0 +#define DEBUG_LEVEL_MASK 0x0000000f +#define DEBUG_FILE 0x00000010 +#define DEBUG_STDERR 0x00000020 +#define DEBUG_ASL 0x00000040 + +#define AUX_URL_MINE "file:///var/log/asl/" +#define AUX_URL_MINE_LEN 20 + +#define SECONDS_PER_HOUR 3600 +#define SECONDS_PER_MINUTE 60 + +/* length of "file://" */ +#define AUX_URL_PATH_OFFSET 7 + +#define NAME_LIST_FLAG_COMPRESSED 0x00000001 + +#define DAEMON_STATE_IDLE 0x00000000 +#define DAEMON_STATE_MAIN 0x00000001 +#define DAEMON_STATE_CACHE 0x00000002 + +typedef struct name_list_s +{ + char *name; + size_t size; + uint32_t flags; + struct name_list_s *next; +} name_list_t; + +const char *keep_str(uint8_t mask); +void set_debug(int flag, const char *str); +void debug_log(int level, char *str, ...); +void debug_close(); + +name_list_t *add_to_name_list(name_list_t *l, const char *name, size_t size, uint32_t flags); +void free_name_list(name_list_t *l); + +int copy_compress_file(asl_out_dst_data_t *asldst, const char *src, const char *dst); + +void filesystem_rename(const char *src, const char *dst); +void filesystem_unlink(const char *path); +void filesystem_truncate(const char *path); +void filesystem_rmdir(const char *path); +int32_t filesystem_copy(asl_out_dst_data_t *asldst, const char *src, const char *dst, uint32_t flags); +int32_t filesystem_reset_ctime(const char *path); + +int remove_directory(const char *path); +size_t directory_size(const char *path); + +time_t parse_ymd_name(const char *name); +uint32_t ymd_file_age(const char *name, time_t now, uid_t *u, gid_t *g); +uint32_t ymd_file_filter(const char *name, const char *path, uint32_t keep_mask, mode_t ymd_mode, uid_t ymd_uid, gid_t ymd_gid); + +int process_asl_data_store(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts); +int module_copy_rename(asl_out_dst_data_t *dst); +int module_expire(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts); +int module_check_size(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts, bool check, size_t *msize); +int process_module(asl_out_module_t *mod, asl_out_dst_data_t *opts); +int process_dst(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts); + +asl_msg_list_t * control_query(asl_msg_t *a); +int checkpoint(const char *name); + +int cache_delete_task(bool query, size_t *size); +void main_task(void); + diff --git a/libsystem_asl.tproj/include/asl.h b/libsystem_asl.tproj/include/asl.h index 1cc2662..218e42e 100644 --- a/libsystem_asl.tproj/include/asl.h +++ b/libsystem_asl.tproj/include/asl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2013 Apple Inc. All rights reserved. + * Copyright (c) 2004-2015 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -31,7 +31,7 @@ #include /* Version number encodes the date YYYYMMDD */ -#define ASL_API_VERSION 20131108 +#define ASL_API_VERSION 20150225 typedef struct __asl_object_s *asl_object_t; typedef asl_object_t aslclient; @@ -902,7 +902,7 @@ asl_object_t asl_open_from_file(int descriptor, const char *ident, const char *f * similarly must still be freed by the caller by calling asl_free() if the * caller loses reference to it. Any changes made to it after calling * asl_log_descriptor() are not applicable to the message used. descriptor - * is treated differentlty based on the value of fd_type. + * is treated differently based on the value of fd_type. * * If fd_type is ASL_LOG_DESCRIPTOR_READ, the descriptor must be open for read * access. ASL uses GCD to read from the descriptor as data becomes available. diff --git a/libsystem_asl.tproj/include/asl_client.h b/libsystem_asl.tproj/include/asl_client.h index e0383aa..060fe4e 100644 --- a/libsystem_asl.tproj/include/asl_client.h +++ b/libsystem_asl.tproj/include/asl_client.h @@ -96,6 +96,9 @@ ASL_STATUS asl_client_send(asl_client_t *client, asl_msg_t *msg) __OSX_AVAILABLE asl_msg_list_t *asl_client_search(asl_client_t *client, asl_msg_t *query) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); asl_msg_list_t *asl_client_match(asl_client_t *client, asl_msg_list_t *querylist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t direction) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +uint32_t asl_client_set_control(asl_client_t *client, uint32_t filter) __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); +uint32_t asl_client_get_control(asl_client_t *client) __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); + __END_DECLS #endif /* __ASL_CLIENT_H__ */ diff --git a/libsystem_asl.tproj/include/asl_core.h b/libsystem_asl.tproj/include/asl_core.h index 3b29a4a..f933872 100644 --- a/libsystem_asl.tproj/include/asl_core.h +++ b/libsystem_asl.tproj/include/asl_core.h @@ -29,6 +29,19 @@ #include #include #include +#include + +#define streq(A, B) (strcmp(A, B) == 0) +#define strneq(A, B) (strcmp(A, B) != 0) + +#define streq_len(A, B, C) (strncmp(A, B, C) == 0) +#define strneq_len(A, B, C) (strncmp(A, B, C) != 0) + +#define strcaseeq(A, B) (strcasecmp(A, B) == 0) +#define strcaseneq(A, B) (strcasecmp(A, B) != 0) + +#define strcaseeq_len(A, B, C) (strncasecmp(A, B, C) == 0) +#define strcaseneq_len(A, B, C) (strcasecmp(A, B, C) != 0) typedef uint32_t ASL_STATUS; @@ -84,8 +97,13 @@ typedef uint32_t ASL_STATUS; #define ASL_PLACE_DATABASE 0 #define ASL_PLACE_ARCHIVE 1 +#if TARGET_OS_SIMULATOR +#define ASL_PLACE_DATABASE_DEFAULT asl_filesystem_path(ASL_PLACE_DATABASE) +#define ASL_PLACE_ARCHIVE_DEFAULT asl_filesystem_path(ASL_PLACE_ARCHIVE) +#else #define ASL_PLACE_DATABASE_DEFAULT "/var/log/asl" #define ASL_PLACE_ARCHIVE_DEFAULT "/var/log/asl.archive" +#endif mach_port_t asl_core_get_service_port(int reset) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); @@ -100,6 +118,9 @@ char *asl_core_encode_buffer(const char *in, uint32_t len) __OSX_AVAILABLE_START int32_t asl_core_decode_buffer(const char *in, char **buf, uint32_t *len) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); time_t asl_core_parse_time(const char *in, uint32_t *tlen) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +size_t asl_core_str_to_size(char *s) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); //TODO: 10_11 & 7_1 or 8_0 +time_t asl_core_str_to_time(char *s, uint32_t def_n) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); //TODO: 10_11 & 7_1 or 8_0 +void asl_core_time_to_str(time_t s, char *str, size_t len) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); //TODO: 10_11 & 7_1 or 8_0 const char *asl_filesystem_path(uint32_t place) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); diff --git a/libsystem_asl.tproj/include/asl_file.h b/libsystem_asl.tproj/include/asl_file.h index e3d38ab..07a2a2b 100644 --- a/libsystem_asl.tproj/include/asl_file.h +++ b/libsystem_asl.tproj/include/asl_file.h @@ -70,7 +70,10 @@ #define ASL_FILE_FILTER_FLAG_KEEP_MATCHES 0x00000001 /* NB CACHE_SIZE must be > 1 */ -#define CACHE_SIZE 256 +#define CACHE_SIZE 128 + +/* This makes the maximum size of a file_string_t 128 bytes */ +#define CACHE_MAX_STRING_LEN 108 /* Size of the fixed-length part of a MSG record */ #define MSG_RECORD_FIXED_LENGTH 122 @@ -101,7 +104,7 @@ typedef struct file_string_s uint64_t where; uint32_t hash; struct file_string_s *next; - char str[]; + char str[CACHE_MAX_STRING_LEN]; } file_string_t; typedef struct asl_file_s @@ -113,8 +116,10 @@ typedef struct asl_file_s uint32_t string_cache_count; uint32_t msg_count; file_string_t *string_list; + file_string_t *string_spare; uint64_t first; uint64_t last; + uint64_t last_mid; uint64_t prev; uint64_t cursor; uint64_t cursor_xid; diff --git a/libsystem_asl.tproj/include/asl_msg.h b/libsystem_asl.tproj/include/asl_msg.h index 104cd9d..a346ec6 100644 --- a/libsystem_asl.tproj/include/asl_msg.h +++ b/libsystem_asl.tproj/include/asl_msg.h @@ -25,14 +25,21 @@ #define __ASL_MSG_H__ #include +#include +#include #include #include #include #define IndexNull ((uint32_t)-1) -#define ASL_MSG_PAGE_DATA_SIZE 830 -#define ASL_MSG_PAGE_SLOTS 25 +#define ASL_MSG_PAGE_DATA_SIZE 220 + +#define ASL_MSG_KVO_COUNT 30 +// ASL_MSG_KVO_QUERY_SLOTS = ASL_MSG_KVO_COUNT / 3; +#define ASL_MSG_KVO_QUERY_SLOTS 10 +// ASL_MSG_KVO_MSG_SLOTS = ASL_MSG_KVO_COUNT / 2; +#define ASL_MSG_KVO_MSG_SLOTS 15 #define ASL_MSG_OFFSET_MASK 0x3fff #define ASL_MSG_KV_MASK 0xc000 @@ -90,9 +97,10 @@ typedef struct asl_msg_s uint32_t data_size; uint64_t mem_size; struct asl_msg_s *next; - uint16_t key[ASL_MSG_PAGE_SLOTS]; - uint16_t val[ASL_MSG_PAGE_SLOTS]; - uint16_t op[ASL_MSG_PAGE_SLOTS]; +#ifndef __LP64__ + uint32_t pad; +#endif + uint16_t kvo[ASL_MSG_KVO_COUNT]; char data[ASL_MSG_PAGE_DATA_SIZE]; } asl_msg_t; @@ -130,6 +138,8 @@ asl_string_t * asl_string_append_asl_msg(asl_string_t *str, asl_msg_t *msg) __OS int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +void _asl_log_args_to_xpc(asl_object_t client, asl_object_t msg, xpc_object_t dict); //TODO: ADD AVAILABLITY INFO + __END_DECLS #endif /* __ASL_MSG_H__ */ diff --git a/libsystem_asl.tproj/include/asl_private.h b/libsystem_asl.tproj/include/asl_private.h index dcac0a4..03cf96c 100644 --- a/libsystem_asl.tproj/include/asl_private.h +++ b/libsystem_asl.tproj/include/asl_private.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2011 Apple Inc. All rights reserved. + * Copyright (c) 2007-2015 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -29,15 +29,13 @@ #include #include #include +#include #include #include #include #include #include -#define streq(A, B) (strcmp(A, B) == 0) -#define strcaseeq(A, B) (strcasecmp(A, B) == 0) - #define ASL_QUERY_OP_NULL 0x00000 #define ASLMANAGER_SERVICE_NAME "com.apple.aslmanager" @@ -54,12 +52,27 @@ /* File and Store Open Option */ #define ASL_OPT_OPEN_READ 0x80000000 +#define ASL_OPT_SHIM_NO_ASL 0x10000000 +#define ASL_OPT_SHIM_NO_TRACE 0x20000000 + #define ASL_STORE_LOCATION_FILE 0 #define ASL_STORE_LOCATION_MEMORY 1 #define ASL_OPT_SYSLOG_LEGACY 0x00010000 #define ASL_KEY_FREE_NOTE "ASLFreeNotify" +#define ASL_KEY_MESSAGETRACER "com.apple.message.domain" + +/* remote control bits */ +#define EVAL_LEVEL_MASK 0x000000ff +#define EVAL_ACTION_MASK 0xffff0000 +#define EVAL_ACTIVE 0x00010000 +#define EVAL_SEND_ASL 0x00020000 +#define EVAL_SEND_TRACE 0x00040000 +#define EVAL_TEXT_FILE 0x00080000 +#define EVAL_ASL_FILE 0x00100000 +#define EVAL_TUNNEL 0x00200000 +#define EVAL_QUOTA 0x00400000 /* * Private types @@ -72,6 +85,22 @@ #define NOQUOTA_FILE_PATH "/etc/asl/.noquota" +// TODO: this could move to vm_statistics.h +#ifndef VM_MEMORY_ASL +#define VM_MEMORY_ASL (VM_MEMORY_APPLICATION_SPECIFIC_1 + 7) +#endif + +/* + * Memory limits: work queue size for syslogd and max message size in libasl + */ +#if TARGET_OS_EMBEDDED +#define SYSLOGD_WORK_QUEUE_MEMORY 3072000 +#define LIBASL_MAX_MSG_SIZE 2048000 +#else +#define SYSLOGD_WORK_QUEUE_MEMORY 10240000 +#define LIBASL_MAX_MSG_SIZE 8192000 +#endif + __BEGIN_DECLS int asl_store_location() __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); @@ -80,6 +109,8 @@ int asl_syslog_faciliy_name_to_num(const char *name) __OSX_AVAILABLE_STARTING(__ const char *asl_syslog_faciliy_num_to_name(int n) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); int asl_trigger_aslmanager(void) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); int asl_get_filter(asl_object_t client, int *local, int *master, int *remote, int *active) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); +uint32_t asl_set_local_control(asl_object_t client, uint32_t filter) __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); +uint32_t asl_get_local_control(asl_object_t client) __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); /* EXCLUSIVLY FOR USE BY DEV TOOLS */ /* DO NOT USE THIS INTERFACE OTHERWISE */ diff --git a/libsystem_asl.tproj/man/asl.3 b/libsystem_asl.tproj/man/asl.3 index f2fdda0..106aa90 100644 --- a/libsystem_asl.tproj/man/asl.3 +++ b/libsystem_asl.tproj/man/asl.3 @@ -490,7 +490,7 @@ except that it takes a va_list argument. .Fc is similar to .Fn asl_log , -except the value for ASL_KEY_MESSAGE is taken from +except the value for ASL_KEY_MSG is taken from .Ar msg rather than being constructed using a .Fn printf diff --git a/libsystem_asl.tproj/src/asl.c b/libsystem_asl.tproj/src/asl.c index 745a788..8e268db 100644 --- a/libsystem_asl.tproj/src/asl.c +++ b/libsystem_asl.tproj/src/asl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2013 Apple Inc. All rights reserved. + * Copyright (c) 2004-2015 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -52,6 +52,8 @@ #include #include #include +#include +#include #include #include #include @@ -64,14 +66,8 @@ #define FETCH_BATCH 256 -#define LEVEL_MASK 0x0000000f -#define EVAL_MASK 0x000000f0 -#define EVAL_IGNORE 0x00000000 -#define EVAL_ASLFILE 0x00000010 -#define EVAL_SEND 0x00000020 -#define EVAL_TUNNEL 0x00000040 -#define EVAL_FILE 0x00000080 -#define EVAL_QUOTA 0x00000100 +#define EVAL_DEFAULT_ACTION (EVAL_SEND_ASL | EVAL_SEND_TRACE) +#define EVAL_ASL (EVAL_SEND_ASL | EVAL_TEXT_FILE | EVAL_ASL_FILE) /* * Clients get a max of 36000 messages per hour. @@ -83,8 +79,21 @@ #define NOQUOTA_ENV "ASL_QUOTA_DISABLED" #define QUOTA_DISABLED_MSG "*** MESSAGE QUOTA DISABLED FOR THIS PROCESS ***" #define QUOTA_MSG "*** LOG MESSAGE QUOTA EXCEEDED - SOME MESSAGES FROM THIS PROCESS HAVE BEEN DISCARDED ***" -#define QUOTA_LEVEL 2 -#define QUOTA_LEVEL_STR "2" +#define QUOTA_LEVEL ASL_LEVEL_CRIT +#define QUOTA_LEVEL_STR ASL_STRING_CRIT + +/* + * Limit the size of messages sent to syslogd. + */ +#define SIZE_LIMIT_MSG "*** ASL MESSAGE SIZE (%u bytes) EXCEEDED MAXIMIMUM SIZE (%u bytes) ***" + +static const uint8_t shim_asl_to_trace_type[8] = { + OS_TRACE_TYPE_FAULT, OS_TRACE_TYPE_FAULT, OS_TRACE_TYPE_FAULT, // Emergency, Alert, Critical + OS_TRACE_TYPE_ERROR, // Error + OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_RELEASE, // Warning, Notice, Info + OS_TRACE_TYPE_DEBUG // Debug +}; + /* forward */ static ASL_STATUS _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstring); @@ -428,13 +437,14 @@ asl_set_filter(asl_object_t client, int f) /* * Evaluate client / message / level to determine what to do with a message. - * Checks filters, tunneling, and log files. Returns EVAL_IGNORE if the message - * can be ignored. Otherwise it returns the bits below, ORed with the level. + * Checks filters, tunneling, and log files. + * Returns the bits below, ORed with the message level. * - * EVAL_ASLFILE - will write to an asl file (see asl_open_from_file) - * EVAL_SEND - will send to syslogd - * EVAL_TUNNEL - will send to syslogd with tunneling enabled - * EVAL_FILE - will write to file + * EVAL_SEND_ASL - send this message to syslogd + * EVAL_SEND_TRACE - log this message with Activity Tracing + * EVAL_ASL_FILE - write to a standalone ASL file (see asl_open_from_file) + * EVAL_TEXT_FILE - write this message to a text file / stderr + * EVAL_TUNNEL - tunneling enabled when sending to syslogd */ uint32_t _asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel) @@ -445,37 +455,45 @@ _asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel) int check; uint64_t v64; const char *val; + uint32_t eval; level = ASL_LEVEL_DEBUG; if (slevel >= 0) level = slevel; - + val = NULL; if ((asl_msg_lookup(msg, ASL_KEY_LEVEL, &val, NULL) == 0) && (val != NULL)) level = atoi(val); - + if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG; else if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG; if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) { /* sending to something other than a client */ - return (level | EVAL_SEND); + return EVAL_ACTIVE | EVAL_SEND_ASL | level; } asl = (asl_client_t *)client; + if ((asl != NULL) && (asl->aslfile != NULL)) return (EVAL_ASL_FILE | level); + + if (asl == NULL) asl = _asl_open_default(); if (asl == NULL) { - asl = _asl_open_default(); - if (asl == NULL) return EVAL_IGNORE; + eval = EVAL_ACTIVE | EVAL_DEFAULT_ACTION | level; + eval &= ~EVAL_SEND_ASL; + return eval; } - if (asl->aslfile != NULL) return (level | EVAL_ASLFILE); - - lmask = ASL_FILTER_MASK(level); + eval = (asl_client_get_control(asl) & EVAL_ACTION_MASK) | level; filter = asl->filter & 0xff; tunnel = (asl->filter & ASL_FILTER_MASK_TUNNEL) >> 8; + if (tunnel != 0) eval |= EVAL_TUNNEL; + + /* don't send MessageTracer messages to Activity Tracing */ + val = NULL; + if ((asl_msg_lookup(msg, ASL_KEY_MESSAGETRACER, &val, NULL) == 0) && (val != NULL)) eval &= ~EVAL_SEND_TRACE; - if (!(asl->options & ASL_OPT_NO_REMOTE)) + if ((asl->options & ASL_OPT_NO_REMOTE) == 0) { pthread_mutex_lock(&_asl_global.lock); @@ -502,39 +520,34 @@ _asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel) } } - pthread_mutex_unlock(&_asl_global.lock); - /* master filter overrides local filter */ - if (_asl_global.master_filter != 0) + if (_asl_global.master_filter & EVAL_ACTIVE) { - filter = _asl_global.master_filter; - tunnel = 1; - } + /* clear bits and set according to master */ + eval &= ~(EVAL_SEND_ASL | EVAL_SEND_TRACE); + eval |= (_asl_global.master_filter & (EVAL_SEND_ASL | EVAL_SEND_TRACE)); + eval |= EVAL_TUNNEL; - /* process-specific filter overrides local and master */ - if (_asl_global.proc_filter != 0) - { - filter = _asl_global.proc_filter; - tunnel = 1; + if ((_asl_global.master_filter & EVAL_LEVEL_MASK) != 0) filter = _asl_global.proc_filter & EVAL_LEVEL_MASK; } - } - if ((filter != 0) && ((filter & lmask) != 0)) - { - level |= EVAL_SEND; - if (tunnel != 0) level |= EVAL_TUNNEL; - if (asl->out_count > 0) level |= EVAL_FILE; + if (_asl_global.proc_filter & EVAL_ACTIVE) + { + /* clear bits and set according to proc */ + eval &= ~(EVAL_SEND_ASL | EVAL_SEND_TRACE | EVAL_TEXT_FILE); + eval |= (_asl_global.proc_filter & (EVAL_SEND_ASL | EVAL_SEND_TRACE | EVAL_TEXT_FILE)); + eval |= EVAL_TUNNEL; - return level; - } + if ((_asl_global.proc_filter & EVAL_LEVEL_MASK) != 0) filter = _asl_global.proc_filter & EVAL_LEVEL_MASK; + } - if ((asl->options & ASL_OPT_SYSLOG_LEGACY) && (filter != 0) && ((filter & lmask) == 0)) - { - return EVAL_IGNORE; + pthread_mutex_unlock(&_asl_global.lock); } - if (asl->out_count > 0) return (level | EVAL_FILE); + lmask = ASL_FILTER_MASK(level); + if ((filter != 0) && ((filter & lmask) == 0)) eval &= ~EVAL_SEND_ASL; + if (asl->out_count > 0) eval |= EVAL_TEXT_FILE; - return EVAL_IGNORE; + return eval; } /* @@ -546,7 +559,7 @@ _asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel) * ap: va_list for the format * returns 0 for success, non-zero for failure */ -static ASL_STATUS +__private_extern__ ASL_STATUS _asl_lib_vlog(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *format, va_list ap) { int saved_errno = errno; @@ -588,11 +601,7 @@ _asl_lib_vlog(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *for if (expand != 0) { fmt = malloc(len + 1); - if (fmt == NULL) - { - if (estr != NULL) free(estr); - return ASL_STATUS_NO_MEMORY; - } + if (fmt == NULL) return ASL_STATUS_NO_MEMORY; len = 0; @@ -645,16 +654,38 @@ _asl_lib_vlog(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *for int asl_vlog(asl_object_t client, asl_object_t msg, int level, const char *format, va_list ap) { + ASL_STATUS status = ASL_STATUS_OK; uint32_t eval = _asl_evaluate_send(client, msg, level); - if (eval == EVAL_IGNORE) return 0; - ASL_STATUS status = _asl_lib_vlog(client, eval, msg, format, ap); + if (eval & EVAL_SEND_TRACE) + { + va_list ap_copy; + if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG; + if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG; + uint8_t trace_type = shim_asl_to_trace_type[level]; + + va_copy(ap_copy, ap); + os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, format, ap_copy, ^(xpc_object_t xdict) {_asl_log_args_to_xpc(client, msg, xdict);} ); + va_end(ap_copy); + } + + if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL)) + { + asl_msg_t *smsg = asl_msg_new(ASL_TYPE_MSG); + if (eval & EVAL_SEND_TRACE) asl_msg_set_key_val(smsg, "ASLSHIM", "1"); + smsg = asl_msg_merge(smsg, (asl_msg_t *)msg); + + status = _asl_lib_vlog(client, eval, (asl_object_t)smsg, format, ap); + + asl_msg_release(smsg); + } + return (status == ASL_STATUS_OK) ? 0 : -1; } /* * _asl_lib_log - * SPI used by ASL_PREFILTER_LOG. Converts format arguments to a va_list and + * SPI used by legacy (non-shim) ASL_PREFILTER_LOG. Converts format arguments to a va_list and * forwards the call to _asl_lib_vlog. * msg: an asl message * eval: log level and send flags for the message @@ -665,13 +696,16 @@ asl_vlog(asl_object_t client, asl_object_t msg, int level, const char *format, v int _asl_lib_log(asl_object_t client, uint32_t eval, asl_object_t msg, const char *format, ...) { - int status; - if (eval == EVAL_IGNORE) return 0; + int status = 0; - va_list ap; - va_start(ap, format); - status = _asl_lib_vlog(client, eval, msg, format, ap); - va_end(ap); + if (eval & EVAL_ASL) + { + va_list ap; + + va_start(ap, format); + status = _asl_lib_vlog(client, eval, msg, format, ap); + va_end(ap); + } return status; } @@ -688,14 +722,34 @@ _asl_lib_log(asl_object_t client, uint32_t eval, asl_object_t msg, const char *f int asl_log(asl_object_t client, asl_object_t msg, int level, const char *format, ...) { - ASL_STATUS status; + ASL_STATUS status = ASL_STATUS_OK; uint32_t eval = _asl_evaluate_send(client, msg, level); - if (eval == EVAL_IGNORE) return 0; - va_list ap; - va_start(ap, format); - status = _asl_lib_vlog(client, eval, msg, format, ap); - va_end(ap); + if (eval & EVAL_SEND_TRACE) + { + va_list ap; + if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG; + if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG; + uint8_t trace_type = shim_asl_to_trace_type[level]; + + va_start(ap, format); + os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, format, ap, ^(xpc_object_t xdict) {_asl_log_args_to_xpc(client, msg, xdict);} ); + va_end(ap); + } + + if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL)) + { + va_list ap; + asl_msg_t *smsg = asl_msg_new(ASL_TYPE_MSG); + if (eval & EVAL_SEND_TRACE) asl_msg_set_key_val(smsg, "ASLSHIM", "1"); + smsg = asl_msg_merge(smsg, (asl_msg_t *)msg); + + va_start(ap, format); + status = _asl_lib_vlog(client, eval, (asl_object_t)smsg, format, ap); + va_end(ap); + + asl_msg_release(smsg); + } return (status == ASL_STATUS_OK) ? 0 : -1; } @@ -711,14 +765,33 @@ asl_log(asl_object_t client, asl_object_t msg, int level, const char *format, .. int asl_log_message(int level, const char *format, ...) { - int status; + ASL_STATUS status = ASL_STATUS_OK; uint32_t eval = _asl_evaluate_send(NULL, NULL, level); - if (eval == EVAL_IGNORE) return 0; - va_list ap; - va_start(ap, format); - status = _asl_lib_vlog(NULL, eval, NULL, format, ap); - va_end(ap); + if (eval & EVAL_SEND_TRACE) + { + va_list ap; + if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG; + if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG; + uint8_t trace_type = shim_asl_to_trace_type[level]; + + va_start(ap, format); + os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, format, ap, NULL); + va_end(ap); + } + + if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL)) + { + va_list ap; + asl_msg_t *smsg = asl_msg_new(ASL_TYPE_MSG); + if (eval & EVAL_SEND_TRACE) asl_msg_set_key_val(smsg, "ASLSHIM", "1"); + + va_start(ap, format); + status = _asl_lib_vlog(NULL, eval, (asl_object_t)smsg, format, ap); + va_end(ap); + + asl_msg_release(smsg); + } return (status == ASL_STATUS_OK) ? 0 : -1; } @@ -746,7 +819,7 @@ asl_get_filter(asl_object_t client, int *local, int *master, int *remote, int *a asl = (asl_client_t *)client; if (asl == NULL) asl = asl_default; - if (asl != NULL) l = asl->filter & 0xff; + if (asl != NULL) l = asl->filter & EVAL_LEVEL_MASK; if ((asl_default != NULL) && (!(asl_default->options & ASL_OPT_NO_REMOTE))) { @@ -792,15 +865,43 @@ asl_get_filter(asl_object_t client, int *local, int *master, int *remote, int *a return 0; } +/* SPI for SHIM control */ +uint32_t +asl_set_local_control(asl_object_t client, uint32_t filter) +{ + asl_client_t *asl = (asl_client_t *)client; + if (asl == NULL) + { + asl = _asl_open_default(); + if (asl == NULL) return UINT32_MAX; + } + else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX; + + return asl_client_set_control(asl, filter); +} + +uint32_t +asl_get_local_control(asl_object_t client) +{ + asl_client_t *asl = (asl_client_t *)client; + if (asl == NULL) + { + asl = _asl_open_default(); + if (asl == NULL) return UINT32_MAX; + } + else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX; + + return asl_client_get_control(asl); +} + /* - * Sets Host, PID, UID, GID, and OSActivityID values in a new message. + * Sets PID and OSActivityID values in a new message. * Also sets Level, Time, TimeNanoSec, Sender, Facility and Message if provided. */ 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) { char aux_val[64]; - char aux_host[_POSIX_HOST_NAME_MAX]; asl_msg_t *aux; int status; unsigned int osacount = 1; @@ -815,7 +916,7 @@ asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const /* Time and TimeNanoSec */ if (tv != NULL) { - snprintf(aux_val, sizeof(aux_val), "%lu", tv->tv_sec); + snprintf(aux_val, sizeof(aux_val), "%llu", (unsigned long long) tv->tv_sec); asl_msg_set_key_val(aux, ASL_KEY_TIME, aux_val); snprintf(aux_val, sizeof(aux_val), "%d", tv->tv_usec * 1000); @@ -825,22 +926,10 @@ asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const /* Message */ if (mstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_MSG, mstr); - /* Host */ - memset(&aux_host, 0, _POSIX_HOST_NAME_MAX); - if (gethostname(aux_host, _POSIX_HOST_NAME_MAX) == 0) asl_msg_set_key_val(aux, ASL_KEY_HOST, aux_host); - /* PID */ snprintf(aux_val, sizeof(aux_val), "%u", getpid()); asl_msg_set_key_val(aux, ASL_KEY_PID, aux_val); - /* UID */ - snprintf(aux_val, sizeof(aux_val), "%d", getuid()); - asl_msg_set_key_val(aux, ASL_KEY_UID, aux_val); - - /* GID */ - snprintf(aux_val, sizeof(aux_val), "%d", getgid()); - asl_msg_set_key_val(aux, ASL_KEY_GID, aux_val); - /* OSActivityID */ if (os_activity_get_active(&osaid, &osacount) == 1) { @@ -849,7 +938,7 @@ asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const } /* Sender */ - if (sstr == NULL) + if ((sstr == NULL) && (asl != NULL)) { /* See if the client has a value for ASL_KEY_SENDER */ status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_SENDER, &sstr, NULL); @@ -883,7 +972,7 @@ asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const if (sstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_SENDER, sstr); /* Facility */ - if (fstr == NULL) + if ((fstr == NULL) && (asl != NULL)) { status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_FACILITY, &fstr, NULL); if (status != 0) fstr = NULL; @@ -944,6 +1033,29 @@ asl_prepared_message(asl_client_t *asl, asl_msg_t *msg) } #endif +static void +_asl_set_option(asl_msg_t *msg, const char *opt) +{ + const char *val = NULL; + uint32_t status; + + if (msg == NULL) return; + if (opt == NULL) return; + + status = asl_msg_lookup(msg, ASL_KEY_OPTION, &val, NULL); + if ((status != 0) || (val == NULL)) + { + asl_msg_set_key_val(msg, ASL_KEY_OPTION, opt); + } + else + { + char *option = NULL; + asprintf(&option, "%s %s", opt, val); + asl_msg_set_key_val(msg, ASL_KEY_OPTION, option); + free(option); + } +} + static ASL_STATUS _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstr) { @@ -958,7 +1070,7 @@ _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *m asl_client_t *asl = NULL; static dispatch_once_t noquota_once; - if (eval == EVAL_IGNORE) return ASL_STATUS_OK; + if ((eval & EVAL_ASL) == 0) return ASL_STATUS_OK; if (obj == NULL) { @@ -971,12 +1083,10 @@ _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *m { objtype = asl_get_type(obj); if (objtype == ASL_TYPE_CLIENT) asl = (asl_client_t *)obj; - else asl = _asl_open_default(); } - level = eval & LEVEL_MASK; + level = eval & EVAL_LEVEL_MASK; if (level > 7) level = 7; - eval &= EVAL_MASK; lmask = ASL_FILTER_MASK(level); if ((objtype == ASL_TYPE_CLIENT) && (asl->aslfile != NULL)) use_global_lock = 1; @@ -1001,22 +1111,7 @@ _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *m if (sendmsg == NULL) return ASL_STATUS_FAILED; /* Set "ASLOption store" if tunneling */ - if (eval & EVAL_TUNNEL) - { - const char *val = NULL; - status = asl_msg_lookup(msg, ASL_KEY_OPTION, &val, NULL); - if ((status != 0) || (val == NULL)) - { - asl_msg_set_key_val(sendmsg, ASL_KEY_OPTION, ASL_OPT_STORE); - } - else - { - char *option = NULL; - asprintf(&option, "%s %s", ASL_OPT_STORE, val); - asl_msg_set_key_val(sendmsg, ASL_KEY_OPTION, option); - free(option); - } - } + if (eval & EVAL_TUNNEL) _asl_set_option(sendmsg, ASL_OPT_STORE); outstatus = -1; @@ -1062,28 +1157,34 @@ _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *m * - Environment variable ASL_QUOTA_DISABLED == 1 * - /etc/asl/.noquota existed at the time that the process started * - * Note that we just check /etc/asl/.noquota once, since it would be + * We just check /etc/asl/.noquota once, since it would be * expensive to stat() for every log message. + * + * We only check the Environment variable once, since getenv() is + * not thread safe. If someone is changing the environment, + * this can crash. */ - + dispatch_once(&noquota_once, ^{ struct stat sb; memset(&sb, 0, sizeof(struct stat)); - if (stat(NOQUOTA_FILE_PATH, &sb) == 0) _asl_global.quota = UINT32_MAX; - }); - - if (_asl_global.quota != UINT32_MAX) - { - const char *qtest = getenv(NOQUOTA_ENV); - if ((qtest != NULL) && (!strcmp(qtest, "1"))) + + int save_errno = errno; + + if (stat(NOQUOTA_FILE_PATH, &sb) == 0) { _asl_global.quota = UINT32_MAX; - - qd_msg = asl_base_msg(asl, QUOTA_LEVEL, &tval, sstr, fstr, QUOTA_DISABLED_MSG); - asl_msg_set_key_val(qd_msg, ASL_KEY_OPTION, ASL_OPT_STORE); } - } - + else + { + const char *qtest = getenv(NOQUOTA_ENV); + if ((qtest != NULL) && (!strcmp(qtest, "1"))) _asl_global.quota = UINT32_MAX; + } + + /* reset errno since we want stat() to fail silently */ + errno = save_errno; + }); + if (((eval & EVAL_TUNNEL) == 0) && (_asl_global.quota != UINT32_MAX)) { time_t last_send = _asl_global.last_send; @@ -1115,7 +1216,7 @@ _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *m } else { - eval &= ~EVAL_SEND; + eval &= ~EVAL_SEND_ASL; } } else @@ -1124,7 +1225,7 @@ _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *m } } - if ((_asl_global.server_port != MACH_PORT_NULL) && (eval & EVAL_SEND)) + if ((_asl_global.server_port != MACH_PORT_NULL) && (eval & EVAL_SEND_ASL)) { asl_string_t *send_str; const char *str; @@ -1146,9 +1247,31 @@ _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *m if ((str != NULL) && (vmsize != 0)) vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize); asl_msg_release(qd_msg); } - + send_str = asl_msg_to_string_raw(ASL_STRING_MIG, sendmsg, "raw"); len = asl_string_length(send_str); + + if (len > LIBASL_MAX_MSG_SIZE) + { + char tmp[256]; + + snprintf(tmp, sizeof(tmp), SIZE_LIMIT_MSG, len, LIBASL_MAX_MSG_SIZE); + asl_msg_t *limitmsg = asl_base_msg(asl, ASL_LEVEL_CRIT, &tval, sstr, fstr, tmp); + + asl_string_release(send_str); + len = 0; + + if (limitmsg != NULL) + { + /* Set "ASLOption store" if tunneling */ + if (eval & EVAL_TUNNEL) _asl_set_option(limitmsg, ASL_OPT_STORE); + + send_str = asl_msg_to_string_raw(ASL_STRING_MIG, limitmsg, "raw"); + len = asl_string_length(send_str); + asl_msg_release(limitmsg); + } + } + vmsize = asl_string_allocated_size(send_str); str = asl_string_release_return_bytes(send_str); @@ -1552,7 +1675,7 @@ _asl_server_control_query(void) res = NULL; reslen = 0; - 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) return NULL; memmove(vmstr, ctlstr, len); @@ -1655,7 +1778,7 @@ asl_open_path(const char *path, uint32_t opts) if (opts & ASL_OPT_CREATE_STORE) { if (asl_store_open_write(path, &sout) != ASL_STATUS_OK) return NULL; - return (asl_object_t)fout; + return (asl_object_t)sout; } else { diff --git a/libsystem_asl.tproj/src/asl_client.c b/libsystem_asl.tproj/src/asl_client.c index 4dd77db..7026a50 100644 --- a/libsystem_asl.tproj/src/asl_client.c +++ b/libsystem_asl.tproj/src/asl_client.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Apple Inc. All rights reserved. + * Copyright (c) 2015 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -136,6 +136,10 @@ asl_client_open(const char *ident, const char *facility, uint32_t opts) client->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE); + client->filter |= EVAL_ACTIVE; + if (!(opts & ASL_OPT_SHIM_NO_ASL)) client->filter |= EVAL_SEND_ASL; + if (!(opts & ASL_OPT_SHIM_NO_TRACE)) client->filter |= EVAL_SEND_TRACE; + if (client->options & ASL_OPT_STDERR) { /* only add stderr if it is valid */ @@ -161,6 +165,7 @@ asl_client_open_from_file(int descriptor, const char *ident, const char *facilit if (client == NULL) return NULL; client->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG); + client->filter |= (EVAL_ACTIVE | EVAL_SEND_ASL); status = asl_file_open_write_fd(descriptor, &(client->aslfile)); if (status != ASL_STATUS_OK) @@ -224,7 +229,7 @@ _do_server_match(asl_msg_list_t *qlist, size_t *last, size_t start, size_t count if (str == NULL) return NULL; - 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) return NULL; memmove(vmstr, str, len); @@ -274,7 +279,7 @@ _do_server_search(asl_msg_t *q) if (str == NULL) return NULL; - 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) return NULL; memmove(vmstr, str, len); @@ -367,18 +372,40 @@ asl_client_search(asl_client_t *client, asl_msg_t *query) #pragma mark - #pragma mark output control -/* returns last filter value, or -1 on error */ +/* + * Returns last filter value, or -1 on error. + * Note that this allows ASL_FILTER_MASK_TUNNEL (0x100) to be set. + * That is SPI that's used by some clients. + */ int asl_client_set_filter(asl_client_t *client, int filter) { - int last; - if (client == NULL) return -1; - last = client->filter; + + uint32_t allbits = client->filter; + int last = allbits & (~EVAL_ACTION_MASK); + client->filter = (allbits & EVAL_ACTION_MASK) | (filter & (~EVAL_ACTION_MASK)); + return last; +} + +/* SPI */ +uint32_t +asl_client_set_control(asl_client_t *client, uint32_t filter) +{ + if (client == NULL) return UINT32_MAX; + + uint32_t last = client->filter; client->filter = filter; return last; } +uint32_t +asl_client_get_control(asl_client_t *client) +{ + if (client == NULL) return UINT32_MAX; + return client->filter; +} + ASL_STATUS asl_client_add_output_file(asl_client_t *client, int descriptor, const char *mfmt, const char *tfmt, int filter, int text_encoding) { @@ -414,7 +441,9 @@ asl_client_add_output_file(asl_client_t *client, int descriptor, const char *mfm client->out_list[client->out_count].fd = descriptor; client->out_list[client->out_count].encoding = text_encoding; client->out_list[client->out_count].filter = filter; + client->out_list[client->out_count].mfmt = NULL; if (mfmt != NULL) client->out_list[client->out_count].mfmt = strdup(mfmt); + client->out_list[client->out_count].tfmt = NULL; if (tfmt != NULL) client->out_list[client->out_count].tfmt = strdup(tfmt); client->out_count++; diff --git a/libsystem_asl.tproj/src/asl_core.c b/libsystem_asl.tproj/src/asl_core.c index 3ae25de..30de51b 100644 --- a/libsystem_asl.tproj/src/asl_core.c +++ b/libsystem_asl.tproj/src/asl_core.c @@ -53,9 +53,6 @@ const char *ASL_LEVEL_TO_STRING[] = ASL_STRING_DEBUG }; -static char *asl_filesystem_path_database = NULL; -static char *asl_filesystem_path_archive = NULL; - /* * Message ID generation */ @@ -86,7 +83,7 @@ asl_core_get_service_port(int reset) static mach_port_t server_port = MACH_PORT_NULL; mach_port_t tmp; kern_return_t kstatus; - + if ((reset != 0) && (server_port != MACH_PORT_NULL)) { mach_port_t tmp = server_port; @@ -327,12 +324,14 @@ const char * asl_filesystem_path(uint32_t place) { static dispatch_once_t once; + static char *asl_filesystem_path_database = NULL; + static char *asl_filesystem_path_archive = NULL; dispatch_once(&once, ^{ char *asl_var_log = NULL; const char *const_asl_var_log = "/var/log"; -#if TARGET_IPHONE_SIMULATOR +#if TARGET_OS_SIMULATOR asl_var_log = getenv("SIMULATOR_LOG_ROOT"); #endif @@ -346,12 +345,10 @@ asl_filesystem_path(uint32_t place) { case ASL_PLACE_DATABASE: { - if (asl_filesystem_path_database == NULL) return ASL_PLACE_DATABASE_DEFAULT; return asl_filesystem_path_database; } case ASL_PLACE_ARCHIVE: { - if (asl_filesystem_path_archive == NULL) return ASL_PLACE_ARCHIVE_DEFAULT; return asl_filesystem_path_archive; } default: @@ -583,25 +580,25 @@ asl_core_str_match(const char *target, const char *mset, uint32_t mincount, uint { const char *x; uint32_t n; - + if (length == NULL) length = &n; - + if (target == NULL) return (mincount == 0); - + for (x = target, *length = 0; *x != '\0'; x++, *length = *length + 1) { char *s; - + if ((*length == maxcount) && (maxcount > 0)) return true; if (mset == NULL) continue; - + s = strchr(mset, *x); if ((s == NULL) && (flags & MFLAG_EXCLUDE)) continue; if ((s != NULL) && (flags & MFLAG_INCLUDE)) continue; - + break; } - + return (*length >= mincount); } @@ -609,15 +606,15 @@ bool asl_core_str_match_char(const char *target, const char c, uint32_t mincount, uint32_t flags, uint32_t *length) { uint32_t n; - + if (length == NULL) length = &n; *length = 0; - + if (target == NULL) return (mincount == 0); - + if ((*target == c) && (flags & MFLAG_INCLUDE)) *length = 1; if ((*target != c) && (flags & MFLAG_EXCLUDE)) *length = 1; - + return (*length >= mincount); } @@ -625,16 +622,96 @@ uint32_t asl_core_str_to_uint32(const char *target, uint32_t length) { uint32_t i, d, out = 0; - + for (i = 0; i < length; i++) { d = target[i] - '0'; out = (out * 10) + d; } - + + return out; +} + +size_t +asl_core_str_to_size(char *s) +{ + size_t len, n, max; + char x; + + if (s == NULL) return 0; + + len = strlen(s); + if (len == 0) return 0; + + n = 1; + x = s[len - 1]; + if (x > 90) x -= 32; + if (x == 'K') n = 1ll << 10; + else if (x == 'M') n = 1ll << 20; + else if (x == 'G') n = 1ll << 30; + + max = atoll(s) * n; + return max; +} + +time_t +asl_core_str_to_time(char *s, uint32_t def_n) +{ + size_t len; + time_t n, out; + char x; + + if (s == NULL) return 0; + + len = strlen(s); + if (len == 0) return 0; + + n = def_n; + + x = s[len - 1]; + if (x > 90) x -= 32; + + if (x == 'S') n = 1; + else if (x == 'M') n = SECONDS_PER_MINUTE; + else if (x == 'H') n = SECONDS_PER_HOUR; + else if (x == 'D') n = SECONDS_PER_DAY; + + out = atoll(s) * n; return out; } +void +asl_core_time_to_str(time_t s, char *str, size_t len) +{ + char days[32], hms[32]; + uint32_t d, h, m; + + d = s / SECONDS_PER_DAY; + s %= SECONDS_PER_DAY; + + h = s / SECONDS_PER_HOUR; + s %= SECONDS_PER_HOUR; + + m = s / SECONDS_PER_MINUTE; + s %= SECONDS_PER_MINUTE; + + memset(days, 0, sizeof(days)); + if (d > 0) snprintf(days, sizeof(days), "%u day%s", d, (d == 1) ? "" : "s"); + + memset(hms, 0, sizeof(hms)); + snprintf(hms, sizeof(hms), "%02u:%02u:%02lld", h, m, (long long) s); + + if ((h + m + s) == 0) + { + if (d == 0) snprintf(str, len, "0"); + else snprintf(str, len, "%s", days); + return; + } + + if (d == 0) snprintf(str, len, "%s", hms); + else snprintf(str, len, "%s %s", days, hms); +} + static bool asl_core_str_match_absolute_or_relative_time(const char *target, time_t *tval, uint32_t *tlen) { @@ -643,37 +720,37 @@ asl_core_str_match_absolute_or_relative_time(const char *target, time_t *tval, u bool test; const char *p; time_t start = 0; - + if (target == NULL) return false; - + /* [+-] */ p = target; test = asl_core_str_match(p, "+-", 0, 1, MFLAG_INCLUDE, &len); if (!test) return false; - + if (len == 1) { /* relative time */ start = time(NULL); if (*p == '-') sign = -1; } - + /* [0-9]+ */ p += len; test = asl_core_str_match(p, DIGITS, 1, 0, MFLAG_INCLUDE, &len); if (!test) return false; val = asl_core_str_to_uint32(p, len); - + /* [shmdw] */ p += len; test = asl_core_str_match(p, "SsMmHhDdWw", 0, 1, MFLAG_INCLUDE, &len); if (!test) return false; - + if ((*p == 'M') || (*p == 'm')) val *= SECONDS_PER_MINUTE; else if ((*p == 'H') || (*p == 'h')) val *= SECONDS_PER_HOUR; else if ((*p == 'D') || (*p == 'd')) val *= SECONDS_PER_DAY; else if ((*p == 'W') || (*p == 'w')) val *= SECONDS_PER_WEEK; - + /* matched string must be followed by space, tab, newline (not counted in length) */ p += len; if (*p != '\0') @@ -681,10 +758,10 @@ asl_core_str_match_absolute_or_relative_time(const char *target, time_t *tval, u test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len); if (!test) return false; } - + if (tlen != NULL) *tlen = p - target; if (tval != NULL) *tval = start + (sign * val); - + return true; } @@ -704,7 +781,7 @@ _month_num(const char *s) if (!strncasecmp(s, "nov", 3)) return 10; if (!strncasecmp(s, "dec", 3)) return 11; return -1; - + } /* @@ -718,71 +795,71 @@ asl_core_str_match_c_time(const char *target, time_t *tval, uint32_t *tlen) const char *p; struct tm t; time_t now; - + if (target == NULL) return false; memset(&t, 0, sizeof(t)); - + /* determine current date */ now = time(NULL); localtime_r(&now, &t); y = t.tm_year; memset(&t, 0, sizeof(t)); t.tm_year = y; - + /* Mth */ p = target; t.tm_mon = _month_num(p); len = 3; if (t.tm_mon == -1) return false; - + /* whitespace */ p += len; test = asl_core_str_match(p, WHITESPACE, 1, 0, MFLAG_INCLUDE, &len); if (!test) return false; - + /* [D]D */ p += len; test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len); if (!test) return false; t.tm_mday = asl_core_str_to_uint32(p, len); if (t.tm_mday > 31) return false; - + /* whitespace */ p += len; test = asl_core_str_match(p, WHITESPACE, 1, 0, MFLAG_INCLUDE, &len); if (!test) return false; - + /* [h]h */ p += len; test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len); if (!test) return false; t.tm_hour = asl_core_str_to_uint32(p, len); if (t.tm_hour > 23) return false; - + /* : */ p += len; if (*p != ':') return false; len = 1; - + /* mm */ p += len; test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len); if (!test) return false; t.tm_min = asl_core_str_to_uint32(p, len); if (t.tm_min > 59) return false; - + /* : */ p += len; if (*p != ':') return false; len = 1; - + /* ss */ p += len; test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len); if (!test) return false; t.tm_sec = asl_core_str_to_uint32(p, len); if (t.tm_sec > 59) return false; - + /* matched string must be followed by space, tab, newline (not counted in length) */ p += len; if (*p != '\0') @@ -790,12 +867,12 @@ asl_core_str_match_c_time(const char *target, time_t *tval, uint32_t *tlen) test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len); if (!test) return false; } - + t.tm_isdst = -1; - + if (tlen != NULL) *tlen = p - target; if (tval != NULL) *tval = mktime(&t); - + return true; } @@ -809,21 +886,21 @@ asl_core_str_match_dotted_time(const char *target, time_t *tval, uint32_t *tlen) bool test; const char *p; struct tm t; - + if (target == NULL) return false; memset(&t, 0, sizeof(t)); - + /* YYYY */ p = target; test = asl_core_str_match(p, DIGITS, 4, 4, MFLAG_INCLUDE, &len); if (!test) return false; t.tm_year = asl_core_str_to_uint32(p, len) - 1900; - + /* . */ p += len; if (*p != '.') return false; len = 1; - + /* [M]M */ p += len; test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len); @@ -832,65 +909,65 @@ asl_core_str_match_dotted_time(const char *target, time_t *tval, uint32_t *tlen) if (t.tm_mon < 1) return false; if (t.tm_mon > 12) return false; t.tm_mon -= 1; - + /* . */ p += len; if (*p != '.') return false; len = 1; - + /* [D]D */ p += len; test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len); if (!test) return false; t.tm_mday = asl_core_str_to_uint32(p, len); if (t.tm_mday > 31) return false; - + /* whitespace */ p += len; test = asl_core_str_match(p, WHITESPACE, 1, 0, MFLAG_INCLUDE, &len); if (!test) return false; - + /* [h]h */ p += len; test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len); if (!test) return false; t.tm_hour = asl_core_str_to_uint32(p, len); if (t.tm_hour > 23) return false; - + /* : */ p += len; if (*p != ':') return false; len = 1; - + /* mm */ p += len; test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len); if (!test) return false; t.tm_min = asl_core_str_to_uint32(p, len); if (t.tm_min > 59) return false; - + /* : */ p += len; if (*p != ':') return false; len = 1; - + /* ss */ p += len; test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len); if (!test) return false; t.tm_sec = asl_core_str_to_uint32(p, len); if (t.tm_sec > 59) return false; - + /* whitespace */ p += len; test = asl_core_str_match(p, WHITESPACE, 1, 0, MFLAG_INCLUDE, &len); if (!test) return false; - + /* UTC */ p += len; if (strncmp(p, "UTC", 3)) return false; len = 3; - + /* matched string must be followed by space, tab, newline (not counted in length) */ p += len; if (*p != '\0') @@ -898,10 +975,10 @@ asl_core_str_match_dotted_time(const char *target, time_t *tval, uint32_t *tlen) test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len); if (!test) return false; } - + if (tlen != NULL) *tlen = p - target; if (tval != NULL) *tval = timegm(&t); - + return true; } @@ -916,21 +993,21 @@ asl_core_str_match_iso_8601_time(const char *target, time_t *tval, uint32_t *tle const char *p; struct tm t; int32_t tzh, tzs, sign = -1; - + if (target == NULL) return false; memset(&t, 0, sizeof(t)); - + /* YYYY */ p = target; test = asl_core_str_match(p, DIGITS, 4, 4, MFLAG_INCLUDE, &len); if (!test) return false; t.tm_year = asl_core_str_to_uint32(p, len) - 1900; - + /* [-] */ p += len; test = asl_core_str_match_char(p, '-', 0, MFLAG_INCLUDE, &len); if (!test) return false; - + /* MM */ p += len; test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len); @@ -939,72 +1016,72 @@ asl_core_str_match_iso_8601_time(const char *target, time_t *tval, uint32_t *tle if (t.tm_mon < 1) return false; if (t.tm_mon > 12) return false; t.tm_mon -= 1; - + /* [-] */ p += len; test = asl_core_str_match_char(p, '-', 0, MFLAG_INCLUDE, &len); if (!test) return false; - + /* DD */ p += len; test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len); if (!test) return false; t.tm_mday = asl_core_str_to_uint32(p, len); if (t.tm_mday > 31) return false; - + /* T or t */ p += len; test = asl_core_str_match(p, "Tt", 1, 1, MFLAG_INCLUDE, &len); if (!test) return false; - + /* hh */ p += len; test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len); if (!test) return false; t.tm_hour = asl_core_str_to_uint32(p, len); if (t.tm_hour > 23) return false; - + /* [:] */ p += len; test = asl_core_str_match_char(p, ':', 0, MFLAG_INCLUDE, &len); if (!test) return false; - + /* mm */ p += len; test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len); if (!test) return false; t.tm_min = asl_core_str_to_uint32(p, len); if (t.tm_min > 59) return false; - + /* [:] */ p += len; test = asl_core_str_match_char(p, ':', 0, MFLAG_INCLUDE, &len); if (!test) return false; - + /* ss */ p += len; test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len); if (!test) return false; t.tm_sec = asl_core_str_to_uint32(p, len); if (t.tm_sec > 59) return false; - + p += len; - + /* default to local time if we hit the end of the string */ if ((*p == '\0') || (*p == ' ') || (*p == '\t') || (*p == '\n')) { t.tm_isdst = -1; - + if (tlen != NULL) *tlen = p - target; if (tval != NULL) *tval = mktime(&t); - + return true; } - + /* Z, z, +, or - */ test = asl_core_str_match(p, "Zz+-", 1, 1, MFLAG_INCLUDE, &len); if (!test) return false; - + if ((*p == 'Z') || (*p == 'z')) { /* matched string must be followed by space, tab, newline (not counted in length) */ @@ -1014,36 +1091,36 @@ asl_core_str_match_iso_8601_time(const char *target, time_t *tval, uint32_t *tle test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len); if (!test) return false; } - + if (tlen != NULL) *tlen = p - target; if (tval != NULL) *tval = timegm(&t); - + return true; } - + if (*p == '-') sign = 1; - + /* [h]h */ p += len; test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len); if (!test) return false; tzh = asl_core_str_to_uint32(p, len); if (tzh > 23) return false; - + /* [:] */ p += len; test = asl_core_str_match_char(p, ':', 0, MFLAG_INCLUDE, &len); if (!test) return false; - + /* mm */ p += len; test = asl_core_str_match(p, DIGITS, 0, 2, MFLAG_INCLUDE, &len); if (!test) return false; tzs = asl_core_str_to_uint32(p, len); if (tzs > 59) return false; - + t.tm_sec += (sign * (tzh * SECONDS_PER_HOUR) + (tzs * SECONDS_PER_MINUTE)); - + /* matched string must be followed by space, tab, newline (not counted in length) */ p += len; if (*p != '\0') @@ -1051,10 +1128,10 @@ asl_core_str_match_iso_8601_time(const char *target, time_t *tval, uint32_t *tle test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len); if (!test) return false; } - + if (tlen != NULL) *tlen = p - target; if (tval != NULL) *tval = timegm(&t); - + return true; } @@ -1063,55 +1140,55 @@ asl_core_parse_time(const char *in, uint32_t *tlen) { time_t tval = 0; uint32_t inlen; - + if (tlen != NULL) *tlen = 0; if (in == NULL) return -1; - + /* * Heuristics to determine the string format. * Warning: this code must be checked and may need to be adjusted if new formats are added. */ inlen = strlen(in); if (inlen == 0) return -1; - + /* leading plus or minus means it must be a relative time */ if ((in[0] == '+') || (in[0] == '-')) { if (asl_core_str_match_absolute_or_relative_time(in, &tval, tlen)) return tval; return -1; } - + /* leading alphabetic char means it must be ctime() format */ if (((in[0] >= 'a') && (in[0] <= 'z')) || ((in[0] >= 'A') && (in[0] <= 'Z'))) { if (asl_core_str_match_c_time(in, &tval, tlen)) return tval; return -1; } - + /* only absolute, dotted, or iso8601 formats at this point */ - + /* one to for chars means it must be absolute */ if (inlen < 5) { if (asl_core_str_match_absolute_or_relative_time(in, &tval, tlen)) return tval; return -1; } - + /* check for dot */ if (in[4] == '.') { if (asl_core_str_match_dotted_time(in, &tval, tlen)) return tval; return -1; } - + /* only absolute or iso8601 at this point */ - + /* check for absolute first, since that's quicker */ if (asl_core_str_match_absolute_or_relative_time(in, &tval, tlen)) return tval; - + if (asl_core_str_match_iso_8601_time(in, &tval, tlen)) return tval; - + return -1; } diff --git a/libsystem_asl.tproj/src/asl_file.c b/libsystem_asl.tproj/src/asl_file.c index ceef2c9..4b63529 100644 --- a/libsystem_asl.tproj/src/asl_file.c +++ b/libsystem_asl.tproj/src/asl_file.c @@ -181,6 +181,34 @@ asl_file_read_uint64(asl_file_t *s, off_t off, uint64_t *out) return ASL_STATUS_OK; } +static file_string_t * +file_string_create(asl_file_t *s) +{ + if ((s != NULL) && (s->string_spare != NULL)) + { + file_string_t *out = s->string_spare; + s->string_spare = NULL; + return out; + } + + return (file_string_t *)calloc(1, sizeof(file_string_t)); +} + +static void +file_string_dispose(asl_file_t *s, file_string_t *x) +{ + if ((s != NULL) && (s->string_spare == NULL)) + { + s->string_spare = x; + memset(s->string_spare, 0, sizeof(file_string_t)); + } + else + { + free(x); + } +} + + asl_file_t * asl_file_retain(asl_file_t *s) { @@ -224,6 +252,8 @@ _asl_file_free_internal(asl_file_t *s) s->string_list = x; } + free(s->string_spare); + if (s->store != NULL) fclose(s->store); if (s->scratch != NULL) free(s->scratch); @@ -465,6 +495,18 @@ asl_file_open_write(const char *path, mode_t mode, uid_t uid, gid_t gid, asl_fil if ((out->last + last_len) > out->file_size) out->last = 0; } + if (out->last != 0) + { + /* skip type (uint16_t), len (uint32_t), and next (uint64_t) */ + off = out->last + sizeof(uint16_t) + sizeof (uint32_t) + sizeof(uint64_t); + status = asl_file_read_uint64(out, off, &(out->last_mid)); + if (status != ASL_STATUS_OK) + { + asl_file_close(out); + return status; + } + } + aslstatus = asl_file_read_set_position(out, ASL_FILE_POSITION_LAST); if (aslstatus != ASL_STATUS_OK) { @@ -717,28 +759,34 @@ asl_file_string_encode(asl_file_t *s, const char *str, uint64_t *out) return ASL_STATUS_OK; } - /* check the cache */ - hash = asl_core_string_hash(str, len); + /* cached strings include trailing nul */ + len++; - sp = NULL; - for (sx = s->string_list; sx != NULL; sx = sx->next) + if (len <= CACHE_MAX_STRING_LEN) { - if ((hash == sx->hash) && (!strcmp(str, sx->str))) + /* check the cache */ + hash = asl_core_string_hash(str, len); + + sp = NULL; + for (sx = s->string_list; sx != NULL; sx = sx->next) { - /* Move this string to the head of the list */ - if (sp != NULL) + if ((hash == sx->hash) && (!strcmp(str, sx->str))) { - sl = s->string_list; - sp->next = sx->next; - sx->next = sl; - s->string_list = sx; + /* Move this string to the head of the list */ + if (sp != NULL) + { + sl = s->string_list; + sp->next = sx->next; + sx->next = sl; + s->string_list = sx; + } + + *out = sx->where; + return ASL_STATUS_OK; } - *out = sx->where; - return ASL_STATUS_OK; + sp = sx; } - - sp = sx; } off = ftello(s->store); @@ -749,47 +797,56 @@ asl_file_string_encode(asl_file_t *s, const char *str, uint64_t *out) if (i != 1) return ASL_STATUS_WRITE_FAILED; /* Length (includes trailing nul) */ - x32 = htonl(len + 1); + x32 = htonl(len); i = fwrite(&x32, sizeof(uint32_t), 1, s->store); if (i != 1) return ASL_STATUS_WRITE_FAILED; /* String data (nul terminated) */ - i = fwrite(str, len + 1, 1, s->store); + i = fwrite(str, len, 1, s->store); if (i != 1) return ASL_STATUS_WRITE_FAILED; /* flush data */ fflush(s->store); - /* create file_string_t and insert into the cache */ - sx = (file_string_t *)calloc(1, offsetof(file_string_t, str) + len + 1); - if (sx == NULL) return ASL_STATUS_NO_MEMORY; + /* + * Create file_string_t and insert into the cache, but only if the + * string is small. This prevents a huge string from eating memory. + * It's unlikely that large strings will be very re-usable. + */ + if (len <= CACHE_MAX_STRING_LEN) + { + sx = file_string_create(s); + if (sx == NULL) return ASL_STATUS_NO_MEMORY; - sx->where = off; - sx->hash = hash; - sx->next = s->string_list; - memcpy(sx->str, str, len); + sx->where = off; + sx->hash = hash; + sx->next = s->string_list; - s->string_list = sx; + /* includes trailing nul */ + memcpy(sx->str, str, len); - if (((s->flags & ASL_FILE_FLAG_UNLIMITED_CACHE) == 0) && (s->string_cache_count == CACHE_SIZE)) - { - /* drop last (lru) string from cache */ - sp = s->string_list; - sx = sp->next; + s->string_list = sx; - /* NB CACHE_SIZE must be > 1 */ - while (sx->next != NULL) + if (((s->flags & ASL_FILE_FLAG_UNLIMITED_CACHE) == 0) && (s->string_cache_count == CACHE_SIZE)) { - sp = sx; - sx = sx->next; - } + /* drop last (lru) string from cache */ + sp = s->string_list; + sx = sp->next; - sp->next = NULL; - free(sx); - } - else - { - s->string_cache_count++; + /* NB CACHE_SIZE must be > 1 */ + while (sx->next != NULL) + { + sp = sx; + sx = sx->next; + } + + sp->next = NULL; + file_string_dispose(s, sx); + } + else + { + s->string_cache_count++; + } } *out = off; @@ -800,6 +857,8 @@ asl_file_string_encode(asl_file_t *s, const char *str, uint64_t *out) * Encode an asl_msg_t *as a record structure. * Creates and caches strings. */ +#define KVSTACK_SIZE 128 + ASL_STATUS asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid) { @@ -807,6 +866,8 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid) uint32_t i, len, x, status; file_record_t r; uint64_t k, v; + uint64_t kvstack[KVSTACK_SIZE]; + uint64_t *kvmalloc = NULL; uint64_t *kvlist; off_t off; asl_msg_t *msg; @@ -822,6 +883,9 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid) memset(&r, 0, sizeof(file_record_t)); + r.mid = UINT64_MAX; + if ((mid != NULL ) && (*mid != 0)) r.mid = *mid; + r.flags = 0; r.level = ASL_LEVEL_DEBUG; r.pid = -1; @@ -832,7 +896,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid) r.time = 0; r.nano = 0; r.prev = s->prev; - kvlist = NULL; + kvlist = kvstack; key = NULL; val = NULL; @@ -858,7 +922,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid) status = asl_file_string_encode(s, val, &(r.host)); if (status != ASL_STATUS_OK) { - if (kvlist != NULL) free(kvlist); + free(kvmalloc); return status; } } @@ -870,7 +934,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid) status = asl_file_string_encode(s, val, &(r.sender)); if (status != ASL_STATUS_OK) { - if (kvlist != NULL) free(kvlist); + free(kvmalloc); return status; } } @@ -902,7 +966,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid) status = asl_file_string_encode(s, val, &(r.message)); if (status != ASL_STATUS_OK) { - if (kvlist != NULL) free(kvlist); + free(kvmalloc); return status; } } @@ -914,7 +978,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid) status = asl_file_string_encode(s, val, &(r.facility)); if (status != ASL_STATUS_OK) { - if (kvlist != NULL) free(kvlist); + free(kvmalloc); return status; } } @@ -926,7 +990,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid) status = asl_file_string_encode(s, val, &(r.refproc)); if (status != ASL_STATUS_OK) { - if (kvlist != NULL) free(kvlist); + free(kvmalloc); return status; } } @@ -938,7 +1002,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid) status = asl_file_string_encode(s, val, &(r.session)); if (status != ASL_STATUS_OK) { - if (kvlist != NULL) free(kvlist); + free(kvmalloc); return status; } } @@ -961,7 +1025,11 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid) } else if (!strcmp(key, ASL_KEY_MSG_ID)) { - if (s->flags & ASL_FILE_FLAG_PRESERVE_MSG_ID) *mid = atoll(val); + if (s->flags & ASL_FILE_FLAG_PRESERVE_MSG_ID) + { + r.mid = atoll(val); + if (mid != NULL) *mid = r.mid; + } } else if (!strcmp(key, ASL_KEY_OPTION)) { @@ -972,7 +1040,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid) status = asl_file_string_encode(s, key, &k); if (status != ASL_STATUS_OK) { - if (kvlist != NULL) free(kvlist); + free(kvmalloc); return status; } @@ -982,23 +1050,24 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid) status = asl_file_string_encode(s, val, &v); if (status != ASL_STATUS_OK) { - if (kvlist != NULL) free(kvlist); + free(kvmalloc); return status; } } - if (r.kvcount == 0) + if (r.kvcount >= KVSTACK_SIZE) { - kvlist = (uint64_t *)calloc(2, sizeof(uint64_t)); - } - else - { - kvlist = (uint64_t *)reallocf(kvlist, (r.kvcount + 2) * sizeof(uint64_t)); - } + /* out of space for the kvlist on the stack - fall back to malloc */ + kvmalloc = reallocf(kvmalloc, (r.kvcount + 2) * sizeof(uint64_t)); + if (kvmalloc == NULL) return ASL_STATUS_NO_MEMORY; - if (kvlist == NULL) - { - return ASL_STATUS_NO_MEMORY; + kvlist = kvmalloc; + + if (r.kvcount == KVSTACK_SIZE) + { + /* copy kvstack to kvmalloc */ + for (i = 0; i < KVSTACK_SIZE; i++) kvmalloc[i] = kvstack[i]; + } } kvlist[r.kvcount++] = k; @@ -1022,14 +1091,10 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid) if (buf == NULL) return ASL_STATUS_NO_MEMORY; - if (*mid != 0) + if (r.mid == UINT64_MAX) { - r.mid = *mid; - } - else - { - r.mid = asl_core_new_msg_id(0); - *mid = r.mid; + s->last_mid = s->last_mid + 1; + r.mid = s->last_mid; } p = buf; @@ -1110,8 +1175,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid) _asl_put_64(r.prev, p); p += sizeof(uint64_t); - free(kvlist); - kvlist = NULL; + free(kvmalloc); /* write record at end of file */ status = fseeko(s->store, 0, SEEK_END); @@ -1161,7 +1225,7 @@ asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid) } static ASL_STATUS -asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outlen) +asl_file_fetch_object(asl_file_t *s, uint16_t fetch_type, uint64_t where, char **out, uint32_t *outlen) { char ils[9]; char *p; @@ -1180,12 +1244,14 @@ asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outle *out = NULL; *outlen = 0; - + inls = 0; x64 = asl_core_htonq(where); memcpy(&inls, &x64, 1); if (inls & 0x80) { + if (fetch_type != ASL_FILE_TYPE_STR) return ASL_STATUS_INVALID_STORE; + /* inline string */ inls &= 0x0f; if (inls > 7) return ASL_STATUS_INVALID_STORE; @@ -1200,6 +1266,38 @@ asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outle return ASL_STATUS_OK; } + if (fetch_type == ASL_FILE_TYPE_STR) + { + /* check the string cache */ + file_string_t *sx, *sp; + + sp = NULL; + for (sx = s->string_list; sx != NULL; sx = sx->next) + { + if (sx->where == where) + { + *out = strdup(sx->str); + if (*out == NULL) return ASL_STATUS_NO_MEMORY; + + /* N.B. hash field is used to hold length when reading */ + *outlen = sx->hash; + + /* Move this string to the head of the list */ + if (sp != NULL) + { + file_string_t *sl = s->string_list; + sp->next = sx->next; + sx->next = sl; + s->string_list = sx; + } + + return ASL_STATUS_OK; + } + + sp = sx; + } + } + off = where; if ((off + sizeof(uint16_t) + sizeof(uint32_t)) > s->file_size) return ASL_STATUS_READ_FAILED; @@ -1209,8 +1307,11 @@ asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outle /* Type */ status = fread(&type, sizeof(uint16_t), 1, s->store); if (status != 1) return ASL_STATUS_READ_FAILED; + type = ntohs(type); off += sizeof(uint16_t); + if (type != fetch_type) return ASL_STATUS_INVALID_STORE; + /* Length */ len = 0; status = fread(&len, sizeof(uint32_t), 1, s->store); @@ -1232,6 +1333,44 @@ asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outle } *outlen = len; + + if ((fetch_type == ASL_FILE_TYPE_STR) && (len <= CACHE_MAX_STRING_LEN)) + { + file_string_t *sx = file_string_create(s); + if (sx != NULL) + { + sx->where = where; + + /* N.B. hash field is used to hold length when reading */ + sx->hash = len; + sx->next = s->string_list; + memcpy(sx->str, *out, len); + + s->string_list = sx; + + if (((s->flags & ASL_FILE_FLAG_UNLIMITED_CACHE) == 0) && (s->string_cache_count == CACHE_SIZE)) + { + /* drop last (lru) string from cache */ + file_string_t *sp = s->string_list; + sx = sp->next; + + /* NB CACHE_SIZE must be > 1 */ + while (sx->next != NULL) + { + sp = sx; + sx = sx->next; + } + + sp->next = NULL; + file_string_dispose(s, sx); + } + else + { + s->string_cache_count++; + } + } + } + return ASL_STATUS_OK; } @@ -1304,7 +1443,7 @@ asl_file_fetch_helper_str(asl_file_t *s, char **p, asl_msg_t *m, const char *key val = NULL; len = 0; status = ASL_STATUS_OK; - if (out != 0) status = asl_file_fetch_object(s, out, &val, &len); + if (out != 0) status = asl_file_fetch_object(s, ASL_FILE_TYPE_STR, out, &val, &len); if (err != NULL) *err = status; if ((status == ASL_STATUS_OK) && (val != NULL)) @@ -1333,7 +1472,7 @@ asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, asl_msg_t **msg) buf = NULL; buflen = 0; - status = asl_file_fetch_object(s, where, &buf, &buflen); + status = asl_file_fetch_object(s, ASL_FILE_TYPE_MSG, where, &buf, &buflen); if ((status != ASL_STATUS_OK) || (buf == NULL)) { s->cursor = 0; @@ -1403,7 +1542,7 @@ asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, asl_msg_t **msg) kv = _asl_get_64(p); p += sizeof(uint64_t); - status = asl_file_fetch_object(s, kv, &k, &len); + status = asl_file_fetch_object(s, ASL_FILE_TYPE_STR, kv, &k, &len); if (status != ASL_STATUS_OK) { asl_msg_release(out); @@ -1419,7 +1558,7 @@ asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, asl_msg_t **msg) if (kv != 0) { - status = asl_file_fetch_object(s, kv, &v, &len); + status = asl_file_fetch_object(s, ASL_FILE_TYPE_STR, kv, &v, &len); if (status != ASL_STATUS_OK) { free(k); diff --git a/libsystem_asl.tproj/src/asl_msg.c b/libsystem_asl.tproj/src/asl_msg.c index 48ba6ab..6f634df 100644 --- a/libsystem_asl.tproj/src/asl_msg.c +++ b/libsystem_asl.tproj/src/asl_msg.c @@ -9,7 +9,7 @@ * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -17,7 +17,7 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_LICENSE_HEADER_END@ */ @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -62,12 +63,6 @@ #define forever for(;;) -#define streq(A, B) (strcmp(A, B) == 0) -#define streq_len(A, B, C) (strncmp(A, B, C) == 0) -#define strneq(A, B) (strcmp(A, B) != 0) -#define strcaseeq(A, B) (strcasecmp(A, B) == 0) -#define strcaseneq(A, B) (strcasecmp(A, B) != 0) - #ifndef ASL_QUERY_OP_FALSE #define ASL_QUERY_OP_FALSE 0 #endif @@ -221,21 +216,132 @@ _asl_msg_std_key(const char *s, uint32_t len) #pragma mark - #pragma mark asl_msg -static asl_msg_t * -_asl_msg_make_page(void) +static uint32_t +_slot_count(asl_msg_t *m) { - int i; - asl_msg_t *out = (asl_msg_t *)calloc(1, sizeof(asl_msg_t)); + if (m == NULL) return 0; + if (m->asl_type == ASL_TYPE_MSG) return ASL_MSG_KVO_MSG_SLOTS; + if (m->asl_type == ASL_TYPE_QUERY) return ASL_MSG_KVO_QUERY_SLOTS; + return 0; +} - if (out == NULL) return NULL; - for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++) +static uint16_t +_get_slot_key(asl_msg_t *m, uint32_t slot) +{ + if (m == NULL) return 0; + + if (m->asl_type == ASL_TYPE_MSG) + { + if (slot < ASL_MSG_KVO_MSG_SLOTS) return m->kvo[slot]; + return 0; + } + + if (m->asl_type == ASL_TYPE_QUERY) + { + if (slot < ASL_MSG_KVO_QUERY_SLOTS) return m->kvo[slot]; + return 0; + } + + return 0; +} + + +static void +_set_slot_key(asl_msg_t *m, uint32_t slot, uint16_t x) +{ + if (m == NULL) return; + + if (m->asl_type == ASL_TYPE_MSG) + { + if (slot < ASL_MSG_KVO_MSG_SLOTS) m->kvo[slot] = x; + return; + } + + if (m->asl_type == ASL_TYPE_QUERY) + { + if (slot < ASL_MSG_KVO_QUERY_SLOTS) m->kvo[slot] = x; + return; + } +} + + +static uint16_t +_get_slot_val(asl_msg_t *m, uint32_t slot) +{ + if (m == NULL) return 0; + if (m->asl_type == ASL_TYPE_MSG) + { + if (slot < ASL_MSG_KVO_MSG_SLOTS) return m->kvo[slot + ASL_MSG_KVO_MSG_SLOTS]; + return 0; + } + + if (m->asl_type == ASL_TYPE_QUERY) { - out->key[i] = ASL_MSG_SLOT_FREE; - out->val[i] = ASL_MSG_SLOT_FREE; + if (slot < ASL_MSG_KVO_QUERY_SLOTS) return m->kvo[slot + ASL_MSG_KVO_QUERY_SLOTS]; + return 0; } + return 0; +} + +static void +_set_slot_val(asl_msg_t *m, uint32_t slot, uint16_t x) +{ + if (m == NULL) return; + + if (m->asl_type == ASL_TYPE_MSG) + { + if (slot < ASL_MSG_KVO_MSG_SLOTS) m->kvo[slot + ASL_MSG_KVO_MSG_SLOTS] = x; + return; + } + + if (m->asl_type == ASL_TYPE_QUERY) + { + if (slot < ASL_MSG_KVO_QUERY_SLOTS) m->kvo[slot + ASL_MSG_KVO_QUERY_SLOTS] = x; + return; + } +} + +static uint16_t +_get_slot_op(asl_msg_t *m, uint32_t slot) +{ + if (m == NULL) return 0; + + if (m->asl_type == ASL_TYPE_QUERY) + { + if (slot < ASL_MSG_KVO_QUERY_SLOTS) return m->kvo[slot + (ASL_MSG_KVO_QUERY_SLOTS * 2)]; + return 0; + } + + return 0; +} + +static void +_set_slot_op(asl_msg_t *m, uint32_t slot, uint16_t x) +{ + if (m == NULL) return; + + if (m->asl_type == ASL_TYPE_QUERY) + { + if (slot < ASL_MSG_KVO_QUERY_SLOTS) m->kvo[slot + (ASL_MSG_KVO_QUERY_SLOTS * 2)] = x; + } +} + +static asl_msg_t * +_asl_msg_make_page(uint32_t type) +{ + uint32_t i, n = 0; + asl_msg_t *out = (asl_msg_t *)calloc(1, sizeof(asl_msg_t)); + if (out == NULL) return NULL; + + if (type == ASL_TYPE_MSG) n = ASL_MSG_KVO_MSG_SLOTS * 2; + else if (type == ASL_TYPE_QUERY) n = ASL_MSG_KVO_QUERY_SLOTS * 2; + + for (i = 0; i < n; i++) out->kvo[i] = ASL_MSG_SLOT_FREE; + out->mem_size = sizeof(asl_msg_t); + out->asl_type = type; return out; } @@ -259,28 +365,33 @@ static const char * _asl_msg_slot_key(asl_msg_t *page, uint32_t slot) { const char *out; - uint16_t x; + uint16_t x, k; if (page == NULL) return NULL; - if (slot >= ASL_MSG_PAGE_SLOTS) return NULL; - if (page->key[slot] == ASL_MSG_SLOT_FREE) return NULL; - switch (page->key[slot] & ASL_MSG_KV_MASK) + if ((page->asl_type == ASL_TYPE_MSG) && (slot >= ASL_MSG_KVO_MSG_SLOTS)) return NULL; + else if ((page->asl_type == ASL_TYPE_QUERY) && (slot >= ASL_MSG_KVO_QUERY_SLOTS)) return NULL; + + k = _get_slot_key(page, slot); + + if (k == ASL_MSG_SLOT_FREE) return NULL; + + switch (k & ASL_MSG_KV_MASK) { case ASL_MSG_KV_INLINE: { - return page->data + page->key[slot]; + return page->data + k; } case ASL_MSG_KV_DICT: { - if ((page->key[slot] > ASL_STD_KEY_BASE) && (page->key[slot] <= ASL_STD_KEY_LAST)) + if ((k > ASL_STD_KEY_BASE) && (k <= ASL_STD_KEY_LAST)) { - x = page->key[slot] - ASL_STD_KEY_BASE - 1; + x = k - ASL_STD_KEY_BASE - 1; return ASLStandardKey[x]; } - else if ((page->key[slot] > ASL_MT_KEY_BASE) && (page->key[slot] <= ASL_MT_KEY_LAST)) + else if ((k > ASL_MT_KEY_BASE) && (k <= ASL_MT_KEY_LAST)) { - x = page->key[slot] - ASL_MT_KEY_BASE - 1; + x = k - ASL_MT_KEY_BASE - 1; return MTStandardKey[x]; } @@ -288,7 +399,7 @@ _asl_msg_slot_key(asl_msg_t *page, uint32_t slot) } case ASL_MSG_KV_EXTERN: { - x = page->key[slot] & ASL_MSG_OFFSET_MASK; + x = k & ASL_MSG_OFFSET_MASK; memcpy(&out, page->data + x, sizeof(char *)); return out; } @@ -301,22 +412,26 @@ static const char * _asl_msg_slot_val(asl_msg_t *page, uint32_t slot) { const char *out; - uint16_t x, type; + uint16_t x, v, type; if (page == NULL) return NULL; - if (slot >= ASL_MSG_PAGE_SLOTS) return NULL; - if (page->val[slot] == ASL_MSG_SLOT_FREE) return NULL; + if ((page->asl_type == ASL_TYPE_MSG) && (slot >= ASL_MSG_KVO_MSG_SLOTS)) return NULL; + else if ((page->asl_type == ASL_TYPE_QUERY) && (slot >= ASL_MSG_KVO_QUERY_SLOTS)) return NULL; - type = page->val[slot] & ASL_MSG_KV_MASK; + v = _get_slot_val(page, slot); + + if (v == ASL_MSG_SLOT_FREE) return NULL; + + type = v & ASL_MSG_KV_MASK; if (type == ASL_MSG_KV_INLINE) { - return page->data + page->val[slot]; + return page->data + v; } else if (type == ASL_MSG_KV_EXTERN) { - x = page->val[slot] & ASL_MSG_OFFSET_MASK; + x = v & ASL_MSG_OFFSET_MASK; memcpy(&out, page->data + x, sizeof(char *)); return out; } @@ -332,7 +447,7 @@ asl_msg_new(uint32_t type) { asl_msg_t *out; - out = _asl_msg_make_page(); + out = _asl_msg_make_page(type); if (out == NULL) return NULL; out->asl_type = type; @@ -344,28 +459,33 @@ asl_msg_new(uint32_t type) static void _asl_msg_free_page(asl_msg_t *page) { - uint32_t i; + uint32_t i, mslots; char *p; if (page == NULL) return; - for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++) + mslots = _slot_count(page); + + for (i = 0; i < mslots; i++) { - if (page->key[i] == ASL_STD_KEY_FREE_NOTE) + uint16_t k = _get_slot_key(page, i); + uint16_t v = _get_slot_val(page, i); + + if (k == ASL_STD_KEY_FREE_NOTE) { const char *x = _asl_msg_slot_val(page, i); if (x != NULL) notify_post(x); } - if ((page->key[i] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) + if ((k & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) { - memcpy(&p, page->data + (page->key[i] & ASL_MSG_OFFSET_MASK), sizeof(char *)); + memcpy(&p, page->data + (k & ASL_MSG_OFFSET_MASK), sizeof(char *)); free(p); } - if ((page->val[i] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) + if ((v & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) { - memcpy(&p, page->data + (page->val[i] & ASL_MSG_OFFSET_MASK), sizeof(char *)); + memcpy(&p, page->data + (v & ASL_MSG_OFFSET_MASK), sizeof(char *)); free(p); } } @@ -456,7 +576,7 @@ _asl_msg_dump_kv(FILE *f, asl_msg_t *msg, uint16_t x) void _asl_msg_dump(FILE *f, const char *comment, asl_msg_t *msg) { - int i, page1 = 1; + uint32_t i, mslots, page1 = 1; if (f == NULL) return; if (msg == NULL) @@ -465,6 +585,8 @@ _asl_msg_dump(FILE *f, const char *comment, asl_msg_t *msg) return; } + mslots = _slot_count(msg); + while (msg != NULL) { if (page1 == 1) @@ -484,13 +606,13 @@ _asl_msg_dump(FILE *f, const char *comment, asl_msg_t *msg) fprintf(f, " mem_size: %llu\n", msg->mem_size); fprintf(f, " next: %p\n", msg->next); - for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++) + for (i = 0; i < mslots; i++) { fprintf(f, " slot[%d]: ", i); - _asl_msg_dump_kv(f, msg, msg->key[i]); + _asl_msg_dump_kv(f, msg, _get_slot_key(msg, i)); fprintf(f, " "); - _asl_msg_dump_kv(f, msg, msg->val[i]); - fprintf(f, " 0x%04x\n", msg->op[i]); + _asl_msg_dump_kv(f, msg, _get_slot_val(msg, i)); + if (msg->asl_type == ASL_TYPE_QUERY) fprintf(f, " 0x%04x\n", _get_slot_op(msg, i)); } msg = msg->next; @@ -506,7 +628,7 @@ _asl_msg_dump(FILE *f, const char *comment, asl_msg_t *msg) static uint32_t _asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opage) { - uint32_t i, len, slot; + uint32_t i, len, slot, mslots; uint16_t kx; asl_msg_t *page; const char *kp; @@ -516,6 +638,8 @@ _asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opa i = 0; slot = 0; + mslots = _slot_count(msg); + if (oslot != NULL) *oslot = slot; page = msg; @@ -526,24 +650,24 @@ _asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opa forever { - if (page->key[slot] != ASL_MSG_SLOT_FREE) + if (_get_slot_key(page, slot) != ASL_MSG_SLOT_FREE) { if (kx != 0) { - if (page->key[slot] == kx) return i; + if (_get_slot_key(page, slot) == kx) return i; } - else if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_DICT) + else if ((_get_slot_key(page, slot) & ASL_MSG_KV_MASK) == ASL_MSG_KV_DICT) { - /* page->key[slot] is a dictionary key, but key is not (kx == 0) so skip this slot */ + /* _get_slot_key(page, slot) is a dictionary key, but key is not (kx == 0) so skip this slot */ } - else if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) + else if ((_get_slot_key(page, slot) & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) { - memcpy(&kp, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *)); + memcpy(&kp, page->data + (_get_slot_key(page, slot) & ASL_MSG_OFFSET_MASK), sizeof(char *)); if (streq(key, kp)) return i; } else { - kp = page->data + page->key[slot]; + kp = page->data + _get_slot_key(page, slot); if (streq(key, kp)) return i; } } @@ -552,7 +676,7 @@ _asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opa slot++; if (oslot != NULL) *oslot = slot; - if (slot >= ASL_MSG_PAGE_SLOTS) + if (slot >= mslots) { if (page->next == NULL) return IndexNull; @@ -573,7 +697,7 @@ _asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opa static int _asl_msg_resolve_index(asl_msg_t *msg, uint32_t n, asl_msg_t **page, uint32_t *slot) { - uint32_t i, sx; + uint32_t i, sx, mslots; asl_msg_t *px; if (msg == NULL) return -1; @@ -581,6 +705,8 @@ _asl_msg_resolve_index(asl_msg_t *msg, uint32_t n, asl_msg_t **page, uint32_t *s *slot = IndexNull; *page = NULL; + mslots = _slot_count(msg); + sx = 0; /* find page */ @@ -595,9 +721,9 @@ _asl_msg_resolve_index(asl_msg_t *msg, uint32_t n, asl_msg_t **page, uint32_t *s *page = px; /* find slot */ - for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++) + for (i = 0; i < mslots; i++) { - if (px->key[i] != ASL_MSG_SLOT_FREE) + if (px->kvo[i] != ASL_MSG_SLOT_FREE) { if (sx == n) { @@ -614,7 +740,7 @@ _asl_msg_resolve_index(asl_msg_t *msg, uint32_t n, asl_msg_t **page, uint32_t *s } /* - * asl_msg_fetch: iterate over entries + * asl_msg_fetch: iterate over entries * initial value of n should be 0. Subseqent calls should use the last * returned value. Returns IndexNull when there are no more entries * Sets the pointers for the next key, value, and op in the msg. @@ -624,11 +750,13 @@ _asl_msg_resolve_index(asl_msg_t *msg, uint32_t n, asl_msg_t **page, uint32_t *s uint32_t asl_msg_fetch(asl_msg_t *msg, uint32_t x, const char **keyout, const char **valout, uint16_t *opout) { - uint32_t p, xpn, xsn; + uint32_t p, xpn, xsn, mslots; asl_msg_t *page = NULL; if (msg == NULL) return IndexNull; + mslots = _slot_count(msg); + xsn = x >> 24; xpn = x & 0x00ffffff; @@ -644,14 +772,14 @@ asl_msg_fetch(asl_msg_t *msg, uint32_t x, const char **keyout, const char **valo if (keyout != NULL) *keyout = _asl_msg_slot_key(page, xsn); if (valout != NULL) *valout = _asl_msg_slot_val(page, xsn); - if (opout != NULL) *opout = (uint32_t)(page->op[xsn]); + if (opout != NULL) *opout = _get_slot_op(page, xsn); /* advance to the next slot */ forever { xsn++; - if (xsn >= ASL_MSG_PAGE_SLOTS) + if (xsn >= mslots) { if (page->next == NULL) return 0xff000000; xsn = 0; @@ -659,7 +787,7 @@ asl_msg_fetch(asl_msg_t *msg, uint32_t x, const char **keyout, const char **valo xpn++; } - if (page->key[xsn] != ASL_MSG_SLOT_FREE) return ((xsn << 24) | xpn); + if (page->kvo[xsn] != ASL_MSG_SLOT_FREE) return ((xsn << 24) | xpn); } return IndexNull; @@ -682,7 +810,7 @@ asl_msg_lookup(asl_msg_t *msg, const char *key, const char **valout, uint16_t *o if (i == IndexNull) return -1; if (valout != NULL) *valout = _asl_msg_slot_val(page, slot); - if (opout != NULL) *opout = (uint32_t)(page->op[slot]); + if (opout != NULL) *opout = _get_slot_op(page, slot); return 0; } @@ -706,17 +834,19 @@ asl_msg_get_val_for_key(asl_msg_t *msg, const char *key) const char * asl_msg_key(asl_msg_t *msg, uint32_t n) { - uint32_t slot, i; + uint32_t slot, i, mslots; asl_msg_t *page; if (msg == NULL) return NULL; + mslots = _slot_count(msg); + i = 0; for (page = msg; page != NULL; page = page->next) { - for (slot = 0; slot < ASL_MSG_PAGE_SLOTS; slot++) + for (slot = 0; slot < mslots; slot++) { - if (page->key[slot] != ASL_MSG_SLOT_FREE) + if (_get_slot_key(page, slot) != ASL_MSG_SLOT_FREE) { if (i == n) return _asl_msg_slot_key(page, slot); i++; @@ -733,15 +863,18 @@ asl_msg_key(asl_msg_t *msg, uint32_t n) static int _asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32_t op) { - uint32_t slot, keylen, vallen, total; + uint32_t slot, keylen, vallen, total, mslots; uint64_t klen, vlen; - uint16_t kx; + uint16_t kx, k, v, o; asl_msg_t *page, *last; char *extkey, *extval; if (msg == NULL) return -1; if (key == NULL) return -1; + mslots = _slot_count(msg); + + o = op; extkey = NULL; extval = NULL; @@ -809,15 +942,15 @@ _asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32 if (total <= (ASL_MSG_PAGE_DATA_SIZE - page->data_size)) { /* check for a free slot */ - for (slot = 0; (slot < ASL_MSG_PAGE_SLOTS) && (page->key[slot] != ASL_MSG_SLOT_FREE); slot++); - if (slot < ASL_MSG_PAGE_SLOTS) break; + for (slot = 0; (slot < mslots) && (_get_slot_key(page, slot) != ASL_MSG_SLOT_FREE); slot++); + if (slot < mslots) break; } } if (page == NULL) { /* allocate a new page and attach it */ - page = _asl_msg_make_page(); + page = _asl_msg_make_page(msg->asl_type); if (page == NULL) { if (extkey != NULL) free(extkey); @@ -832,44 +965,47 @@ _asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32 /* copy key or external key pointer into page data */ if (kx != 0) { - page->key[slot] = kx; + k = kx; } else if (extkey == NULL) { - page->key[slot] = page->data_size; + k = page->data_size; memcpy(page->data + page->data_size, key, keylen); } else { - page->key[slot] = page->data_size | ASL_MSG_KV_EXTERN; + k = page->data_size | ASL_MSG_KV_EXTERN; memcpy(page->data + page->data_size, &extkey, keylen); page->mem_size += klen; } + _set_slot_key(page, slot, k); page->data_size += keylen; /* copy val or external val pointer into page data */ - page->val[slot] = ASL_MSG_SLOT_FREE; + + v = ASL_MSG_SLOT_FREE; if (val != NULL) { if (extval == NULL) { - page->val[slot] = page->data_size; + v = page->data_size; memcpy(page->data + page->data_size, val, vallen); } else { - page->val[slot] = page->data_size | ASL_MSG_KV_EXTERN; + v = page->data_size | ASL_MSG_KV_EXTERN; memcpy(page->data + page->data_size, &extval, vallen); page->mem_size += vlen; } + _set_slot_val(page, slot, v); page->data_size += vallen; } /* set op */ - page->op[slot] = (uint16_t)op; + _set_slot_op(page, slot, o); /* update page count */ page->count++; @@ -888,17 +1024,22 @@ _asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32 static int _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op) { - uint32_t i, slot, newexternal; + uint32_t i, slot, mslots, newexternal; asl_msg_t *page; uint32_t intvallen, extvallen, newvallen; char *intval, *extval, *newval; + uint16_t k, v, o; if (msg == NULL) return -1; if (key == NULL) return -1; + mslots = _slot_count(msg); + slot = IndexNull; page = NULL; + o = op; + if ((msg->asl_type == ASL_TYPE_QUERY) || (IndexNull == _asl_msg_index(msg, key, &slot, &page))) { /* add key */ @@ -911,17 +1052,19 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op) extval = NULL; extvallen = 0; - if (page->val[slot] != ASL_MSG_SLOT_FREE) + v = _get_slot_val(page, slot); + + if (v != ASL_MSG_SLOT_FREE) { - if ((page->val[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) + if ((v & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) { - i = page->val[slot] & ASL_MSG_OFFSET_MASK; + i = v & ASL_MSG_OFFSET_MASK; memcpy(&extval, page->data + i, sizeof(char *)); extvallen = sizeof(char *); } else { - intval = page->data + page->val[slot]; + intval = page->data + v; intvallen = strlen(intval) + 1; } } @@ -937,41 +1080,41 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op) free(extval); } - page->val[slot] = ASL_MSG_SLOT_FREE; - if (op != IndexNull) page->op[slot] = (uint16_t)op; + _set_slot_val(page, slot, ASL_MSG_SLOT_FREE); + if (op != IndexNull) _set_slot_op(page, slot, o); return 0; } /* trivial case - internal val doesn't change */ if ((intval != NULL) && (streq(val, intval))) { - if (op != IndexNull) page->op[slot] = (uint16_t)op; + if (op != IndexNull) _set_slot_op(page, slot, o); return 0; } /* trivial case - external val doesn't change */ if ((extval != NULL) && (streq(val, extval))) { - if (op != IndexNull) page->op[slot] = (uint16_t)op; + if (op != IndexNull) _set_slot_op(page, slot, o); return 0; } /* * special case: we generally don't compress out holes in the data * space, but if this is the last string in the currently used data space - * we can just back up the data_size and reset page->val[slot] + * we can just back up the data_size and reset page->val[slot] (a.k.a. page->kvo[slot + mslots]) */ - i = page->val[slot] & ASL_MSG_OFFSET_MASK; + i = v & ASL_MSG_OFFSET_MASK; if ((intval != NULL) && ((i + intvallen) == page->data_size)) { - page->val[slot] = ASL_MSG_SLOT_FREE; + _set_slot_val(page, slot, ASL_MSG_SLOT_FREE); page->data_size -= intvallen; intval = NULL; intvallen = 0; } else if ((extval != NULL) && ((i + extvallen) == page->data_size)) { - page->val[slot] = ASL_MSG_SLOT_FREE; + _set_slot_val(page, slot, ASL_MSG_SLOT_FREE); page->data_size -= extvallen; page->mem_size -= (strlen(extval) + 1); free(extval); @@ -1001,7 +1144,7 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op) extval = NULL; /* we can re-use the space of the old value */ - i = page->val[slot] & ASL_MSG_OFFSET_MASK; + i = v & ASL_MSG_OFFSET_MASK; if (newexternal == 1) { @@ -1010,17 +1153,17 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op) if (newval == NULL) return -1; page->mem_size += (strlen(newval) + 1); - page->val[slot] = i | ASL_MSG_KV_EXTERN; + _set_slot_val(page, slot, i | ASL_MSG_KV_EXTERN); memcpy(page->data + i, &newval, sizeof(char *)); } else { /* new internal value */ - page->val[slot] = i; + _set_slot_val(page, slot, i); memcpy(page->data + i, val, newvallen); } - if (op != IndexNull) page->op[slot] = (uint16_t)op; + if (op != IndexNull) _set_slot_op(page, slot, o); return 0; } @@ -1046,32 +1189,32 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op) if (newval == NULL) return -1; page->mem_size += (strlen(newval) + 1); - page->val[slot] = i | ASL_MSG_KV_EXTERN; + _set_slot_val(page, slot, i | ASL_MSG_KV_EXTERN); memcpy(page->data + i, &newval, sizeof(char *)); } else { /* new internal value */ - page->val[slot] = i; + _set_slot_val(page, slot, i); memcpy(page->data + i, val, newvallen); } - if (op != IndexNull) page->op[slot] = (uint16_t)op; + if (op != IndexNull) _set_slot_op(page, slot, o); return 0; } /* no room on this page - free up existing entry and treat this as a new entry */ - if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) + if ((k & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) { - memcpy(&extval, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *)); + memcpy(&extval, page->data + (k & ASL_MSG_OFFSET_MASK), sizeof(char *)); page->mem_size -= (strlen(extval) + 1); free(extval); } - page->key[slot] = ASL_MSG_SLOT_FREE; - page->val[slot] = ASL_MSG_SLOT_FREE; - page->op[slot] = 0; + _set_slot_key(page, slot, ASL_MSG_SLOT_FREE); + _set_slot_val(page, slot, ASL_MSG_SLOT_FREE); + _set_slot_op(page, slot, 0); return _asl_msg_new_key_val_op(msg, key, val, op); } @@ -1083,6 +1226,9 @@ asl_msg_set_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32_ uint32_t i, len; int status; + if (msg == NULL) return -1; + if (key == NULL) return -1; + /* Special case handling */ special = NULL; @@ -1148,28 +1294,34 @@ static void _asl_msg_unset_page_slot(asl_msg_t *page, uint32_t slot) { char *ext; + uint16_t k, v; if (page == NULL) return; - if (slot >= ASL_MSG_PAGE_SLOTS) return; - if (page->key[slot] == ASL_MSG_SLOT_FREE) return; - if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) + if (slot >= _slot_count(page)) return; + + k = _get_slot_key(page, slot); + v = _get_slot_val(page, slot); + + if (k == ASL_MSG_SLOT_FREE) return; + + if ((k & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) { - memcpy(&ext, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *)); + memcpy(&ext, page->data + (k & ASL_MSG_OFFSET_MASK), sizeof(char *)); page->mem_size -= (strlen(ext) + 1); free(ext); } - if ((page->val[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) + if ((v & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) { - memcpy(&ext, page->data + (page->val[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *)); + memcpy(&ext, page->data + (v & ASL_MSG_OFFSET_MASK), sizeof(char *)); page->mem_size -= (strlen(ext) + 1); free(ext); } - page->key[slot] = ASL_MSG_SLOT_FREE; - page->val[slot] = ASL_MSG_SLOT_FREE; - page->op[slot] = 0; + _set_slot_key(page, slot, ASL_MSG_SLOT_FREE); + _set_slot_val(page, slot, ASL_MSG_SLOT_FREE); + _set_slot_op(page, slot, 0); page->count--; } @@ -1798,8 +1950,8 @@ _asl_time_string(const char *infmt, const char *str, const char *nano) off %= 3600; zm = off / 60; - if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02ld", neg ? '-' : '+', zh); - else snprintf(zstr, sizeof(zstr), "%c%02ld:%02ld", neg ? '-' : '+', zh, zm); + if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02lld", neg ? '-' : '+', (long long) zh); + else snprintf(zstr, sizeof(zstr), "%c%02lld:%02lld", neg ? '-' : '+', (long long) zh, (long long) zm); asprintf(&out, "%d-%02d-%02d%c%02d:%02d:%02d%s%s", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, sep, stm.tm_hour, stm.tm_min, stm.tm_sec, nanobuf, zstr); return out; @@ -1815,8 +1967,8 @@ _asl_time_string(const char *infmt, const char *str, const char *nano) off %= 3600; zm = off / 60; - if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02ld", neg ? '-' : '+', zh); - else snprintf(zstr, sizeof(zstr), "%c%02ld:%02ld", neg ? '-' : '+', zh, zm); + if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02lld", neg ? '-' : '+', (long long) zh); + else snprintf(zstr, sizeof(zstr), "%c%02lld:%02lld", neg ? '-' : '+', (long long) zh, (long long) zm); asprintf(&out, "%d%02d%02dT%02d%02d%02d%s%s", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec, nanobuf, zstr); return out; @@ -1824,7 +1976,7 @@ _asl_time_string(const char *infmt, const char *str, const char *nano) if ((!strcasecmp(fmt, "sec")) || (!strcasecmp(fmt, "raw"))) { - asprintf(&out, "%lu%s", tick, nanobuf); + asprintf(&out, "%llu%s", (unsigned long long) tick, nanobuf); return out; } @@ -1882,8 +2034,8 @@ _asl_time_string(const char *infmt, const char *str, const char *nano) off = (zh * 3600) + (zm * 60); if (neg) off *= -1; - if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02ld", neg ? '-' : '+', zh); - else snprintf(zstr, sizeof(zstr), "%c%02ld:%02ld", neg ? '-' : '+', zh, zm); + if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02lld", neg ? '-' : '+', (long long) zh); + else snprintf(zstr, sizeof(zstr), "%c%02lld:%02lld", neg ? '-' : '+', (long long) zh, (long long) zm); } @@ -2879,6 +3031,114 @@ asl_format_message(asl_msg_t *msg, const char *mfmt, const char *tfmt, uint32_t return out; } +#pragma mark - +#pragma mark xpc conversion + +static void +_asl_msg_to_xpc(asl_msg_t *msg, xpc_object_t dict) +{ + uint32_t x, len; + const char *key, *val, *nano; + uint16_t kx; + + if (msg == NULL) return; + if (dict == NULL) return; + + nano = NULL; + asl_msg_lookup(msg, ASL_KEY_TIME_NSEC, &nano, NULL); + + for (x = asl_msg_fetch(msg, 0, &key, &val, NULL); x != IndexNull; x = asl_msg_fetch(msg, x, &key, &val, NULL)) + { + if (key == NULL) continue; + + len = strlen(key); + kx = _asl_msg_std_key(key, len); + + if (val == NULL) + { + xpc_object_t obj = xpc_null_create(); + xpc_dictionary_set_value(dict, key, obj); + xpc_release(obj); + } + else if (kx == 0) + { + if (streq(key, ASL_KEY_SENDER_MACH_UUID)) + { + uuid_t v; + if (uuid_parse(val, v) == 0) + { + xpc_object_t obj = xpc_uuid_create(v); + xpc_dictionary_set_value(dict, key, obj); + xpc_release(obj); + } + } + else + { + xpc_object_t obj = xpc_string_create(val); + xpc_dictionary_set_value(dict, key, obj); + xpc_release(obj); + } + } + else if (kx == ASL_STD_KEY_TIME) + { + uint64_t t = NSEC_PER_SEC * asl_core_parse_time(val, NULL); + if (nano != NULL) t += atoll(nano); + xpc_object_t obj = xpc_date_create(t); + xpc_dictionary_set_value(dict, key, obj); + xpc_release(obj); + } + else if (kx == ASL_STD_KEY_NANO) + { + /* handled with ASL_STD_KEY_TIME */ + } + else if ((kx == ASL_STD_KEY_PID) || (kx == ASL_STD_KEY_REF_PID)) + { + int64_t v = atoll(val); + xpc_object_t obj = xpc_int64_create(v); + xpc_dictionary_set_value(dict, key, obj); + xpc_release(obj); + } + else if ((kx == ASL_STD_KEY_UID) || (kx == ASL_STD_KEY_GID)) + { + int64_t v = atoll(val); + xpc_object_t obj = xpc_int64_create(v); + xpc_dictionary_set_value(dict, key, obj); + xpc_release(obj); + } + else if (kx == ASL_STD_KEY_LEVEL) + { + int64_t v = atoll(val); + xpc_object_t obj = xpc_int64_create(v); + xpc_dictionary_set_value(dict, key, obj); + xpc_release(obj); + } + else if ((kx == ASL_STD_KEY_READ_UID) || (kx == ASL_STD_KEY_READ_GID)) + { + int64_t v = atoll(val); + xpc_object_t obj = xpc_int64_create(v); + xpc_dictionary_set_value(dict, key, obj); + xpc_release(obj); + } + else if (kx == ASL_STD_KEY_MSG_ID) + { + /* ignore */ + } + else + { + xpc_object_t obj = xpc_string_create(val); + xpc_dictionary_set_value(dict, key, obj); + xpc_release(obj); + } + } +} + +void +_asl_log_args_to_xpc(asl_object_t client, asl_object_t msg, xpc_object_t dict) +{ + _asl_msg_to_xpc(asl_client_kvdict((asl_client_t *)client), dict); + _asl_msg_to_xpc((asl_msg_t *)msg, dict); +} + #pragma mark - #pragma mark asl_object support @@ -2930,7 +3190,8 @@ _jump_get_key_val_op_at_index(asl_object_private_t *obj, size_t n, const char ** if (key != NULL) *key = _asl_msg_slot_key(page, slot); if (val != NULL) *val = _asl_msg_slot_val(page, slot); - if (op != NULL) *op = page->op[slot]; + if (op != NULL) *op = _get_slot_op(page, slot); + return 0; } diff --git a/libsystem_asl.tproj/src/asl_object.c b/libsystem_asl.tproj/src/asl_object.c index 39286bf..e09032e 100644 --- a/libsystem_asl.tproj/src/asl_object.c +++ b/libsystem_asl.tproj/src/asl_object.c @@ -161,7 +161,7 @@ asl_object_remove_object_at_index(asl_object_private_t *obj, size_t n) void asl_object_append(asl_object_private_t *obj, asl_object_private_t *newobj) { - int type = ASL_TYPE_CLIENT; + uint32_t type = ASL_TYPE_CLIENT; if (obj != NULL) type = obj->asl_type; if (type >= ASL_TYPE_COUNT) return; diff --git a/libsystem_asl.tproj/src/asl_store.c b/libsystem_asl.tproj/src/asl_store.c index 08da1a1..b03dbb6 100644 --- a/libsystem_asl.tproj/src/asl_store.c +++ b/libsystem_asl.tproj/src/asl_store.c @@ -91,7 +91,7 @@ asl_store_open_write(const char *basedir, asl_store_t **s) asl_store_t *out; struct stat sb; uint32_t i, flags; - char *path; + char path[MAXPATHLEN]; FILE *sd; uint64_t last_id; time_t start; @@ -104,26 +104,26 @@ asl_store_open_write(const char *basedir, asl_store_t **s) if (basedir == NULL) basedir = PATH_ASL_STORE; memset(&sb, 0, sizeof(struct stat)); - if (stat(basedir, &sb) != 0) return ASL_STATUS_INVALID_STORE; - if (!S_ISDIR(sb.st_mode)) return ASL_STATUS_INVALID_STORE; - - path = NULL; - asprintf(&path, "%s/%s", basedir, FILE_ASL_STORE_DATA); - if (path == NULL) return ASL_STATUS_NO_MEMORY; + if (stat(basedir, &sb) != 0) + { + if (errno != ENOENT) return ASL_STATUS_INVALID_STORE; + if (mkdir(basedir, 0755) != 0) return ASL_STATUS_WRITE_FAILED; + } + else + { + if (!S_ISDIR(sb.st_mode)) return ASL_STATUS_INVALID_STORE; + } + + snprintf(path, sizeof(path), "%s/%s", basedir, FILE_ASL_STORE_DATA); sd = NULL; memset(&sb, 0, sizeof(struct stat)); if (stat(path, &sb) != 0) { - if (errno != ENOENT) - { - free(path); - return ASL_STATUS_FAILED; - } + if (errno != ENOENT) return ASL_STATUS_FAILED; sd = fopen(path, "w+"); - free(path); if (sd == NULL) return ASL_STATUS_FAILED; @@ -150,7 +150,6 @@ asl_store_open_write(const char *basedir, asl_store_t **s) else { sd = fopen(path, "r+"); - free(path); if (sd == NULL) return ASL_STATUS_FAILED; if (fread(&last_id, sizeof(uint64_t), 1, sd) != 1) @@ -370,7 +369,7 @@ asl_store_sweep_file_cache(asl_store_t *s) static char * asl_store_make_ug_path(const char *dir, const char *base, const char *ext, uid_t ruid, gid_t rgid, uid_t *u, gid_t *g, mode_t *m) { - char *path = NULL; + char *path = NULL; *u = 0; *g = 0; @@ -516,7 +515,8 @@ asl_store_save(asl_store_t *s, asl_msg_t *msg) { struct tm ctm; time_t msg_time, now, bb; - char *path, *tmp_path, *tstring, *scratch; + char *path; + char tstring[128], tmp_path[MAXPATHLEN]; const char *val; uid_t ruid; gid_t rgid; @@ -600,7 +600,6 @@ asl_store_save(asl_store_t *s, asl_msg_t *msg) if (localtime_r((const time_t *)&msg_time, &ctm) == NULL) return ASL_STATUS_FAILED; - tstring = NULL; if (bb == 1) { /* @@ -619,19 +618,14 @@ asl_store_save(asl_store_t *s, asl_msg_t *msg) bb = mktime(&ctm); if (localtime_r((const time_t *)&bb, &ctm) == NULL) return ASL_STATUS_FAILED; - asprintf(&tstring, "BB.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); + snprintf(tstring, sizeof(tstring), "BB.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); } else { - asprintf(&tstring, "%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); + snprintf(tstring, sizeof(tstring), "%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); } - if (tstring == NULL) return ASL_STATUS_NO_MEMORY; - status = asl_store_file_open_write(s, tstring, ruid, rgid, bb, &f, now, check_cache); - free(tstring); - tstring = NULL; - if (status != ASL_STATUS_OK) return status; status = asl_file_save(f, msg, &xid); @@ -652,36 +646,22 @@ asl_store_save(asl_store_t *s, asl_msg_t *msg) if (path != NULL) { - tmp_path = NULL; - len = strlen(path); if ((len >= 4) && (!strcmp(path + len - 4, ".asl"))) { /* rename xxxxxxx.asl to xxxxxxx.timestamp.asl */ - scratch = strdup(path); - if (scratch != NULL) - { - scratch[len - 4] = '\0'; - asprintf(&tmp_path, "%s.%llu.asl", scratch, ftime); - free(scratch); - - } + char scratch[MAXPATHLEN]; + snprintf(scratch, sizeof(scratch), "%s", path); + scratch[len - 4] = '\0'; + snprintf(tmp_path, sizeof(tmp_path), "%s.%llu.asl", scratch, ftime); } else { /* append timestamp */ - asprintf(&tmp_path, "%s.%llu", path, ftime); + snprintf(tmp_path, sizeof(tmp_path), "%s.%llu", path, ftime); } - if (tmp_path == NULL) - { - status = ASL_STATUS_NO_MEMORY; - } - else - { - if (rename(path, tmp_path) != 0) status = ASL_STATUS_FAILED; - free(tmp_path); - } + if (rename(path, tmp_path) != 0) status = ASL_STATUS_FAILED; free(path); } @@ -695,12 +675,11 @@ asl_store_save(asl_store_t *s, asl_msg_t *msg) static ASL_STATUS asl_store_mkdir(asl_store_t *s, const char *dir, mode_t m) { - char *tstring = NULL; + char tstring[MAXPATHLEN]; int status; struct stat sb; - asprintf(&tstring, "%s/%s", s->base_dir, dir); - if (tstring == NULL) return ASL_STATUS_NO_MEMORY; + snprintf(tstring, sizeof(tstring), "%s/%s", s->base_dir, dir); memset(&sb, 0, sizeof(struct stat)); status = stat(tstring, &sb); @@ -708,32 +687,22 @@ asl_store_mkdir(asl_store_t *s, const char *dir, mode_t m) if (status == 0) { /* must be a directory */ - if (!S_ISDIR(sb.st_mode)) - { - free(tstring); - return ASL_STATUS_INVALID_STORE; - } + if (!S_ISDIR(sb.st_mode)) return ASL_STATUS_INVALID_STORE; } else { if (errno == ENOENT) { /* doesn't exist - create it */ - if (mkdir(tstring, m) != 0) - { - free(tstring); - return ASL_STATUS_WRITE_FAILED; - } + if (mkdir(tstring, m) != 0) return ASL_STATUS_WRITE_FAILED; } else { /* stat failed for some other reason */ - free(tstring); return ASL_STATUS_FAILED; } } - free(tstring); return ASL_STATUS_OK; } @@ -742,7 +711,8 @@ asl_store_open_aux(asl_store_t *s, asl_msg_t *msg, int *out_fd, char **url) { struct tm ctm; time_t msg_time, bb; - char *path, *dir, *tstring; + char *path; + char tstring[128], dir[128]; const char *val; uid_t ruid, u; gid_t rgid, g; @@ -782,7 +752,6 @@ asl_store_open_aux(asl_store_t *s, asl_msg_t *msg, int *out_fd, char **url) if (localtime_r((const time_t *)&msg_time, &ctm) == NULL) return ASL_STATUS_FAILED; - dir = NULL; if (bb == 1) { /* @@ -801,35 +770,25 @@ asl_store_open_aux(asl_store_t *s, asl_msg_t *msg, int *out_fd, char **url) bb = mktime(&ctm); if (localtime_r((const time_t *)&bb, &ctm) == NULL) return ASL_STATUS_FAILED; - asprintf(&dir, "BB.AUX.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); + snprintf(dir, sizeof(dir), "BB.AUX.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); } else { - asprintf(&dir, "AUX.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); + snprintf(dir, sizeof(dir), "AUX.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); } - if (dir == NULL) return ASL_STATUS_NO_MEMORY; - status = asl_store_mkdir(s, dir, 0755); - if (status != ASL_STATUS_OK) - { - free(dir); - return status; - } + if (status != ASL_STATUS_OK) return status; fid = s->next_id; s->next_id++; - tstring = NULL; - asprintf(&tstring, "%s/%llu", dir, fid); - free(dir); - if (tstring == NULL) return ASL_STATUS_NO_MEMORY; + snprintf(tstring, sizeof(tstring), "%s/%llu", dir, fid); u = 0; g = 0; m = 0644; path = asl_store_make_ug_path(s->base_dir, tstring, NULL, ruid, rgid, &u, &g, &m); - free(tstring); if (path == NULL) return ASL_STATUS_NO_MEMORY; fd = asl_file_create(path, u, g, m); @@ -857,7 +816,7 @@ asl_store_match(asl_store_t *s, asl_msg_list_t *qlist, uint64_t *last_id, uint64 struct dirent *dent; uint32_t status; asl_file_t *f; - char *path; + char path[MAXPATHLEN]; asl_file_list_t *files; asl_msg_list_t *res; @@ -875,12 +834,10 @@ asl_store_match(asl_store_t *s, asl_msg_list_t *qlist, uint64_t *last_id, uint64 { if (dent->d_name[0] == '.') continue; - path = NULL; - asprintf(&path, "%s/%s", s->base_dir, dent->d_name); + snprintf(path, sizeof(path), "%s/%s", s->base_dir, dent->d_name); /* NB asl_file_open_read will fail if path is NULL, if the file is not an ASL store file, or if it isn't readable */ status = asl_file_open_read(path, &f); - if (path != NULL) free(path); if ((status != ASL_STATUS_OK) || (f == NULL)) continue; files = asl_file_list_add(files, f); @@ -986,7 +943,7 @@ asl_store_match_start(asl_store_t *s, uint64_t start_id, int32_t direction) struct dirent *dent; uint32_t status; asl_file_t *f; - char *path; + char path[MAXPATHLEN]; asl_file_list_t *files; if (s == NULL) return ASL_STATUS_INVALID_STORE; @@ -1006,8 +963,7 @@ asl_store_match_start(asl_store_t *s, uint64_t start_id, int32_t direction) { if (dent->d_name[0] == '.') continue; - path = NULL; - asprintf(&path, "%s/%s", s->base_dir, dent->d_name); + snprintf(path, sizeof(path), "%s/%s", s->base_dir, dent->d_name); /* * NB asl_file_open_read will fail if path is NULL, @@ -1015,7 +971,6 @@ asl_store_match_start(asl_store_t *s, uint64_t start_id, int32_t direction) * We expect that. */ status = asl_file_open_read(path, &f); - if (path != NULL) free(path); if ((status != ASL_STATUS_OK) || (f == NULL)) continue; files = asl_file_list_add(files, f); @@ -1141,7 +1096,6 @@ _jump_search(asl_object_private_t *obj, asl_object_private_t *query) asl_msg_list_t *out = NULL; asl_msg_list_t *ql = NULL; uint64_t last; - uint32_t status = ASL_STATUS_FAILED; if (query == NULL) { @@ -1160,7 +1114,6 @@ _jump_search(asl_object_private_t *obj, asl_object_private_t *query) asl_msg_list_release(ql); } - if (status != ASL_STATUS_OK) return NULL; return (asl_object_private_t *)out; } diff --git a/libsystem_asl.tproj/src/asl_string.c b/libsystem_asl.tproj/src/asl_string.c index 9ab5221..ecb04d3 100644 --- a/libsystem_asl.tproj/src/asl_string.c +++ b/libsystem_asl.tproj/src/asl_string.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2013 Apple Inc. All rights reserved. + * Copyright (c) 2007-2015 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -38,6 +38,9 @@ #define ASL_STRING_QUANTUM 256 static const char *cvis_7_13 = "abtnvfr"; +/* Forward */ +asl_string_t *asl_string_append_no_encoding_len(asl_string_t *str, const char *app, size_t copylen); + asl_string_t * asl_string_new(uint32_t encoding) { @@ -53,7 +56,7 @@ asl_string_new(uint32_t encoding) str->bufsize = 0; str->cursor = 0; - if (encoding & ASL_STRING_LEN) asl_string_append_no_encoding(str, " 0 "); + if (encoding & ASL_STRING_LEN) asl_string_append_no_encoding_len(str, " 0 ", 11); return str; } @@ -90,6 +93,13 @@ asl_string_release_return_bytes(asl_string_t *str) char *out; if (str == NULL) return NULL; + if (str->encoding & ASL_STRING_LEN) + { + char tmp[11]; + snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10); + memcpy(str->buf, tmp, 10); + } + if (OSAtomicDecrement32Barrier(&(str->refcount)) != 0) { /* string is still retained - copy buf */ @@ -98,7 +108,7 @@ asl_string_release_return_bytes(asl_string_t *str) if (str->bufsize == 0) return NULL; vm_address_t new = 0; - kern_return_t kstatus = vm_allocate(mach_task_self(), &new, str->bufsize, TRUE); + kern_return_t kstatus = vm_allocate(mach_task_self(), &new, str->bufsize, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL)); if (kstatus != KERN_SUCCESS) return NULL; memcpy((void *)new, str->buf, str->bufsize); @@ -120,6 +130,14 @@ char * asl_string_bytes(asl_string_t *str) { if (str == NULL) return NULL; + + if (str->encoding & ASL_STRING_LEN) + { + char tmp[11]; + snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10); + memcpy(str->buf, tmp, 10); + } + return str->buf; } @@ -166,7 +184,7 @@ _asl_string_grow(asl_string_t *str, size_t len) kern_return_t kstatus; vm_address_t new = 0; - kstatus = vm_allocate(mach_task_self(), &new, newlen, TRUE); + kstatus = vm_allocate(mach_task_self(), &new, newlen, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL)); if (kstatus != KERN_SUCCESS) { new = 0; @@ -208,32 +226,26 @@ asl_string_append_char_no_encoding(asl_string_t *str, const char c) len = 1; if (str->bufsize == 0) len++; - if (_asl_string_grow(str, len) < 0) return str; str->buf[str->cursor] = c; str->cursor++; str->buf[str->cursor] = '\0'; - if (str->encoding & ASL_STRING_LEN) - { - char tmp[11]; - snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10); - memcpy(str->buf, tmp, 10); - } - return str; } asl_string_t * -asl_string_append_no_encoding(asl_string_t *str, const char *app) +asl_string_append_no_encoding_len(asl_string_t *str, const char *app, size_t copylen) { size_t len, applen; if (str == NULL) return NULL; if (app == NULL) return str; - applen = strlen(app); + applen = copylen; + if (applen == 0) applen = strlen(app); + len = applen; if (str->bufsize == 0) len++; @@ -244,21 +256,21 @@ asl_string_append_no_encoding(asl_string_t *str, const char *app) str->cursor += applen; str->buf[str->cursor] = '\0'; - if (str->encoding & ASL_STRING_LEN) - { - char tmp[11]; - snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10); - memcpy(str->buf, tmp, 10); - } - return str; } +asl_string_t * +asl_string_append_no_encoding(asl_string_t *str, const char *app) +{ + return asl_string_append_no_encoding_len(str, app, 0); +} + static asl_string_t * asl_string_append_internal(asl_string_t *str, const char *app, int encode_space) { - uint8_t x; - const char *p; + uint8_t x, y, z; + const uint8_t *s, *p; + size_t copylen; if (str == NULL) return NULL; if (app == NULL) return str; @@ -267,33 +279,91 @@ asl_string_append_internal(asl_string_t *str, const char *app, int encode_space) { case ASL_ENCODE_NONE: { - return asl_string_append_no_encoding(str, app); + return asl_string_append_no_encoding_len(str, app, 0); } case ASL_ENCODE_SAFE: { /* minor encoding to reduce the likelyhood of spoof attacks */ const char *p; + s = NULL; + copylen = 0; + for (p = app; *p != '\0'; p++) { - if ((*p == 10) || (*p == 13)) + x = p[0]; + y = 0; + z = 0; + + if (x != 0) y = p[1]; + if (y != 0) z = p[2]; + + if ((x == 10) || (x == 13)) { - asl_string_append_no_encoding(str, "\n\t"); + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + + asl_string_append_no_encoding_len(str, "\n\t", 2); } - else if (*p == 8) + else if (x == 8) { - asl_string_append_no_encoding(str, "^H"); + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + + asl_string_append_no_encoding_len(str, "^H", 2); + } + else if ((x == 0xc2) && (y == 0x85)) + { + p++; + + /* next line - format like newline */ + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + + asl_string_append_no_encoding_len(str, "\n\t", 2); + } + else if ((x == 0xe2) && (y == 0x80) && ((z == 0xa8) || (z == 0xa9))) + { + p += 3; + + /* line separator or paragraph separator - format like newline */ + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + + asl_string_append_no_encoding_len(str, "\n\t", 2); } else { - asl_string_append_char_no_encoding(str, *p); + if (s == NULL) s = p; + copylen++; } } + if (copylen > 0) asl_string_append_no_encoding_len(str, s, copylen); + return str; } case ASL_ENCODE_ASL: { + s = NULL; + copylen = 0; + for (p = app; *p != '\0'; p++) { int meta = 0; @@ -306,11 +376,25 @@ asl_string_append_internal(asl_string_t *str, const char *app, int encode_space) /* except meta-space, which is \240 */ if (x == 160) { - asl_string_append_no_encoding(str, "\\240"); + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + + asl_string_append_no_encoding_len(str, "\\240", 4); continue; } - asl_string_append_no_encoding(str, "\\M"); + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + + asl_string_append_no_encoding_len(str, "\\M", 2); x &= 0x7f; meta = 1; } @@ -320,26 +404,48 @@ asl_string_append_internal(asl_string_t *str, const char *app, int encode_space) { if (encode_space == 0) { - asl_string_append_char_no_encoding(str, ' '); + if (s == NULL) s = p; + copylen++; continue; } - asl_string_append_no_encoding(str, "\\s"); + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + + asl_string_append_no_encoding_len(str, "\\s", 2); continue; } /* \ is escaped */ if ((meta == 0) && (x == 92)) { - asl_string_append_no_encoding(str, "\\\\"); + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + + asl_string_append_no_encoding_len(str, "\\\\", 2); continue; } /* [ and ] are escaped in ASL encoding */ if ((str->encoding & ASL_ENCODE_ASL) && (meta == 0) && ((*p == 91) || (*p == 93))) { - if (*p == '[') asl_string_append_no_encoding(str, "\\["); - else asl_string_append_no_encoding(str, "\\]"); + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + + if (*p == '[') asl_string_append_no_encoding_len(str, "\\[", 2); + else asl_string_append_no_encoding_len(str, "\\]", 2); continue; } @@ -348,10 +454,24 @@ asl_string_append_internal(asl_string_t *str, const char *app, int encode_space) { if (meta == 0) { + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + asl_string_append_char_no_encoding(str, '\\'); } - asl_string_append_no_encoding(str, "^?"); + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + + asl_string_append_no_encoding_len(str, "^?", 2); continue; } @@ -360,16 +480,34 @@ asl_string_append_internal(asl_string_t *str, const char *app, int encode_space) { if (meta == 1) { + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + asl_string_append_char_no_encoding(str, '-'); + asl_string_append_char_no_encoding(str, x); + continue; } - asl_string_append_char_no_encoding(str, x); + if (s == NULL) s = p; + copylen++; + continue; } /* non-meta BEL, BS, HT, NL, VT, NP, CR (7-13) are \a, \b, \t, \n, \v, \f, and \r */ if ((meta == 0) && (x >= 7) && (x <= 13)) { + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + asl_string_append_char_no_encoding(str, '\\'); asl_string_append_char_no_encoding(str, cvis_7_13[x - 7]); continue; @@ -380,56 +518,133 @@ asl_string_append_internal(asl_string_t *str, const char *app, int encode_space) { if (meta == 0) { + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + asl_string_append_char_no_encoding(str, '\\'); } + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + asl_string_append_char_no_encoding(str, '^'); asl_string_append_char_no_encoding(str, 64 + x); continue; } - asl_string_append_char_no_encoding(str, x); + if (s == NULL) s = p; + copylen++; + } + + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; } return str; } case ASL_ENCODE_XML: { + s = NULL; + copylen = 0; + for (p = app; *p != '\0'; p++) { x = *p; if (x == '&') { - asl_string_append_no_encoding(str, "&"); + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + + asl_string_append_no_encoding_len(str, "&", 5); } else if (x == '<') { - asl_string_append_no_encoding(str, "<"); + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + + asl_string_append_no_encoding_len(str, "<", 4); } else if (x == '>') { - asl_string_append_no_encoding(str, ">"); + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + + asl_string_append_no_encoding_len(str, ">", 4); } else if (x == '"') { - asl_string_append_no_encoding(str, """); + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + + asl_string_append_no_encoding_len(str, """, 6); } else if (x == '\'') { - asl_string_append_no_encoding(str, "'"); + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + + asl_string_append_no_encoding_len(str, "'", 6); } else if (iscntrl(x)) { + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + char tmp[8]; snprintf(tmp, sizeof(tmp), "&#x%02hhx;", x); - asl_string_append_no_encoding(str, tmp); + asl_string_append_no_encoding_len(str, tmp, 6); } else { - asl_string_append_char_no_encoding(str, x); + if (s == NULL) s = p; + copylen++; } } + + if (copylen > 0) + { + asl_string_append_no_encoding_len(str, s, copylen); + s = NULL; + copylen = 0; + } + + return str; } default: { @@ -514,19 +729,19 @@ asl_string_append_op(asl_string_t *str, uint32_t op) } opstr[i] = '\0'; - return asl_string_append_no_encoding(str, opstr); + return asl_string_append_no_encoding_len(str, opstr, 0); } asl_string_t * asl_string_append_xml_tag(asl_string_t *str, const char *tag, const char *s) { - asl_string_append_no_encoding(str, "\t\t<"); - asl_string_append_no_encoding(str, tag); - asl_string_append_no_encoding(str, ">"); + asl_string_append_no_encoding_len(str, "\t\t<", 3); + asl_string_append_no_encoding_len(str, tag, 0); + asl_string_append_char_no_encoding(str, '>'); asl_string_append_internal(str, s, 0); - asl_string_append_no_encoding(str, "\n"); + asl_string_append_no_encoding_len(str, "\n", 2); return str; } diff --git a/libsystem_asl.tproj/src/asl_util.c b/libsystem_asl.tproj/src/asl_util.c index 2965f97..45f9409 100644 --- a/libsystem_asl.tproj/src/asl_util.c +++ b/libsystem_asl.tproj/src/asl_util.c @@ -35,6 +35,7 @@ #include #include #include +#include #include static uint8_t *b64charset = (uint8_t *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; diff --git a/libsystem_asl.tproj/src/syslog.c b/libsystem_asl.tproj/src/syslog.c index 91fb213..1975d4d 100644 --- a/libsystem_asl.tproj/src/syslog.c +++ b/libsystem_asl.tproj/src/syslog.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2013 Apple Inc. All rights reserved. + * Copyright (c) 1999-2015 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -65,6 +65,8 @@ #include #include #include +#include +#include #ifdef __STDC__ #include @@ -77,79 +79,150 @@ extern const char *asl_syslog_faciliy_num_to_name(int n); #ifdef BUILDING_VARIANT __private_extern__ pthread_mutex_t _sl_lock; -__private_extern__ aslclient _sl_asl; +__private_extern__ asl_object_t _sl_asl; __private_extern__ char *_sl_ident; __private_extern__ int _sl_fac; __private_extern__ int _sl_opts; __private_extern__ int _sl_mask; #else /* !BUILDING_VARIANT */ __private_extern__ pthread_mutex_t _sl_lock = PTHREAD_MUTEX_INITIALIZER; -__private_extern__ aslclient _sl_asl = NULL; +__private_extern__ asl_object_t _sl_asl = NULL; __private_extern__ char *_sl_ident = NULL; __private_extern__ int _sl_fac = 0; __private_extern__ int _sl_opts = 0; __private_extern__ int _sl_mask = 0; #endif /* BUILDING_VARIANT */ +#define EVAL_ASL (EVAL_SEND_ASL | EVAL_TEXT_FILE | EVAL_ASL_FILE) + +static const uint8_t shim_syslog_to_trace_type[8] = { + OS_TRACE_TYPE_FAULT, OS_TRACE_TYPE_FAULT, OS_TRACE_TYPE_FAULT, // LOG_EMERG, LOG_ALERT, LOG_CRIT + OS_TRACE_TYPE_ERROR, // LOG_ERROR + OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_RELEASE, // LOG_WARN, LOG_NOTICE, LOG_INFO + OS_TRACE_TYPE_DEBUG // LOG_DEBUG +}; + +extern uint32_t _asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel); +extern uint32_t _asl_lib_vlog(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *format, va_list ap); + + +/* SHIM SPI */ +asl_object_t +_syslog_asl_client() +{ + pthread_mutex_lock(&_sl_lock); + if (_sl_asl == NULL) + { + _sl_asl = asl_open(NULL, NULL, ASL_OPT_SYSLOG_LEGACY); + _sl_mask = ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG); + asl_set_filter(_sl_asl, _sl_mask); + } + pthread_mutex_unlock(&_sl_lock); + + return _sl_asl; +} + /* * syslog, vsyslog -- * print message on log file; output is intended for syslogd(8). */ + +void +vsyslog(int pri, const char *fmt, va_list ap) +{ + int level = pri & LOG_PRIMASK; + uint32_t eval; + + _syslog_asl_client(); + + eval = _asl_evaluate_send(_sl_asl, NULL, level); + + if (eval & EVAL_SEND_TRACE) + { + va_list ap_copy; + uint8_t trace_type = shim_syslog_to_trace_type[level]; + + va_copy(ap_copy, ap); + os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, fmt, ap_copy, NULL); + va_end(ap_copy); + } + + if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL)) + { + asl_object_t msg = asl_new(ASL_TYPE_MSG); + const char *facility; + int fac = pri & LOG_FACMASK; + + if (fac != 0) + { + facility = asl_syslog_faciliy_num_to_name(fac); + if (facility != NULL) asl_set(msg, ASL_KEY_FACILITY, facility); + } + + if (eval & EVAL_SEND_TRACE) asl_set(msg, "ASLSHIM", "2"); + + _asl_lib_vlog(_sl_asl, eval, msg, fmt, ap); + + asl_release(msg); + } +} + void #ifdef __STDC__ syslog(int pri, const char *fmt, ...) #else syslog(pri, fmt, va_alist) - int pri; - char *fmt; - va_dcl +int pri; +char *fmt; +va_dcl #endif { - va_list ap; - + int level = pri & LOG_PRIMASK; + uint32_t eval; + + _syslog_asl_client(); + + eval = _asl_evaluate_send(_sl_asl, NULL, level); + + if (eval & EVAL_SEND_TRACE) + { + va_list ap; + uint8_t trace_type = shim_syslog_to_trace_type[level]; + #ifdef __STDC__ - va_start(ap, fmt); + va_start(ap, fmt); #else - va_start(ap); + va_start(ap); #endif - vsyslog(pri, fmt, ap); - va_end(ap); -} - -void -vsyslog(int pri, const char *fmt, va_list ap) -{ - int fac; - asl_msg_t *facmsg; - const char *facility; - - facmsg = NULL; - fac = pri & LOG_FACMASK; - if (fac != 0) + os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, fmt, ap, NULL); + va_end(ap); + } + + if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL)) { - facility = asl_syslog_faciliy_num_to_name(fac); - if (facility != NULL) + va_list ap; + asl_object_t msg = asl_new(ASL_TYPE_MSG); + const char *facility; + int fac = pri & LOG_FACMASK; + + if (fac != 0) { - facmsg = asl_msg_new(ASL_TYPE_MSG); - asl_msg_set_key_val(facmsg, ASL_KEY_FACILITY, facility); + facility = asl_syslog_faciliy_num_to_name(fac); + if (facility != NULL) asl_set(msg, ASL_KEY_FACILITY, facility); } + + if (eval & EVAL_SEND_TRACE) asl_set(msg, "ASLSHIM", "2"); + +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + _asl_lib_vlog(_sl_asl, eval, msg, fmt, ap); + va_end(ap); + + asl_release(msg); } - - pthread_mutex_lock(&_sl_lock); - - /* open syslog ASL client if required */ - if (_sl_asl == NULL) - { - _sl_asl = asl_open(NULL, NULL, ASL_OPT_SYSLOG_LEGACY); - _sl_mask = ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG); - asl_set_filter(_sl_asl, _sl_mask); - } - - asl_vlog(_sl_asl, (aslmsg)facmsg, LOG_PRI(pri), fmt, ap); - - pthread_mutex_unlock(&_sl_lock); - - if (facmsg != NULL) asl_msg_release(facmsg); } #ifndef BUILDING_VARIANT @@ -162,7 +235,7 @@ openlog(const char *ident, int opts, int logfac) pthread_mutex_lock(&_sl_lock); - if (_sl_asl != NULL) asl_close(_sl_asl); + if (_sl_asl != NULL) asl_release(_sl_asl); _sl_asl = NULL; free(_sl_ident); diff --git a/syslog.xcodeproj/project.pbxproj b/syslog.xcodeproj/project.pbxproj index 566416b..31b7100 100644 --- a/syslog.xcodeproj/project.pbxproj +++ b/syslog.xcodeproj/project.pbxproj @@ -33,7 +33,6 @@ isa = PBXAggregateTarget; buildConfigurationList = 3FFD4402174862D0007DAC1B /* Build configuration list for PBXAggregateTarget "executables_Sim" */; buildPhases = ( - 3F5F5B9C17487ADB00C12281 /* Configuration */, ); dependencies = ( 3FFD440717486325007DAC1B /* PBXTargetDependency */, @@ -59,6 +58,7 @@ /* Begin PBXBuildFile section */ 2D30656E150E6EFF00F31A54 /* asl_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D30656C150E6EFF00F31A54 /* asl_common.c */; }; + 2D30D2811AE6C84200673818 /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D30D27F1AE6C84200673818 /* daemon.c */; }; 2D31F3C517E77F3300F2A60C /* asl_client.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D31F3C117E77F3300F2A60C /* asl_client.h */; settings = {ATTRIBUTES = (Private, ); }; }; 2D31F3C617E77F3300F2A60C /* asl_msg_list.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D31F3C217E77F3300F2A60C /* asl_msg_list.h */; settings = {ATTRIBUTES = (Private, ); }; }; 2D31F3C717E77F3300F2A60C /* asl_object.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D31F3C317E77F3300F2A60C /* asl_object.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -69,7 +69,11 @@ 2D31F3D017E77F8800F2A60C /* asl_string.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D31F3CC17E77F8800F2A60C /* asl_string.c */; }; 2D60F61115657D0F00F2E3F9 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D60F61015657D0F00F2E3F9 /* libz.dylib */; }; 2D9DEB64150E6FE80059BA61 /* asl_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D30656D150E6EFF00F31A54 /* asl_common.h */; }; + 2DAF75551AE8613000054190 /* com.apple.activity_tracing.CacheDelete.plist in Copy CacheDelete plist */ = {isa = PBXBuildFile; fileRef = 2DAF75541AE8610200054190 /* com.apple.activity_tracing.CacheDelete.plist */; }; 2DCF701A150E97C0002D5E8F /* libaslcommon.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 505ACB9D108FD16400197086 /* libaslcommon.a */; }; + 2DEE8C411AE575A2007B5CBE /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DEE8C401AE575A2007B5CBE /* CoreFoundation.framework */; }; + 2DEE8C431AE575AB007B5CBE /* CacheDelete.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DEE8C421AE575AB007B5CBE /* CacheDelete.framework */; }; + 2DEE8C461AE5798B007B5CBE /* cache_delete.c in Sources */ = {isa = PBXBuildFile; fileRef = 2DEE8C441AE5798B007B5CBE /* cache_delete.c */; }; 3F6F43F21613A8E300CA9ADB /* asl.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F6F43CF1613A8E300CA9ADB /* asl.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3F6F43F31613A8E300CA9ADB /* asl_core.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F6F43D01613A8E300CA9ADB /* asl_core.h */; settings = {ATTRIBUTES = (Private, ); }; }; 3F6F43F41613A8E300CA9ADB /* asl_file.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F6F43D11613A8E300CA9ADB /* asl_file.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -181,10 +185,21 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ + 2D30D27D1AE6BBA000673818 /* Copy CacheDelete plist */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /System/Library/CacheDelete; + dstSubfolderSpec = 0; + files = ( + 2DAF75551AE8613000054190 /* com.apple.activity_tracing.CacheDelete.plist in Copy CacheDelete plist */, + ); + name = "Copy CacheDelete plist"; + runOnlyForDeploymentPostprocessing = 1; + }; 3F6F44131613AA9300CA9ADB /* Install man3 */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; - dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man3"; + dstPath = /usr/share/man/man3; dstSubfolderSpec = 0; files = ( 3F6F44141613AAA600CA9ADB /* asl.3 in Install man3 */, @@ -196,7 +211,7 @@ 503A82631099037D00B0D08A /* Copy Manpage.8 */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; - dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man8"; + dstPath = /usr/share/man/man8; dstSubfolderSpec = 0; files = ( 503A82741099045F00B0D08A /* aslmanager.8 in Copy Manpage.8 */, @@ -207,7 +222,7 @@ 503A8285109904FD00B0D08A /* Copy Manpage.1 */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; - dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man1"; + dstPath = /usr/share/man/man1; dstSubfolderSpec = 0; files = ( 503A82761099049900B0D08A /* syslog.1 in Copy Manpage.1 */, @@ -218,7 +233,7 @@ 503A8286109904FD00B0D08A /* Copy Manpage.8 */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; - dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man8"; + dstPath = /usr/share/man/man8; dstSubfolderSpec = 0; files = ( 503A8278109904C000B0D08A /* syslogd.8 in Copy Manpage.8 */, @@ -229,7 +244,7 @@ 503A8287109904FD00B0D08A /* Copy Manpages.5 */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; - dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man5"; + dstPath = /usr/share/man/man5; dstSubfolderSpec = 0; files = ( 503A827A109904E400B0D08A /* asl.conf.5 in Copy Manpages.5 */, @@ -243,6 +258,8 @@ /* Begin PBXFileReference section */ 2D30656C150E6EFF00F31A54 /* asl_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_common.c; sourceTree = ""; }; 2D30656D150E6EFF00F31A54 /* asl_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_common.h; sourceTree = ""; }; + 2D30D27F1AE6C84200673818 /* daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = daemon.c; path = aslmanager.tproj/daemon.c; sourceTree = ""; }; + 2D30D2801AE6C84200673818 /* daemon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = daemon.h; path = aslmanager.tproj/daemon.h; sourceTree = ""; }; 2D31F3C117E77F3300F2A60C /* asl_client.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_client.h; sourceTree = ""; }; 2D31F3C217E77F3300F2A60C /* asl_msg_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_msg_list.h; sourceTree = ""; }; 2D31F3C317E77F3300F2A60C /* asl_object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_object.h; sourceTree = ""; }; @@ -252,8 +269,14 @@ 2D31F3CB17E77F8800F2A60C /* asl_object.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_object.c; sourceTree = ""; }; 2D31F3CC17E77F8800F2A60C /* asl_string.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_string.c; sourceTree = ""; }; 2D60F61015657D0F00F2E3F9 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; + 2D9C4F131B3A29E700219FB3 /* com.apple.system.log */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = com.apple.system.log; path = syslogd.tproj/com.apple.system.log; sourceTree = ""; }; + 2DAF75541AE8610200054190 /* com.apple.activity_tracing.CacheDelete.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.activity_tracing.CacheDelete.plist; path = aslmanager.tproj/com.apple.activity_tracing.CacheDelete.plist; sourceTree = ""; }; 2DB4DA0A125FC69A001CDC45 /* after_install.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = after_install.sh; path = syslogd.tproj/after_install.sh; sourceTree = ""; }; 2DB8178915589D0C004D0BDE /* entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; name = entitlements.plist; path = util.tproj/entitlements.plist; sourceTree = ""; }; + 2DEE8C401AE575A2007B5CBE /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = ../../../../../../../../System/Library/Frameworks/CoreFoundation.framework; sourceTree = ""; }; + 2DEE8C421AE575AB007B5CBE /* CacheDelete.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CacheDelete.framework; path = ../../../../../../../../System/Library/PrivateFrameworks/CacheDelete.framework; sourceTree = ""; }; + 2DEE8C441AE5798B007B5CBE /* cache_delete.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cache_delete.c; path = aslmanager.tproj/cache_delete.c; sourceTree = ""; }; + 2DEE8C451AE5798B007B5CBE /* cache_delete.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cache_delete.h; path = aslmanager.tproj/cache_delete.h; sourceTree = ""; }; 3F6B6311185AF66C00F692C5 /* aslmanager.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = aslmanager.xcconfig; sourceTree = ""; }; 3F6B6312185AF66C00F692C5 /* base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = base.xcconfig; sourceTree = ""; }; 3F6B6313185AF66C00F692C5 /* syslogd.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = syslogd.xcconfig; sourceTree = ""; }; @@ -277,7 +300,10 @@ 3F6F43E81613A8E300CA9ADB /* asl_store.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_store.c; sourceTree = ""; }; 3F6F43E91613A8E300CA9ADB /* asl_util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_util.c; sourceTree = ""; }; 3F900DB619383950003CA7E6 /* sim-compat-symlink.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "sim-compat-symlink.sh"; sourceTree = ""; }; - 3FCCB5361749B53D00F8FEBC /* asl_sim.conf */ = {isa = PBXFileReference; lastKnownFileType = text; name = asl_sim.conf; path = syslogd.tproj/asl_sim.conf; sourceTree = ""; }; + 3FCCB5361749B53D00F8FEBC /* asl.conf.ios_sim */ = {isa = PBXFileReference; lastKnownFileType = text; name = asl.conf.ios_sim; path = syslogd.tproj/asl.conf.ios_sim; sourceTree = ""; }; + 3FE6E8391A529FEF0075D75F /* asl.conf.ios */ = {isa = PBXFileReference; lastKnownFileType = text; name = asl.conf.ios; path = syslogd.tproj/asl.conf.ios; sourceTree = ""; }; + 3FE6E83A1A529FEF0075D75F /* asl.conf.osx */ = {isa = PBXFileReference; lastKnownFileType = text; name = asl.conf.osx; path = syslogd.tproj/asl.conf.osx; sourceTree = ""; }; + 3FE6E83B1A529FEF0075D75F /* syslog.conf */ = {isa = PBXFileReference; lastKnownFileType = text; name = syslog.conf; path = syslogd.tproj/syslog.conf; sourceTree = ""; }; 3FE798E316161F2A00D547B0 /* syslog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = syslog.c; sourceTree = ""; }; 3FE798E516161F3A00D547B0 /* syslog.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = syslog.3; sourceTree = ""; }; 3FFD43F817485C5B007DAC1B /* libasl.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = libasl.xcconfig; sourceTree = ""; }; @@ -323,6 +349,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 2DEE8C431AE575AB007B5CBE /* CacheDelete.framework in Frameworks */, + 2DEE8C411AE575A2007B5CBE /* CoreFoundation.framework in Frameworks */, 2D60F61115657D0F00F2E3F9 /* libz.dylib in Frameworks */, 2DCF701A150E97C0002D5E8F /* libaslcommon.a in Frameworks */, ); @@ -358,6 +386,8 @@ 08FB7794FE84155DC02AAC07 /* syslog */ = { isa = PBXGroup; children = ( + 2DEE8C421AE575AB007B5CBE /* CacheDelete.framework */, + 2DEE8C401AE575A2007B5CBE /* CoreFoundation.framework */, 505ACBA1108FD18400197086 /* aslcommon */, 503917691091404D0001165E /* aslmanager */, 503917C41091412B0001165E /* util */, @@ -454,8 +484,13 @@ 503917691091404D0001165E /* aslmanager */ = { isa = PBXGroup; children = ( + 2DAF75541AE8610200054190 /* com.apple.activity_tracing.CacheDelete.plist */, + 2DEE8C441AE5798B007B5CBE /* cache_delete.c */, + 2DEE8C451AE5798B007B5CBE /* cache_delete.h */, 5039176B1091408B0001165E /* aslmanager.8 */, 5039176C1091408B0001165E /* aslmanager.c */, + 2D30D27F1AE6C84200673818 /* daemon.c */, + 2D30D2801AE6C84200673818 /* daemon.h */, 5039176D1091408B0001165E /* com.apple.aslmanager.plist */, ); name = aslmanager; @@ -464,7 +499,11 @@ 503917711091409F0001165E /* syslogd */ = { isa = PBXGroup; children = ( - 3FCCB5361749B53D00F8FEBC /* asl_sim.conf */, + 3FE6E8391A529FEF0075D75F /* asl.conf.ios */, + 2D9C4F131B3A29E700219FB3 /* com.apple.system.log */, + 3FE6E83A1A529FEF0075D75F /* asl.conf.osx */, + 3FCCB5361749B53D00F8FEBC /* asl.conf.ios_sim */, + 3FE6E83B1A529FEF0075D75F /* syslog.conf */, 503917A61091410E0001165E /* asl_action.c */, 2DB4DA0A125FC69A001CDC45 /* after_install.sh */, 503917A81091410E0001165E /* asl.conf.5 */, @@ -580,6 +619,7 @@ 50391764109140450001165E /* Frameworks */, 503A82631099037D00B0D08A /* Copy Manpage.8 */, FCAC6D7410AB34C9008DEAC9 /* ShellScript */, + 2D30D27D1AE6BBA000673818 /* Copy CacheDelete plist */, ); buildRules = ( ); @@ -683,20 +723,6 @@ /* End PBXProject section */ /* Begin PBXShellScriptBuildPhase section */ - 3F5F5B9C17487ADB00C12281 /* Configuration */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 8; - files = ( - ); - inputPaths = ( - ); - name = Configuration; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 1; - shellPath = /bin/sh; - shellScript = "mkdir -p ${DSTROOT}${INSTALL_PATH_PREFIX}/etc\ncp ${SRCROOT}/syslogd.tproj/asl_sim.conf ${DSTROOT}${INSTALL_PATH_PREFIX}/etc/asl.conf\n"; - }; 3F900DB41938393C003CA7E6 /* Sim compat symlink */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 8; @@ -737,7 +763,7 @@ ); runOnlyForDeploymentPostprocessing = 1; shellPath = /bin/sh; - shellScript = "set -e\n\nDESTDIR=\"$DSTROOT$INSTALL_PATH_PREFIX\"/System/Library/LaunchDaemons\ninstall -d -m 0755 -o root -g wheel -d \"$DESTDIR\"\ninstall -m 0644 -o root -g wheel \"$SRCROOT\"/aslmanager.tproj/com.apple.aslmanager.plist \"$DESTDIR\"\nplutil -convert binary1 \"$DESTDIR\"/com.apple.aslmanager.plist"; + shellScript = "set -e\n\nDESTDIR=\"$DSTROOT\"/System/Library/LaunchDaemons\ninstall -d -m 0755 -o root -g wheel -d \"$DESTDIR\"\ninstall -m 0644 -o root -g wheel \"$SRCROOT\"/aslmanager.tproj/com.apple.aslmanager.plist \"$DESTDIR\"\nplutil -convert binary1 \"$DESTDIR\"/com.apple.aslmanager.plist"; showEnvVarsInLog = 0; }; FCF3762A10D2F47C00C0EC8D /* ShellScript */ = { @@ -781,7 +807,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2D30D2811AE6C84200673818 /* daemon.c in Sources */, 5039176F1091408B0001165E /* aslmanager.c in Sources */, + 2DEE8C461AE5798B007B5CBE /* cache_delete.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -950,11 +978,16 @@ COPY_PHASE_STRIP = YES; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + ); GCC_DYNAMIC_NO_PIC = NO; OTHER_CFLAGS = ( "-Wall", "-DINET6", ); + OTHER_LDFLAGS = ""; PRODUCT_NAME = aslmanager; ZERO_LINK = NO; }; diff --git a/syslogd.tproj/after_install.sh b/syslogd.tproj/after_install.sh index d54cd6a..6fb20af 100755 --- a/syslogd.tproj/after_install.sh +++ b/syslogd.tproj/after_install.sh @@ -1,35 +1,44 @@ -#! /bin/bash -set -e +#! /bin/bash -e -x -if [ "${RC_ProjectName%_Sim}" != "${RC_ProjectName}" ] ; then +if [[ "${PLATFORM_NAME}" =~ "simulator" ]] ; then PLIST="${SRCROOT}"/syslogd.tproj/com.apple.syslogd_sim.plist + ASL_CONF="${SRCROOT}"/syslogd.tproj/asl.conf.ios_sim +elif [[ "${PLATFORM_NAME}" == "macosx" ]] ; then + PLIST="${SRCROOT}"/syslogd.tproj/com.apple.syslogd.plist + ASL_CONF="${SRCROOT}"/syslogd.tproj/asl.conf.osx + SYSLOG_CONF="${SRCROOT}"/syslogd.tproj/syslog.conf else PLIST="${SRCROOT}"/syslogd.tproj/com.apple.syslogd.plist + ASL_CONF="${SRCROOT}"/syslogd.tproj/asl.conf.ios + SYSLOG_CONF="${SRCROOT}"/syslogd.tproj/syslog.conf + SYSTEM_LOG_CONF="${SRCROOT}"/syslogd.tproj/com.apple.system.log fi -DESTDIR="${DSTROOT}${INSTALL_PATH_PREFIX}"/System/Library/LaunchDaemons +DESTDIR="${DSTROOT}"/private/etc +install -d -m 0755 -o root -g wheel "${DESTDIR}" +install -m 0644 -o root -g wheel "${ASL_CONF}" "${DESTDIR}"/asl.conf +if [[ -n "${SYSLOG_CONF}" ]] ; then + install -m 0644 -o root -g wheel "${SYSLOG_CONF}" "${DESTDIR}" +fi +DESTDIR="${DSTROOT}"/System/Library/LaunchDaemons install -d -m 0755 -o root -g wheel "${DESTDIR}" install -m 0644 -o root -g wheel "${PLIST}" "${DESTDIR}"/com.apple.syslogd.plist plutil -convert binary1 "${DESTDIR}"/com.apple.syslogd.plist -if [ "${RC_ProjectName%_Sim}" != "${RC_ProjectName}" ] ; then +if [[ "${PLATFORM_NAME}" =~ "simulator" ]] ; then exit 0 fi install -d -m 0755 -o root -g wheel "$DSTROOT"/private/var/log/asl -PRODUCT=$(xcodebuild -sdk "${SDKROOT}" -version PlatformPath | head -1 | sed 's,^.*/\([^/]*\)\.platform$,\1,') - -if [ ${SDKROOT}x = x ]; then - PRODUCT=MacOSX -fi - -if [ ${PRODUCT}x = x ]; then - PRODUCT=MacOSX -fi - -if [ ${PRODUCT} = iPhone ]; then +if [[ "${PLATFORM_NAME}" != "macosx" ]]; then install -d -m 0755 -o root -g wheel "$DSTROOT"/usr/share/sandbox install -m 0644 -o root -g wheel "$SRCROOT"/syslogd.tproj/syslogd.sb "$DSTROOT"/usr/share/sandbox fi + +if ! [[ "${PLATFORM_NAME}" =~ "simulator" || "${PLATFORM_NAME}" == "macosx" ]]; then + DESTDIR="${DSTROOT}"/usr/local/etc/asl + install -d -m 0755 -o root -g wheel "${DESTDIR}" + install -m 0644 -o root -g wheel "${SYSTEM_LOG_CONF}" "${DESTDIR}"/com.apple.system.log +fi diff --git a/syslogd.tproj/asl.conf.5 b/syslogd.tproj/asl.conf.5 index 5d6e115..4402046 100644 --- a/syslogd.tproj/asl.conf.5 +++ b/syslogd.tproj/asl.conf.5 @@ -523,63 +523,26 @@ The FILE ROTATION section describes this in detail. .It rotate=NAME_STYLE Enables log file rotation and specifies the file naming scheme for rotated files. This option does not apply to ASL directories. -Four styles are supported: -.Pp -.Bl -tag -width "local-basic" -compact -indent -.It sec -Rotated file names are of the form -.Dq example.log.T1340607600 . -The file names include the creation time of the file in seconds since the epoch. -.Pp -.It utc -Rotated file names are in ISO 8601 extended format, for example -.Dq example.log.2012-06-24T07:00:00Z . -The file names includes its creation time as a UTC date and time. -.Pp -.It utc-basic -Rotated file names are in ISO 8601 basic format, for example -.Dq example.log.20120624T070000Z . -The file names includes its creation time as a UTC date and time. -.Pp -.It local -Rotated file names are in ISO 8601 extended format, for example -.Dq example.log.2012-06-24T07:00:00-7 . -The file names includes its creation time as date and time in the local time zone. -The local timezone offset is included as a trailing part of the name. -.Pp -.It local-basic -Rotated file names are in ISO 8601 basic format, for example -.Dq example.log.20120624T070000-07 . -The file names includes its creation time as date and time in the local time zone. -The local timezone offset is included as a trailing part of the name. -.Pp -.It seq -Rotated file names are of the form -.Dq example.log.N -where N is an integer sequence number. -Files are re-numbered on each rotation so that the -.Dq 0 -file is the most recent. -.El +NAME_STYLE may either be a simple time-stamp style: +.Dq sec , +.Dq utc , +.Dq utc-basic , +.Dq local , +.Dq local-basic , +or +.Dq seq ; +or the value may contain the file's base name, a file name extension, and one of the time-stame styles. +For example +.Dq example.seq.log +or +.Dq example.log.utc-basic. +A detailed description of name styles may be found in the FILE ROTATION section below. .Pp If the option .Dq rotate appears without a value, the naming style defaults to .Dq "sec" . .Pp -Note that using the local timezone for timestamped files may cause odd behavior on highly-mobile systems. -.Nm aslmanager -will delete files after a specified time-to-live (see below). -The age of the file is determined by the file name. -If files are created in different timezones but saved with a non-absolute timestamp, -the age calculation may result in some files being considered older or newer than they are in reality. -.Pp -Also note that sequenced files (using the -.Dq seq -style) will initially be checkpointed using a file name containing a timestamp in seconds. -.Nm aslmanager -will re-sequence the files when it scans for checkpoint files. -.Pp .It ttl=DAYS Specifies the number of days that older versions of rotated files should be allowed to remain in the filesystem. Rotated files older than this limit are deleted. @@ -605,6 +568,13 @@ Enables gzip file compression for rotated log files. When compressed, the extension .Dq .gz is appended to the file name. +When the output is an ASL directory, data files are compressed after midnight local time. +This means that messages written in the current day will be readable using +.Nm syslog Fl d +or using the +.Xr asl 3 +API. +Messages in compressed data files will not be available until the files are un-compressed. .Pp .It file_max=SIZE Limits the size of an active log file. @@ -629,17 +599,130 @@ Specifies a size limit for the total of all rotated versions of a file. .Nm aslmanager will delete rotated files, oldest first, to reduce the total below the limit. SIZE may be specified in the same format as the file_max option. +.Pp +.It basestamp +Causes +.Nm syslogd +to add a timestamp to the file name when it is created. +For example, +.Pp +.Dl +> example.log rotate=utc-basic basestamp +.Pp +will result in syslogd writing to, e.g. +.Dq example.log.20120625T070000Z +rather than to +.Dq example.log . +Note that this option does nothing with sequenced (``seq'') files. +.Pp +.It symlink +This option may only be used together with the basestamp option. +It causes +.Nm syslogd +to create a symlink with the unstamped file name to the currently active log file. +For example, +.Pp +.Dl +> example.log rotate=sec basestamp symlink +.Pp +will result in syslogd writing to, e.g. +.Dq example.log.T1340607600 , +and creating a sybolic link from +.Dq example.log +to the active file. +.Pp .El .Ss FILE ROTATION .Nm syslogd and .Nm aslmanager -work together to automatically provide all the features of file rotation. -However, it is useful to understand how the process works. +work together to provide the features of file rotation. This section describes the file rotation options that may be used in /etc/asl.conf or an ASL Output Module configuration file, together with a description of how the system works to support those features. .Pp +File rotation or file rolling is enabled by the +.Dq rotate +output configuration option. +It is typically specificed with a value which specifies the naming sytle for rotated files. +Name styles may simply be a timestamp format, which is appended to the filename. +.Pp +.Bl -tag -width "local-basic" -compact -indent +.It sec +Rotated file names are of the form +.Dq example.log.T1340607600 . +The file names include the creation time of the file in seconds since the epoch. +.Pp +.It utc +Rotated file names are in ISO 8601 extended format, for example +.Dq example.log.2012-06-24T07:00:00Z . +The file names includes its creation time as a UTC date and time. +.Pp +.It utc-basic +Rotated file names are in ISO 8601 basic format, for example +.Dq example.log.20120624T070000Z . +The file names includes its creation time as a UTC date and time. +.Pp +.It local +Rotated file names are in ISO 8601 extended format, for example +.Dq example.log.2012-06-24T07:00:00-7 . +The file names includes its creation time as date and time in the local time zone. +The local timezone offset is included as a trailing part of the name. +The value +.Dq lcl +is an alias for +.Dq local . +.Pp +.It local-basic +Rotated file names are in ISO 8601 basic format, for example +.Dq example.log.20120624T070000-07 . +The file names includes its creation time as date and time in the local time zone. +The local timezone offset is included as a trailing part of the name. +The value +.Dq lcl-basic +is an alias for +.Dq local-basic . +.Pp +.It seq +Rotated file names are of the form +.Dq example.log.N +where N is an integer sequence number. +Files are re-numbered on each rotation so that the +.Dq 0 +file is the most recent. +.El +.Pp +Note that using the local timezone for timestamped files may cause odd behavior on highly mobile systems. +.Nm aslmanager +will delete files after a specified time-to-live (see below). +The age of the file is determined by the file name. +If files are created in different timezones but saved with a non-absolute timestamp, +the age calculation may result in some files being considered older or newer than they are in reality. +.Pp +Also note that sequenced files (using the +.Dq seq +style) will initially be checkpointed using a file name containing a timestamp in seconds. +.Nm aslmanager +will re-sequence the files when it scans for checkpoint files. +.Pp +.Pp +Alternatively, the name style may be have two or three components. +The first component is the +.Dq base +name of the file, with no filename extension. +The base name may be followed by a timestamp format and optionally by a filename extension, +or the base name may be followed by an extension (the extension is optional) and a timestamp format. +These components must be separated by a dot character. +.Pp +For example, this output configuration line specifies that the output file +.Dq example.log +should be rotated to create the files +.Dq example.0.log , +.Dq example.1.log , +and so on. +.Pp +.Dl > example.log rotate=example.seq.log +.Pp If a file is marked for rotation, .Nm syslogd will close the file at the start of a new day or when the file exceeds its @@ -647,8 +730,9 @@ will close the file at the start of a new day or when the file exceeds its size limit. At that point, .Nm syslogd -renames the file and starts a new file to continue logging. -The old file is renamed with the file's creation time included in its name. +renames the file with the file's creation time included in its name +(unless the basestamp option is present, in which case the file's creation time +is already included in the filename) and starts a new file to continue logging. This operation is called checkpointing the file. .Pp For example, diff --git a/syslogd.tproj/asl.conf.ios b/syslogd.tproj/asl.conf.ios new file mode 100644 index 0000000..ae10c60 --- /dev/null +++ b/syslogd.tproj/asl.conf.ios @@ -0,0 +1,30 @@ +## +# configuration file for syslogd and aslmanager +## + +# aslmanager logs +> /var/log/asl/Logs/aslmanager external style=lcl-b ttl=2 + +# authpriv messages are root/admin readable +? [= Facility authpriv] access 0 80 + +# remoteauth critical, alert, and emergency messages are root/admin readable +? [= Facility remoteauth] [<= Level critical] access 0 80 + +# broadcast emergency messages +? [= Level emergency] broadcast + +# save kernel [PID 0] and launchd [PID 1] messages +? [<= PID 1] store + +# ignore "internal" facility +? [= Facility internal] ignore + +# save everything from emergency to notice +? [<= Level notice] store + +# Specify owner, group, and access bits for mobile-owned log directories +> /var/mobile/Library uid=501 gid=501 mode=0700 +> /var/mobile/Library/Logs uid=501 gid=501 mode=0755 +> /var/mobile/Library/Logs/CrashReporter uid=501 gid=501 mode=0755 +> /var/mobile/Library/Logs/CrashReporter/DiagnosticLogs uid=501 gid=501 mode=0755 diff --git a/syslogd.tproj/asl_sim.conf b/syslogd.tproj/asl.conf.ios_sim similarity index 95% rename from syslogd.tproj/asl_sim.conf rename to syslogd.tproj/asl.conf.ios_sim index e2cc06a..9ba0797 100644 --- a/syslogd.tproj/asl_sim.conf +++ b/syslogd.tproj/asl.conf.ios_sim @@ -11,9 +11,6 @@ # redirect com.apple.eventmonitor* messages to $ENV(SIMULATOR_LOG_ROOT)/eventmonitor ? [A= Facility com.apple.eventmonitor] store_dir $ENV(SIMULATOR_LOG_ROOT)/eventmonitor -# broadcast emergency messages -? [= Level emergency] broadcast - # ignore "internal" facility ? [= Facility internal] ignore diff --git a/syslogd.tproj/asl.conf.osx b/syslogd.tproj/asl.conf.osx new file mode 100644 index 0000000..ef9dc9b --- /dev/null +++ b/syslogd.tproj/asl.conf.osx @@ -0,0 +1,34 @@ +## +# configuration file for syslogd and aslmanager +## + +# aslmanager logs +> /var/log/asl/Logs/aslmanager external style=lcl-b ttl=2 + +# authpriv messages are root/admin readable +? [= Facility authpriv] access 0 80 + +# remoteauth critical, alert, and emergency messages are root/admin readable +? [= Facility remoteauth] [<= Level critical] access 0 80 + +# broadcast emergency messages +? [= Level emergency] broadcast + +# save kernel [PID 0] and launchd [PID 1] messages +? [<= PID 1] store + +# ignore "internal" facility +? [= Facility internal] ignore + +# save everything from emergency to notice +? [<= Level notice] store + +# Rules for /var/log/system.log +> system.log mode=0640 format=bsd rotate=seq compress file_max=5M all_max=50M +? [= Sender kernel] file system.log +? [<= Level notice] file system.log +? [= Facility auth] [<= Level info] file system.log +? [= Facility authpriv] [<= Level info] file system.log + +# Facility com.apple.alf.logging gets saved in appfirewall.log +? [= Facility com.apple.alf.logging] file appfirewall.log file_max=5M all_max=50M diff --git a/syslogd.tproj/asl_action.c b/syslogd.tproj/asl_action.c index b33d582..ca0d19d 100644 --- a/syslogd.tproj/asl_action.c +++ b/syslogd.tproj/asl_action.c @@ -500,7 +500,7 @@ _asl_dir_today_close(asl_out_rule_t *r) if (as_data->pending != 0) { char *str = NULL; - asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message ASL Store %s was closed with %d pending messages]", global.pid, r->dst->fname, as_data->pending); + asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message ASL Store %s was closed with %d pending messages]", global.pid, r->dst->current_name, as_data->pending); internal_log_message(str); free(str); } @@ -529,8 +529,8 @@ _asl_dir_today_close(asl_out_rule_t *r) as_data->p_month = 0; as_data->p_day = 0; - free(r->dst->fname); - r->dst->fname = NULL; + free(r->dst->current_name); + r->dst->current_name = NULL; as_data->aslfile = NULL; } @@ -541,22 +541,22 @@ _asl_dir_today_close(asl_out_rule_t *r) static int _act_checkpoint(asl_out_rule_t *r, uint32_t force) { - char tmpfname[MAXPATHLEN], *fn; + char tmpcurrent_name[MAXPATHLEN], *fn; if (r == NULL) return 0; if (r->dst == NULL) return 0; - fn = r->dst->fname; + fn = r->dst->current_name; if (fn == NULL) { if (r->dst->path == NULL) return 0; - asl_make_dst_filename(r->dst, tmpfname, sizeof(tmpfname)); - fn = tmpfname; + asl_dst_make_current_name(r->dst, 0, tmpcurrent_name, sizeof(tmpcurrent_name)); + fn = tmpcurrent_name; } if ((force == CHECKPOINT_TEST) && (r->dst->file_max == 0)) return 0; - if ((r->dst->size == 0) || (r->dst->stamp == 0)) + if ((r->dst->size == 0) || (r->dst->timestamp == 0)) { struct stat sb; @@ -568,8 +568,8 @@ _act_checkpoint(asl_out_rule_t *r, uint32_t force) return -1; } - if (r->dst->stamp == 0) r->dst->stamp = sb.st_birthtimespec.tv_sec; - if (r->dst->stamp == 0) r->dst->stamp = sb.st_mtimespec.tv_sec; + if (r->dst->timestamp == 0) r->dst->timestamp = sb.st_birthtimespec.tv_sec; + if (r->dst->timestamp == 0) r->dst->timestamp = sb.st_mtimespec.tv_sec; r->dst->size = sb.st_size; } @@ -583,19 +583,21 @@ _act_checkpoint(asl_out_rule_t *r, uint32_t force) { char srcpath[MAXPATHLEN]; char dstpath[MAXPATHLEN]; - char tstamp[32]; - - if (r->dst->stamp == 0) r->dst->stamp = time(NULL); - asl_make_timestamp(r->dst->stamp, r->dst->flags, tstamp, sizeof(tstamp)); snprintf(srcpath, sizeof(srcpath), "%s", fn); - snprintf(dstpath, sizeof(dstpath), "%s.%s", fn, tstamp); + + r->dst->timestamp = time(NULL); + asl_dst_make_current_name(r->dst, MODULE_FLAG_BASESTAMP, dstpath, sizeof(dstpath)); _act_dst_close(r, DST_CLOSE_CHECKPOINT); - rename(srcpath, dstpath); + if (strneq(srcpath, dstpath)) + { + rename(srcpath, dstpath); + asldebug("CHECKPOINT RENAME %s %s\n", srcpath, dstpath); + } } - r->dst->stamp = 0; + r->dst->timestamp = 0; r->dst->size = 0; return 1; } @@ -640,7 +642,7 @@ _asl_dir_today_open(asl_out_rule_t *r, const time_t *tick) /* checks file_max and closes if required */ status = _act_checkpoint(r, CHECKPOINT_TEST); - if (status == 1) trigger_aslmanager(); + if (status == 1) asl_trigger_aslmanager(); if (as_data->aslfile != NULL) { @@ -663,16 +665,16 @@ _asl_dir_today_open(asl_out_rule_t *r, const time_t *tick) tick = (const time_t *)&now; } - asl_make_timestamp(now, r->dst->flags, tstamp, sizeof(tstamp)); - asprintf(&(r->dst->fname), "%s/%s.asl", r->dst->path, tstamp); + asl_make_timestamp(now, r->dst->style_flags, tstamp, sizeof(tstamp)); + asprintf(&(r->dst->current_name), "%s/%s.asl", r->dst->path, tstamp); } else { - asprintf(&(r->dst->fname), "%s/%d.%02d.%02d.asl", r->dst->path, ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); + asprintf(&(r->dst->current_name), "%s/%d.%02d.%02d.asl", r->dst->path, ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); } - if (r->dst->fname == NULL) + if (r->dst->current_name == NULL) { asldebug("_asl_dir_today_open: asprintf error %s\n", strerror(errno)); return -1; @@ -687,22 +689,22 @@ _asl_dir_today_open(asl_out_rule_t *r, const time_t *tick) #endif mask = umask(0); - status = asl_file_open_write(r->dst->fname, (r->dst->mode & 00666), uid, gid, &(as_data->aslfile)); + status = asl_file_open_write(r->dst->current_name, (r->dst->mode & 00666), uid, gid, &(as_data->aslfile)); umask(mask); if (status != ASL_STATUS_OK) { - asldebug("_asl_dir_today_open: asl_file_open_write %s error %s\n", r->dst->fname, asl_core_error(status)); - free(r->dst->fname); - r->dst->fname = NULL; + asldebug("_asl_dir_today_open: asl_file_open_write %s error %s\n", r->dst->current_name, asl_core_error(status)); + free(r->dst->current_name); + r->dst->current_name = NULL; return -1; } if (fseek(as_data->aslfile->store, 0, SEEK_END) != 0) { - asldebug("_asl_dir_today_open: fseek %s error %s\n", r->dst->fname, strerror(errno)); - free(r->dst->fname); - r->dst->fname = NULL; + asldebug("_asl_dir_today_open: fseek %s error %s\n", r->dst->current_name, strerror(errno)); + free(r->dst->current_name); + r->dst->current_name = NULL; return -1; } @@ -729,7 +731,7 @@ _asl_dir_today_open(asl_out_rule_t *r, const time_t *tick) dispatch_resume(as_data->aslfile_monitor); } - asldebug("_asl_dir_today_open ASL file %s fd %d\n", r->dst->fname, fd); + asldebug("_asl_dir_today_open ASL file %s fd %d\n", r->dst->current_name, fd); return 0; } @@ -746,7 +748,7 @@ _asl_file_close(asl_out_rule_t *r) if (af_data->pending != 0) { char *str = NULL; - asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message ASL File %s was closed with %d pending messages]", global.pid, r->dst->fname, af_data->pending); + asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message ASL File %s was closed with %d pending messages]", global.pid, r->dst->current_name, af_data->pending); internal_log_message(str); free(str); } @@ -796,18 +798,18 @@ _asl_file_open(asl_out_rule_t *r) fd = _act_file_create_open(r->dst); if (fd < 0) { - asldebug("_asl_file_open: _act_file_create_open %s failed %d %s\n", r->dst->fname, errno, strerror(errno)); + asldebug("_asl_file_open: _act_file_create_open %s failed %d %s\n", r->dst->current_name, errno, strerror(errno)); return -1; } close(fd); - if (r->dst->fname == NULL) return -1; + if (r->dst->current_name == NULL) return -1; - status = asl_file_open_write(r->dst->fname, 0, -1, -1, &(af_data->aslfile)); + status = asl_file_open_write(r->dst->current_name, 0, -1, -1, &(af_data->aslfile)); if (status != ASL_STATUS_OK) { - asldebug("_asl_file_open: asl_file_open_write %s failed %d %s\n", r->dst->fname, errno, strerror(errno)); + asldebug("_asl_file_open: asl_file_open_write %s failed %d %s\n", r->dst->current_name, errno, strerror(errno)); return -1; } @@ -830,7 +832,7 @@ _asl_file_open(asl_out_rule_t *r) dispatch_resume(af_data->monitor); } - asldebug("_asl_file_open ASL file %s fd %d\n", r->dst->fname, fd); + asldebug("_asl_file_open ASL file %s fd %d\n", r->dst->current_name, fd); return 0; } @@ -843,7 +845,7 @@ _text_file_close(asl_out_rule_t *r) if (f_data->pending != 0) { char *str = NULL; - asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message File %s was closed with %d pending messages]", global.pid, r->dst->fname, f_data->pending); + asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message File %s was closed with %d pending messages]", global.pid, r->dst->current_name, f_data->pending); internal_log_message(str); free(str); } @@ -969,12 +971,12 @@ _act_dst_close(asl_out_rule_t *r, int why) } else if (r->action == ACTION_ASL_FILE) { - asldebug("_act_dst_close: %s ASL FILE %s\n", why_str[why], (r->dst->fname == NULL) ? r->dst->path : r->dst->fname); + asldebug("_act_dst_close: %s ASL FILE %s\n", why_str[why], (r->dst->current_name == NULL) ? r->dst->path : r->dst->current_name); _asl_file_close(r); } else if (r->action == ACTION_FILE) { - asldebug("_act_dst_close: %s FILE %s\n", why_str[why], (r->dst->fname == NULL) ? r->dst->path : r->dst->fname); + asldebug("_act_dst_close: %s FILE %s\n", why_str[why], (r->dst->current_name == NULL) ? r->dst->path : r->dst->current_name); _text_file_close(r); } } @@ -1181,7 +1183,7 @@ _act_store_file(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg) { r->dst->size = af_data->aslfile->file_size; - if (_act_checkpoint(r, CHECKPOINT_TEST) == 1) trigger_aslmanager(); + if (_act_checkpoint(r, CHECKPOINT_TEST) == 1) asl_trigger_aslmanager(); } } @@ -1337,7 +1339,7 @@ _send_repeat_msg(asl_out_rule_t *r) if ((status < 0) || (status < len)) { - asldebug("%s: error writing repeat message (%s): %s\n", MY_ID, r->dst->fname, strerror(errno)); + asldebug("%s: error writing repeat message (%s): %s\n", MY_ID, r->dst->current_name, strerror(errno)); return -1; } @@ -1449,7 +1451,7 @@ _act_file_checkpoint_all(uint32_t force) if (_act_file_checkpoint(m, NULL, force) > 0) did_checkpoint = 1; } - trigger_aslmanager(); + asl_trigger_aslmanager(); return did_checkpoint; } @@ -1466,6 +1468,8 @@ _act_file_final(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg) char *str; time_t now; + if (r == NULL) return; + if (r->dst == NULL) return; if (r->dst->private == NULL) return; f_data = (asl_action_file_data_t *)r->dst->private; @@ -1559,7 +1563,7 @@ _act_file_final(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg) size_t bytes = write(f_data->fd, str, len - 1); if (bytes > 0) r->dst->size += bytes; - if (_act_checkpoint(r, CHECKPOINT_TEST) == 1) trigger_aslmanager(); + if (_act_checkpoint(r, CHECKPOINT_TEST) == 1) asl_trigger_aslmanager(); } } @@ -1702,7 +1706,7 @@ _asl_out_process_message(asl_out_module_t *m, asl_msg_t *msg) } void -asl_out_message(asl_msg_t *msg) +asl_out_message(asl_msg_t *msg, int64_t msize) { OSAtomicIncrement32(&global.asl_queue_count); asl_msg_retain(msg); @@ -1744,6 +1748,14 @@ asl_out_message(asl_msg_t *msg) p = asl_msg_get_val_for_key(msg, ASL_KEY_FINAL_NOTIFICATION); if (p != NULL) asl_msg_set_key_val(msg, ASL_KEY_FREE_NOTE, p); + /* chain to the next output module (done this way to make queue size accounting easier */ +#if !TARGET_IPHONE_SIMULATOR + if (global.bsd_out_enabled) bsd_out_message(msg, msize); + else OSAtomicAdd64(-1ll * msize, &global.memory_size); +#else + OSAtomicAdd64(-1ll * msize, &global.memory_size); +#endif + asl_msg_release(msg); OSAtomicDecrement32(&global.asl_queue_count); diff --git a/syslogd.tproj/bsd_out.c b/syslogd.tproj/bsd_out.c index 935b01a..9cd9d43 100644 --- a/syslogd.tproj/bsd_out.c +++ b/syslogd.tproj/bsd_out.c @@ -658,7 +658,7 @@ _bsd_match_and_send(asl_msg_t *msg) } void -bsd_out_message(asl_msg_t *msg) +bsd_out_message(asl_msg_t *msg, int64_t msize) { if (msg == NULL) return; @@ -668,6 +668,10 @@ bsd_out_message(asl_msg_t *msg) dispatch_async(bsd_out_queue, ^{ _bsd_match_and_send(msg); asl_msg_release((asl_msg_t *)msg); + + /* end of the output module chain (after asl) - decrement global memory stats */ + OSAtomicAdd64(-1ll * msize, &global.memory_size); + OSAtomicDecrement32(&global.bsd_queue_count); }); } diff --git a/syslogd.tproj/com.apple.system.log b/syslogd.tproj/com.apple.system.log new file mode 100644 index 0000000..4903a9d --- /dev/null +++ b/syslogd.tproj/com.apple.system.log @@ -0,0 +1,8 @@ +# Rules for /var/log/system.log +# This file is installed in /usr/local/etc/asl on iOS for Apple Internal +# +> /var/log/system.log mode=0640 format=bsd rotate=system.seq.log compress file_max=5M all_max=50M +? [= Sender kernel] file system.log +? [<= Level notice] file system.log +? [= Facility auth] [<= Level info] file system.log +? [= Facility authpriv] [<= Level info] file system.log diff --git a/syslogd.tproj/daemon.c b/syslogd.tproj/daemon.c index 5122d6d..5c87c22 100644 --- a/syslogd.tproj/daemon.c +++ b/syslogd.tproj/daemon.c @@ -42,9 +42,11 @@ #include #include #include +#include #include "daemon.h" #define LIST_SIZE_DELTA 256 +#define STATS_TABLE_SIZE 256 #define forever for(;;) @@ -70,26 +72,26 @@ static char myname[MAXHOSTNAMELEN + 1] = {0}; static int name_change_token = -1; static OSSpinLock count_lock = 0; -static int aslmanager_triggered = 0; - #if !TARGET_OS_EMBEDDED static vproc_transaction_t vproc_trans = {0}; -#define DEFAULT_WORK_QUEUE_SIZE_MAX 10240000 -#else -#define DEFAULT_WORK_QUEUE_SIZE_MAX 4096000 #endif +#define DEFAULT_MEMORY_MAX SYSLOGD_WORK_QUEUE_MEMORY + #define QUOTA_KERN_EXCEEDED_MESSAGE "*** kernel exceeded %d log message per second limit - remaining messages this second discarded ***" #define DEFAULT_DB_FILE_MAX 25600000 -#define DEFAULT_DB_MEMORY_MAX 512 -#define DEFAULT_DB_MEMORY_STR_MAX 4096000 +#define DEFAULT_DB_MEMORY_MAX 256 +#define DEFAULT_DB_MEMORY_STR_MAX 1024000 #define DEFAULT_MPS_LIMIT 500 #define DEFAULT_REMOTE_DELAY 5000 #define DEFAULT_BSD_MAX_DUP_SEC 30 #define DEFAULT_MARK_SEC 0 #define DEFAULT_UTMP_TTL_SEC 31622400 +#define DEFAULT_STATS_INTERVAL 600 + +#define ASL_STATS_LEVEL 5 static time_t quota_time = 0; static int32_t kern_quota; @@ -107,7 +109,115 @@ static const char *kern_notify_key[] = "com.apple.system.log.kernel.debug" }; -static int kern_notify_token[8] = {-1, -1, -1, -1, -1, -1, -1, -1 }; +static int kern_notify_token[8] = {-1, -1, -1, -1, -1, -1, -1, -1}; + +static stats_table_t * +stats_table_new() +{ + stats_table_t *t = (stats_table_t *)malloc(sizeof(stats_table_t)); + if (t == NULL) return NULL; + + t->bucket_count = STATS_TABLE_SIZE; + t->bucket = (sender_stats_t **)calloc(t->bucket_count, sizeof(sender_stats_t *)); + if (t->bucket == NULL) + { + free(t); + return NULL; + } + + t->mcount = 0; + t->shim_count = 0; + + return t; +} + +static asl_msg_t * +stats_table_final(stats_table_t *t) +{ + uint32_t i; + asl_msg_t *msg; + char val[64]; + + if (t == NULL) return NULL; + + msg = asl_msg_new(ASL_TYPE_MSG); + if (msg == NULL) return NULL; + + asl_msg_set_key_val(msg, ASL_KEY_MSG, "ASL Sender Statistics"); + asl_msg_set_key_val(msg, ASL_KEY_SENDER, "syslogd"); + asl_msg_set_key_val(msg, ASL_KEY_FACILITY, "com.apple.asl.statistics"); + snprintf(val, sizeof(val), "%d", global.pid); + asl_msg_set_key_val(msg, ASL_KEY_PID, val); + snprintf(val, sizeof(val), "%d", ASL_STATS_LEVEL); + asl_msg_set_key_val(msg, ASL_KEY_LEVEL, val); + snprintf(val, sizeof(val), "%u", t->mcount); + asl_msg_set_key_val(msg, "MsgCount", val); + snprintf(val, sizeof(val), "%u", t->shim_count); + asl_msg_set_key_val(msg, "ShimCount", val); + + for (i = 0; i < t->bucket_count; i++) + { + sender_stats_t *s; + s = t->bucket[i]; + while (s != NULL) + { + char val[64], *key = NULL; + sender_stats_t *n = s->next; + + snprintf(val, sizeof(val), "%llu %llu", s->count, s->size); + asprintf(&key, "*%s", s->sender); + if (key != NULL) asl_msg_set_key_val(msg, key, val); + free(key); + free(s->sender); + free(s); + s = n; + } + } + + free(t->bucket); + free(t); + + return msg; +} + +static void +stats_table_update(stats_table_t *t, const char *sender, uint64_t msg_size) +{ + uint32_t i; + sender_stats_t *s; + uint8_t *p; + + if (t == NULL) return; + if (sender == NULL) return; + + /* hash */ + i = 0; + for (p = (uint8_t *)sender; *p != '\0'; p++) i = (i << 1) ^ (i ^ *p); + i %= STATS_TABLE_SIZE; + + for (s = t->bucket[i]; s != NULL; s = s->next) + { + if ((s->sender != NULL) && (strcmp(sender, s->sender) == 0)) + { + s->count++; + s->size += msg_size; + return; + } + } + + s = (sender_stats_t *)malloc(sizeof(sender_stats_t)); + s->sender = strdup(sender); + if (s->sender == NULL) + { + free(s); + return; + } + + s->count = 1; + s->size = msg_size; + s->next = t->bucket[i]; + t->bucket[i] = s; +} static uint32_t kern_quota_check(time_t now, asl_msg_t *msg, uint32_t level) @@ -146,12 +256,42 @@ kern_quota_check(time_t now, asl_msg_t *msg, uint32_t level) return VERIFY_STATUS_OK; } +static void +stats_msg(const char *sender, time_t now, asl_msg_t *msg) +{ + asl_msg_t *x; + uint64_t msize = 0; + + /* flush stats after N seconds */ + if ((global.stats_interval != 0) && ((now - global.stats_last) >= global.stats_interval) && (global.stats != NULL)) + { + asl_msg_t *msg = stats_table_final(global.stats); + process_message(msg, SOURCE_INTERNAL); + global.stats = NULL; + global.stats_last = now; + } + + if (global.stats == NULL) global.stats = stats_table_new(); + + for (x = msg; x != NULL; x = x->next) msize += x->mem_size; + + const char *shim_vers = asl_msg_get_val_for_key(msg, "ASLSHIM"); + global.stats->mcount++; + if (shim_vers != NULL) global.stats->shim_count++; + + /* update count and total size - total and for this sender */ + stats_table_update(global.stats, "*", msize); + stats_table_update(global.stats, sender, msize); +} + static const char * whatsmyhostname() { static dispatch_once_t once; int check, status; + if (global.hostname != NULL) return global.hostname; + dispatch_once(&once, ^{ snprintf(myname, sizeof(myname), "%s", "localhost"); notify_register_check(kNotifySCHostNameChange, &name_change_token); @@ -219,7 +359,7 @@ asl_client_count_decrement() static uint32_t aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t *uid_out) { - const char *val, *fac, *ruval, *rgval; + const char *val, *fac, *ruval, *rgval, *sval = NULL; char buf[64]; time_t tick, now; uid_t uid; @@ -244,11 +384,13 @@ aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t * if (val == NULL) asl_msg_set_key_val(msg, ASL_KEY_PID, "0"); else pid = (pid_t)atoi(val); - /* if PID is 1 (launchd), use the refpid if provided */ + /* if PID is 1 (launchd), use the RefPID and RefProc provided */ if (pid == 1) { val = asl_msg_get_val_for_key(msg, ASL_KEY_REF_PID); if (val != NULL) pid = (pid_t)atoi(val); + + sval = asl_msg_get_val_for_key(msg, ASL_KEY_REF_PROC); } /* Level */ @@ -260,6 +402,7 @@ aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t * snprintf(buf, sizeof(buf), "%d", level); asl_msg_set_key_val(msg, ASL_KEY_LEVEL, buf); + /* check kernel quota if enabled and no processes are watching */ if ((pid == 0) && (global.mps_limit > 0) && (global.watchers_active == 0)) { @@ -286,7 +429,7 @@ aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t * if ((tick == 0) || (tick > now)) tick = now; /* Canonical form: seconds since the epoch */ - snprintf(buf, sizeof(buf) - 1, "%lu", tick); + snprintf(buf, sizeof(buf) - 1, "%llu", (unsigned long long) tick); asl_msg_set_key_val(msg, ASL_KEY_TIME, buf); /* Host */ @@ -365,19 +508,21 @@ aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t * } /* Sender */ - val = asl_msg_get_val_for_key(msg, ASL_KEY_SENDER); - if (val == NULL) + if (sval == NULL) sval = asl_msg_get_val_for_key(msg, ASL_KEY_SENDER); + if (sval == NULL) { switch (source) { case SOURCE_KERN: { - asl_msg_set_key_val(msg, ASL_KEY_SENDER, "kernel"); + sval = "kernel"; + asl_msg_set_key_val(msg, ASL_KEY_SENDER, sval); break; } case SOURCE_INTERNAL: { - asl_msg_set_key_val(msg, ASL_KEY_SENDER, "syslogd"); + sval = "syslogd"; + asl_msg_set_key_val(msg, ASL_KEY_SENDER, sval); break; } default: @@ -386,10 +531,11 @@ aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t * } } } - else if ((source != SOURCE_KERN) && (uid != 0) && (!strcmp(val, "kernel"))) + else if ((source != SOURCE_KERN) && (uid != 0) && (!strcmp(sval, "kernel"))) { /* allow UID 0 to send messages with "Sender kernel", but nobody else */ asl_msg_set_key_val(msg, ASL_KEY_SENDER, "Unknown"); + sval = NULL; } /* Facility */ @@ -442,14 +588,14 @@ aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t * /* Set DB Expire Time for com.apple.system.utmpx and lastlog */ if ((!strcmp(fac, "com.apple.system.utmpx")) || (!strcmp(fac, "com.apple.system.lastlog"))) { - snprintf(buf, sizeof(buf), "%lu", tick + global.utmp_ttl); + snprintf(buf, sizeof(buf), "%llu", (unsigned long long) tick + global.utmp_ttl); asl_msg_set_key_val(msg, ASL_KEY_EXPIRE_TIME, buf); } /* Set DB Expire Time for Filesystem errors */ if (!strcmp(fac, FSLOG_VAL_FACILITY)) { - snprintf(buf, sizeof(buf), "%lu", tick + FS_TTL_SEC); + snprintf(buf, sizeof(buf), "%llu", (unsigned long long) tick + FS_TTL_SEC); asl_msg_set_key_val(msg, ASL_KEY_EXPIRE_TIME, buf); } @@ -462,6 +608,11 @@ aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t * disaster_message(msg); } + /* + * gather sender stats + */ + if (source != SOURCE_INTERNAL) stats_msg(sval, now, msg); + return VERIFY_STATUS_OK; } @@ -526,7 +677,8 @@ init_globals(void) global.bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC; global.mark_time = DEFAULT_MARK_SEC; global.utmp_ttl = DEFAULT_UTMP_TTL_SEC; - global.max_work_queue_size = DEFAULT_WORK_QUEUE_SIZE_MAX; + global.memory_max = DEFAULT_MEMORY_MAX; + global.stats_interval = DEFAULT_STATS_INTERVAL; global.asl_out_module = asl_out_module_init(); OSSpinLockUnlock(&global.lock); @@ -603,7 +755,22 @@ control_set_param(const char *s, bool eval) return -1; } - if (!strcasecmp(l[0], "mark_time")) + if (!strcasecmp(l[0], "hostname")) + { + /* = hostname name */ + OSSpinLockLock(&global.lock); + if (eval) + { + global.hostname = strdup(l[1]); + } + else + { + free(global.hostname); + global.hostname = NULL; + } + OSSpinLockUnlock(&global.lock); + } + else if (!strcasecmp(l[0], "mark_time")) { /* = mark_time seconds */ OSSpinLockLock(&global.lock); @@ -643,12 +810,20 @@ control_set_param(const char *s, bool eval) else global.mps_limit = DEFAULT_MPS_LIMIT; OSSpinLockUnlock(&global.lock); } - else if (!strcasecmp(l[0], "max_work_queue_size")) + else if (!strcasecmp(l[0], "memory_max")) { - /* = max_work_queue_size number */ + /* = memory_max number */ OSSpinLockLock(&global.lock); - if (eval) global.max_work_queue_size = (int64_t)atoll(l[1]); - else global.max_work_queue_size = DEFAULT_WORK_QUEUE_SIZE_MAX; + if (eval) global.memory_max = (int64_t)atoll(l[1]); + else global.memory_max = DEFAULT_MEMORY_MAX; + OSSpinLockUnlock(&global.lock); + } + else if (!strcasecmp(l[0], "stats_interval")) + { + /* = stats_interval number */ + OSSpinLockLock(&global.lock); + if (eval) global.stats_interval = (time_t)atoll(l[1]); + else global.stats_interval = DEFAULT_STATS_INTERVAL; OSSpinLockUnlock(&global.lock); } else if (!strcasecmp(l[0], "max_file_size")) @@ -752,7 +927,6 @@ void process_message(asl_msg_t *msg, uint32_t source) { int64_t msize = 0; - static bool wq_draining = false; bool is_control = false; asl_msg_t *x; @@ -760,38 +934,24 @@ process_message(asl_msg_t *msg, uint32_t source) is_control = asl_check_option(msg, ASL_OPT_CONTROL) != 0; - if ((!is_control) && wq_draining) - { - if (global.work_queue_size >= (global.max_work_queue_size / 2)) - { - asldebug("Work queue draining: dropped message.\n"); - asl_msg_release(msg); - return; - } - else - { - asldebug("Work queue re-enabled at 1/2 max. size %llu max %llu\n", global.work_queue_size, global.max_work_queue_size); - wq_draining = false; - } - } + __block vproc_transaction_t vt = vproc_transaction_begin(NULL); for (x = msg; x != NULL; x = x->next) msize += x->mem_size; - if ((global.work_queue_size + msize) >= global.max_work_queue_size) + if ((global.memory_size + msize) >= global.memory_max) { - char *str = NULL; - - wq_draining = true; + char str[256]; asl_msg_release(msg); - asldebug("Work queue disabled. msize %llu size %llu max %llu\n", msize, global.work_queue_size + msize, global.max_work_queue_size); - asprintf(&str, "[Sender syslogd] [Level 2] [PID %u] [Message Internal work queue size limit exceeded - dropping messages] [UID 0] [UID 0] [Facility syslog]", global.pid); + asldebug("Work queue memory limit - dropped message. msize %lld size %lld max %lld\n", msize, global.memory_size + msize, global.memory_max); + snprintf(str, sizeof(str), "[Sender syslogd] [Level 2] [PID %u] [Message Received message size %lld overflows work queue limit %lld - dropping message] [UID 0] [UID 0] [Facility syslog]", global.pid, msize, global.memory_max); msg = asl_msg_from_string(str); - free(str); + for (x = msg; x != NULL; x = x->next) msize += x->mem_size; } - OSAtomicAdd64(msize, &global.work_queue_size); + OSAtomicAdd64(msize, &global.memory_size); OSAtomicIncrement32(&global.work_queue_count); + dispatch_async(global.work_queue, ^{ int32_t kplevel; uint32_t status; @@ -817,17 +977,21 @@ process_message(asl_msg_t *msg, uint32_t source) if ((uid == 0) && is_control) control_message(msg); - /* send message to output modules */ - asl_out_message(msg); -#if !TARGET_IPHONE_SIMULATOR - if (global.bsd_out_enabled) bsd_out_message(msg); -#endif + /* + * Send message to output module chain (asl is first). + * The last module in the chain will decrement global.memory_size. + */ + asl_out_message(msg, msize); + } + else + { + OSAtomicAdd64(-1ll * msize, &global.memory_size); } asl_msg_release(msg); - OSAtomicAdd64(-1ll * msize, &global.work_queue_size); OSAtomicDecrement32(&global.work_queue_count); + vproc_transaction_end(NULL, vt); }); } @@ -846,34 +1010,6 @@ internal_log_message(const char *str) return 0; } -void -trigger_aslmanager() -{ - dispatch_async(dispatch_get_main_queue(), ^{ - if (aslmanager_triggered == 0) - { - aslmanager_triggered = 1; - - time_t now = time(0); - if ((now - global.aslmanager_last_trigger) >= ASLMANAGER_DELAY) - { - global.aslmanager_last_trigger = now; - asl_trigger_aslmanager(); - aslmanager_triggered = 0; - } - else - { - uint64_t delta = ASLMANAGER_DELAY - (now - global.aslmanager_last_trigger); - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delta * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - global.aslmanager_last_trigger = time(0); - asl_trigger_aslmanager(); - aslmanager_triggered = 0; - }); - } - } - }); -} - int asldebug(const char *str, ...) { @@ -887,6 +1023,9 @@ asldebug(const char *str, ...) if (dfp == NULL) return 0; va_start(v, str); + fprintf(dfp, "W %d %llu", global.work_queue_count, global.memory_size); + if (global.memory_db != NULL) fprintf(dfp, " M %u %u %lu", global.memory_db->record_count, global.memory_db->string_count, global.memory_db->curr_string_mem); + fprintf(dfp, " ; "); vfprintf(dfp, str, v); va_end(v); @@ -1200,7 +1339,7 @@ launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t se /* Time */ if (when != NULL) { - snprintf(str, sizeof(str), "%lu", when->tv_sec); + snprintf(str, sizeof(str), "%llu", (unsigned long long) when->tv_sec); asl_msg_set_key_val(m, ASL_KEY_TIME, str); snprintf(str, sizeof(str), "%lu", 1000 * (unsigned long int)when->tv_usec); @@ -1209,7 +1348,7 @@ launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t se else { now = time(NULL); - snprintf(str, sizeof(str), "%lu", now); + snprintf(str, sizeof(str), "%llu", (unsigned long long) now); asl_msg_set_key_val(m, ASL_KEY_TIME, str); } diff --git a/syslogd.tproj/daemon.h b/syslogd.tproj/daemon.h index 93de9f0..106059b 100644 --- a/syslogd.tproj/daemon.h +++ b/syslogd.tproj/daemon.h @@ -91,8 +91,21 @@ extern const char *_path_syslogd_log; #define SEC_PER_DAY 86400 -/* trigger aslmanager no more often than 300 seconds */ -#define ASLMANAGER_DELAY 300 +typedef struct sender_stats_s +{ + char *sender; + uint64_t count; + uint64_t size; + struct sender_stats_s *next; +} sender_stats_t; + +typedef struct +{ + uint32_t mcount; + uint32_t shim_count; + uint32_t bucket_count; + sender_stats_t **bucket; +} stats_table_t; typedef struct { @@ -118,7 +131,8 @@ struct global_s int reset; pid_t pid; int32_t work_queue_count; - int64_t work_queue_size; + /* memory_size must be aligned for OSAtomicAdd64 */ + __attribute__((aligned(8))) int64_t memory_size; int32_t asl_queue_count; int32_t bsd_queue_count; pthread_mutex_t *db_lock; @@ -134,11 +148,13 @@ struct global_s int launchd_enabled; module_t **module; asl_out_module_t *asl_out_module; - time_t aslmanager_last_trigger; + time_t stats_last; + stats_table_t *stats; /* parameters below are configurable as command-line args or in /etc/asl.conf */ int debug; char *debug_file; + char *hostname; int dbtype; uint32_t db_file_max; uint32_t db_memory_max; @@ -148,7 +164,8 @@ struct global_s uint64_t bsd_max_dup_time; uint64_t mark_time; time_t utmp_ttl; - int64_t max_work_queue_size; + time_t stats_interval; + int64_t memory_max; }; extern struct global_s global; @@ -178,13 +195,11 @@ const char *asl_syslog_faciliy_num_to_name(int num); asl_msg_t *asl_input_parse(const char *in, int len, char *rhost, uint32_t source); void process_message(asl_msg_t *msg, uint32_t source); -void asl_out_message(asl_msg_t *msg); -void bsd_out_message(asl_msg_t *msg); +void asl_out_message(asl_msg_t *msg, int64_t msize); +void bsd_out_message(asl_msg_t *msg, int64_t msize); int control_set_param(const char *s, bool eval); int asl_action_control_set_param(const char *s); -void trigger_aslmanager(); - /* notify SPI */ uint32_t notify_register_plain(const char *name, int *out_token); diff --git a/syslogd.tproj/dbserver.c b/syslogd.tproj/dbserver.c index b5d812f..7f82959 100644 --- a/syslogd.tproj/dbserver.c +++ b/syslogd.tproj/dbserver.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2012 Apple Inc. All rights reserved. + * Copyright (c) 2007-2015 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -72,6 +73,8 @@ #define ASL_ENTITLEMENT_UID_KEY "com.apple.asl.access_as_uid" #define ASL_ENTITLEMENT_GID_KEY "com.apple.asl.access_as_gid" +#define PAGE_ROUND_UP(x) ((((x)+PAGE_SIZE-1)/PAGE_SIZE)*PAGE_SIZE) + static dispatch_queue_t asl_server_queue; static dispatch_queue_t watch_queue; static dispatch_once_t watch_init_once; @@ -143,7 +146,7 @@ db_asl_open(uint32_t dbtype) else { if (global.db_file_max != 0) asl_store_max_file_size(global.file_db, global.db_file_max); - trigger_aslmanager(); + asl_trigger_aslmanager(); } } @@ -916,14 +919,26 @@ syslogd_state_query(asl_msg_t *q, asl_msg_list_t **res, uid_t uid) if (all || (0 == asl_msg_lookup(q, "utmp_ttl", NULL, NULL))) { - snprintf(val, sizeof(val), "%lu", global.utmp_ttl); + snprintf(val, sizeof(val), "%llu", (unsigned long long) global.utmp_ttl); asl_msg_set_key_val(m, "utmp_ttl", val); } - if (all || (0 == asl_msg_lookup(q, "max_work_queue_size", NULL, NULL))) + if (all || (0 == asl_msg_lookup(q, "memory_size", NULL, NULL))) { - snprintf(val, sizeof(val), "%lld", global.max_work_queue_size); - asl_msg_set_key_val(m, "max_work_queue_size", val); + snprintf(val, sizeof(val), "%lld", global.memory_size); + asl_msg_set_key_val(m, "memory_size", val); + } + + if (all || (0 == asl_msg_lookup(q, "memory_max", NULL, NULL))) + { + snprintf(val, sizeof(val), "%lld", global.memory_max); + asl_msg_set_key_val(m, "memory_max", val); + } + + if (all || (0 == asl_msg_lookup(q, "stats_interval", NULL, NULL))) + { + snprintf(val, sizeof(val), "%lld", (long long) global.stats_interval); + asl_msg_set_key_val(m, "stats_interval", val); } if (all || (0 == asl_msg_lookup(q, "work_queue_count", NULL, NULL))) @@ -1010,22 +1025,132 @@ syslogd_state_query(asl_msg_t *q, asl_msg_list_t **res, uid_t uid) return ASL_STATUS_OK; } +static kern_return_t +_server_message_processing(asl_request_msg *request) +{ + const uint32_t sbits = MACH_SEND_MSG | MACH_SEND_TIMEOUT;; + kern_return_t ks; + asl_reply_msg *reply = calloc(1, sizeof(asl_reply_msg) + MAX_TRAILER_SIZE); + + voucher_mach_msg_state_t voucher = voucher_mach_msg_adopt(&(request->head)); + + /* MIG server routine */ + asl_ipc_server(&(request->head), &(reply->head)); + + if (!(reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) + { + if (reply->reply.Reply__asl_server_message.RetCode == MIG_NO_REPLY) + { + reply->head.msgh_remote_port = MACH_PORT_NULL; + } + else if ((reply->reply.Reply__asl_server_message.RetCode != KERN_SUCCESS) && (request->head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) + { + /* destroy the request - but not the reply port */ + request->head.msgh_remote_port = MACH_PORT_NULL; + mach_msg_destroy(&(request->head)); + } + } + + if (reply->head.msgh_remote_port != MACH_PORT_NULL) + { + ks = mach_msg(&(reply->head), sbits, reply->head.msgh_size, 0, MACH_PORT_NULL, 10, MACH_PORT_NULL); + if ((ks == MACH_SEND_INVALID_DEST) || (ks == MACH_SEND_TIMED_OUT)) + { + /* clean up */ + mach_msg_destroy(&(reply->head)); + } + else if (ks == MACH_SEND_INVALID_HEADER) + { + /* + * This should never happen, but we can continue running. + */ + char str[256]; + asldebug("ERROR: mach_msg() send failed with MACH_SEND_INVALID_HEADER 0x%08x\n", ks); + snprintf(str, sizeof(str), "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message mach_msg() send failed with status 0x%08x (MACH_SEND_INVALID_HEADER)]", global.pid, ks); + internal_log_message(str); + mach_msg_destroy(&(reply->head)); + } + else if (ks == MACH_SEND_NO_BUFFER) + { + /* + * This should never happen, but the kernel can run out of memory. + * We clean up and continue running. + */ + char str[256]; + asldebug("ERROR: mach_msg() send failed with MACH_SEND_NO_BUFFER 0x%08x\n", ks); + snprintf(str, sizeof(str), "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message mach_msg() send failed with status 0x%08x (MACH_SEND_NO_BUFFER)]", global.pid, ks); + internal_log_message(str); + mach_msg_destroy(&(reply->head)); + } + else if (ks != KERN_SUCCESS) + { + /* + * Failed to send a reply message. This should never happen, + * but the best action is to crash. + */ + char str[256]; + asldebug("FATAL ERROR: mach_msg() send failed with status 0x%08x\n", ks); + snprintf(str, sizeof(str), "[Sender syslogd] [Level 1] [PID %u] [Facility syslog] [Message FATAL ERROR: mach_msg() send failed with status 0x%08x]", global.pid, ks); + internal_log_message(str); + sleep(1); + abort(); + } + } + else if (reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX) + { + mach_msg_destroy(&reply->head); + } + + voucher_mach_msg_revert(voucher); + free(request); + free(reply); +} + /* * Receives messages on the "com.apple.system.logger" mach port. * Services database search requests. * Runs in it's own thread. + * + * The logic in this routine got a bit more complex due to (1) increased logging load and (2) 16K page size. + * Out-of-line (OOL) memory sent to syslogd from libasl is allocated in pages, so the minimum size of a + * message is one page. Since this routine can get slammed with messages at a very high rate, and since + * the message queue in the kernel is only 5 messages, it is critical that this routine service the port + * as fast as possible. To that end, it needs to do as little processing as possible. + * In the version of this code found up to syslog-312, this routine received messages and dispatched them + * on the asl_server_queue for further processing. When pages were only 4K, this was not a problem. With + * 16K pages, it only takes about 650 messages to run syslogd's dirty memoory size up to the point of its + * jetsam limit. Code was added here to track the memory being used in this queue + the work queue that's + * used by process_message(), such that messages will get dropped if the queues reach a memory limit. + * The actual message data in the VM pages is typically only a few hundred bytes, so holding VM pages in + * the queue was a waste, and seriously limited the number of queued messages. + * + * The solution implemented here is a bit of a hack. It peeks at the received message header to determine + * which MIG routine is being called. If the call is for _asl_server_message, it calls asl_ipc_server() + * on the server thread. This routes the call through the MIG server code for error checking and so on, + * and invokes _asl_server_message() on this thread. _asl_server_message() has been modified to copy + * the message data into malloced memory, vm_deallocate the OOL memory, and then it dispatches the real + * work onto the asl_server_queue. */ void database_server() { asl_request_msg *request; - uint32_t rqs; + uint32_t rqs, asl_server_message_num = 0; + size_t i; struct timeval now, send_time; mach_dead_name_notification_t *deadname; const uint32_t rbits = MACH_RCV_MSG | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) | MACH_RCV_VOUCHER; - send_time.tv_sec = 0; send_time.tv_usec = 0; + struct mig_map_s { + const char *routine; + int num; + } migmap[] = { subsystem_to_name_map_asl_ipc }; + + for (i = 0; (i < (sizeof(migmap) / sizeof(struct mig_map_s))) && (asl_server_message_num == 0); i++) + { + if (!strcmp(migmap[i].routine, "_asl_server_message")) asl_server_message_num = migmap[i].num; + } rqs = sizeof(asl_request_msg) + MAX_TRAILER_SIZE; @@ -1071,84 +1196,15 @@ database_server() continue; } - dispatch_async(asl_server_queue, ^{ - const uint32_t sbits = MACH_SEND_MSG | MACH_SEND_TIMEOUT;; - kern_return_t ks; - asl_reply_msg *reply = calloc(1, sizeof(asl_reply_msg) + MAX_TRAILER_SIZE); - - voucher_mach_msg_state_t voucher = voucher_mach_msg_adopt(&(request->head)); - - /* MIG server routine */ - asl_ipc_server(&(request->head), &(reply->head)); - - if (!(reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) - { - if (reply->reply.Reply__asl_server_message.RetCode == MIG_NO_REPLY) - { - reply->head.msgh_remote_port = MACH_PORT_NULL; - } - else if ((reply->reply.Reply__asl_server_message.RetCode != KERN_SUCCESS) && (request->head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) - { - /* destroy the request - but not the reply port */ - request->head.msgh_remote_port = MACH_PORT_NULL; - mach_msg_destroy(&(request->head)); - } - } - - if (reply->head.msgh_remote_port != MACH_PORT_NULL) - { - ks = mach_msg(&(reply->head), sbits, reply->head.msgh_size, 0, MACH_PORT_NULL, 10, MACH_PORT_NULL); - if ((ks == MACH_SEND_INVALID_DEST) || (ks == MACH_SEND_TIMED_OUT)) - { - /* clean up */ - mach_msg_destroy(&(reply->head)); - } - else if (ks == MACH_SEND_INVALID_HEADER) - { - /* - * This should never happen, but we can continue running. - */ - char str[256]; - asldebug("ERROR: mach_msg() send failed with MACH_SEND_INVALID_HEADER 0x%08x\n", ks); - snprintf(str, sizeof(str), "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message mach_msg() send failed with status 0x%08x (MACH_SEND_INVALID_HEADER)]", global.pid, ks); - internal_log_message(str); - mach_msg_destroy(&(reply->head)); - } - else if (ks == MACH_SEND_NO_BUFFER) - { - /* - * This should never happen, but the kernel can run out of memory. - * We clean up and continue running. - */ - char str[256]; - asldebug("ERROR: mach_msg() send failed with MACH_SEND_NO_BUFFER 0x%08x\n", ks); - snprintf(str, sizeof(str), "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message mach_msg() send failed with status 0x%08x (MACH_SEND_NO_BUFFER)]", global.pid, ks); - internal_log_message(str); - mach_msg_destroy(&(reply->head)); - } - else if (ks != KERN_SUCCESS) - { - /* - * Failed to send a reply message. This should never happen, - * but the best action is to crash. - */ - char str[256]; - asldebug("FATAL ERROR: mach_msg() send failed with status 0x%08x\n", ks); - snprintf(str, sizeof(str), "[Sender syslogd] [Level 1] [PID %u] [Facility syslog] [Message FATAL ERROR: mach_msg() send failed with status 0x%08x]", global.pid, ks); - internal_log_message(str); - sleep(1); - abort(); - } - } - else if (reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX) - { - mach_msg_destroy(&reply->head); - } - - voucher_mach_msg_revert(voucher); - free(request); - free(reply); - }); + int64_t msize = 0; + if (request->head.msgh_id == asl_server_message_num) + { + _server_message_processing(request); + } + else + { + dispatch_async(asl_server_queue, ^{ _server_message_processing(request); }); + } } } @@ -1288,7 +1344,7 @@ __asl_server_query_internal if ((out == NULL) || (outlen == 0)) return KERN_SUCCESS; - kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, outlen, TRUE); + kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, outlen, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL)); if (kstatus != KERN_SUCCESS) { free(out); @@ -1420,6 +1476,54 @@ __asl_server_prune return KERN_SUCCESS; } +/* + * Does the actual processing for __asl_server_message. + * Dispatched on asl_server_queue. This lets us avoid + * calling asl_msg_from_string(), task_name_for_pid(), + * and register_session() on the database_server() thread. + */ +static void +_asl_message_processing(char *mbuf, uint64_t msize, uid_t uid, gid_t gid, pid_t pid) +{ + asl_msg_t *msg; + char tmp[64]; + kern_return_t kstatus; + mach_port_name_t client; + + msg = asl_msg_from_string(mbuf); + free(mbuf); + + /* + * process_message() will update global.memory_size with the + * size of msg, and it increements the work_queue_count. + */ + OSAtomicAdd64(-1ll * msize, &global.memory_size); + OSAtomicDecrement32(&global.work_queue_count); + + if (msg == NULL) return; + + client = MACH_PORT_NULL; + kstatus = task_name_for_pid(mach_task_self(), pid, &client); + if (kstatus == KERN_SUCCESS) register_session(client, pid); + + snprintf(tmp, sizeof(tmp), "%d", uid); + asl_msg_set_key_val(msg, ASL_KEY_UID, tmp); + + snprintf(tmp, sizeof(tmp), "%d", gid); + asl_msg_set_key_val(msg, ASL_KEY_GID, tmp); + + snprintf(tmp, sizeof(tmp), "%d", pid); + asl_msg_set_key_val(msg, ASL_KEY_PID, tmp); + + process_message(msg, SOURCE_ASL_MESSAGE); +} + +/* + * This MIG server routine is something of a special case in database_server() above. + * It is called on the server thread that's responsible for servicing syslogd's mach port. + * In this routine we copy the actual ASL message raw string out of the message into + * malloc memory, deallocate the message, and dispatch the real work onto the asl_server_queue. + */ kern_return_t __asl_server_message ( @@ -1429,51 +1533,47 @@ __asl_server_message audit_token_t token ) { - asl_msg_t *msg; - char tmp[64]; uid_t uid; gid_t gid; pid_t pid; - kern_return_t kstatus; - mach_port_name_t client; + char *mbuf; - if (message == NULL) + if (message == NULL) return KERN_SUCCESS; + + if (message[messageCnt - 1] != '\0') { + vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt); return KERN_SUCCESS; } - if (message[messageCnt - 1] != '\0') + asldebug("__asl_server_message: %s\n", message); + + if ((global.memory_size + messageCnt) > global.memory_max) { + char str[256]; + asldebug("Server queue dropped message. message size %u queue size %lld max %lld\n", messageCnt, global.memory_size, global.memory_max); + snprintf(str, sizeof(str), "[Sender syslogd] [Level 2] [PID %u] [Message Received message size %u overflows work queue (size %lld limit %lld) - dropping message] [UID 0] [UID 0] [Facility syslog]", global.pid, messageCnt, global.memory_size, global.memory_max); + internal_log_message(str); + vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt); return KERN_SUCCESS; } - asldebug("__asl_server_message: %s\n", (message == NULL) ? "NULL" : message); - - msg = asl_msg_from_string(message); + mbuf = malloc(messageCnt); + if (mbuf != NULL) memcpy(mbuf, message, messageCnt); vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt); - if (msg == NULL) return KERN_SUCCESS; + if (mbuf == NULL) return KERN_SUCCESS; uid = (uid_t)-1; gid = (gid_t)-1; pid = (pid_t)-1; audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL); - client = MACH_PORT_NULL; - kstatus = task_name_for_pid(mach_task_self(), pid, &client); - if (kstatus == KERN_SUCCESS) register_session(client, pid); + OSAtomicIncrement32(&global.work_queue_count); + OSAtomicAdd64(messageCnt, &(global.memory_size)); - snprintf(tmp, sizeof(tmp), "%d", uid); - asl_msg_set_key_val(msg, ASL_KEY_UID, tmp); - - snprintf(tmp, sizeof(tmp), "%d", gid); - asl_msg_set_key_val(msg, ASL_KEY_GID, tmp); - - snprintf(tmp, sizeof(tmp), "%d", pid); - asl_msg_set_key_val(msg, ASL_KEY_PID, tmp); - - process_message(msg, SOURCE_ASL_MESSAGE); + dispatch_async(asl_server_queue, ^{ _asl_message_processing(mbuf, messageCnt, uid, gid, pid); }); return KERN_SUCCESS; } @@ -1574,7 +1674,7 @@ __asl_server_create_aux_link *newurlCnt = strlen(url) + 1; - kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, *newurlCnt, TRUE); + kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, *newurlCnt, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL)); if (kstatus != KERN_SUCCESS) { free(url); diff --git a/syslogd.tproj/remote.c b/syslogd.tproj/remote.c index a050aba..f8c4cd5 100644 --- a/syslogd.tproj/remote.c +++ b/syslogd.tproj/remote.c @@ -619,6 +619,12 @@ session(void *x) } else { + free(out); + out = NULL; + + asl_msg_list_release(res); + res = NULL; + goto exit_session; } } diff --git a/syslogd.tproj/syslog.conf b/syslogd.tproj/syslog.conf new file mode 100644 index 0000000..715162b --- /dev/null +++ b/syslogd.tproj/syslog.conf @@ -0,0 +1,3 @@ +# Note that flat file logs are now configured in /etc/asl.conf + +install.* @127.0.0.1:32376 diff --git a/syslogd.tproj/syslogd.c b/syslogd.tproj/syslogd.c index 6d69769..f5c3f54 100644 --- a/syslogd.tproj/syslogd.c +++ b/syslogd.tproj/syslogd.c @@ -447,10 +447,11 @@ int main(int argc, const char *argv[]) { int32_t i; + uint64_t master_val; #if !TARGET_IPHONE_SIMULATOR int network_change_token; #endif - int quota_file_token, asl_db_token; + int quota_file_token, asl_db_token, master_token; char tstr[32], *notify_key; time_t now; int first_syslogd_start = 1; @@ -650,6 +651,11 @@ main(int argc, const char *argv[]) */ write_boot_log(first_syslogd_start); + /* default NOTIFY_SYSTEM_MASTER settings */ + master_val = 0x0; + notify_register_plain(NOTIFY_SYSTEM_MASTER, &master_token); + notify_set_state(master_token, master_val); + asldebug("reading launch plist\n"); launch_config(); diff --git a/syslogd.tproj/udp_in.c b/syslogd.tproj/udp_in.c index 3f6affd..7555788 100644 --- a/syslogd.tproj/udp_in.c +++ b/syslogd.tproj/udp_in.c @@ -184,7 +184,6 @@ udp_in_init() return 0; } -/* N.B. Does NOT close fds. They "belong" to launchd. */ int udp_in_close(void) { @@ -203,6 +202,7 @@ udp_in_close(void) if (ufd[i] != -1) { + close(ufd[i]); ufd[i] = -1; } } diff --git a/util.tproj/syslog.1 b/util.tproj/syslog.1 index e2d6a73..0e3b4e7 100644 --- a/util.tproj/syslog.1 +++ b/util.tproj/syslog.1 @@ -62,7 +62,7 @@ key val .Fl x Ar file Ar expression .D1 "" .Nm -.Fl c Ar process Op filter +.Fl c Ar process Op mask .D1 "" .Nm .Fl config Op options @@ -717,15 +717,15 @@ time sending messages that are in most cases unnecessary. The .Fl c option may be used to control filtering. -In addition to the internal filter value that processes may set as described above, +In addition to the internal filter mask value that processes may set as described above, the system maintains a global .Dq master -filter. +filter mask. This filter is normally .Dq off , meaning that it has no effect. -If a value is set for the master filter, it overrides the local filter for all processes. -Root user access is required to set the master filter value. +If a value is set for the master filter mask, it overrides the local filter mask for all processes. +Root user access is required to set the master filter mask value. .Pp The current setting of the master filter mask may be inspected using: .Pp @@ -739,11 +739,11 @@ These correspond to the priority levels Emergency (Panic), Alert, Critical, Erro The character .Dq x may be used for Error, as it is used for sending messages. -The master filter may be unset with: +The master filter mask may be deactivated with: .Pp .Dl syslog -c 0 off .Pp -Since it is common to use the filter as a +Since it is common to use the filter mask as a .Dq cutoff mechanism, for example to cut off messages with Debug and Info priority, a single character from the list above may be specified, preceded by a minus sign. @@ -752,11 +752,11 @@ In this case, uses a filter mask starting at level 0 (Emergency) .Dq up to the given level. -For example, to set the master filter level to cause all processes to log messages from Emergency up to Debug: +For example, to set the master filter mask to cause all processes to log messages from Emergency up to Debug: .Pp .Dl syslog -c 0 -d .Pp -While the master filter level may be set to control the messages produced by all processes, +While the master filter mask may be set to control the messages produced by all processes, another filter mask may be specified for an individual process. If a per-process filter mask is set, it overrides both the local filter mask and the master filter mask. The current setting for a per-process filter mask may be inspected using diff --git a/util.tproj/syslog.c b/util.tproj/syslog.c index 1cfb675..2662903 100644 --- a/util.tproj/syslog.c +++ b/util.tproj/syslog.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2011 Apple Inc. All rights reserved. + * Copyright (c) 2007-2015 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -136,15 +136,27 @@ static uint32_t dbselect = DB_SELECT_SYSLOGD; 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 asl_msg_t *asl_msg_from_string(const char *buf); -//extern char *asl_list_to_string(asl_msg_list_t *list, uint32_t *outlen); -//extern asl_msg_list_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 */ static mach_port_t asl_server_port = MACH_PORT_NULL; @@ -155,79 +167,129 @@ static const char *myname = "syslog"; 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 preceding a single letter means \"up to\" that level\n"); - fprintf(stderr, "\n"); - 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"); - 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"); - 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); + + 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); + } + + 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"); + } } const char * @@ -259,6 +321,16 @@ 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) @@ -389,10 +461,10 @@ module_control(int argc, char *argv[]) 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); @@ -512,7 +584,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; @@ -520,7 +592,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); @@ -688,6 +760,18 @@ 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) { @@ -700,27 +784,29 @@ rcontrol_get(pid_t pid, uid_t uid) status = rcontrol_get_string(rcontrol_name(pid, uid), &filter); if (status == NOTIFY_STATUS_OK) { - printf("Master filter mask: %s\n", asl_filter_string(filter)); + printf("Master settings: "); + print_eval_bits(filter); return 0; } - printf("Unable to determine master filter mask\n"); + 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 *rcname; @@ -729,7 +815,7 @@ rcontrol_set(pid_t pid, uid_t uid, int filter) if (pid < 0) { - status = rcontrol_set_string(rcname, filter); + status = rcontrol_set_string(rcname, bits); if (status == NOTIFY_STATUS_OK) { @@ -741,7 +827,7 @@ rcontrol_set(pid_t pid, uid_t uid, int filter) return -1; } - status = rcontrol_set_string(rcname, filter); + status = rcontrol_set_string(rcname, bits); if (status == NOTIFY_STATUS_OK) { status = notify_post(rcname); @@ -763,7 +849,7 @@ rsend(asl_msg_t *msg, 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; @@ -787,14 +873,14 @@ rsend(asl_msg_t *msg, char *rhost) tick = time(NULL); timestr = NULL; - asprintf(×tr, "%lu", tick); + asprintf(×tr, "%llu", (unsigned long long)tick); if (timestr != NULL) { asl_msg_set_key_val(msg, ASL_KEY_TIME, timestr); free(timestr); } - if (gethostname(myname, MAXHOSTNAMELEN) == 0) asl_msg_set_key_val(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((asl_msg_t *)msg, &len); @@ -821,7 +907,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; @@ -841,9 +927,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)); @@ -852,6 +938,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) { @@ -917,20 +1227,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; @@ -966,36 +1280,78 @@ syslog_remote_control(int argc, char *argv[]) if (pid == 0) pid = RC_MASTER; - if (argc == 4) + if (argc == 3) { - if ((pid == RC_MASTER) && (!strcasecmp(argv[3], "off"))) mask = 0; + rcontrol_get(pid, uid); + return 0; + } + + bits = EVAL_ACTIVE | EVAL_SEND_ASL | EVAL_SEND_TRACE; + + for (i = 3; i < argc; i++) + { + 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; - asl_client_t *asl; + 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; @@ -1026,16 +1382,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_client_open(myname, "syslog", 0); - asl_client_set_filter(asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); - m = asl_msg_new(ASL_TYPE_MSG); - asl_msg_set_key_val(m, ASL_KEY_SENDER, myname); + if (asl == NULL) asl = asl_open(myname, "syslog", 0); + asl_set_filter(asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); + + 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_msg_set_key_val(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; @@ -1065,7 +1447,7 @@ syslog_send(int argc, char *argv[]) if (rhost == NULL) { - asl_client_send(asl, m); + asl_send(asl, (asl_object_t)m); } else if (rfmt == SEND_FORMAT_ASL) { @@ -1080,7 +1462,7 @@ syslog_send(int argc, char *argv[]) if (str != NULL) free(str); - asl_client_release(asl); + asl_release(asl); return 0; } @@ -1096,6 +1478,15 @@ syslog_config(int argc, char *argv[]) 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(); @@ -1156,6 +1547,15 @@ syslog_control(int argc, char *argv[]) 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) { @@ -1331,7 +1731,7 @@ syslogd_query(asl_msg_list_t *q, uint64_t start, int count, int dir, uint64_t *l len = 0; 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); @@ -1538,15 +1938,15 @@ sort_compare_key(asl_msg_t *a, asl_msg_t *b, const char *key) } int -sort_compare(const void *ap, const void *bp) +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; + 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); @@ -1921,13 +2321,14 @@ main(int argc, char *argv[]) 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"))) - { - usage(); - exit(0); - } if ((!strcmp(argv[i], "-time")) || (!strcmp(argv[i], "--time"))) { @@ -1936,6 +2337,12 @@ main(int argc, char *argv[]) exit(0); } + if ((!strcmp(argv[i], "-stats")) || (!strcmp(argv[i], "--stats"))) + { + asl_stats(argc, argv); + exit(0); + } + if ((!strcmp(argv[i], "-config")) || (!strcmp(argv[i], "--config"))) { syslog_config(argc, argv); @@ -2113,7 +2520,7 @@ main(int argc, char *argv[]) if ((i + 1) >= argc) { asl_msg_list_release(qlist); - usage(); + usage(HELP_SEARCH); exit(1); } @@ -2126,7 +2533,7 @@ main(int argc, char *argv[]) if ((i + 1) >= argc) { asl_msg_list_release(qlist); - usage(); + usage(HELP_SEARCH); exit(1); } @@ -2143,7 +2550,7 @@ main(int argc, char *argv[]) if ((i + 1) >= argc) { asl_msg_list_release(qlist); - usage(); + usage(HELP_SEARCH); exit(1); } @@ -2178,7 +2585,7 @@ main(int argc, char *argv[]) if ((i + 1) >= argc) { asl_msg_list_release(qlist); - usage(); + usage(HELP_SEARCH); exit(1); } @@ -2240,7 +2647,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); } } @@ -2359,22 +2766,22 @@ main(int argc, char *argv[]) fprintf(stderr, "\ncan't allocate memory - exiting\n"); exit(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; } diff --git a/xcodeconfig/aslmanager.xcconfig b/xcodeconfig/aslmanager.xcconfig index fa9af9e..1c7c293 100644 --- a/xcodeconfig/aslmanager.xcconfig +++ b/xcodeconfig/aslmanager.xcconfig @@ -1,3 +1,3 @@ #include "base.xcconfig" -INSTALL_PATH_ACTUAL = /usr/sbin +INSTALL_PATH = /usr/sbin diff --git a/xcodeconfig/base.xcconfig b/xcodeconfig/base.xcconfig index e3a569e..74940e8 100644 --- a/xcodeconfig/base.xcconfig +++ b/xcodeconfig/base.xcconfig @@ -1,5 +1 @@ #include "/Makefiles/CoreOS/Xcode/BSD.xcconfig" -#include "/AppleInternal/XcodeConfig/SimulatorSupport.xcconfig" - -// Set INSTALL_PATH[sdk=macosx*] when SimulatorSupport.xcconfig is unavailable -INSTALL_PATH[sdk=macosx*] = $(INSTALL_PATH_ACTUAL) diff --git a/xcodeconfig/libasl.xcconfig b/xcodeconfig/libasl.xcconfig index c2ea1af..82e6122 100644 --- a/xcodeconfig/libasl.xcconfig +++ b/xcodeconfig/libasl.xcconfig @@ -8,19 +8,17 @@ EXECUTABLE_PREFIX = libsystem_ PRODUCT_NAME = asl -INSTALL_PATH_ACTUAL = /usr/lib/system +INSTALL_PATH = /usr/lib/system -PUBLIC_HEADERS_FOLDER_PATH = $(INSTALL_PATH_PREFIX)/usr/include -PRIVATE_HEADERS_FOLDER_PATH = $(INSTALL_PATH_PREFIX)/usr/local/include +PUBLIC_HEADERS_FOLDER_PATH = /usr/include +PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include LINK_WITH_STANDARD_LIBRARIES = NO CR_LDFLAGS = -lCrashReporterClient LIBCOMPILER_RT_LDFLAGS = -lcompiler_rt LIBCLOSURE_LDFLAGS = -lsystem_blocks -LIBCLOSURE_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_blocks LIBC_LDFLAGS = -lsystem_c -LIBC_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_c LIBMALLOC_LDFLAGS = -lsystem_malloc LIBNOTIFY_LDFLAGS = -lsystem_notify LIBPLATFORM_LDFLAGS = -lsystem_platform @@ -30,14 +28,10 @@ LIBPTHREAD_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_pthread LIBSYSCALL_LDFLAGS = -lsystem_kernel LIBSYSCALL_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_kernel LIBM_LDFLAGS = -lsystem_m -LIBM_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_m LIBDYLD_LDFLAGS = -ldyld LIBTRACE_LDFLAGS = -lsystem_trace -LIBTRACE_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_trace -LIBUNWIND_LDFLAGS = -LIBUNWIND_LDFLAGS[sdk=iphonesimulator*] = -lunwind_sim +LIBUNWIND_LDFLAGS = -lunwind OTHER_LDFLAGS = -all_load -L/usr/lib/system -umbrella System $(CR_LDFLAGS) $(LIBCOMPILER_RT_LDFLAGS) $(LIBDYLD_LDFLAGS) $(LIBSYSCALL_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(LIBPTHREAD_LDFLAGS) $(LIBMALLOC_LDFLAGS) $(LIBC_LDFLAGS) $(LIBUNWIND_LDFLAGS) $(LIBCLOSURE_LDFLAGS) -ldispatch $(LIBLAUNCH_LDFLAGS) -lxpc $(LIBTRACE_LDFLAGS) $(LIBNOTIFY_LDFLAGS) $(UPWARD_LINKS) UPWARD_LINKS = -Wl,-upward-lsystem_info -UPWARD_LINKS[sdk=iphonesimulator*] = -Wl,-upward-lsystem_sim_info diff --git a/xcodeconfig/syslogd.xcconfig b/xcodeconfig/syslogd.xcconfig index fa9af9e..1c7c293 100644 --- a/xcodeconfig/syslogd.xcconfig +++ b/xcodeconfig/syslogd.xcconfig @@ -1,3 +1,3 @@ #include "base.xcconfig" -INSTALL_PATH_ACTUAL = /usr/sbin +INSTALL_PATH = /usr/sbin diff --git a/xcodeconfig/util.xcconfig b/xcodeconfig/util.xcconfig index 51575c9..7eebb22 100644 --- a/xcodeconfig/util.xcconfig +++ b/xcodeconfig/util.xcconfig @@ -1,3 +1,3 @@ #include "base.xcconfig" -INSTALL_PATH_ACTUAL = /usr/bin +INSTALL_PATH = /usr/bin -- 2.45.2