From f3df4c032d7a59379e2d8e1a5cf8a8f0e9ea9f63 Mon Sep 17 00:00:00 2001 From: Apple Date: Fri, 11 Jul 2014 06:45:47 +0000 Subject: [PATCH] syslog-267.tar.gz --- aslcommon/asl_common.c | 701 ++++++--- aslcommon/asl_common.h | 45 +- aslcommon/asl_ipc.defs | 18 +- aslcommon/asl_memory.c | 205 ++- aslcommon/asl_memory.h | 15 +- aslcommon/asl_mini_memory.c | 1247 --------------- aslcommon/asl_mini_memory.h | 80 - aslmanager.tproj/aslmanager.c | 441 ++++-- libsystem_asl.tproj/include/asl.h | 787 +++++++--- libsystem_asl.tproj/include/asl_client.h | 101 ++ libsystem_asl.tproj/include/asl_core.h | 42 +- libsystem_asl.tproj/include/asl_file.h | 56 +- libsystem_asl.tproj/include/asl_legacy1.h | 6 +- libsystem_asl.tproj/include/asl_msg.h | 41 +- libsystem_asl.tproj/include/asl_msg_list.h | 75 + libsystem_asl.tproj/include/asl_object.h | 78 + libsystem_asl.tproj/include/asl_private.h | 67 +- libsystem_asl.tproj/include/asl_store.h | 47 +- libsystem_asl.tproj/include/asl_string.h | 57 + libsystem_asl.tproj/man/asl.3 | 1075 ++++++++++--- libsystem_asl.tproj/src/asl.c | 1603 ++++++-------------- libsystem_asl.tproj/src/asl_client.c | 584 +++++++ libsystem_asl.tproj/src/asl_core.c | 1029 ++++++++----- libsystem_asl.tproj/src/asl_fd.c | 133 +- libsystem_asl.tproj/src/asl_file.c | 700 ++++++--- libsystem_asl.tproj/src/asl_legacy1.c | 85 +- libsystem_asl.tproj/src/asl_msg.c | 992 +++++++----- libsystem_asl.tproj/src/asl_msg_list.c | 587 +++++++ libsystem_asl.tproj/src/asl_object.c | 426 ++++++ libsystem_asl.tproj/src/asl_store.c | 419 ++++- libsystem_asl.tproj/src/asl_string.c | 532 +++++++ libsystem_asl.tproj/src/asl_util.c | 101 +- libsystem_asl.tproj/src/syslog.c | 23 +- syslog.xcodeproj/project.pbxproj | 113 +- syslogd.tproj/after_install.sh | 4 +- syslogd.tproj/asl.conf.5 | 67 +- syslogd.tproj/asl_action.c | 1496 +++++++++++------- syslogd.tproj/asl_sim.conf | 22 +- syslogd.tproj/bb_convert.c | 534 ------- syslogd.tproj/bsd_in.c | 4 +- syslogd.tproj/bsd_out.c | 22 +- syslogd.tproj/com.apple.syslogd.plist | 2 +- syslogd.tproj/com.apple.syslogd_sim.plist | 13 +- syslogd.tproj/daemon.c | 333 ++-- syslogd.tproj/daemon.h | 43 +- syslogd.tproj/dbserver.c | 368 +++-- syslogd.tproj/klog_in.c | 2 +- syslogd.tproj/remote.c | 80 +- syslogd.tproj/syslogd.c | 148 +- syslogd.tproj/udp_in.c | 2 +- util.tproj/syslog.1 | 11 +- util.tproj/syslog.c | 355 ++--- xcodeconfig/aslmanager.xcconfig | 3 + xcodeconfig/base.xcconfig | 5 + xcodeconfig/libasl.xcconfig | 35 +- xcodeconfig/syslogd.xcconfig | 3 + xcodeconfig/util.xcconfig | 3 + xcodescripts/sim-compat-symlink.sh | 7 + 58 files changed, 9706 insertions(+), 6367 deletions(-) delete mode 100644 aslcommon/asl_mini_memory.c delete mode 100644 aslcommon/asl_mini_memory.h create mode 100644 libsystem_asl.tproj/include/asl_client.h create mode 100644 libsystem_asl.tproj/include/asl_msg_list.h create mode 100644 libsystem_asl.tproj/include/asl_object.h create mode 100644 libsystem_asl.tproj/include/asl_string.h create mode 100644 libsystem_asl.tproj/src/asl_client.c create mode 100644 libsystem_asl.tproj/src/asl_msg_list.c create mode 100644 libsystem_asl.tproj/src/asl_object.c create mode 100644 libsystem_asl.tproj/src/asl_string.c delete mode 100644 syslogd.tproj/bb_convert.c create mode 100644 xcodeconfig/aslmanager.xcconfig create mode 100644 xcodeconfig/base.xcconfig create mode 100644 xcodeconfig/syslogd.xcconfig create mode 100644 xcodeconfig/util.xcconfig create mode 100644 xcodescripts/sim-compat-symlink.sh diff --git a/aslcommon/asl_common.c b/aslcommon/asl_common.c index a4c21d3..fea5e91 100644 --- a/aslcommon/asl_common.c +++ b/aslcommon/asl_common.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include "asl_common.h" @@ -45,6 +46,12 @@ #define _PATH_ASL_CONF "/etc/asl.conf" #define _PATH_ASL_CONF_DIR "/etc/asl" +#define PATH_VAR_LOG "/var/log/" +#define PATH_VAR_LOG_LEN 9 + +#define PATH_LIBRARY_LOGS "/Library/Logs/" +#define PATH_LIBRARY_LOGS_LEN 14 + #if !TARGET_IPHONE_SIMULATOR #define _PATH_ASL_CONF_LOCAL_DIR "/usr/local/etc/asl" #endif @@ -60,6 +67,8 @@ static const char *asl_out_action_name[] = "notify ", "broadcast ", "access ", + "set ", + "unset ", "store ", "asl_file ", "asl_dir ", @@ -71,13 +80,15 @@ static const char *asl_out_action_name[] = "set (profile)" }; -static time_t start_today; - -extern asl_msg_t *asl_msg_from_string(const char *buf); - #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) { @@ -432,8 +443,143 @@ 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) +{ + if (m == NULL) return NULL; + if (path == NULL) return NULL; + + while (m != NULL) + { + 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; + r = r->next; + } + + m = m->next; + } + + return NULL; +} + +/* + * Create a directory path. + * + * mlist provides owner, group, and access mode, which are required for "non-standard" + * directories. Directories for standard paths (/var/log or /Library/Logs) default + * to root/admin/0755 if there is no mlist rule for them. + */ +static int +_asl_common_make_dir_path(asl_out_module_t *mlist, uint32_t flags, const char *path) +{ + int i; + char **path_parts; + asl_string_t *processed_path; + mode_t mode; + + if (path == NULL) return 0; + + path_parts = explode(path, "/"); + if (path_parts == NULL) return 0; + + processed_path = asl_string_new(ASL_ENCODE_NONE); + + i = 0; + if (path[0] == '/') i = 1; + + for (; path_parts[i] != NULL; i++) + { + struct stat sb; + int status; + mode_t mask; + asl_out_dst_data_t *dst; + char *tmp; + + asl_string_append_char_no_encoding(processed_path, '/'); + asl_string_append_no_encoding(processed_path, path_parts[i]); + tmp = asl_string_bytes(processed_path); + + memset(&sb, 0, sizeof(struct stat)); + status = lstat(tmp, &sb); + if ((status == 0) && S_ISLNK(sb.st_mode)) + { + char real[MAXPATHLEN]; + if (realpath(tmp, real) == NULL) + { + asl_string_release(processed_path); + free_string_list(path_parts); + return -1; + } + + memset(&sb, 0, sizeof(struct stat)); + status = stat(real, &sb); + } + + if (status == 0) + { + if (!S_ISDIR(sb.st_mode)) + { + /* path component is not a directory! */ + asl_string_release(processed_path); + free_string_list(path_parts); + return -1; + } + + /* exists and is a directory or a link to a directory */ + continue; + } + else if (errno != ENOENT) + { + /* unexpected status from stat() */ + asl_string_release(processed_path); + free_string_list(path_parts); + return -1; + } + + 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! */ + asl_string_release(processed_path); + free_string_list(path_parts); + return -1; + } + + mode = 0755; + if (dst != NULL) + { + mode = dst->mode; + if (mode == 010000) mode = 0755; + } + + mask = umask(0); + status = mkdir(tmp, mode); + umask(mask); + +#if !TARGET_IPHONE_SIMULATOR + uid_t u = 0; + gid_t g = 80; + + if (dst != NULL) + { + if (dst->nuid > 0) u = dst->uid[0]; + if (dst->ngid > 0) g = dst->gid[0]; + } + + chown(tmp, u, g); +#endif + } + + asl_string_release(processed_path); + free_string_list(path_parts); + + return 0; +} + int -asl_out_mkpath(asl_out_rule_t *r) +asl_out_mkpath(asl_out_module_t *mlist, asl_out_rule_t *r) { char tmp[MAXPATHLEN], *p; struct stat sb; @@ -456,14 +602,18 @@ asl_out_mkpath(asl_out_rule_t *r) status = stat(tmp, &sb); if (status == 0) { - if (!S_ISDIR(sb.st_mode)) return -1; + if (S_ISDIR(sb.st_mode)) return 0; + return -1; } - else if (errno == ENOENT) + + if (errno == ENOENT) { - status = mkpath_np(tmp, 0755); + uint32_t dirflag = r->dst->flags & MODULE_FLAG_NONSTD_DIR; + status = _asl_common_make_dir_path(mlist, dirflag, tmp); + return status; } - return status; + return -1; } void @@ -534,13 +684,16 @@ asl_make_dst_filename(asl_out_dst_data_t *dst, char *buf, size_t len) if (dst == NULL) return; if (buf == NULL) return; - if (dst->flags & MODULE_FLAG_BASESTAMP) + if (dst->flags & (MODULE_FLAG_BASESTAMP | MODULE_FLAG_TYPE_ASL_DIR)) { char tstamp[32]; + const char *name = dst->path; + + if (dst->flags & MODULE_FLAG_TYPE_ASL_DIR) name = dst->fname; if (dst->stamp == 0) dst->stamp = time(NULL); asl_make_timestamp(dst->stamp, dst->flags, tstamp, sizeof(tstamp)); - snprintf(buf, len, "%s.%s", dst->path, tstamp); + snprintf(buf, len, "%s.%s", name, tstamp); } else { @@ -549,95 +702,7 @@ asl_make_dst_filename(asl_out_dst_data_t *dst, char *buf, size_t len) } int -asl_out_dst_checkpoint(asl_out_dst_data_t *dst, uint32_t force) -{ - char newpath[MAXPATHLEN]; - time_t now; - - now = time(NULL); - - /* clock went backwards - force a reset */ - if (now < start_today) start_today = 0; - - /* check start_today and reset if required */ - if (now >= (start_today + SECONDS_PER_DAY)) - { - /* use localtime / mktime since start_today might be zero */ - struct tm t; - - start_today = now; - - localtime_r(&start_today, &t); - - t.tm_sec = 0; - t.tm_min = 0; - t.tm_hour = 0; - - start_today = mktime(&t); - } - - /* sleep to prevent a sub-second rotation */ - while (now == dst->stamp) - { - sleep(1); - now = time(NULL); - } - - if ((dst->stamp == 0) || (dst->size == 0)) - { - struct stat sb; - - memset(&sb, 0, sizeof(struct stat)); - - if (stat(dst->path, &sb) < 0) - { - if (errno == ENOENT) return 0; - return -1; - } - - if (dst->stamp == 0) dst->stamp = sb.st_birthtimespec.tv_sec; - if (dst->stamp == 0) dst->stamp = sb.st_mtimespec.tv_sec; - dst->size = sb.st_size; - } - - if (force == CHECKPOINT_TEST) - { - if ((dst->file_max > 0) && (dst->size >= dst->file_max)) force |= CHECKPOINT_SIZE; - if (dst->stamp < start_today) force |= CHECKPOINT_TIME; - - if (force == CHECKPOINT_TEST) return 0; - } - - if (dst->flags & MODULE_FLAG_TYPE_ASL_DIR) - { - if (force & CHECKPOINT_SIZE) - { - snprintf(newpath, sizeof(newpath), "%s.%c%lu", dst->fname, STYLE_SEC_PREFIX_CHAR, dst->stamp); - rename(dst->fname, newpath); - } - else - { - return 0; - } - } - - if ((dst->flags & MODULE_FLAG_BASESTAMP) == 0) - { - char tstamp[32]; - - asl_make_timestamp(dst->stamp, dst->flags, tstamp, sizeof(tstamp)); - snprintf(newpath, sizeof(newpath), "%s.%s", dst->path, tstamp); - rename(dst->path, newpath); - } - - dst->stamp = 0; - dst->size = 0; - - return 1; -} - -int -asl_check_option(aslmsg msg, const char *opt) +asl_check_option(asl_msg_t *msg, const char *opt) { const char *p; uint32_t len; @@ -648,7 +713,7 @@ asl_check_option(aslmsg msg, const char *opt) len = strlen(opt); if (len == 0) return 0; - p = asl_get(msg, ASL_KEY_OPTION); + p = asl_msg_get_val_for_key(msg, ASL_KEY_OPTION); if (p == NULL) return 0; while (*p != '\0') @@ -737,7 +802,7 @@ asl_out_dst_set_access(int fd, asl_out_dst_data_t *dst) * Don't bother setting group access if this is * file's group and the file is group-readable. */ - if ((dst->gid[i] == fgid) && (dst->mode & 0040)) continue; + if ((dst->gid[i] == fgid) && (dst->mode & 00040)) continue; status = mbr_gid_to_uuid(dst->gid[i], uuid); if (status != 0) @@ -770,7 +835,7 @@ asl_out_dst_set_access(int fd, asl_out_dst_data_t *dst) * Don't bother setting user access if this is * file's owner and the file is owner-readable. */ - if ((dst->uid[i] == fuid) && (dst->mode & 0400)) continue; + if ((dst->uid[i] == fuid) && (dst->mode & 00400)) continue; status = mbr_uid_to_uuid(dst->uid[i], uuid); if (status != 0) @@ -812,7 +877,7 @@ asl_file_create_return: /* create a file with acls */ int -asl_out_dst_file_create_open(asl_out_dst_data_t *dst) +asl_out_dst_file_create_open(asl_out_dst_data_t *dst, char **pathp) { int fd, status; struct stat sb; @@ -822,6 +887,12 @@ asl_out_dst_file_create_open(asl_out_dst_data_t *dst) if (dst->path == NULL) return -1; asl_make_dst_filename(dst, outpath, sizeof(outpath)); + if (dst->fname != NULL) free(dst->fname); + + dst->fname = strdup(outpath); + if (dst->fname == NULL) return -1; + + if (pathp != NULL) *pathp = strdup(outpath); memset(&sb, 0, sizeof(struct stat)); status = stat(outpath, &sb); @@ -845,7 +916,7 @@ asl_out_dst_file_create_open(asl_out_dst_data_t *dst) return -1; } - fd = open(outpath, O_RDWR | O_CREAT | O_EXCL, (dst->mode & 0666)); + fd = open(outpath, O_RDWR | O_CREAT | O_EXCL, (dst->mode & 00666)); if (fd < 0) return -1; dst->stamp = time(NULL); @@ -1176,6 +1247,7 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) char *p, *opts, *path; char **path_parts; int has_dotdot, recursion_limit; + uint32_t i, flags = 0; if (m == NULL) return NULL; if (s == NULL) return NULL; @@ -1233,16 +1305,13 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) } free_string_list(path_parts); + path_parts = NULL; - if ((did_sub == 0) || (has_dotdot == 1)) - { - path_parts = NULL; - } - else + if ((did_sub == 1) && (has_dotdot == 0)) { /* substitution might have added a ".." so check the new path */ free(path); - path = asl_string_free_return_bytes(processed_path); + path = asl_string_release_return_bytes(processed_path); processed_path = asl_string_new(ASL_ENCODE_NONE); path_parts = explode(path, "/"); recursion_limit--; @@ -1250,14 +1319,16 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) } free(path); + free_string_list(path_parts); + path_parts = NULL; if ((has_dotdot != 0) || (recursion_limit == 0)) { - asl_string_free(processed_path); + asl_string_release(processed_path); return NULL; } - path = asl_string_free_return_bytes(processed_path); + path = asl_string_release_return_bytes(processed_path); /* check if there's already a dst for this path */ for (rule = m->ruleset; rule != NULL; rule = rule->next) @@ -1274,20 +1345,38 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) } } + flags |= MODULE_FLAG_NONSTD_DIR; + if (path[0] != '/') { char *t = path; const char *log_root = "/var/log"; #if TARGET_IPHONE_SIMULATOR - log_root = getenv("IPHONE_SIMULATOR_LOG_ROOT"); - assert(log_root); + log_root = getenv("SIMULATOR_LOG_ROOT"); + if (log_root == NULL) log_root = "/tmp/log"; #endif - if (!strcmp(m->name, ASL_MODULE_NAME)) asprintf(&path, "%s/%s", log_root, t); - else asprintf(&path, "%s/module/%s/%s", log_root, m->name, t); + if (!strcmp(m->name, ASL_MODULE_NAME)) + { + asprintf(&path, "%s/%s", log_root, t); + } + else + { + asprintf(&path, "%s/module/%s/%s", log_root, m->name, t); + } free(t); + flags &= ~MODULE_FLAG_NONSTD_DIR; + } + else + { + /* + * 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; } out = (asl_out_rule_t *)calloc(1, sizeof(asl_out_rule_t)); @@ -1303,13 +1392,12 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) dst->refcount = 1; dst->path = path; dst->mode = def_mode; - dst->ttl = DEFAULT_TTL; - dst->flags = MODULE_FLAG_COALESCE; + dst->ttl[LEVEL_ALL] = DEFAULT_TTL; + dst->flags = flags | MODULE_FLAG_COALESCE; while (NULL != (p = next_word_from_string(&opts))) { if (KEYMATCH(p, "mode=")) dst->mode = strtol(p+5, NULL, 0); - else if (KEYMATCH(p, "ttl=")) dst->ttl = strtol(p+4, NULL, 0); #if !TARGET_IPHONE_SIMULATOR else if (KEYMATCH(p, "uid=")) _dst_add_uid(dst, p+4); else if (KEYMATCH(p, "gid=")) _dst_add_gid(dst, p+4); @@ -1326,6 +1414,8 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) } else if (KEYMATCH(p, "compress")) dst->flags |= MODULE_FLAG_COMPRESS; 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); @@ -1375,6 +1465,19 @@ _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, "ttl")) + { + char *q = p + 3; + if (*q == '=') + { + dst->ttl[LEVEL_ALL] = strtol(p+4, NULL, 0); + } + else if ((*q >= '0') && (*q <= '7') && (*(q+1) == '=')) + { + uint32_t x = *q - '0'; + dst->ttl[x] = strtol(p+5, NULL, 0); + } + } free(p); p = NULL; @@ -1382,7 +1485,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)) + if ((KEYMATCH(dst->path, _PATH_CRASHREPORTER)) || (KEYMATCH(dst->path, _PATH_CRASHREPORTER_MOBILE))) { dst->flags |= MODULE_FLAG_ROTATE; dst->flags |= MODULE_FLAG_CRASHLOG; @@ -1391,6 +1494,9 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) } #endif + /* ttl[LEVEL_ALL] must be max of all level-specific ttls */ + for (i = 0; i <= 7; i++) if (dst->ttl[i] > dst->ttl[LEVEL_ALL]) dst->ttl[LEVEL_ALL] = dst->ttl[i]; + /* default text file format is "std" */ if (dst->fmt == NULL) dst->fmt = strdup("std"); @@ -1398,7 +1504,7 @@ _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 (!strcmp(dst->fmt, "std") || !strcmp(dst->fmt, "bsd") || !strcmp(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)) @@ -1410,6 +1516,12 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) /* set time format for raw output */ if (!strcmp(dst->fmt, "raw")) dst->tfmt = "sec"; + /* check for ASL_PLACE_DATABASE_DEFAULT */ + if (!strcmp(dst->path, ASL_PLACE_DATABASE_DEFAULT)) + { + dst->flags = MODULE_FLAG_TYPE_ASL_DIR; + } + out->action = ACTION_OUT_DEST; out->dst = dst; @@ -1455,6 +1567,8 @@ _asl_out_module_parse_query_action(asl_out_module_t *m, char *s) 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)) { /* actions only allowed in com.apple.asl */ @@ -1505,7 +1619,12 @@ _asl_out_module_parse_query_action(asl_out_module_t *m, char *s) } /* store /some/path means save to an asl file */ - if ((out->action == ACTION_ASL_STORE) && (out->options != NULL)) out->action = ACTION_ASL_FILE; + 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 (out->options != NULL) out->action = ACTION_ASL_FILE; + } if ((out->action == ACTION_FILE) || (out->action == ACTION_ASL_FILE) || (out->action == ACTION_ASL_DIR)) { @@ -1519,6 +1638,12 @@ _asl_out_module_parse_query_action(asl_out_module_t *m, char *s) return out; } + /* + * dst might have been set up by a previous ACTION_OUT_DEST ('>') rule with no mode. + * If so, mode would be 010000. Set it now, since we know whether it is a file or dir. + */ + 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"))) { out->action = ACTION_ASL_FILE; @@ -1526,19 +1651,21 @@ _asl_out_module_parse_query_action(asl_out_module_t *m, char *s) if ((out->action == ACTION_ASL_FILE) && (out->dst != NULL)) { - /* remove meaningless flags */ - out->dst->flags &= ~MODULE_FLAG_COALESCE; - out->dst->flags &= ~MODULE_FLAG_STD_BSD_MSG; out->dst->flags |= MODULE_FLAG_TYPE_ASL; } if (out->action == ACTION_ASL_DIR) { - /* remove meaningless flags */ - out->dst->flags &= ~MODULE_FLAG_ROTATE; + /* coalesce is meaningless for ASL directories */ out->dst->flags &= ~MODULE_FLAG_COALESCE; - out->dst->flags &= ~MODULE_FLAG_STD_BSD_MSG; + + /* 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; } /* only ACTION_FILE and ACTION_ASL_FILE may rotate */ @@ -1578,7 +1705,7 @@ asl_out_module_parse_line(asl_out_module_t *m, char *s) } else if (*s == '>') { - _asl_out_module_parse_dst(m, s + 1, 0644); + _asl_out_module_parse_dst(m, s + 1, 010000); } return NULL; @@ -1775,7 +1902,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; + uint32_t i, ttlnset; n = NULL; for (r = m->ruleset; r != NULL; r = n) @@ -1810,9 +1937,9 @@ asl_out_module_print(FILE *f, asl_out_module_t *m) fprintf(f, "%cenabled", c); c = ' '; } - if (o->flags & MODULE_FLAG_LOCAL) + if (o->flags & MODULE_FLAG_SOFT_WRITE) { - fprintf(f, "%clocal", c); + fprintf(f, "%csoft", c); c = ' '; } if (o->flags & MODULE_FLAG_ROTATE) @@ -1830,11 +1957,6 @@ asl_out_module_print(FILE *f, asl_out_module_t *m) fprintf(f, "%ccompress", c); c = ' '; } - if (o->flags & MODULE_FLAG_EXTERNAL) - { - fprintf(f, "%cexternal", c); - c = ' '; - } if (o->flags & MODULE_FLAG_STYLE_SEC) { fprintf(f, "%cseconds", c); @@ -1870,14 +1992,19 @@ asl_out_module_print(FILE *f, asl_out_module_t *m) fprintf(f, "%cbasestamp", c); c = ' '; } - if (o->flags & MODULE_FLAG_CRASHLOG) + if (o->flags & MODULE_FLAG_NONSTD_DIR) { - fprintf(f, "%ccrashlog", c); + fprintf(f, "%cnon-std_dir", c); c = ' '; } - if (o->flags & MODULE_FLAG_SOFT_WRITE) + if (o->flags & MODULE_FLAG_EXTERNAL) { - fprintf(f, "%csoft", c); + fprintf(f, "%cexternal", c); + c = ' '; + } + if (o->flags & MODULE_FLAG_CRASHLOG) + { + fprintf(f, "%ccrashlog", c); c = ' '; } if (o->flags & MODULE_FLAG_TYPE_ASL) @@ -1890,16 +2017,16 @@ asl_out_module_print(FILE *f, asl_out_module_t *m) fprintf(f, "%casl_directory", c); c = ' '; } - if (o->flags & MODULE_FLAG_STD_BSD_MSG) - { - fprintf(f, "%cstd/bsd/msg", c); - c = ' '; - } fprintf(f, ")"); } fprintf(f, "\n"); - fprintf(f, " ttl: %u\n", o->ttl); + fprintf(f, " ttl: %u", o->ttl[LEVEL_ALL]); + 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"); + fprintf(f, " mode: 0%o\n", o->mode); fprintf(f, " file_max: %lu\n", o->file_max); fprintf(f, " all_max: %lu\n", o->all_max); @@ -2033,6 +2160,104 @@ _check_file_name(const char *name, const char *base, bool src, char **stamp) * MODULE_FLAG_STYLE_LCL_B requires a date/time component as the file's timestamp. * E.g. foo.20120406T153000-07 */ +int +_parse_stamp_style(char *stamp, uint32_t flags, uint32_t *sp, time_t *tp) +{ + int i, n; + bool digits; + struct tm t; + char zone; + uint32_t h, m, s; + long utc_offset = 0; + time_t ftime = 0; + + /* check for NULL (no stamp) */ + if (stamp == NULL) return STAMP_STYLE_NULL; + + /* check for MODULE_FLAG_STYLE_SEC (foo.T12345678) */ + if (stamp[0] == 'T') + { + n = atoi(stamp + 1); + if ((n == 0) && strcmp(stamp + 1, "0")) return STAMP_STYLE_INVALID; + if (tp != NULL) *tp = (time_t)n; + + return STAMP_STYLE_SEC; + } + + /* check for MODULE_FLAG_STYLE_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) + { + n = atoi(stamp); + if (sp != NULL) *sp = (uint32_t)n; + return STAMP_STYLE_SEQ; + } + + /* check for MODULE_FLAG_STYLE_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)) + { + 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)) + { + 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 + { + return STAMP_STYLE_INVALID; + } + + if (n < 6) return STAMP_STYLE_INVALID; + + if (n == 6) + { + zone = 'J'; + } + else if ((zone == '-') || (zone == '+')) + { + 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; + } + else if ((zone >= 'A') && (zone <= 'Z')) + { + if (zone < 'J') utc_offset = 3600 * ((zone - 'A') + 1); + else if ((zone >= 'K') && (zone <= 'M')) utc_offset = 3600 * (zone - 'A'); + else if (zone <= 'Y') utc_offset = -3600 * ((zone - 'N') + 1); + } + else if ((zone >= 'a') && (zone <= 'z')) + { + if (zone < 'j') utc_offset = 3600 * ((zone - 'a') + 1); + else if ((zone >= 'k') && (zone <= 'm')) utc_offset = 3600 * (zone - 'a'); + else if (zone <= 'y') utc_offset = -3600 * ((zone - 'n') + 1); + } + else + { + return STAMP_STYLE_INVALID; + } + + t.tm_year -= 1900; + t.tm_mon -= 1; + t.tm_sec += utc_offset; + t.tm_isdst = -1; + + if ((zone == 'J') || (zone == 'j')) ftime = mktime(&t); + else ftime = timegm(&t); + + if (tp != NULL) *tp = ftime; + + return STAMP_STYLE_UTC_OR_LCL; +} + asl_out_file_list_t * asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) { @@ -2042,7 +2267,7 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) uint32_t seq; time_t ftime; struct stat sb; - int n; + int pstyle, fstyle; asl_out_file_list_t *out, *x, *y; if (dir == NULL) return NULL; @@ -2063,90 +2288,33 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) check = _check_file_name(ent->d_name, base, src, &stamp); if (!check) continue; - /* exclude base from dst list */ - seq = IndexNull; ftime = 0; - if (stamp == NULL) - { - } - else if (flags & MODULE_FLAG_STYLE_SEQ) - { - seq = atoi(stamp); - if ((seq == 0) && strcmp(stamp, "0")) - { - free(stamp); - continue; - } - } - else if (flags & MODULE_FLAG_STYLE_SEC) - { - ftime = atoi(stamp + 1); - } - else if ((flags & MODULE_FLAG_STYLE_UTC) || (flags & MODULE_FLAG_STYLE_UTC_B) || (flags & MODULE_FLAG_STYLE_LCL) || (flags & MODULE_FLAG_STYLE_LCL_B)) - { - struct tm t; - char zone; - uint32_t h, m, s; - long utc_offset = 0; - - memset(&t, 0, sizeof(t)); - h = m = s = 0; + pstyle = _parse_stamp_style(stamp, flags, &seq, &ftime); + free(stamp); - n = 0; - if ((flags & MODULE_FLAG_STYLE_UTC) || (flags & MODULE_FLAG_STYLE_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 - { - 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); - } + if (pstyle == STAMP_STYLE_INVALID) continue; - if (n < 6) - { - continue; - } - else if (n == 6) - { - zone = 'J'; - } - else if ((zone == '-') || (zone == '+')) - { - 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; - } - else if ((zone >= 'A') && (zone <= 'Z')) - { - if (zone < 'J') utc_offset = 3600 * ((zone - 'A') + 1); - else if ((zone >= 'K') && (zone <= 'M')) utc_offset = 3600 * (zone - 'A'); - else if (zone <= 'Y') utc_offset = -3600 * ((zone - 'N') + 1); - } - else if ((zone >= 'a') && (zone <= 'z')) - { - if (zone < 'j') utc_offset = 3600 * ((zone - 'a') + 1); - else if ((zone >= 'k') && (zone <= 'm')) utc_offset = 3600 * (zone - 'a'); - else if (zone <= 'y') utc_offset = -3600 * ((zone - 'n') + 1); - } - else - { - free(stamp); - 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; - t.tm_year -= 1900; - t.tm_mon -= 1; - t.tm_sec += utc_offset; - t.tm_isdst = -1; + /* + * accept the file if: + * style is STAMP_STYLE_NULL (no timestamp) + * src is true and style is STAMP_STYLE_SEC + * actual style matches the style implied by the input flags + */ - if ((zone == 'J') || (zone == 'j')) ftime = mktime(&t); - else ftime = timegm(&t); - } + check = false; + if (pstyle == STAMP_STYLE_NULL) check = true; + if ((pstyle == STAMP_STYLE_SEC) && src) check = true; + if (pstyle == fstyle) check = true; - free(stamp); + if (!check) continue; x = (asl_out_file_list_t *)calloc(1, sizeof(asl_out_file_list_t)); if (x == NULL) @@ -2164,14 +2332,14 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) if (stat(path, &sb) == 0) { x->size = sb.st_size; - if (flags & MODULE_FLAG_STYLE_SEQ) + if (pstyle == STAMP_STYLE_SEQ) { x->ftime = sb.st_birthtimespec.tv_sec; if (x->ftime == 0) x->ftime = sb.st_mtimespec.tv_sec; } } - if (flags & MODULE_FLAG_STYLE_SEQ) + if (pstyle == STAMP_STYLE_SEQ) { if (out == NULL) { @@ -2258,7 +2426,7 @@ asl_list_src_files(asl_out_dst_data_t *dst) /* * MODULE_FLAG_EXTERNAL means some process other than syslogd writes the file. - * We simply check for its existence. + * We check for its existence, and that it is non-zero in size. */ if (dst->flags & MODULE_FLAG_EXTERNAL) { @@ -2268,7 +2436,7 @@ asl_list_src_files(asl_out_dst_data_t *dst) if (stat(dst->path, &sb) == 0) { - if (S_ISREG(sb.st_mode)) + if (S_ISREG(sb.st_mode) && (sb.st_size != 0)) { out = (asl_out_file_list_t *)calloc(1, sizeof(asl_out_file_list_t)); if (out != NULL) @@ -2350,3 +2518,78 @@ asl_list_dst_files(asl_out_dst_data_t *dst) return out; } + +static int +asl_secure_open_dir(const char *path) +{ + int fd, i; + char **path_parts; + + if (path == NULL) return -1; + if (path[0] != '/') return -1; + + path_parts = explode(path + 1, "/"); + if (path_parts == NULL) return 0; + + fd = open("/", O_RDONLY | O_NOFOLLOW, 0); + if (fd < 0) + { + free_string_list(path_parts); + return -1; + } + + for (i = 0; path_parts[i] != NULL; i++) + { + int fd_next, status; + struct stat sb; + + fd_next = openat(fd, path_parts[i], O_RDONLY | O_NOFOLLOW, 0); + close(fd); + fd = fd_next; + if (fd < 0) + { + free_string_list(path_parts); + return -1; + } + + memset(&sb, 0, sizeof(sb)); + + status = fstat(fd, &sb); + if (status < 0) + { + free_string_list(path_parts); + return -1; + } + + if (!S_ISDIR(sb.st_mode)) + { + free_string_list(path_parts); + return -1; + } + } + + free_string_list(path_parts); + return fd; +} + +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; + + status = fchown(fd, uid, gid); + if (status < 0) + { + close(fd); + return -1; + } + + if (mode >= 0) status = fchmod(fd, mode); + close(fd); + + if (status < 0) return -1; + return 0; +} diff --git a/aslcommon/asl_common.h b/aslcommon/asl_common.h index 816b591..7802887 100644 --- a/aslcommon/asl_common.h +++ b/aslcommon/asl_common.h @@ -29,6 +29,7 @@ #define ASL_MODULE_NAME "com.apple.asl" #define _PATH_CRASHREPORTER "/Library/Logs/CrashReporter" +#define _PATH_CRASHREPORTER_MOBILE "/var/mobile/Library/Logs/CrashReporter" #define ASL_SERVICE_NAME "com.apple.system.logger" @@ -46,15 +47,17 @@ #define ACTION_NOTIFY 6 #define ACTION_BROADCAST 7 #define ACTION_ACCESS 8 -#define ACTION_ASL_STORE 9 /* Save in main ASL Database */ -#define ACTION_ASL_FILE 10 /* Save in an ASL format data file */ -#define ACTION_ASL_DIR 11 /* Save in an ASL directory */ -#define ACTION_FILE 12 /* Save in a text file */ -#define ACTION_FORWARD 13 -#define ACTION_CONTROL 14 -#define ACTION_SET_FILE 15 /* = foo [File /a/b/c] */ -#define ACTION_SET_PLIST 16 /* = foo [Plist /a/b/c] ... */ -#define ACTION_SET_PROF 17 /* = foo [Profile abc] ... */ +#define ACTION_SET_KEY 9 +#define ACTION_UNSET_KEY 10 +#define ACTION_ASL_STORE 11 /* Save in main ASL Database */ +#define ACTION_ASL_FILE 12 /* Save in an ASL format data file */ +#define ACTION_ASL_DIR 13 /* Save in an ASL directory */ +#define ACTION_FILE 14 /* Save in a text file */ +#define ACTION_FORWARD 15 +#define ACTION_CONTROL 16 +#define ACTION_SET_FILE 17 /* = foo [File /a/b/c] */ +#define ACTION_SET_PLIST 18 /* = foo [Plist /a/b/c] ... */ +#define ACTION_SET_PROF 19 /* = foo [Profile abc] ... */ #define STYLE_SEC_PREFIX_CHAR 'T' @@ -65,7 +68,9 @@ #define MODULE_FLAG_ROTATE 0x00000004 #define MODULE_FLAG_COALESCE 0x00000008 #define MODULE_FLAG_COMPRESS 0x00000010 -#define MODULE_FLAG_EXTERNAL 0x00000020 +#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 */ @@ -79,11 +84,12 @@ #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 CHECKPOINT_TEST 0x00000000 -#define CHECKPOINT_FORCE 0xffffffff -#define CHECKPOINT_SIZE 0x00000001 -#define CHECKPOINT_TIME 0x00000002 -#define CHECKPOINT_CRASH 0x00000004 +#define CHECKPOINT_FORCE 0x00000001 +#define CHECKPOINT_CRASH 0x00000002 + +#define LEVEL_ALL 8 typedef struct { @@ -92,9 +98,10 @@ typedef struct char *fmt; const char *tfmt; char *rotate_dir; + uint32_t pvt_flags; uint32_t flags; uint32_t fails; - uint32_t ttl; + uint32_t ttl[9]; mode_t mode; #if !TARGET_IPHONE_SIMULATOR uid_t *uid; @@ -145,7 +152,7 @@ char *next_word_from_string(char **s); size_t asl_str_to_size(char *s); asl_msg_t *xpc_object_to_asl_msg(xpc_object_t xobj); -int asl_check_option(aslmsg msg, const char *opt); +int asl_check_option(asl_msg_t *msg, const char *opt); /* ASL OUT MODULES */ asl_out_module_t *asl_out_module_new(const char *name); @@ -157,9 +164,9 @@ asl_out_rule_t *asl_out_module_parse_line(asl_out_module_t *m, char *s); 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_rule_t *r); +int asl_out_mkpath(asl_out_module_t *mlist, asl_out_rule_t *r); 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); +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); @@ -175,4 +182,6 @@ void asl_out_file_list_free(asl_out_file_list_t *l); asl_msg_t *configuration_profile_to_asl_msg(const char *ident); +int asl_secure_chown_chmod_dir(const char *path, uid_t uid, gid_t gid, mode_t mode); + #endif /* __ASL_COMMON_H__ */ diff --git a/aslcommon/asl_ipc.defs b/aslcommon/asl_ipc.defs index 360e464..bdbaf83 100644 --- a/aslcommon/asl_ipc.defs +++ b/aslcommon/asl_ipc.defs @@ -51,12 +51,12 @@ routine _asl_server_query_timeout request : ooline_data, dealloc; startid : uint64_t; count : int; - flags : int; WaitTime timeout: natural_t; + flags : int; out reply : ooline_data, dealloc; out lastid : uint64_t; out status : int; - SecToken token : security_token_t + ServerAuditToken token : audit_token_t ); routine _asl_server_prune @@ -110,3 +110,17 @@ routine _asl_server_query_2 out status : int; ServerAuditToken token : audit_token_t ); + +routine _asl_server_match +( + server : mach_port_t; + request : ooline_data, dealloc; + startid : uint64_t; + count : uint64_t; + duration : uint32_t; + direction : int; + out reply : ooline_data, dealloc; + out lastid : uint64_t; + out status : int; + ServerAuditToken token : audit_token_t +); diff --git a/aslcommon/asl_memory.c b/aslcommon/asl_memory.c index 1bf140f..5bd090c 100644 --- a/aslcommon/asl_memory.c +++ b/aslcommon/asl_memory.c @@ -21,8 +21,6 @@ * @APPLE_LICENSE_HEADER_END@ */ -#include -#include "asl_memory.h" #include #include #include @@ -30,19 +28,22 @@ #include #include #include +#include +#include +#include #include +#include "asl_memory.h" #define DEFAULT_MAX_RECORDS 2000 +#define DEFAULT_MAX_STRING_MEMORY 4096000 #define MEM_STRING_HEADER_SIZE 8 #define forever for(;;) -extern time_t asl_parse_time(const char *str); -extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b); uint32_t -asl_memory_statistics(asl_memory_t *s, aslmsg *msg) +asl_memory_statistics(asl_memory_t *s, asl_msg_t **msg) { - aslmsg out; + asl_msg_t * out; uint32_t i, n; uint64_t size; char str[256]; @@ -50,7 +51,7 @@ asl_memory_statistics(asl_memory_t *s, aslmsg *msg) if (s == NULL) return ASL_STATUS_INVALID_STORE; if (msg == NULL) return ASL_STATUS_INVALID_ARG; - out = asl_new(ASL_TYPE_MSG); + out = asl_msg_new(ASL_TYPE_MSG); if (out == NULL) return ASL_STATUS_NO_MEMORY; size = sizeof(asl_memory_t); @@ -63,16 +64,25 @@ asl_memory_statistics(asl_memory_t *s, aslmsg *msg) } snprintf(str, sizeof(str), "%llu", size); - asl_set(out, "Size", str); + asl_msg_set_key_val(out, "Size", str); n = 0; for (i = 0; i < s->record_count; i++) if (s->record[i]->mid != 0) n++; + snprintf(str, sizeof(str), "%u", s->record_count); + asl_msg_set_key_val(out, "MaxRecords", str); + snprintf(str, sizeof(str), "%u", n); - asl_set(out, "RecordCount", str); + asl_msg_set_key_val(out, "RecordCount", str); snprintf(str, sizeof(str), "%u", s->string_count); - asl_set(out, "StringCount", str); + asl_msg_set_key_val(out, "StringCount", str); + + snprintf(str, sizeof(str), "%u", s->curr_string_mem); + asl_msg_set_key_val(out, "StringMemory", str); + + snprintf(str, sizeof(str), "%u", s->max_string_mem); + asl_msg_set_key_val(out, "MaxStringMemory", str); *msg = out; return ASL_STATUS_OK; @@ -117,7 +127,7 @@ asl_memory_close(asl_memory_t *s) } uint32_t -asl_memory_open(uint32_t max_records, asl_memory_t **s) +asl_memory_open(uint32_t max_records, size_t max_str_mem, asl_memory_t **s) { asl_memory_t *out; uint32_t i; @@ -125,10 +135,13 @@ asl_memory_open(uint32_t max_records, asl_memory_t **s) if (s == NULL) return ASL_STATUS_INVALID_ARG; if (max_records == 0) max_records = DEFAULT_MAX_RECORDS; + if (max_str_mem == 0) max_str_mem = DEFAULT_MAX_STRING_MEMORY; out = calloc(1, sizeof(asl_memory_t)); if (out == NULL) 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) @@ -296,6 +309,7 @@ asl_memory_string_retain(asl_memory_t *s, const char *str, int create) new = mem_string_new(str, len, hash); if (new == NULL) return NULL; + s->curr_string_mem += (MEM_STRING_HEADER_SIZE + len + 1); s->string_cache[where] = new; s->string_count++; @@ -326,6 +340,8 @@ 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); + free(m); s->string_count--; @@ -379,11 +395,11 @@ asl_memory_record_free(asl_memory_t *s, mem_record_t *r) } /* - * Encode an aslmsg as a record structure. + * Encode an asl_msg_t as a record structure. * Creates and caches strings. */ static uint32_t -asl_memory_message_encode(asl_memory_t *s, aslmsg msg) +asl_memory_message_encode(asl_memory_t *s, asl_msg_t *msg) { uint32_t x; mem_string_t *k, *v; @@ -417,7 +433,7 @@ asl_memory_message_encode(asl_memory_t *s, aslmsg msg) else if (!strcmp(key, ASL_KEY_TIME)) { - if (val != NULL) r->time = asl_parse_time(val); + if (val != NULL) r->time = asl_core_parse_time(val, NULL); } else if (!strcmp(key, ASL_KEY_TIME_NSEC)) { @@ -487,6 +503,10 @@ asl_memory_message_encode(asl_memory_t *s, aslmsg msg) r->flags |= ASL_MSG_FLAG_READ_GID_SET; } } + else if (!strcmp(key, ASL_KEY_OS_ACTIVITY_ID)) + { + if (val != NULL) r->os_activity_id = atoll(val); + } else if (!strcmp(key, ASL_KEY_MSG_ID)) { /* Ignore */ @@ -524,7 +544,7 @@ asl_memory_message_encode(asl_memory_t *s, aslmsg msg) } uint32_t -asl_memory_save(asl_memory_t *s, aslmsg msg, uint64_t *mid) +asl_memory_save(asl_memory_t *s, asl_msg_t *msg, uint64_t *mid) { uint32_t status; mem_record_t *t; @@ -558,6 +578,14 @@ asl_memory_save(asl_memory_t *s, aslmsg msg, uint64_t *mid) 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; + } + return status; } @@ -565,10 +593,10 @@ asl_memory_save(asl_memory_t *s, aslmsg msg, uint64_t *mid) * Decodes a record structure. */ static uint32_t -asl_memory_message_decode(asl_memory_t *s, mem_record_t *r, aslmsg *out) +asl_memory_message_decode(asl_memory_t *s, mem_record_t *r, asl_msg_t **out) { uint32_t i; - aslmsg msg; + asl_msg_t *msg; char tmp[64]; const char *key, *val; @@ -578,113 +606,120 @@ asl_memory_message_decode(asl_memory_t *s, mem_record_t *r, aslmsg *out) *out = NULL; - msg = asl_new(ASL_TYPE_MSG); + msg = asl_msg_new(ASL_TYPE_MSG); if (msg == NULL) return ASL_STATUS_NO_MEMORY; /* Message ID */ snprintf(tmp, sizeof(tmp), "%llu", r->mid); - asl_set(msg, ASL_KEY_MSG_ID, tmp); + asl_msg_set_key_val(msg, ASL_KEY_MSG_ID, tmp); /* Level */ snprintf(tmp, sizeof(tmp), "%u", r->level); - asl_set(msg, ASL_KEY_LEVEL, tmp); + asl_msg_set_key_val(msg, ASL_KEY_LEVEL, tmp); /* Time */ if (r->time != (uint64_t)-1) { snprintf(tmp, sizeof(tmp), "%llu", r->time); - asl_set(msg, ASL_KEY_TIME, tmp); + asl_msg_set_key_val(msg, ASL_KEY_TIME, tmp); } /* Nanoseconds */ if (r->nano != (uint32_t)-1) { snprintf(tmp, sizeof(tmp), "%u", r->nano); - asl_set(msg, ASL_KEY_TIME_NSEC, tmp); + asl_msg_set_key_val(msg, ASL_KEY_TIME_NSEC, tmp); } /* Host */ if (r->host != NULL) { - asl_set(msg, ASL_KEY_HOST, r->host->str); + asl_msg_set_key_val(msg, ASL_KEY_HOST, r->host->str); } /* Sender */ if (r->sender != NULL) { - asl_set(msg, ASL_KEY_SENDER, r->sender->str); + asl_msg_set_key_val(msg, ASL_KEY_SENDER, r->sender->str); } /* Sender mach UUID */ if (r->sender_mach_uuid != NULL) { - asl_set(msg, ASL_KEY_SENDER_MACH_UUID, r->sender_mach_uuid->str); + asl_msg_set_key_val(msg, ASL_KEY_SENDER_MACH_UUID, r->sender_mach_uuid->str); } /* Facility */ if (r->facility != NULL) { - asl_set(msg, ASL_KEY_FACILITY, r->facility->str); + asl_msg_set_key_val(msg, ASL_KEY_FACILITY, r->facility->str); } /* Ref Proc */ if (r->refproc != NULL) { - asl_set(msg, ASL_KEY_REF_PROC, r->refproc->str); + asl_msg_set_key_val(msg, ASL_KEY_REF_PROC, r->refproc->str); } /* Session */ if (r->session != NULL) { - asl_set(msg, ASL_KEY_SESSION, r->session->str); + asl_msg_set_key_val(msg, ASL_KEY_SESSION, r->session->str); } /* PID */ if (r->pid != -1) { snprintf(tmp, sizeof(tmp), "%d", r->pid); - asl_set(msg, ASL_KEY_PID, tmp); + asl_msg_set_key_val(msg, ASL_KEY_PID, tmp); } /* REF PID */ if (r->refpid != 0) { snprintf(tmp, sizeof(tmp), "%d", r->refpid); - asl_set(msg, ASL_KEY_REF_PID, tmp); + asl_msg_set_key_val(msg, ASL_KEY_REF_PID, tmp); } /* UID */ if (r->uid != -2) { snprintf(tmp, sizeof(tmp), "%d", r->uid); - asl_set(msg, ASL_KEY_UID, tmp); + asl_msg_set_key_val(msg, ASL_KEY_UID, tmp); } /* GID */ if (r->gid != -2) { snprintf(tmp, sizeof(tmp), "%d", r->gid); - asl_set(msg, ASL_KEY_GID, tmp); + asl_msg_set_key_val(msg, ASL_KEY_GID, tmp); } /* Message */ if (r->message != NULL) { - asl_set(msg, ASL_KEY_MSG, r->message->str); + asl_msg_set_key_val(msg, ASL_KEY_MSG, r->message->str); } /* ReadUID */ if (r->flags & ASL_MSG_FLAG_READ_UID_SET) { snprintf(tmp, sizeof(tmp), "%d", r->ruid); - asl_set(msg, ASL_KEY_READ_UID, tmp); + asl_msg_set_key_val(msg, ASL_KEY_READ_UID, tmp); } /* ReadGID */ if (r->flags & ASL_MSG_FLAG_READ_GID_SET) { snprintf(tmp, sizeof(tmp), "%d", r->rgid); - asl_set(msg, ASL_KEY_READ_GID, tmp); + asl_msg_set_key_val(msg, ASL_KEY_READ_GID, tmp); + } + + /* OSActivityID */ + if (r->os_activity_id != 0) + { + snprintf(tmp, sizeof(tmp), "%llu", r->os_activity_id); + asl_msg_set_key_val(msg, ASL_KEY_OS_ACTIVITY_ID, tmp); } /* Key - Value List */ @@ -697,7 +732,7 @@ asl_memory_message_decode(asl_memory_t *s, mem_record_t *r, aslmsg *out) i++; if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) val = r->kvlist[i]->str; - if (key != NULL) asl_set(msg, key, val); + if (key != NULL) asl_msg_set_key_val(msg, key, val); } *out = msg; @@ -705,7 +740,7 @@ asl_memory_message_decode(asl_memory_t *s, mem_record_t *r, aslmsg *out) } uint32_t -asl_memory_fetch(asl_memory_t *s, uint64_t mid, aslmsg *msg, int32_t ruid, int32_t rgid) +asl_memory_fetch(asl_memory_t *s, uint64_t mid, asl_msg_t **msg, int32_t ruid, int32_t rgid) { uint32_t i, status; @@ -728,10 +763,11 @@ asl_memory_fetch(asl_memory_t *s, uint64_t mid, aslmsg *msg, int32_t ruid, int32 } static mem_record_t * -asl_memory_query_to_record(asl_memory_t *s, aslmsg q, uint32_t *type) +asl_memory_query_to_record(asl_memory_t *s, asl_msg_t *q, uint32_t *type) { mem_record_t *out; - uint32_t i, x, op; + uint32_t i, x; + uint16_t op; mem_string_t *mkey, *mval; const char *key, *val; @@ -794,7 +830,7 @@ asl_memory_query_to_record(asl_memory_t *s, aslmsg q, uint32_t *type) } *type |= ASL_QUERY_MATCH_TIME; - out->time = asl_parse_time(val); + out->time = asl_core_parse_time(val, NULL); } else if (!strcmp(key, ASL_KEY_TIME_NSEC)) { @@ -951,7 +987,7 @@ asl_memory_query_to_record(asl_memory_t *s, aslmsg q, uint32_t *type) else if (!strcmp(key, ASL_KEY_SENDER_MACH_UUID)) { if (val == NULL) continue; - + if (*type & ASL_QUERY_MATCH_SMUUID) { asl_memory_record_free(s, out); @@ -1139,9 +1175,9 @@ asl_memory_fast_match(asl_memory_t *s, mem_record_t *r, uint32_t qtype, mem_reco } static uint32_t -asl_memory_slow_match(asl_memory_t *s, mem_record_t *r, aslmsg rawq) +asl_memory_slow_match(asl_memory_t *s, mem_record_t *r, asl_msg_t *rawq) { - aslmsg rawm; + asl_msg_t *rawm; uint32_t status; rawm = NULL; @@ -1150,16 +1186,18 @@ asl_memory_slow_match(asl_memory_t *s, mem_record_t *r, aslmsg rawq) status = 0; if (asl_msg_cmp((asl_msg_t *)rawq, (asl_msg_t *)rawm) != 0) status = 1; - asl_free(rawm); + asl_msg_release(rawm); return status; } uint32_t -asl_memory_match_restricted_uuid(asl_memory_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, int32_t ruid, int32_t rgid, const char *uuid_str) +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) { uint32_t status, i, where, start, j, do_match, did_match, rescount, *qtype; mem_record_t **qp; - aslmsg m; + asl_msg_t *m; + size_t qcount; + struct timeval now, finish; if (s == NULL) return ASL_STATUS_INVALID_STORE; if (res == NULL) return ASL_STATUS_INVALID_ARG; @@ -1167,17 +1205,18 @@ asl_memory_match_restricted_uuid(asl_memory_t *s, aslresponse query, aslresponse qp = NULL; qtype = NULL; rescount = 0; + qcount = asl_msg_list_count(query); - if ((query == NULL) || ((query != NULL) && (query->count == 0))) + if (qcount == 0) { do_match = 0; } else { - qp = (mem_record_t **)calloc(query->count, sizeof(mem_record_t *)); + qp = (mem_record_t **)calloc(qcount, sizeof(mem_record_t *)); if (qp == NULL) return ASL_STATUS_NO_MEMORY; - qtype = (uint32_t *)calloc(query->count, sizeof(uint32_t)); + qtype = (uint32_t *)calloc(qcount, sizeof(uint32_t)); if (qtype == NULL) { free(qp); @@ -1185,9 +1224,9 @@ asl_memory_match_restricted_uuid(asl_memory_t *s, aslresponse query, aslresponse } do_match = 0; - for (i = 0; i < query->count; i++) + for (i = 0; i < qcount; i++) { - qp[i] = asl_memory_query_to_record(s, (aslmsg)query->msg[i], &(qtype[i])); + qp[i] = asl_memory_query_to_record(s, asl_msg_list_get_index(query, i), &(qtype[i])); if (qtype[i] == ASL_QUERY_MATCH_ERROR) { for (j = 0; j < i; j++) asl_memory_record_free(s, qp[j]); @@ -1220,7 +1259,7 @@ asl_memory_match_restricted_uuid(asl_memory_t *s, aslresponse query, aslresponse { if (qp != NULL) { - for (i = 0; i < query->count; i++) asl_memory_record_free(s, qp[i]); + for (i = 0; i < qcount; i++) asl_memory_record_free(s, qp[i]); free(qp); free(qtype); } @@ -1228,6 +1267,27 @@ asl_memory_match_restricted_uuid(asl_memory_t *s, aslresponse query, aslresponse return ASL_STATUS_OK; } + /* start the timer if a duration was specified */ + memset(&finish, 0, sizeof(struct timeval)); + if (duration != 0) + { + if (gettimeofday(&finish, NULL) == 0) + { + finish.tv_sec += (duration / USEC_PER_SEC); + finish.tv_usec += (duration % USEC_PER_SEC); + if (finish.tv_usec > USEC_PER_SEC) + { + finish.tv_usec -= USEC_PER_SEC; + finish.tv_sec += 1; + } + } + else + { + /* shouldn't happen, but if gettimeofday failed we just run without a timeout */ + memset(&finish, 0, sizeof(struct timeval)); + } + } + start = where; /* @@ -1269,7 +1329,7 @@ asl_memory_match_restricted_uuid(asl_memory_t *s, aslresponse query, aslresponse { did_match = 0; - for (j = 0; (j < query->count) && (did_match == 0); j++) + for (j = 0; (j < qcount) && (did_match == 0); j++) { if (qtype[j] == ASL_QUERY_MATCH_TRUE) { @@ -1281,7 +1341,7 @@ asl_memory_match_restricted_uuid(asl_memory_t *s, aslresponse query, aslresponse } else if (qtype[j] == ASL_QUERY_MATCH_SLOW) { - did_match = asl_memory_slow_match(s, s->record[where], (aslmsg)query->msg[j]); + did_match = asl_memory_slow_match(s, s->record[where], asl_msg_list_get_index(query, j)); } else { @@ -1297,6 +1357,12 @@ asl_memory_match_restricted_uuid(asl_memory_t *s, aslresponse query, aslresponse if ((count != 0) && (rescount >= count)) break; } + /* check the timer */ + if ((finish.tv_sec != 0) && (gettimeofday(&now, NULL) == 0)) + { + if ((now.tv_sec > finish.tv_sec) || ((now.tv_sec == finish.tv_sec) && (now.tv_usec > finish.tv_usec))) break; + } + if (direction >= 0) { where++; @@ -1311,9 +1377,9 @@ asl_memory_match_restricted_uuid(asl_memory_t *s, aslresponse query, aslresponse if (where == s->record_first) break; } - if (query != NULL) + if (qp != NULL) { - for (i = 0; i < query->count; i++) asl_memory_record_free(s, qp[i]); + for (i = 0; i < qcount; i++) asl_memory_record_free(s, qp[i]); free(qp); free(qtype); } @@ -1321,22 +1387,14 @@ asl_memory_match_restricted_uuid(asl_memory_t *s, aslresponse query, aslresponse *res = NULL; if (rescount == 0) return ASL_STATUS_OK; - *res = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t)); + *res = asl_msg_list_new(); if (*res == NULL) return ASL_STATUS_NO_MEMORY; - (*res)->count = rescount; - - (*res)->msg = (asl_msg_t **)calloc(rescount, sizeof(asl_msg_t *)); - if ((*res)->msg == NULL) - { - free(*res); - *res = NULL; - return ASL_STATUS_NO_MEMORY; - } - where = start; forever { + int n = 0; + if (s->record[where]->flags & ASL_MSG_FLAG_SEARCH_MATCH) { s->record[where]->flags &= ASL_MSG_FLAG_SEARCH_CLEAR; @@ -1344,13 +1402,15 @@ asl_memory_match_restricted_uuid(asl_memory_t *s, aslresponse query, aslresponse status = asl_memory_message_decode(s, s->record[where], &m); if (status != ASL_STATUS_OK) { - aslresponse_free(*res); + asl_msg_list_release(*res); *res = NULL; return status; } - (*res)->msg[(*res)->curr++] = (asl_msg_t *)m; - if ((*res)->curr == rescount) break; + asl_msg_list_append(*res, m); + asl_msg_release(m); + n++; + if (n == rescount) break; } if (direction >= 0) @@ -1367,12 +1427,11 @@ asl_memory_match_restricted_uuid(asl_memory_t *s, aslresponse query, aslresponse if (where == s->record_first) break; } - (*res)->curr = 0; return ASL_STATUS_OK; } uint32_t -asl_memory_match(asl_memory_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, int32_t ruid, int32_t rgid) +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, direction, ruid, rgid, NULL); + return asl_memory_match_restricted_uuid(s, query, res, last_id, start_id, count, 0, direction, ruid, rgid, NULL); } diff --git a/aslcommon/asl_memory.h b/aslcommon/asl_memory.h index e838ccd..3a1a30a 100644 --- a/aslcommon/asl_memory.h +++ b/aslcommon/asl_memory.h @@ -47,6 +47,7 @@ typedef struct 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; @@ -66,16 +67,18 @@ typedef struct uint32_t record_first; mem_record_t **record; mem_record_t *buffer_record; + uint32_t max_string_mem; + uint32_t curr_string_mem; } asl_memory_t; -uint32_t asl_memory_open(uint32_t max_records, asl_memory_t **s); +uint32_t asl_memory_open(uint32_t max_records, size_t max_str_mem, asl_memory_t **s); uint32_t asl_memory_close(asl_memory_t *s); -uint32_t asl_memory_statistics(asl_memory_t *s, aslmsg *msg); +uint32_t asl_memory_statistics(asl_memory_t *s, asl_msg_t **msg); -uint32_t asl_memory_save(asl_memory_t *s, aslmsg msg, uint64_t *mid); -uint32_t asl_memory_fetch(asl_memory_t *s, uint64_t mid, aslmsg *msg, int32_t ruid, int32_t rgid); +uint32_t asl_memory_save(asl_memory_t *s, asl_msg_t *msg, uint64_t *mid); +uint32_t asl_memory_fetch(asl_memory_t *s, uint64_t mid, asl_msg_t **msg, int32_t ruid, int32_t rgid); -uint32_t asl_memory_match(asl_memory_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, int32_t ruid, int32_t rgid); -uint32_t asl_memory_match_restricted_uuid(asl_memory_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, int32_t ruid, int32_t rgid, const char *uuid_str); +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); +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); #endif /* __ASL_MEMORY_H__ */ diff --git a/aslcommon/asl_mini_memory.c b/aslcommon/asl_mini_memory.c deleted file mode 100644 index 0651cb8..0000000 --- a/aslcommon/asl_mini_memory.c +++ /dev/null @@ -1,1247 +0,0 @@ -/* - * Copyright (c) 2007-2010 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 "asl_mini_memory.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEFAULT_MAX_RECORDS 256 -#define MEM_STRING_HEADER_SIZE 8 -#define CFLOG_LOCAL_TIME_KEY "CFLog Local Time" -#define CFLOG_THREAD_KEY "CFLog Thread" - -#define forever for(;;) -extern time_t asl_parse_time(const char *str); -extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b); - -uint32_t -asl_mini_memory_statistics(asl_mini_memory_t *s, aslmsg *msg) -{ - aslmsg out; - uint32_t i, n; - uint64_t size; - char str[256]; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (msg == NULL) return ASL_STATUS_INVALID_ARG; - - out = asl_new(ASL_TYPE_MSG); - if (out == NULL) return ASL_STATUS_NO_MEMORY; - - size = sizeof(asl_mini_memory_t); - size += ((s->record_count + 1) * sizeof(mini_mem_record_t)); - - for (i = 0; i < s->string_count; i++) - { - size += MEM_STRING_HEADER_SIZE; - if (((mini_mem_string_t *)s->string_cache[i])->str != NULL) size += (strlen(((mini_mem_string_t *)s->string_cache[i])->str) + 1); - } - - snprintf(str, sizeof(str), "%llu", size); - asl_set(out, "Size", str); - - n = 0; - for (i = 0; i < s->record_count; i++) if (s->record[i]->mid != 0) n++; - - snprintf(str, sizeof(str), "%u", n); - asl_set(out, "RecordCount", str); - - snprintf(str, sizeof(str), "%u", s->string_count); - asl_set(out, "StringCount", str); - - *msg = out; - return ASL_STATUS_OK; -} - -uint32_t -asl_mini_memory_close(asl_mini_memory_t *s) -{ - uint32_t i; - - if (s == NULL) return ASL_STATUS_OK; - - if (s->record != NULL) - { - for (i = 0; i < s->record_count; i++) - { - if (s->record[i] != NULL) free(s->record[i]); - s->record[i] = NULL; - } - - free(s->record); - s->record = NULL; - } - - if (s->buffer_record != NULL) free(s->buffer_record); - - if (s->string_cache != NULL) - { - for (i = 0; i < s->string_count; i++) - { - if (s->string_cache[i] != NULL) free(s->string_cache[i]); - s->string_cache[i] = NULL; - } - - free(s->string_cache); - s->string_cache = NULL; - } - - free(s); - - return ASL_STATUS_OK; -} - -uint32_t -asl_mini_memory_open(uint32_t max_records, asl_mini_memory_t **s) -{ - asl_mini_memory_t *out; - uint32_t i; - - if (s == NULL) return ASL_STATUS_INVALID_ARG; - - if (max_records == 0) max_records = DEFAULT_MAX_RECORDS; - - out = calloc(1, sizeof(asl_mini_memory_t)); - if (out == NULL) return ASL_STATUS_NO_MEMORY; - - out->record_count = max_records; - out->record = (mini_mem_record_t **)calloc(max_records, sizeof(mini_mem_record_t *)); - if (out->record == NULL) - { - free(out); - return ASL_STATUS_NO_MEMORY; - } - - for (i = 0; i < max_records; i++) - { - out->record[i] = (mini_mem_record_t *)calloc(1, sizeof(mini_mem_record_t)); - if (out->record[i] == NULL) - { - asl_mini_memory_close(out); - return ASL_STATUS_NO_MEMORY; - } - } - - out->buffer_record = (mini_mem_record_t *)calloc(1, sizeof(mini_mem_record_t)); - if (out->buffer_record == NULL) - { - asl_mini_memory_close(out); - return ASL_STATUS_NO_MEMORY; - } - - out->next_id = 1; - - *s = out; - return ASL_STATUS_OK; -} - -static mini_mem_string_t * -mem_string_new(const char *str, uint32_t len, uint32_t hash) -{ - mini_mem_string_t *out; - size_t ss; - - if (str == NULL) return NULL; - - ss = MEM_STRING_HEADER_SIZE + len + 1; - out = (mini_mem_string_t *)calloc(1, ss); - if (out == NULL) return NULL; - - out->hash = hash; - out->refcount = 1; - memcpy(out->str, str, len); - - 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. - * 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 - * new strings. Note that the caller needs to do extra work after calling this routine. - */ -static uint32_t -asl_mini_memory_string_cache_search_hash(asl_mini_memory_t *s, uint32_t hash) -{ - uint32_t top, bot, mid, range; - mini_mem_string_t *ms; - - if (s->string_count == 0) return 0; - if (s->string_count == 1) - { - ms = (mini_mem_string_t *)s->string_cache[0]; - if (hash < ms->hash) return 0; - return 1; - } - - range = top = s->string_count - 1; - bot = 0; - mid = top / 2; - - while (range > 1) - { - ms = (mini_mem_string_t *)s->string_cache[mid]; - - if (hash == ms->hash) - { - while (mid > 0) - { - ms = (mini_mem_string_t *)s->string_cache[mid - 1]; - if (hash != ms->hash) break; - mid--; - } - - return mid; - } - else - { - ms = (mini_mem_string_t *)s->string_cache[mid]; - if (hash < ms->hash) top = mid; - else bot = mid; - } - - range = top - bot; - mid = bot + (range / 2); - } - - ms = (mini_mem_string_t *)s->string_cache[bot]; - if (hash <= ms->hash) return bot; - - ms = (mini_mem_string_t *)s->string_cache[top]; - if (hash <= ms->hash) return top; - - return s->string_count; -} - -/* - * Search the string cache. - * If the string is in the cache, increment refcount and return it. - * If the string is not in cache and create flag is on, create a new string. - * Otherwise, return NULL. - */ -static mini_mem_string_t * -asl_mini_memory_string_retain(asl_mini_memory_t *s, const char *str, int create) -{ - uint32_t i, where, hash, len; - mini_mem_string_t *new; - - if (s == NULL) return NULL; - if (str == NULL) return NULL; - len = strlen(str); - - /* check the cache */ - hash = asl_core_string_hash(str, len); - where = asl_mini_memory_string_cache_search_hash(s, hash); - - /* asl_mini_memory_string_cache_search_hash just tells us where to look */ - if (where < s->string_count) - { - while (((mini_mem_string_t *)(s->string_cache[where]))->hash == hash) - { - if (!strcmp(str, ((mini_mem_string_t *)(s->string_cache[where]))->str)) - { - ((mini_mem_string_t *)(s->string_cache[where]))->refcount++; - return s->string_cache[where]; - } - - where++; - } - } - - /* not found */ - if (create == 0) return NULL; - - /* create a new mini_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]; - } - - if (s->string_cache == NULL) - { - s->string_count = 0; - return NULL; - } - - new = mem_string_new(str, len, hash); - if (new == NULL) return NULL; - - s->string_cache[where] = new; - s->string_count++; - - return s->string_cache[where]; -} - -static uint32_t -asl_mini_memory_string_release(asl_mini_memory_t *s, mini_mem_string_t *m) -{ - uint32_t i, where; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (m == NULL) return ASL_STATUS_OK; - - if (m->refcount > 0) m->refcount--; - if (m->refcount > 0) return ASL_STATUS_OK; - - where = asl_mini_memory_string_cache_search_hash(s, m->hash); - if (((mini_mem_string_t *)(s->string_cache[where]))->hash != m->hash) return ASL_STATUS_OK; - - while (s->string_cache[where] != m) - { - if (((mini_mem_string_t *)(s->string_cache[where]))->hash != m->hash) return ASL_STATUS_OK; - - where++; - if (where >= s->string_count) return ASL_STATUS_OK; - } - - for (i = where + 1; i < s->string_count; i++) s->string_cache[i - 1] = s->string_cache[i]; - - free(m); - s->string_count--; - - if (s->string_count == 0) - { - free(s->string_cache); - s->string_cache = NULL; - return ASL_STATUS_OK; - } - - s->string_cache = (void **)reallocf(s->string_cache, s->string_count * sizeof(void *)); - if (s->string_cache == NULL) - { - s->string_count = 0; - return ASL_STATUS_NO_MEMORY; - } - - return ASL_STATUS_OK; -} - -/* - * Release all a record's strings and reset it's values - */ -static void -asl_mini_memory_record_clear(asl_mini_memory_t *s, mini_mem_record_t *r) -{ - uint32_t i; - - if (s == NULL) return; - if (r == NULL) return; - - asl_mini_memory_string_release(s, r->sender); - asl_mini_memory_string_release(s, r->sender_mach_uuid); - asl_mini_memory_string_release(s, r->facility); - asl_mini_memory_string_release(s, r->message); - - for (i = 0; i < r->kvcount; i++) asl_mini_memory_string_release(s, r->kvlist[i]); - - if (r->kvlist != NULL) free(r->kvlist); - memset(r, 0, sizeof(mini_mem_record_t)); -} - -static void -asl_mini_memory_record_free(asl_mini_memory_t *s, mini_mem_record_t *r) -{ - asl_mini_memory_record_clear(s, r); - free(r); -} - -/* - * Encode an aslmsg as a record structure. - * Creates and caches strings. - */ -static uint32_t -asl_mini_memory_message_encode(asl_mini_memory_t *s, aslmsg msg) -{ - uint32_t x; - mini_mem_string_t *k, *v; - mini_mem_record_t *r; - const char *key, *val; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (s->buffer_record == NULL) return ASL_STATUS_INVALID_STORE; - if (msg == NULL) return ASL_STATUS_INVALID_MESSAGE; - - r = s->buffer_record; - - memset(r, 0, sizeof(mini_mem_record_t)); - - r->flags = 0; - r->level = ASL_LEVEL_DEBUG; - r->pid = -1; - r->ruid = -1; - r->rgid = -1; - r->time = (uint64_t)-1; - r->nano = (uint32_t)-1; - - key = NULL; - val = NULL; - - for (x = asl_msg_fetch((asl_msg_t *)msg, 0, &key, &val, NULL); x != IndexNull; x = asl_msg_fetch((asl_msg_t *)msg, x, &key, &val, NULL)) - { - if (key == NULL) continue; - - else if (!strcmp(key, ASL_KEY_TIME)) - { - if (val != NULL) r->time = asl_parse_time(val); - } - else if (!strcmp(key, ASL_KEY_TIME_NSEC)) - { - if (val != NULL) r->nano = atoi(val); - } - else if (!strcmp(key, ASL_KEY_SENDER)) - { - if (val != NULL) r->sender = asl_mini_memory_string_retain(s, val, 1); - } - else if (!strcmp(key, ASL_KEY_SENDER_MACH_UUID)) - { - if (val != NULL) r->sender_mach_uuid = asl_mini_memory_string_retain(s, val, 1); - } - else if (!strcmp(key, ASL_KEY_PID)) - { - if (val != NULL) r->pid = atoi(val); - } - else if (!strcmp(key, ASL_KEY_LEVEL)) - { - if (val != NULL) r->level = atoi(val); - } - else if (!strcmp(key, ASL_KEY_MSG)) - { - if (val != NULL) r->message = asl_mini_memory_string_retain(s, val, 1); - } - else if (!strcmp(key, ASL_KEY_FACILITY)) - { - if (val != NULL) r->facility = asl_mini_memory_string_retain(s, val, 1); - } - else if (!strcmp(key, ASL_KEY_MSG_ID)) - { - /* Ignore */ - continue; - } - else if (!strcmp(key, ASL_KEY_TIME_NSEC)) - { - /* Ignore */ - continue; - } - else if (!strcmp(key, ASL_KEY_HOST)) - { - /* Ignore */ - continue; - } - else if (!strcmp(key, ASL_KEY_REF_PID)) - { - /* Ignore */ - continue; - } - else if (!strcmp(key, ASL_KEY_REF_PROC)) - { - /* Ignore */ - continue; - } - else if (!strcmp(key, ASL_KEY_SESSION)) - { - /* Ignore */ - continue; - } - else if (!strcmp(key, ASL_KEY_UID)) - { - /* Ignore */ - continue; - } - else if (!strcmp(key, ASL_KEY_GID)) - { - /* Ignore */ - continue; - } - else if (!strcmp(key, ASL_KEY_READ_UID)) - { - if (((r->flags & ASL_MSG_FLAG_READ_UID_SET) == 0) && (val != NULL)) - { - r->ruid = atoi(val); - r->flags |= ASL_MSG_FLAG_READ_UID_SET; - } - } - else if (!strcmp(key, ASL_KEY_READ_GID)) - { - if (((r->flags & ASL_MSG_FLAG_READ_GID_SET) == 0) && (val != NULL)) - { - r->rgid = atoi(val); - r->flags |= ASL_MSG_FLAG_READ_GID_SET; - } - } - else if (!strcmp(key, CFLOG_LOCAL_TIME_KEY)) - { - /* Ignore */ - continue; - } - else if (!strcmp(key, CFLOG_THREAD_KEY)) - { - /* Ignore */ - continue; - } - else - { - k = asl_mini_memory_string_retain(s, key, 1); - if (k == NULL) continue; - - v = NULL; - if (val != NULL) v = asl_mini_memory_string_retain(s, val, 1); - - if (r->kvcount == 0) - { - r->kvlist = (mini_mem_string_t **)calloc(2, sizeof(mini_mem_string_t *)); - } - else - { - r->kvlist = (mini_mem_string_t **)reallocf(r->kvlist, (r->kvcount + 2) * sizeof(mini_mem_string_t *)); - } - - if (r->kvlist == NULL) - { - asl_mini_memory_record_clear(s, r); - return ASL_STATUS_NO_MEMORY; - } - - r->kvlist[r->kvcount++] = k; - r->kvlist[r->kvcount++] = v; - } - } - - return ASL_STATUS_OK; -} - -uint32_t -asl_mini_memory_save(asl_mini_memory_t *s, aslmsg msg, uint64_t *mid) -{ - uint32_t status; - mini_mem_record_t *t; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (s->buffer_record == NULL) return ASL_STATUS_INVALID_STORE; - - /* asl_mini_memory_message_encode creates and caches strings */ - status = asl_mini_memory_message_encode(s, msg); - if (status != ASL_STATUS_OK) return status; - - s->buffer_record->mid = s->next_id; - s->next_id++; - - /* clear the first record */ - t = s->record[s->record_first]; - asl_mini_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; - - *mid = s->buffer_record->mid; - - return status; -} - -/* - * Decodes a record structure. - */ -static uint32_t -asl_mini_memory_message_decode(asl_mini_memory_t *s, mini_mem_record_t *r, aslmsg *out) -{ - uint32_t i; - aslmsg msg; - char tmp[64]; - const char *key, *val; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (r == NULL) return ASL_STATUS_INVALID_ARG; - if (out == NULL) return ASL_STATUS_INVALID_ARG; - - *out = NULL; - - msg = asl_new(ASL_TYPE_MSG); - if (msg == NULL) return ASL_STATUS_NO_MEMORY; - - /* Message ID */ - snprintf(tmp, sizeof(tmp), "%u", r->mid); - asl_set(msg, ASL_KEY_MSG_ID, tmp); - - /* Level */ - snprintf(tmp, sizeof(tmp), "%u", r->level); - asl_set(msg, ASL_KEY_LEVEL, tmp); - - /* Time */ - if (r->time != (uint64_t)-1) - { - snprintf(tmp, sizeof(tmp), "%llu", r->time); - asl_set(msg, ASL_KEY_TIME, tmp); - } - - /* Nanoseconds */ - if (r->nano != (uint32_t)-1) - { - snprintf(tmp, sizeof(tmp), "%u", r->nano); - asl_set(msg, ASL_KEY_TIME_NSEC, tmp); - } - - /* Sender */ - if (r->sender != NULL) - { - asl_set(msg, ASL_KEY_SENDER, r->sender->str); - } - - /* Sender mach UUID */ - if (r->sender_mach_uuid != NULL) - { - asl_set(msg, ASL_KEY_SENDER_MACH_UUID, r->sender_mach_uuid->str); - } - - /* Facility */ - if (r->facility != NULL) - { - asl_set(msg, ASL_KEY_FACILITY, r->facility->str); - } - - /* PID */ - if (r->pid != -1) - { - snprintf(tmp, sizeof(tmp), "%d", r->pid); - asl_set(msg, ASL_KEY_PID, tmp); - } - - /* Message */ - if (r->message != NULL) - { - asl_set(msg, ASL_KEY_MSG, r->message->str); - } - - /* ReadUID */ - if (r->flags & ASL_MSG_FLAG_READ_UID_SET) - { - snprintf(tmp, sizeof(tmp), "%d", r->ruid); - asl_set(msg, ASL_KEY_READ_UID, tmp); - } - - /* ReadGID */ - if (r->flags & ASL_MSG_FLAG_READ_GID_SET) - { - snprintf(tmp, sizeof(tmp), "%d", r->rgid); - asl_set(msg, ASL_KEY_READ_GID, tmp); - } - - /* Key - Value List */ - for (i = 0; i < r->kvcount; i++) - { - key = NULL; - val = NULL; - - if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) key = r->kvlist[i]->str; - i++; - if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) val = r->kvlist[i]->str; - - if (key != NULL) asl_set(msg, key, val); - } - - *out = msg; - return ASL_STATUS_OK; -} - -uint32_t -asl_mini_memory_fetch(asl_mini_memory_t *s, uint64_t mid, aslmsg *msg, int32_t ruid, int32_t rgid) -{ - uint32_t i, 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; - - 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) return status; - return asl_mini_memory_message_decode(s, s->record[i], msg); - } - } - - return ASL_STATUS_INVALID_ID; -} - -static mini_mem_record_t * -asl_mini_memory_query_to_record(asl_mini_memory_t *s, asl_msg_t *q, uint32_t *type) -{ - mini_mem_record_t *out; - uint32_t i, x, op; - mini_mem_string_t *mkey, *mval; - const char *key, *val; - - if (type == NULL) return NULL; - - if (s == NULL) - { - *type = ASL_QUERY_MATCH_ERROR; - return NULL; - } - - /* NULL query matches anything */ - *type = ASL_QUERY_MATCH_TRUE; - if (q == NULL) return NULL; - if (asl_msg_count((asl_msg_t *)q) == 0) return NULL; - - - /* we can only do fast match on equality tests */ - *type = ASL_QUERY_MATCH_SLOW; - - for (x = asl_msg_fetch((asl_msg_t *)q, 0, NULL, NULL, &op); x != IndexNull; x = asl_msg_fetch((asl_msg_t *)q, x, NULL, NULL, &op)) - { - if (op != ASL_QUERY_OP_EQUAL) return NULL; - } - - out = (mini_mem_record_t *)calloc(1, sizeof(mini_mem_record_t)); - if (out == NULL) - { - *type = ASL_QUERY_MATCH_ERROR; - return NULL; - } - - for (x = asl_msg_fetch((asl_msg_t *)q, 0, &key, &val, &op); x != IndexNull; x = asl_msg_fetch((asl_msg_t *)q, x, &key, &val, &op)) - { - if (key == NULL) continue; - - else if (!strcmp(key, ASL_KEY_MSG_ID)) - { - if (val == NULL) continue; - - if (*type & ASL_QUERY_MATCH_MSG_ID) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_SLOW; - return NULL; - } - - *type |= ASL_QUERY_MATCH_MSG_ID; - out->mid = atoll(val); - } - else if (!strcmp(key, ASL_KEY_TIME)) - { - if (val == NULL) continue; - - if (*type & ASL_QUERY_MATCH_TIME) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_SLOW; - return NULL; - } - - *type |= ASL_QUERY_MATCH_TIME; - out->time = asl_parse_time(val); - } - else if (!strcmp(key, ASL_KEY_TIME_NSEC)) - { - if (val == NULL) continue; - - if (*type & ASL_QUERY_MATCH_NANO) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_SLOW; - return NULL; - } - - *type |= ASL_QUERY_MATCH_NANO; - out->nano = atoll(val); - } - else if (!strcmp(key, ASL_KEY_LEVEL)) - { - if (val == NULL) continue; - - if (*type & ASL_QUERY_MATCH_LEVEL) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_SLOW; - return NULL; - } - - *type |= ASL_QUERY_MATCH_LEVEL; - out->level = atoi(val); - } - else if (!strcmp(key, ASL_KEY_PID)) - { - if (val == NULL) continue; - - if (*type & ASL_QUERY_MATCH_PID) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_SLOW; - return NULL; - } - - *type |= ASL_QUERY_MATCH_PID; - out->pid = atoi(val); - } - else if (!strcmp(key, ASL_KEY_READ_UID)) - { - if (val == NULL) continue; - - if (*type & ASL_QUERY_MATCH_RUID) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_SLOW; - return NULL; - } - - *type |= ASL_QUERY_MATCH_RUID; - out->ruid = atoi(val); - } - else if (!strcmp(key, ASL_KEY_READ_GID)) - { - if (val == NULL) continue; - - if (*type & ASL_QUERY_MATCH_RGID) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_SLOW; - return NULL; - } - - *type |= ASL_QUERY_MATCH_RGID; - out->rgid = atoi(val); - } - else if (!strcmp(key, ASL_KEY_SENDER)) - { - if (val == NULL) continue; - - if (*type & ASL_QUERY_MATCH_SENDER) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_SLOW; - return NULL; - } - - *type |= ASL_QUERY_MATCH_SENDER; - out->sender = asl_mini_memory_string_retain(s, val, 0); - if (out->sender == NULL) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_FALSE; - return NULL; - } - } - else if (!strcmp(key, ASL_KEY_SENDER_MACH_UUID)) - { - if (val == NULL) continue; - - if (*type & ASL_QUERY_MATCH_SMUUID) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_SLOW; - return NULL; - } - - *type |= ASL_QUERY_MATCH_SMUUID; - out->sender_mach_uuid = asl_mini_memory_string_retain(s, val, 0); - if (out->sender_mach_uuid == NULL) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_FALSE; - return NULL; - } - } - else if (!strcmp(key, ASL_KEY_FACILITY)) - { - if (val == NULL) continue; - - if (*type & ASL_QUERY_MATCH_FACILITY) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_SLOW; - return NULL; - } - - *type |= ASL_QUERY_MATCH_FACILITY; - out->facility = asl_mini_memory_string_retain(s, val, 0); - if (out->facility == NULL) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_FALSE; - return NULL; - } - } - else if (!strcmp(key, ASL_KEY_MSG)) - { - if (val == NULL) continue; - - if (*type & ASL_QUERY_MATCH_MESSAGE) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_SLOW; - return NULL; - } - - *type |= ASL_QUERY_MATCH_MESSAGE; - out->message = asl_mini_memory_string_retain(s, val, 0); - if (out->message == NULL) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_FALSE; - return NULL; - } - } - else - { - mkey = asl_mini_memory_string_retain(s, key, 0); - if (mkey == NULL) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_FALSE; - return NULL; - } - - for (i = 0; i < out->kvcount; i += 2) - { - if (out->kvlist[i] == mkey) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_SLOW; - return NULL; - } - } - - mval = asl_mini_memory_string_retain(s, val, 0); - - if (out->kvcount == 0) - { - out->kvlist = (mini_mem_string_t **)calloc(2, sizeof(mini_mem_string_t *)); - } - else - { - out->kvlist = (mini_mem_string_t **)reallocf(out->kvlist, (out->kvcount + 2) * sizeof(mini_mem_string_t *)); - } - - if (out->kvlist == NULL) - { - asl_mini_memory_record_free(s, out); - *type = ASL_QUERY_MATCH_ERROR; - return NULL; - } - - out->kvlist[out->kvcount++] = mkey; - out->kvlist[out->kvcount++] = mval; - } - } - - return out; -} - -static uint32_t -asl_mini_memory_fast_match(asl_mini_memory_t *s, mini_mem_record_t *r, uint32_t qtype, mini_mem_record_t *q) -{ - uint32_t i, j; - - if (s == NULL) return 0; - if (r == NULL) return 0; - if (q == NULL) return 1; - - if ((qtype & ASL_QUERY_MATCH_MSG_ID) && (q->mid != r->mid)) return 0; - if ((qtype & ASL_QUERY_MATCH_TIME) && (q->time != r->time)) return 0; - if ((qtype & ASL_QUERY_MATCH_NANO) && (q->nano != r->nano)) return 0; - if ((qtype & ASL_QUERY_MATCH_LEVEL) && (q->level != r->level)) return 0; - if ((qtype & ASL_QUERY_MATCH_PID) && (q->pid != r->pid)) return 0; - if ((qtype & ASL_QUERY_MATCH_RUID) && (q->ruid != r->ruid)) return 0; - if ((qtype & ASL_QUERY_MATCH_RGID) && (q->rgid != r->rgid)) return 0; - if ((qtype & ASL_QUERY_MATCH_SENDER) && (q->sender != r->sender)) return 0; - if ((qtype & ASL_QUERY_MATCH_SMUUID) && (q->sender_mach_uuid != r->sender_mach_uuid)) return 0; - if ((qtype & ASL_QUERY_MATCH_FACILITY) && (q->facility != r->facility)) return 0; - if ((qtype & ASL_QUERY_MATCH_MESSAGE) && (q->message != r->message)) return 0; - - for (i = 0; i < q->kvcount; i += 2) - { - for (j = 0; j < r->kvcount; j += 2) - { - if (q->kvlist[i] == r->kvlist[j]) - { - if (q->kvlist[i + 1] == r->kvlist[j + 1]) break; - return 0; - } - } - - if (j >= r->kvcount) return 0; - } - - return 1; -} - -static uint32_t -asl_mini_memory_slow_match(asl_mini_memory_t *s, mini_mem_record_t *r, mini_mem_record_t *q, aslmsg rawq) -{ - aslmsg rawm; - uint32_t status; - - rawm = NULL; - status = asl_mini_memory_message_decode(s, r, &rawm); - if (status != ASL_STATUS_OK) return 0; - - status = 0; - if (asl_msg_cmp((asl_msg_t *)rawq, (asl_msg_t *)rawm) != 0) status = 1; - asl_free(rawm); - return status; -} - -uint32_t -asl_mini_memory_match_restricted_uuid(asl_mini_memory_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, 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; - mini_mem_record_t **qp; - aslmsg m; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (res == NULL) return ASL_STATUS_INVALID_ARG; - - qp = NULL; - qtype = NULL; - rescount = 0; - - if ((query == NULL) || ((query != NULL) && (query->count == 0))) - { - do_match = 0; - } - else - { - qp = (mini_mem_record_t **)calloc(query->count, sizeof(mini_mem_record_t *)); - if (qp == NULL) return ASL_STATUS_NO_MEMORY; - - qtype = (uint32_t *)calloc(query->count, sizeof(uint32_t)); - if (qtype == NULL) - { - free(qp); - return ASL_STATUS_NO_MEMORY; - } - - do_match = 0; - for (i = 0; i < query->count; i++) - { - qp[i] = asl_mini_memory_query_to_record(s, query->msg[i], &(qtype[i])); - if (qtype[i] == ASL_QUERY_MATCH_ERROR) - { - for (j = 0; j < i; j++) asl_mini_memory_record_free(s, qp[j]); - free(qp); - free(qtype); - return ASL_STATUS_FAILED; - } - - if (qtype[i] != ASL_QUERY_MATCH_TRUE) do_match = 1; - } - } - - for (i = 0; i < s->record_count; i++) - { - if (direction >= 0) - { - where = (s->record_first + i) % s->record_count; - if (s->record[where]->mid == 0) continue; - if (s->record[where]->mid >= start_id) break; - } - else - { - where = ((s->record_count - (i + 1)) + s->record_first) % s->record_count; - if (s->record[where]->mid == 0) continue; - if (s->record[where]->mid <= start_id) break; - } - } - - if (i >= s->record_count) - { - if (qp != NULL) - { - for (i = 0; i < query->count; i++) asl_mini_memory_record_free(s, qp[i]); - free(qp); - free(qtype); - } - - return ASL_STATUS_OK; - } - - start = where; - - /* - * loop through records - */ - for (i = 0; i < s->record_count; i++) - { - status = ASL_STATUS_INVALID_ID; - if (s->record[where]->mid != 0) status = asl_core_check_access(s->record[where]->ruid, s->record[where]->rgid, ruid, rgid, s->record[where]->flags); - - if ((status == ASL_STATUS_OK) && (uuid_str != NULL)) - { - if (s->record[where]->sender_mach_uuid == NULL) status = ASL_STATUS_INVALID_ID; - else if (strcmp(s->record[where]->sender_mach_uuid->str, uuid_str) != 0) status = ASL_STATUS_INVALID_ID; - } - - if (status != ASL_STATUS_OK) - { - if (direction >= 0) - { - where++; - if (where >= s->record_count) where = 0; - } - else - { - if (where == 0) where = s->record_count - 1; - else where--; - } - - if (where == s->record_first) break; - continue; - } - - s->record[where]->flags &= ASL_MINI_MSG_FLAG_SEARCH_CLEAR; - *last_id = s->record[where]->mid; - did_match = 1; - - if (do_match != 0) - { - did_match = 0; - - for (j = 0; (j < query->count) && (did_match == 0); j++) - { - if (qtype[j] == ASL_QUERY_MATCH_TRUE) - { - did_match = 1; - } - else if (qtype[j] == ASL_QUERY_MATCH_FALSE) - { - did_match = 0; - } - else if (qtype[j] == ASL_QUERY_MATCH_SLOW) - { - did_match = asl_mini_memory_slow_match(s, s->record[where], qp[j], (aslmsg)query->msg[j]); - } - else - { - did_match = asl_mini_memory_fast_match(s, s->record[where], qtype[j], qp[j]); - } - } - } - - if (did_match == 1) - { - s->record[where]->flags |= ASL_MINI_MSG_FLAG_SEARCH_MATCH; - rescount++; - if ((count != 0) && (rescount >= count)) break; - } - - if (direction >= 0) - { - where++; - if (where >= s->record_count) where = 0; - } - else - { - if (where == 0) where = s->record_count - 1; - else where--; - } - - if (where == s->record_first) break; - } - - if (query != NULL) - { - for (i = 0; i < query->count; i++) asl_mini_memory_record_free(s, qp[i]); - free(qp); - free(qtype); - } - - *res = NULL; - if (rescount == 0) return ASL_STATUS_OK; - - *res = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t)); - if (*res == NULL) return ASL_STATUS_NO_MEMORY; - - (*res)->count = rescount; - - (*res)->msg = (asl_msg_t **)calloc(rescount, sizeof(asl_msg_t *)); - if ((*res)->msg == NULL) - { - free(*res); - *res = NULL; - return ASL_STATUS_NO_MEMORY; - } - - where = start; - forever - { - if (s->record[where]->flags & ASL_MINI_MSG_FLAG_SEARCH_MATCH) - { - s->record[where]->flags &= ASL_MINI_MSG_FLAG_SEARCH_CLEAR; - - status = asl_mini_memory_message_decode(s, s->record[where], &m); - if (status != ASL_STATUS_OK) - { - aslresponse_free(*res); - *res = NULL; - return status; - } - - (*res)->msg[(*res)->curr++] = (asl_msg_t *)m; - if ((*res)->curr == rescount) break; - } - - if (direction >= 0) - { - where++; - if (where >= s->record_count) where = 0; - } - else - { - if (where == 0) where = s->record_count - 1; - else where--; - } - - if (where == s->record_first) break; - } - - (*res)->curr = 0; - return ASL_STATUS_OK; -} - -uint32_t -asl_mini_memory_match(asl_mini_memory_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, int32_t ruid, int32_t rgid) -{ - return asl_mini_memory_match_restricted_uuid(s, query, res, last_id, start_id, count, direction, ruid, rgid, NULL); -} diff --git a/aslcommon/asl_mini_memory.h b/aslcommon/asl_mini_memory.h deleted file mode 100644 index 7e81608..0000000 --- a/aslcommon/asl_mini_memory.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2007-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, - * 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@ - */ - -#ifndef __ASL_MINI_MEMORY_H__ -#define __ASL_MINI_MEMORY_H__ -#include -#include - -#define ASL_MINI_MSG_FLAG_SEARCH_MATCH 0x80 -#define ASL_MINI_MSG_FLAG_SEARCH_CLEAR 0x7f - -typedef struct -{ - uint32_t hash; - uint32_t refcount; - char str[]; -} mini_mem_string_t; - -typedef struct -{ - uint32_t mid; - uint64_t time; - uint32_t nano; - uint8_t level; - uint8_t flags; - uint32_t pid; - uint32_t uid; - uint32_t gid; - uint32_t ruid; - uint32_t rgid; - uint32_t kvcount; - mini_mem_string_t *sender; - mini_mem_string_t *sender_mach_uuid; - mini_mem_string_t *facility; - mini_mem_string_t *message; - mini_mem_string_t **kvlist; -} mini_mem_record_t; - -typedef struct -{ - uint32_t next_id; - uint32_t string_count; - void **string_cache; - uint32_t record_count; - uint32_t record_first; - mini_mem_record_t **record; - mini_mem_record_t *buffer_record; -} asl_mini_memory_t; - -uint32_t asl_mini_memory_open(uint32_t max_records, asl_mini_memory_t **s); -uint32_t asl_mini_memory_close(asl_mini_memory_t *s); -uint32_t asl_mini_memory_statistics(asl_mini_memory_t *s, aslmsg *msg); - -uint32_t asl_mini_memory_save(asl_mini_memory_t *s, aslmsg msg, uint64_t *mid); -uint32_t asl_mini_memory_fetch(asl_mini_memory_t *s, uint64_t mid, aslmsg *msg, int32_t ruid, int32_t rgid); - -uint32_t asl_mini_memory_match(asl_mini_memory_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, int32_t ruid, int32_t rgid); -uint32_t asl_mini_memory_match_restricted_uuid(asl_mini_memory_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, int32_t ruid, int32_t rgid, const char *uuid_str); - -#endif /* __ASL_MINI_MEMORY_H__ */ diff --git a/aslmanager.tproj/aslmanager.c b/aslmanager.tproj/aslmanager.c index a2c4f76..02eb7e0 100644 --- a/aslmanager.tproj/aslmanager.c +++ b/aslmanager.tproj/aslmanager.c @@ -61,6 +61,12 @@ #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, @@ -93,6 +99,25 @@ typedef struct name_list_s 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) { @@ -133,12 +158,12 @@ debug_log(int level, const char *str, ...) if (aslc == NULL) { aslc = asl_open("aslmanager", "syslog", 0); - aslmsg msg = asl_new(ASL_TYPE_MSG); + asl_msg_t *msg = asl_msg_new(ASL_TYPE_MSG); - asl_set(msg, ASL_KEY_MSG, "Status Report"); - asl_set(msg, ASL_KEY_LEVEL, ASL_STRING_NOTICE); - asl_create_auxiliary_file(msg, "Status Report", "public.text", &asl_aux_fd); - asl_free(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); @@ -209,18 +234,17 @@ free_name_list(name_list_t *l) free(l); } - /* * Copy ASL files by reading and writing each record. - * Setting ASL_FILE_FLAG_UNLIMITED_CACHE when copying optimizes tring uniquing. */ uint32_t copy_asl_file(const char *src, const char *dst, mode_t mode) { - asl_search_result_t *res; + 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; @@ -232,14 +256,14 @@ copy_asl_file(const char *src, const char *dst, mode_t mode) res = NULL; mid = 0; - status = asl_file_match(f, NULL, &res, &mid, 0, 0, 1); + res = asl_file_match(f, NULL, &mid, 0, 0, 0, 1); asl_file_close(f); - if (status != ASL_STATUS_OK) return status; if (res == NULL) return ASL_STATUS_OK; - if (res->count == 0) + rcount = asl_msg_list_count(res); + if (rcount == 0) { - aslresponse_free(res); + asl_msg_list_release(res); return ASL_STATUS_OK; } @@ -248,12 +272,12 @@ copy_asl_file(const char *src, const char *dst, mode_t mode) if (status != ASL_STATUS_OK) return status; if (f == ASL_STATUS_OK) return ASL_STATUS_FAILED; - f->flags = ASL_FILE_FLAG_UNLIMITED_CACHE | ASL_FILE_FLAG_PRESERVE_MSG_ID; + f->flags = ASL_FILE_FLAG_PRESERVE_MSG_ID; - for (i = 0; i < res->count; i++) + for (i = 0; i < rcount; i++) { mid = 0; - status = asl_file_save(f, (aslmsg)(res->msg[i]), &mid); + status = asl_file_save(f, asl_msg_list_get_index(res, i), &mid); if (status != ASL_STATUS_OK) break; } @@ -300,6 +324,54 @@ copy_compress_file(asl_out_dst_data_t *asldst, const char *src, const char *dst) 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) { @@ -353,42 +425,6 @@ filesystem_copy(asl_out_dst_data_t *asldst, const char *src, const char *dst, ui return 1; } -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_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); -} - int remove_directory(const char *path) { @@ -417,6 +453,123 @@ remove_directory(const char *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" @@ -461,7 +614,7 @@ _aslmanager_set_param(asl_out_dst_data_t *dst, char *s) else if (!strcasecmp(l[0], "store_ttl")) { /* = store_ttl days */ - dst->ttl = (time_t)atoll(l[1]); + dst->ttl[LEVEL_ALL] = (time_t)atoll(l[1]); } else if (!strcasecmp(l[0], "module_ttl")) { @@ -597,7 +750,7 @@ process_asl_data_store(asl_out_dst_data_t *dst) /* ttl 0 means files never expire */ ymd_expire = 0; - ttl = dst->ttl * SECONDS_PER_DAY; + ttl = dst->ttl[LEVEL_ALL] * SECONDS_PER_DAY; if ((ttl > 0) && (ttl <= now)) ymd_expire = now - ttl; @@ -677,22 +830,48 @@ process_asl_data_store(asl_out_dst_data_t *dst) e = ymd_list; while (e != NULL) { - /* stop when a file name/date is after the expire date */ - if (strncmp(e->name, expire_ymd_string, expire_ymd_stringlen) > 0) break; - - if (dst->rotate_dir != NULL) + if (strncmp(e->name, expire_ymd_string, expire_ymd_stringlen) <= 0) { - str = NULL; - asprintf(&str, "%s/%s", dst->rotate_dir, e->name); - if (str == NULL) return -1; + /* 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_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; + } - filesystem_unlink(e->name); - store_size -= e->size; - e->size = 0; + 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; } @@ -794,8 +973,15 @@ process_asl_data_store(asl_out_dst_data_t *dst) { if (e->size != 0) { - /* stop when we get to today's files */ - if (strncmp(e->name, today_ymd_string, today_ymd_stringlen) == 0) break; + 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) { @@ -925,7 +1111,11 @@ module_copy_rename(asl_out_dst_data_t *dst) 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) filesystem_unlink(fpathsrc); + if (moved != 0) + { + if (dst->flags & MODULE_FLAG_TRUNCATE) filesystem_truncate(fpathsrc); + else filesystem_unlink(fpathsrc); + } } } else @@ -951,7 +1141,11 @@ module_copy_rename(asl_out_dst_data_t *dst) } moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags); - if (moved != 0) filesystem_unlink(fpathsrc); + if (moved != 0) + { + if (dst->flags & MODULE_FLAG_TRUNCATE) filesystem_truncate(fpathsrc); + else filesystem_unlink(fpathsrc); + } } } @@ -973,11 +1167,11 @@ module_expire(asl_out_dst_data_t *dst) if (dst == NULL) return -1; if (dst->path == NULL) return -1; - if (dst->ttl == 0) return 0; + if (dst->ttl[LEVEL_ALL] == 0) return 0; ttl = 0; if (module_ttl > 0) ttl = module_ttl; - else ttl = dst->ttl; + else ttl = dst->ttl[LEVEL_ALL]; ttl *= SECONDS_PER_DAY; @@ -1026,7 +1220,7 @@ module_expire(asl_out_dst_data_t *dst) static int module_check_size(asl_out_dst_data_t *dst) { - asl_out_file_list_t *dst_list, *f; + asl_out_file_list_t *dst_list, *f, *dst_end; char *base, *dst_dir, fpath[MAXPATHLEN]; size_t total; @@ -1035,32 +1229,40 @@ module_check_size(asl_out_dst_data_t *dst) if (dst->all_max == 0) return 0; + dst_list = asl_list_dst_files(dst); + if (dst_list == NULL) + { + debug_log(ASL_LEVEL_INFO, " no dst files\n"); + return 0; + } + base = NULL; dst_dir = dst->rotate_dir; if (dst_dir == NULL) { dst_dir = dst->path; base = strrchr(dst->path, '/'); - if (base == NULL) return -1; + if (base == NULL) + { + asl_out_file_list_free(dst_list); + return -1; + } + *base = '\0'; } - dst_list = asl_list_dst_files(dst); - - if (dst_list == NULL) - { - debug_log(ASL_LEVEL_INFO, " no dst files\n"); - } - else + debug_log(ASL_LEVEL_INFO, " dst files\n"); + dst_end = dst_list; + for (f = dst_list; f != NULL; f = f->next) { - debug_log(ASL_LEVEL_INFO, " dst files\n"); - for (f = dst_list; f != NULL; f = f->next) debug_log(ASL_LEVEL_INFO, " %s size %lu\n", f->name, f->size); + 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; - - for (f = dst_list; (total > dst->all_max) && (f != NULL); f = f->next) + + for (f = dst_end; (total > dst->all_max) && (f != NULL); f = f->prev) { snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name); filesystem_unlink(fpath); @@ -1100,9 +1302,9 @@ process_module(asl_out_module_t *mod) module_copy_rename(r->dst); - if (r->dst->ttl > 0) + if (r->dst->ttl[LEVEL_ALL] > 0) { - debug_log(ASL_LEVEL_NOTICE, "- Check for expired files - TTL = %d days\n", r->dst->ttl); + debug_log(ASL_LEVEL_NOTICE, "- Check for expired files - TTL = %d days\n", r->dst->ttl[LEVEL_ALL]); module_expire(r->dst); } @@ -1112,7 +1314,7 @@ process_module(asl_out_module_t *mod) module_check_size(r->dst); } } - else if ((r->dst->flags & MODULE_FLAG_TYPE_ASL_DIR) && (r->dst->ttl > 0)) + else if ((r->dst->flags & MODULE_FLAG_TYPE_ASL_DIR) && (r->dst->ttl[LEVEL_ALL] > 0)) { process_asl_data_store(r->dst); } @@ -1123,10 +1325,10 @@ process_module(asl_out_module_t *mod) return 0; } -aslresponse -control_query(aslmsg a) +asl_msg_list_t * +control_query(asl_msg_t *a) { - asl_search_result_t *out; + asl_msg_list_t *out; char *qstr, *str, *res; uint32_t len, reslen, status; uint64_t cmax, qmin; @@ -1179,7 +1381,7 @@ control_query(aslmsg a) if (res == NULL) return NULL; - out = asl_list_from_string(res); + out = asl_msg_list_from_string(res); vm_deallocate(mach_task_self(), (vm_address_t)res, reslen); return out; @@ -1192,17 +1394,17 @@ checkpoint(const char *name) debug_log(ASL_LEVEL_NOTICE, "Checkpoint module %s\n", (name == NULL) ? "*" : name); if (dryrun != 0) return 0; - aslmsg qmsg = asl_new(ASL_TYPE_QUERY); + asl_msg_t *qmsg = asl_msg_new(ASL_TYPE_QUERY); char *tmp = NULL; - aslresponse res; + asl_msg_list_t *res; asprintf(&tmp, "%s checkpoint", (name == NULL) ? "*" : name); - asl_set_query(qmsg, "action", tmp, ASL_QUERY_OP_EQUAL); + asl_msg_set_key_val_op(qmsg, "action", tmp, ASL_QUERY_OP_EQUAL); free(tmp); res = control_query(qmsg); - aslresponse_free(res); + asl_msg_list_release(res); return 0; } @@ -1212,7 +1414,7 @@ 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_out_dst_data_t store, *asl_store_dst = NULL; const char *mname = NULL; if (geteuid() != 0) @@ -1226,21 +1428,39 @@ cli_main(int argc, char *argv[]) module_ttl = DEFAULT_TTL; - /* cobble up a dst_data for the main asl_store */ + /* cobble up a dst_data with defaults and parameter settings */ memset(&store, 0, sizeof(store)); - store.ttl = DEFAULT_TTL; + store.ttl[LEVEL_ALL] = DEFAULT_TTL; store.all_max = DEFAULT_MAX_SIZE; + for (i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "-s")) + { + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) + { + store.path = strdup(argv[++i]); + asl_store_dst = &store; + } + } + } + /* get parameters from asl.conf */ mod = asl_out_module_init(); if (mod != NULL) { + for (r = mod->ruleset; r != NULL; r = r->next) + { + if ((asl_store_dst == NULL) && (r->action == ACTION_OUT_DEST) && (!strcmp(r->dst->path, PATH_ASL_STORE))) + asl_store_dst = r->dst; + } + for (r = mod->ruleset; r != NULL; r = r->next) { if (r->action == ACTION_SET_PARAM) { - if (r->query == NULL) _aslmanager_set_param(&store, r->options); + if (r->query == NULL) _aslmanager_set_param(asl_store_dst, r->options); } } } @@ -1251,17 +1471,13 @@ cli_main(int argc, char *argv[]) { if (!strcmp(argv[i], "-a")) { - if (((i + 1) < argc) && (argv[i + 1][0] != '-')) store.rotate_dir = strdup(argv[++i]); - else store.rotate_dir = strdup(PATH_ASL_ARCHIVE); - store.mode = 0400; - } - else if (!strcmp(argv[i], "-s")) - { - if (((i + 1) < argc) && (argv[i + 1][0] != '-')) store.path = strdup(argv[++i]); + 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] != '-')) store.ttl = atoi(argv[++i]); + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) asl_store_dst->ttl[LEVEL_ALL] = atoi(argv[++i]); } else if (!strcmp(argv[i], "-module_ttl")) { @@ -1269,11 +1485,11 @@ cli_main(int argc, char *argv[]) } else if (!strcmp(argv[i], "-ttl")) { - if (((i + 1) < argc) && (argv[i + 1][0] != '-')) module_ttl = store.ttl = atoi(argv[++i]); + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) module_ttl = asl_store_dst->ttl[LEVEL_ALL] = atoi(argv[++i]); } else if (!strcmp(argv[i], "-size")) { - if (((i + 1) < argc) && (argv[i + 1][0] != '-')) store.all_max = asl_str_to_size(argv[++i]); + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) asl_store_dst->all_max = asl_str_to_size(argv[++i]); } else if (!strcmp(argv[i], "-checkpoint")) { @@ -1307,14 +1523,11 @@ cli_main(int argc, char *argv[]) } } - if (store.path == NULL) store.path = strdup(PATH_ASL_STORE); + 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" : ""); - if (work & DO_ASLDB) process_asl_data_store(&store); - - free(store.path); - free(store.rotate_dir); + if (work & DO_ASLDB) process_asl_data_store(asl_store_dst); if (work & DO_MODULE) { diff --git a/libsystem_asl.tproj/include/asl.h b/libsystem_asl.tproj/include/asl.h index 1ae909c..1cc2662 100644 --- a/libsystem_asl.tproj/include/asl.h +++ b/libsystem_asl.tproj/include/asl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2012 Apple Inc. All rights reserved. + * Copyright (c) 2004-2013 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -25,13 +25,18 @@ #define __ASL_H__ #include +#include #include #include #include -typedef struct __aslclient *aslclient; -typedef struct __aslmsg *aslmsg; -typedef struct __aslresponse *aslresponse; +/* Version number encodes the date YYYYMMDD */ +#define ASL_API_VERSION 20131108 + +typedef struct __asl_object_s *asl_object_t; +typedef asl_object_t aslclient; +typedef asl_object_t aslmsg; +typedef asl_object_t aslresponse; /*! @header * These routines provide an interface to the Apple System Log facility. @@ -54,6 +59,8 @@ typedef struct __aslresponse *aslresponse; #define __printflike(a,b) #endif +#pragma mark - + /*! @defineblock Log Message Priority Levels * Log levels of the message. */ @@ -67,6 +74,8 @@ typedef struct __aslresponse *aslresponse; #define ASL_LEVEL_DEBUG 7 /*! @/defineblock */ +#pragma mark - + /*! @defineblock Log Message Priority Level Strings * Strings corresponding to log levels. */ @@ -80,6 +89,8 @@ typedef struct __aslresponse *aslresponse; #define ASL_STRING_DEBUG "Debug" /*! @/defineblock */ +#pragma mark - + /*! @defineblock Attribute Matching * Attribute value comparison operations. */ @@ -99,44 +110,82 @@ typedef struct __aslresponse *aslresponse; #define ASL_QUERY_OP_TRUE 0x0007 /*! @/defineblock */ +#pragma mark - + /*! @defineblock Message Attributes - * * These attributes are known by ASL, and are generally * associated with all log messages. * Additional attributes may be added as desired. */ -#define ASL_KEY_TIME "Time" /* Timestamp. Set automatically */ -#define ASL_KEY_TIME_NSEC "TimeNanoSec" /* Nanosecond time. */ -#define ASL_KEY_HOST "Host" /* Sender's address (set by the server). */ -#define ASL_KEY_SENDER "Sender" /* Sender's identification string. Default is process name. */ -#define ASL_KEY_FACILITY "Facility" /* Sender's facility. Default is "user". */ -#define ASL_KEY_PID "PID" /* Sending process ID encoded as a string. Set automatically. */ -#define ASL_KEY_UID "UID" /* UID that sent the log message (set by the server). */ -#define ASL_KEY_GID "GID" /* GID that sent the log message (set by the server). */ -#define ASL_KEY_LEVEL "Level" /* Log level number encoded as a string. See levels above. */ -#define ASL_KEY_MSG "Message" /* Message text. */ -#define ASL_KEY_READ_UID "ReadUID" /* User read access (-1 is any user). */ -#define ASL_KEY_READ_GID "ReadGID" /* Group read access (-1 is any group). */ -#define ASL_KEY_EXPIRE_TIME "ASLExpireTime" /* Expiration time for messages with long TTL. */ -#define ASL_KEY_MSG_ID "ASLMessageID" /* 64-bit message ID number (set by the server). */ -#define ASL_KEY_SESSION "Session" /* Session (set by the launchd). */ -#define ASL_KEY_REF_PID "RefPID" /* Reference PID for messages proxied by launchd */ -#define ASL_KEY_REF_PROC "RefProc" /* Reference process for messages proxied by launchd */ -#define ASL_KEY_AUX_TITLE "ASLAuxTitle" /* Auxiliary title string */ -#define ASL_KEY_AUX_UTI "ASLAuxUTI" /* Auxiliary Uniform Type ID */ -#define ASL_KEY_AUX_URL "ASLAuxURL" /* Auxiliary Uniform Resource Locator */ -#define ASL_KEY_AUX_DATA "ASLAuxData" /* Auxiliary in-line data */ -#define ASL_KEY_OPTION "ASLOption" /* Internal */ -#define ASL_KEY_SENDER_INSTANCE "SenderInstance" /* Sender instance UUID. */ +#define ASL_KEY_TIME "Time" /* Timestamp. Set automatically */ +#define ASL_KEY_TIME_NSEC "TimeNanoSec" /* Nanosecond time. */ +#define ASL_KEY_HOST "Host" /* Sender's address (set by the server). */ +#define ASL_KEY_SENDER "Sender" /* Sender's identification string. Default is process name. */ +#define ASL_KEY_FACILITY "Facility" /* Sender's facility. Default is "user". */ +#define ASL_KEY_PID "PID" /* Sending process ID encoded as a string. Set automatically. */ +#define ASL_KEY_UID "UID" /* UID that sent the log message (set by the server). */ +#define ASL_KEY_GID "GID" /* GID that sent the log message (set by the server). */ +#define ASL_KEY_LEVEL "Level" /* Log level number encoded as a string. See levels above. */ +#define ASL_KEY_MSG "Message" /* Message text. */ +#define ASL_KEY_READ_UID "ReadUID" /* User read access (-1 is any user). */ +#define ASL_KEY_READ_GID "ReadGID" /* Group read access (-1 is any group). */ +#define ASL_KEY_EXPIRE_TIME "ASLExpireTime" /* Expiration time for messages with long TTL. */ +#define ASL_KEY_MSG_ID "ASLMessageID" /* 64-bit message ID number (set by the server). */ +#define ASL_KEY_SESSION "Session" /* Session (set by the launchd). */ +#define ASL_KEY_REF_PID "RefPID" /* Reference PID for messages proxied by launchd */ +#define ASL_KEY_REF_PROC "RefProc" /* Reference process for messages proxied by launchd */ +#define ASL_KEY_AUX_TITLE "ASLAuxTitle" /* Auxiliary title string */ +#define ASL_KEY_AUX_UTI "ASLAuxUTI" /* Auxiliary Uniform Type ID */ +#define ASL_KEY_AUX_URL "ASLAuxURL" /* Auxiliary Uniform Resource Locator */ +#define ASL_KEY_AUX_DATA "ASLAuxData" /* Auxiliary in-line data */ +#define ASL_KEY_OPTION "ASLOption" /* Internal */ +#define ASL_KEY_MODULE "ASLModule" /* Internal */ +#define ASL_KEY_SENDER_INSTANCE "SenderInstance" /* Sender instance UUID. */ +#define ASL_KEY_SENDER_MACH_UUID "SenderMachUUID" /* Sender Mach-O UUID. */ +#define ASL_KEY_FINAL_NOTIFICATION "ASLFinalNotification" /* syslogd posts value as a notification when message has been processed */ +#define ASL_KEY_OS_ACTIVITY_ID "OSActivityID" /* Current OS Activity for the logging thread */ /*! @/defineblock */ -/*! @defineblock aslmsg Types - * Message type argument passed to asl_new(). +#pragma mark - + +/*! @defineblock ASL Object Types + * The library uses only one opaque type - asl_object_t. + * Many of the routines can operate on several different types. + * For example, asl_search() can be used to search a list of messages, + * an ASL database directory or data file, or the main ASL database. + * It can even be used to check a single message against a query + * message, or against another message to check for exact match. + * + * The first three types are container objects - messages, queries, + * and lists of messages or queries. The following types are + * abstractions for ASL data files and ASL data stores (directories + * containing data files). + * + * ASL_TYPE_CLIENT is a high-level object that abstracts ASL + * interactions. It may access ASL stores or files directly, + * and it may communicate with ASL daemons. + * */ +#define ASL_TYPE_UNDEF 0xffffffff #define ASL_TYPE_MSG 0 #define ASL_TYPE_QUERY 1 +#define ASL_TYPE_LIST 2 +#define ASL_TYPE_FILE 3 +#define ASL_TYPE_STORE 4 +#define ASL_TYPE_CLIENT 5 +/*! @/defineblock */ + +#pragma mark - + +/*! @defineblock search directions + * Used for asl_store_match(), asl_file_match(), and asl_match(). + */ +#define ASL_MATCH_DIRECTION_FORWARD 1 +#define ASL_MATCH_DIRECTION_REVERSE -1 /*! @/defineblock */ +#pragma mark - + /*! @defineblock Filter Masks * Used in client-side filtering, which determines which * messages are sent by the client to the syslogd server. @@ -151,6 +200,8 @@ typedef struct __aslresponse *aslresponse; #define ASL_FILTER_MASK_DEBUG 0x80 /*! @/defineblock */ +#pragma mark - + /*! @defineblock Filter Mask Macros * Macros to create bitmasks for filter settings - see asl_set_filter(). */ @@ -158,20 +209,36 @@ typedef struct __aslresponse *aslresponse; #define ASL_FILTER_MASK_UPTO(level) ((1 << ((level) + 1)) - 1) /*! @/defineblock */ +#pragma mark - + /*! @defineblock Client Creation Options * Options for asl_open(). + * Note that ASL_OPT_NO_DELAY no longer has any effect. */ #define ASL_OPT_STDERR 0x00000001 #define ASL_OPT_NO_DELAY 0x00000002 #define ASL_OPT_NO_REMOTE 0x00000004 /*! @/defineblock */ +#pragma mark - + +/*! @defineblock File and Store Open Options + * Options for asl_open_path(). + */ +#define ASL_OPT_OPEN_WRITE 0x00000001 +#define ASL_OPT_CREATE_STORE 0x00000002 +/*! @/defineblock */ + +#pragma mark - + /*! @defineblock File Descriptor Types * Instructions on how to treat the file descriptor in asl_log_descriptor(). */ #define ASL_LOG_DESCRIPTOR_READ 1 #define ASL_LOG_DESCRIPTOR_WRITE 2 +#pragma mark - + /*! @defineblock Output file message and time formats. * These select internally defined formats for printed log messages for * asl_add_output_file(). Custom message and time formats may also be @@ -188,6 +255,8 @@ typedef struct __aslresponse *aslresponse; #define ASL_TIME_FMT_UTC "utc" #define ASL_TIME_FMT_LCL "lcl" +#pragma mark - + /*! @defineblock Text Encoding Types * These are used by the library when formatting messages to be written * to file descriptors associated with an ASL client handle with @@ -202,6 +271,8 @@ typedef struct __aslresponse *aslresponse; #define ASL_ENCODE_ASL 2 #define ASL_ENCODE_XML 3 +#pragma mark - + /*! * ASL_PREFILTER_LOG is a macro similar to asl_log(), but it first checks * if the message will simply be ignored due to local filter settings. @@ -209,67 +280,100 @@ typedef struct __aslresponse *aslresponse; * Note that the message may still be processed if it will be written * to a file or stderr. * - * @param asl - * (input) An ASL client handle + * @param client + * (input) An ASL_TYPE_CLIENT object. * @param msg - * (input) An aslmsg (default attributes will be supplied if msg is NULL) + * (input) An asl_object_t of type ASL_TYPE_MSG (default attributes will be supplied if msg is NULL). * @param level - * (input) Log level (ASL_LEVEL_DEBUG to ASL_LEVEL_EMERG) + * (input) Log level (ASL_LEVEL_DEBUG to ASL_LEVEL_EMERG). * @param format - * (input) A printf() - style format string followed by a list of arguments + * (input) A printf() - style format string followed by a list of arguments. */ -#define ASL_PREFILTER_LOG(asl, msg, level, format, ...) \ +#define ASL_PREFILTER_LOG(client, msg, level, format, ...) \ do { \ - aslclient _asl = (asl); \ - aslmsg _msg = (msg); \ - uint32_t _asl_eval = _asl_evaluate_send(_asl, _msg, (level)); \ - if (_asl_eval != 0) _asl_lib_log(_asl, _asl_eval, _msg, (format), ## __VA_ARGS__); \ + asl_object_t _client = (client); \ + asl_object_t _msg = (msg); \ + uint32_t _asl_eval = _asl_evaluate_send(_client, _msg, (level)); \ + if (_asl_eval != 0) _asl_lib_log(_client, _asl_eval, _msg, (format), ## __VA_ARGS__); \ } while (0) +#pragma mark - + __BEGIN_DECLS /* ASL Library SPI - do not call directly */ -int _asl_lib_log(aslclient asl, uint32_t eval, aslmsg msg, const char *format, ...) __printflike(4, 5); - -uint32_t _asl_evaluate_send(aslclient asl, aslmsg msg, int level); +int _asl_lib_log(asl_object_t client, uint32_t eval, asl_object_t msg, const char *format, ...) __printflike(4, 5); +uint32_t _asl_evaluate_send(asl_object_t client, asl_object_t msg, int level); /*! * Initialize a connection to the ASL server. * - * This call is optional in most cases. The library will perform any + * This call is optional in many cases. The library will perform any * necessary initializations on the fly. A call to asl_open() is required * if optional settings must be made before messages are sent to the server. * These include setting the client filter and managing additional output * file descriptors. Note that the default setting of the client filter is * ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE), so ASL_LEVEL_DEBUG and ASL_LEVEL_INFO * messages are not sent to the server by default. - * + * A separate client connection is required for multiple threads or + * dispatch queues. + * * Options (defined above) may be set using the opts parameter. They are: * * ASL_OPT_STDERR - adds stderr as an output file descriptor * - * ASL_OPT_NO_DELAY - connects to the server immediately - * * ASL_OPT_NO_REMOTE - disables the remote-control mechanism for adjusting * filter levers for processes using e.g. syslog -c ... * * @param ident - * (input) Sender name + * (input) Sender name. * @param facility - * (input) Facility name + * (input) Facility name. * @param opts - * (input) Options (see asl_open Options) - * @result Returns an ASL client handle + * (input) Options (see Client Creation Options). + * @result Returns an ASL client handle (asl_object_t of type ASL_TYPE_CLIENT). */ -aslclient asl_open(const char *ident, const char *facility, uint32_t opts); +asl_object_t asl_open(const char *ident, const char *facility, uint32_t opts) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0); + +/*! + * Open an ASL database or ASL data file for read or write access. + * + * Opens an ASL database if the path specifies a directory, or + * an ASL data file if the path specifies a file. Opens the system + * ASL database if path is NULL. + * + * If the ASL_OPT_OPEN_READ option is specified, the database or data file may be + * searched with asl_search() or asl_match(). asl_next() and asl_prev() may be used + * to iterate over the messages in the database or file. + * + * If the ASL_OPT_OPEN_WRITE option is specified, an existing file or database is + * opened for writing. New messages may be added to the file or database using + * asl_append(), asl_send(), asl_log(), or asl_vlog(). Existing messages in the + * store or file may not be deleted or modified. + * + * If the path does not exist, asl_open_path() will create a new database if + * ASL_OPT_CREATE_STORE is set in the options, or a new data file otherwise. + * The file will be created with the user's effective UID and GID as owner and + * group. The mode will be 0644. If a different mode, UID, or GID is desired, + * an empty file or directory may be pre-created with the desired settings. + * + * @param path + * (input) Location of the ASL database or ASL data file in the filesystem. + * A value of NULL may be used to open the system's database. + * @param opts + * (input) Options (see File and Store Open Options). + * @result Returns an ASL object of type ASL_TYPE_STORE or ASL_TYPE_FILE, or NULL on failure. + */ +asl_object_t asl_open_path(const char *path, uint32_t opts) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); /*! * Shuts down a connection to the server. + * This routine is identical to asl_release(). * - * @param asl - * (input) An ASL client handle + * @param obj + * (input) An ASL object. */ -void asl_close(aslclient asl); +void asl_close(asl_object_t obj) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0); /*! * Write log messages to the given file descriptor. @@ -278,13 +382,13 @@ void asl_close(aslclient asl); * This is equivalent to calling: * asl_add_output_file(asl, descriptor, ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG), ASL_ENCODE_SAFE) * - * @param asl - * (input) An ASL client handle + * @param client + * (input) An ASL client handle (asl_object_t of type ASL_TYPE_CLIENT). * @param descriptor - * (input) A file descriptor - * @result Returns 0 on success, non-zero on failure + * (input) A file descriptor. + * @result Returns 0 on success, non-zero on failure. */ -int asl_add_log_file(aslclient asl, int descriptor); +int asl_add_log_file(asl_object_t client, int descriptor) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0); /*! * Write log messages to the given file descriptor. @@ -295,21 +399,21 @@ int asl_add_log_file(aslclient asl, int descriptor); * control of the time zone used when printing time values, and allowing * individual filtering control for each log file. * - * @param asl - * (input) An ASL client handle + * @param client + * (input) An ASL client handle (asl_object_t of type ASL_TYPE_CLIENT). * @param descriptor - * (input) A file descriptor + * (input) A file descriptor. * @param mfmt - * (input) A character string specifying the message format + * (input) A character string specifying the message format. * @param tfmt - * (input) A character string specifying the time format + * (input) A character string specifying the time format. * @param filter - * (input) A filter value + * (input) A filter value. * @param text_encoding - * (input) A text encoding type - * @result Returns 0 on success, non-zero on failure + * (input) A text encoding type. + * @result Returns 0 on success, non-zero on failure. */ -int asl_add_output_file(aslclient asl, int descriptor, const char *mfmt, const char *tfmt, int filter, int text_encoding) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +int asl_add_output_file(asl_object_t client, int fd, const char *mfmt, const char *tfmt, int filter, int text_encoding) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); /*! * Write log messages to the given file descriptor. @@ -317,27 +421,27 @@ int asl_add_output_file(aslclient asl, int descriptor, const char *mfmt, const c * Sets or changes a filter value for filtering messages written to a file associated * with an ASL client handle using asl_add_output_file() or asl_add_log_file(). * - * @param asl - * (input) An ASL client handle + * @param client + * (input) An ASL client handle (asl_object_t of type ASL_TYPE_CLIENT). * @param descriptor - * (input) A file descriptor + * (input) A file descriptor. * @param filter - * (input) A filter value - * @result Returns the previous filter value + * (input) A filter value. + * @result Returns the previous filter value. */ -int asl_set_output_file_filter(aslclient ac, int fd, int filter) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +int asl_set_output_file_filter(asl_object_t client, int fd, int filter) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); /*! * Stop writing log messages to the given file descriptor. * The file descripter is not closed by this routine. * - * @param asl - * (input) An ASL client handle + * @param client + * (input) An ASL client handle (asl_object_t of type ASL_TYPE_CLIENT). * @param descriptor - * (input) A file descriptor - * @result Returns 0 on success, non-zero on failure + * (input) A file descriptor. + * @result Returns 0 on success, non-zero on failure. */ -int asl_remove_log_file(aslclient asl, int descriptor); +int asl_remove_log_file(asl_object_t client, int descriptor) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0); /*! * Set a filter for messages being sent to the server. @@ -351,102 +455,166 @@ int asl_remove_log_file(aslclient asl, int descriptor); * The default setting is ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE). * Returns the previous filter value. * - * @param asl - * (input) An ASL client handle + * @param client + * (input) An ASL client handle (asl_object_t of type ASL_TYPE_CLIENT). * @param f - * (input) A filter value - * @result Returns the previous filter value + * (input) A filter value. + * @result Returns the previous filter value. */ -int asl_set_filter(aslclient asl, int f); +int asl_set_filter(asl_object_t client, int f) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0); /* * Examine attribute keys. * * @param msg - * (input) An ASL message + * (input) An ASL message or query (asl_object_t of type ASL_TYPE_MSG or ASL_TYPE_QUERY). * @param n - * (input) An index value + * (input) An index value. * @result Returns the key of the nth attribute in a message (beginning at zero), * or NULL if n is greater than the largest message index. */ -const char *asl_key(aslmsg msg, uint32_t n); +const char *asl_key(asl_object_t msg, uint32_t n) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0); + +/* + * Examine attribute keys. + * + * @param msg + * (input) An ASL message or query (asl_object_t of type ASL_TYPE_MSG or ASL_TYPE_QUERY). + * @param key + * (output) key at the given index. May be NULL. + * @param val + * (output) val at the given index. May be NULL. + * @param op + * (output) op at the given index. May be NULL. + * @param n + * (input) An index value. + * @result returns 0 for success, non-zero for failure. + */ +int asl_fetch_key_val_op(asl_object_t msg, uint32_t n, const char **key, const char **val, uint32_t *op) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); /*! - * Create a new log message or query message. + * Create a new log message, query message, message list, or a connection to the system database. * * @param type - * (input) Message type (see aslmsg Types) - * @result Returns a newly allocated asmsg of the specified type + * (input) ASL_TYPE_MSG, ASL_TYPE_QUERY, ASL_TYPE_LIST, or ASL_TYPE_CLIENT. + * @result Returns a newly allocated asl_object_t of the specified type. + * + * @discussion + * New objects of type ASL_TYPE_CLIENT will be created with default settings for + * a client connection, equivalent to asl_open(NULL, NULL, 0). + * The Sender and Facility values associated with an ASL_TYPE_CLIENT may + * be reset using asl_set(). */ -aslmsg asl_new(uint32_t type); +asl_object_t asl_new(uint32_t type) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0); /*! - * Set or re-set a message attribute. + * Set or re-set a message or query attribute. + * May also be used to set values associated with an ASL_TYPE_CLIENT object, + * such as Sender and Facility. * - * @param msg - * (input) An aslmsg + * @param obj + * (input) An ASL object of type ASL_TYPE_MSG, ASL_TYPE_QUERY, or ASL_TYPE_CLIENT. * @param key - * (input) Attribute key + * (input) Attribute key. * @param value - * (input) Attribute value - * @result returns 0 for success, non-zero for failure + * (input) Attribute value. + * @result returns 0 for success, non-zero for failure. */ -int asl_set(aslmsg msg, const char *key, const char *value); +int asl_set(asl_object_t obj, const char *key, const char *value) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0); /*! - * Remove a message attribute. + * Remove a key/value attribute. * - * @param msg - * (input) An aslmsg + * @param obj + * (input) An ASL object of type ASL_TYPE_MSG, ASL_TYPE_QUERY, or ASL_TYPE_CLIENT. * @param key - * (input) Attribute key - * returns 0 for success, non-zero for failure + * (input) Attribute key. + * returns 0 for success, non-zero for failure. */ -int asl_unset(aslmsg msg, const char *key); +int asl_unset(asl_object_t obj, const char *key) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0); /*! - * Get the value of a message attribute. + * Get the value associated with an attribute key. * - * @param msg - * (input) An aslmsg + * @param obj + * (input) An ASL object of type ASL_TYPE_MSG, ASL_TYPE_QUERY, or ASL_TYPE_CLIENT. * @param key - * (input) Attribute key - * @result Returns the attribute value, or NULL if the message does not contain the key + * (input) Attribute key. + * @result Returns the attribute value, or NULL if the object does not contain the key. */ -const char *asl_get(aslmsg msg, const char *key); +const char *asl_get(asl_object_t msg, const char *key) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0); /*! * Log a message with a particular log level. * - * @param asl - * (input) An ASL client handle + * @param obj + * (input) An asl_object_t or NULL. * @param msg - * (input) An aslmsg (default attributes will be supplied if msg is NULL) + * (input) An asl_object_t of type ASL_TYPE_MSG (default attributes will be supplied if msg is NULL). * @param level - * (input) Log level (ASL_LEVEL_DEBUG to ASL_LEVEL_EMERG) + * (input) Log level (ASL_LEVEL_DEBUG to ASL_LEVEL_EMERG). * @param format - * (input) A printf() - style format string followed by a list of arguments - * @result Returns 0 for success, non-zero for failure + * (input) A printf() - style format string followed by a list of arguments. + * @result Returns 0 for success, non-zero for failure. + * + * @discussion + * The input object may be of any type. + * In typical usage, obj is of type ASL_TYPE_CLIENT or obj is NULL. + * NULL causes the library to use the default ASL client handle. + * This routine prepares a message for tranmission to the ASL server daemon (syslogd), + * The message is sent to the server subject to filter settings. The message may also + * be formatted and printed to various output files. + * + * For ASL_TYPE_MSG, this routine will set all key/value pairs in the input object as + * they would appear if the message were being sent to the server. This includes + * setting alues for ASL_KEY_TIME, ASL_KEY_TIME_NSEC, ASL_KEY_HOST, and so on. + * + * If the object is of type ASL_TYPE_STORE or ASL_TYPE_FILE, a message will be + * constructed (as above) and saved in the file or data store. No filtering is done. + * + * If obj is of type ASL_TYPE_LIST, a message is created and appended to the list. + * + * The object type ASL_TYPE_QUERY is supported, but the key/value pairs set in the + * object will have an operator value of zero. + */ +int asl_log(asl_object_t client, asl_object_t msg, int level, const char *format, ...) __printflike(4, 5) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0); + +/*! + * Log a message with a particular log level. + * + * This API is a simplified version of asl_log(). It uses the default (NULL) ASL client handle, + * and does not have a msg parameter to supply additonal key/value pairs to be attached to the + * message sent to the syslogd server. + * + * @param level + * (input) Log level (ASL_LEVEL_DEBUG to ASL_LEVEL_EMERG). + * @param format + * (input) A printf() - style format string followed by a list of arguments. + * @result Returns 0 for success, non-zero for failure. */ -int asl_log(aslclient asl, aslmsg msg, int level, const char *format, ...) __printflike(4, 5); +int asl_log_message(int level, const char *format, ...) __printflike(2, 3) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); /*! * Log a message with a particular log level. * Similar to asl_log, but takes a va_list argument. * * @param asl - * (input) An ASL client handle + * (input) An ASL object or NULL. * @param msg - * (input) An aslmsg (default attributes will be supplied if msg is NULL) + * (input) An asl_object_t of type ASL_TYPE_MSG (default attributes will be supplied if msg is NULL). * @param level - * (input) Log level (ASL_LEVEL_DEBUG to ASL_LEVEL_EMERG) + * (input) Log level (ASL_LEVEL_DEBUG to ASL_LEVEL_EMERG). * @param format - * (input) A printf() - style format string followed by a list of arguments + * (input) A printf() - style format string followed by a list of arguments. * @param ap - * (input) A va_list containing the values for the format string - * @result Returns 0 for success, non-zero for failure + * (input) A va_list containing the values for the format string. + * @result Returns 0 for success, non-zero for failure. + * @discussion + * See the discussion for asl_log() for a description of how this routine treats different + * types of input object. + * */ -int asl_vlog(aslclient asl, aslmsg msg, int level, const char *format, va_list ap) __printflike(4, 0); +int asl_vlog(asl_object_t obj, asl_object_t msg, int level, const char *format, va_list ap) __printflike(4, 0) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0); /*! * Log a message. @@ -455,20 +623,52 @@ int asl_vlog(aslclient asl, aslmsg msg, int level, const char *format, va_list a * has been used to set all of a message's attributes. * * @param asl - * (input) An ASL client handle + * (input) An ASL object or NULL. * @param msg - * (input) An aslmsg - * @result Returns 0 for success, non-zero for failure + * (input) An asl_object_t of type ASL_TYPE_MSG. + * @result Returns 0 for success, non-zero for failure. + * @discussion + * See the discussion for asl_log() for a description of how this routine treats different + * types of input object. */ -int asl_send(aslclient asl, aslmsg msg); +int asl_send(asl_object_t obj, asl_object_t msg) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0); /*! - * Free a message. Frees all the attribute keys and values. + * DEPRECATED: Free an ASL object and all internal resources associated with it. + * This routine is identical to asl_release(), which should be used instead. + * Note that we don't issue a deprecation warning - yet. * - * @param msg - * (input) An aslmsg to free + * @param obj + * (input) An ASL object to free. + */ +void asl_free(asl_object_t obj) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0); + +/*! + * Increment the internal reference count of an ASL object. + * + * @param obj + * (input) An ASL object to retain. + * @result Returns the object. + */ +asl_object_t asl_retain(asl_object_t obj) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +/*! + * Decrement the internal reference count of an ASL object. + * Frees the object when the reference count becomes zero. + * + * @param obj + * (input) An ASL object to release. + */ +void asl_release(asl_object_t obj) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +/*! + * Get the internal type of an ASL object. + * + * @param obj + * (input) An ASL object. + * @result Returns the object type. */ -void asl_free(aslmsg msg); +uint32_t asl_get_type(asl_object_t obj) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); /*! * Set arbitrary parameters of a query. @@ -476,7 +676,7 @@ void asl_free(aslmsg msg); * See ASL_QUERY_OP_* above. * * @param msg - * (input) An aslmsg + * (input) An ASL object of type ASL_TYPE_QUERY. * @param key * (input) Attribute key * @param value @@ -485,34 +685,123 @@ void asl_free(aslmsg msg); * (input) An operation (ASL_QUERY_OP_*) * @result Returns 0 for success, non-zero for failure */ -int asl_set_query(aslmsg msg, const char *key, const char *value, uint32_t op); +int asl_set_query(asl_object_t msg, const char *key, const char *value, uint32_t op) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0); /*! - * Search for messages matching the criteria described by the aslmsg. + * Search for messages matching the criteria described by an query object. * The caller should set the attributes to match using asl_set_query() or asl_set(). - * The operatoin ASL_QUERY_OP_EQUAL is used for attributes set with asl_set(). + * The operation ASL_QUERY_OP_EQUAL is used for attributes set with asl_set(). * - * @param msg - * (input) An aslmsg to match - * @result Returns a set of messages accessable using aslresponse_next(), + * @param obj + * (input) An ASL object to search. + * @param query + * (input) An asl_object_t of type ASL_TYPE_QUERY or ASL_TYPE_MSG. + * query may be NULL, which matches anything. + * @result Returns an ASL object containing messages matching the query, or NULL if there are no matches. + * + * @discussion + * The object to search may be of any type. + * ASL_TYPE_CLIENT searches the main ASL database. + * ASL_TYPE_STORE searches an ASL database in the filesystem. + * ASL_TYPE_FILE searches an ASL data file in the filesystem. + * ASL_TYPE_LIST searches for matches in a list of messages. + * + * A NULL query matches anything. + * + * If obj is of type ASL_TYPE_MSG and query is of type ASL_TYPE_QUERY, obj is matched against the query, + * and a list containing the "obj" object is returned if the match succeeds. + * + * If both obj and query are objects of type ASL_TYPE_MSG or both are of type ASL_TYPE_QUERY, + * they are tested for exact match. A list containing the "obj" object is returned if the match is exact. + * + * If obj is of type ASL_TYPE_QUERY and query is of type ASL_TYPE_MSG, the routine returns NULL. + * + */ +asl_object_t asl_search(asl_object_t obj, asl_object_t query) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0); + +/*! + * DEPRECATED: Iterate over messages in an asl_object_t (same as an aslresponse). + * This routine is identical to asl_next(). + * + * @param list + * (input) An asl_object_t (aslresponse). + * @result Returns the next message contained in an ASL object, or NULL when there are no more messages. + * + * @discussion + * This routine is deprecated in favor of asl_next(). + */ +asl_object_t aslresponse_next(asl_object_t obj) __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_4,__MAC_10_10,__IPHONE_2_0,__IPHONE_7_0, "Use asl_next instead"); + +/*! + * DEPRECATED: Free an asl_object_t. + * This routine is identical to asl_release(). + * + * @param list + * (input) An asl_object_t (aslresponse). + * + * @discussion + * This routine is deprecated in favor of asl_release(). + */ +void aslresponse_free(asl_object_t obj) __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_4,__MAC_10_10,__IPHONE_2_0,__IPHONE_7_0, "Use asl_release instead"); + +/*! + * Append messages to an object of type ASL_TYPE_LIST. The input "obj" + * parameter may be of type ASL_TYPE_MSG or ASL_TYPE_QUERY, in which case + * the object is appended to the list, or "obj" may be of type ASL_TYPE_LIST, + * in which case each object in that list is appended to the "list" object. + * Does nothing if either list or obj are NULL. + * + * @param obj + * (input) An object of type ASLTYPE_CLIENT or ASL_TYPE_LIST, or an object of type + * ASL_TYPE_FILE or ASL_TYPE_STORE that is open for write operations. + * @param obj_to_add + * (input) An object of type ASL_TYPE_MSG, ASL_TYPE_QUERY or type ASL_TYPE_LIST. + */ +void asl_append(asl_object_t obj, asl_object_t obj_to_add) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +/*! + * Prepend messages to an object of type ASL_TYPE_LIST. The input "obj" + * parameter may be of type ASL_TYPE_MSG or ASL_TYPE_QUERY, in which case + * the object is prepended to the list, or "obj" may be of type ASL_TYPE_LIST, + * in which case each object in that list is prepended to the "list" object. + * Does nothing if either list or obj are NULL. + * + * @param obj + * (input) An object of type ASL_TYPE_LIST. + * @param obj_to_add + * (input) An object of type ASL_TYPE_MSG, ASL_TYPE_QUERY or type ASL_TYPE_LIST. + */ +void asl_prepend(asl_object_t obj, asl_object_t obj_to_add) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +/*! + * Get the number of key/value pairs in an object of type ASL_TYPE_MSG or ASL_TYPE_QUERY, + * or the number of components in an object of type ASL_TYPE_LIST. + * + * @param obj + * (input) An asl_object_t of type ASL_TYPE_MSG, ASL_TYPE_QUERY, or ASL_TYPE_LIST. + * @result The number of components in the object. + * Returns zero if object is empty or NULL, or if the type is not + * ASL_TYPE_MSG, ASL_TYPE_QUERY, or ASL_TYPE_LIST. */ -aslresponse asl_search(aslclient asl, aslmsg msg); +size_t asl_count(asl_object_t obj) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); /*! - * Iterate over responses returned from asl_search(). + * Retreive a message from an object of type ASL_TYPE_LIST. * - * @param r - * (input) An aslresponse returned by asl_search() - * @result Returns the next message (an aslmsg) in the response, or NULL when there are no more messages + * @param obj + * (input) An asl_object_t of type ASL_TYPE_LIST + * @result Returns the message (an object of type ASL_TYPE_MSG or ASL_TYPE_QUERY) at the specified index. + * Returns NULL if the index is out of range or if list is not an object of type ASL_TYPE_LIST. */ -aslmsg aslresponse_next(aslresponse r); +asl_object_t asl_get_index(asl_object_t list, size_t index) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); /*! - * Free a response returned from asl_search(). - * @param r - * (input) An aslresponse returned by asl_search() + * Remove the message at a specified index from an object of type ASL_TYPE_LIST. + * + * @param list + * (input) An object of type ASL_TYPE_LIST. */ -void aslresponse_free(aslresponse r); +void asl_remove_index(asl_object_t list, size_t index) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); /*! * Creates an auxiliary file that may be used to save arbitrary data. The ASL message msg @@ -532,17 +821,16 @@ void aslresponse_free(aslresponse r); * seconds after the Epoch, or it may be ctime() format, e.g "Thu Jun 24 18:22:48 2010". * * @param msg - * (input) An aslmsg + * (input) An object of type ASL_TYPE_MSG. * @param tite - * (input) A title string for the file + * (input) A title string for the file. * @param uti - * (input) Uniform Type Identifier for the file + * (input) Uniform Type Identifier for the file. * @param out_descriptor - * (output) A writable file descriptor + * (output) A writable file descriptor. * @result Returns 0 for success, non-zero for failure */ -int asl_create_auxiliary_file(aslmsg msg, const char *title, const char *uti, int *out_descriptor) -__OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0); +int asl_create_auxiliary_file(asl_object_t msg, const char *title, const char *uti, int *out_descriptor) __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0); /*! * Close an auxiliary file opened by asl_create_auxiliary_file() when writing is complete. @@ -553,8 +841,7 @@ __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0); * (input) The file descriptor * @result Returns 0 for success, non-zero for failure */ -int asl_close_auxiliary_file(int descriptor) -__OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0); +int asl_close_auxiliary_file(int descriptor) __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0); /*! * Sends an ASL message to syslogd along with a title string, Uniform Resource Locator, @@ -563,7 +850,7 @@ __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0); * type "public.data" is used. * * @param msg - * (input) An aslmsg + * (input) An object of type ASL_TYPE_MSG. * @param title * (input) A title string for the file * @param uti @@ -572,34 +859,39 @@ __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0); * (input) Uniform Type Locator * @result Returns 0 for success, non-zero for failure */ -int asl_log_auxiliary_location(aslmsg msg, const char *title, const char *uti, const char *url) -__OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0); +int asl_log_auxiliary_location(asl_object_t msg, const char *title, const char *uti, const char *url) __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0); /*! - * Creates an aslclient for logging to a file descriptor. The file must be opened for read and - * write access. This routine may be used in conjunction with asl_create_auxiliary_file() to - * save ASL format log messages to an auxiliary file. + * Creates an object of type ASL_TYPE_CLIENT for logging to a file descriptor. + * The file must be opened for read and write access. This routine may be used in conjunction + * with asl_create_auxiliary_file() to save ASL format log messages to an auxiliary file. * - * The file will be truncated if it is not empty. When logging to the auxiliary file is complete, - * aslclient should be closed using asl_close(). The file should be closed using - * asl_close_auxiliary_file() if it was returned by asl_create_auxiliary_file(), or close() - * otherwise. + * When logging to the file is complete, the returned object should be released with asl_release(). + * The file descriptor should be closed using asl_close_auxiliary_file() if it was returned by + * asl_create_auxiliary_file(), or close() otherwise. * - * The returned aslclient is thread-safe. + * The returned client object is thread-safe. It contains a lock that is aquired by + * the calling thread. Note that this may cause unexpected syncronization behavior + * if multiple threads log to the returned object, or in applications that use the + * object in multiple dispatch queues. * * Note that per-message read access controls (ReadUID and ReadGID) and message expire * times (ASLExpireTime) keys have no effect for messages written to this file. * + * Also note that files are NOT truncated. This is a change in OS X 10.9 and iOS 7.0. + * Previous versions of this routine truncated the file before writing. Callers + * may use ftruncate() to truncate the file if desired. If an existing non-empty + * file is used, it must be an ASL format data file. + * * @param descriptor * (input) A file descriptor * @param ident * (input) Sender name * @param facility * (input) Facility name - * @result An aslclient + * @result An object of type ASL_TYPE_CLIENT. */ -aslclient asl_open_from_file(int descriptor, const char *ident, const char *facility) -__OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0); +asl_object_t asl_open_from_file(int descriptor, const char *ident, const char *facility) __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0); /*! * This API provides functionality to use file descriptors to send logging @@ -631,10 +923,10 @@ __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0); * asl_log_descriptor(c, m, ASL_LEVEL_NOTICE, STDOUT_FILENO, ASL_LOG_DESCRIPTOR_WRITE); * asl_log_descriptor(c, m, ASL_LEVEL_ERR, STDERR_FILENO, ASL_LOG_DESCRIPTOR_WRITE); * - * @param asl - * (input) An ASL client handle + * @param client + * (input) An ASL object of type ASL_TYPE_CLIENT. * @param msg - * (input) An aslmsg (default attributes will be supplied if msg is NULL) + * (input) An asl_object_t of type ASL_TYPE_MSG (default attributes will be supplied if msg is NULL). * @param level * (input) Log level (ASL_LEVEL_DEBUG to ASL_LEVEL_EMERG) * @param descriptor @@ -643,8 +935,149 @@ __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0); * (input) Either ASL_LOG_DESCRIPTOR_READ or ASL_LOG_DESCRIPTOR_WRITE * @result Returns 0 for success, non-zero for failure */ -int asl_log_descriptor(aslclient asl, aslmsg msg, int level, int descriptor, uint32_t fd_type) -__OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_5_1); +int asl_log_descriptor(asl_object_t asl, asl_object_t msg, int level, int descriptor, uint32_t fd_type) __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_5_1); + +#pragma mark - + + +/*! + * Creates a string representation of an ASL message. + * + * This utility creates a character string suitable for printing an ASL message. + * The returned string ends with a newline character. The caller is responsible + * for freeing the returned string. + * The message is formatted according to the specified format string. Timestamps + * are formatted accoring to the specified time format string. Special characters + * are enoded as specified by the text_encoding parameter. + * + * @param msg + * (input) An asl_object_t of type ASL_TYPE_MSG. + * @param fmt + * (input) A format specification string. See "Output file message and time formats" + * for standard formats. See the syslog(1) man page for more discussion on formats. + * @param fmt + * (input) A time format specification string. See "Output file message and time formats" + * for standard formats. See the syslog(1) man page for more discussion on time formats. + * @param text_encoding + * (input) Text encoding control (for special characters). See "Text Encoding Types". +* @result Returns a character string, or NULL in case of a failure. + */ +char *asl_format(asl_object_t msg, const char *msg_fmt, const char *time_fmt, uint32_t text_encoding) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +/*! + * Encodes a buffer with embedded nul characters into a nul terminated C string. + * The result must be freed by the caller. + * + * This utility is used to encode the value associated with ASL_KEY_AUX_DATA + * in an ASL_TYPE_MSG object. An ASL_KEY_AUX_DATA key/value pair is used to hold the + * data written to a file descriptor created by asl_create_auxiliary_file on iOS + * systems, where the ASL database is stored in memory. + * + * @param buf + * (input) Pointer to a data buffer. + * @param len + * (input) Length (in octets) of data buffer. + * @result Returns an encoded character string. + */ +char *asl_encode_buffer(const char *buf, size_t len) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +/*! + * Decodes a C string previously created by asl_encode_buffer back into a buffer, + * possibly containing embedded nul characters. Allocates memory for the buffer + * and returns a pointer in an output parameter "buf". + * The caller is responsible for freeing the buffer. + * + * This routine should be used to decode the value associated with an + * ASL_KEY_AUX_DATA key in an ASL_TYPE_MSG object. + * + * @param in + * (input) Pointer to nul-terminated string created by asl_encode_buffer. + * @param buf + * (output) Pointer to a newly allocated data buffer. + * @param len + * (input) Length (in octets) of data buffer. + * @result Returns 0 on success, non-zero on failure. + */ +int asl_decode_buffer(const char *in, char **buf, size_t *len) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +/*! + * Iterate forward through messages in an asl_object_t. + * The asl_object_t object maintains an internal position index for the underlying + * collection of ASL messages, whether the asl_object_t represents a list, a + * data file, or an ASL database. The position index is moved forward and the + * "next" message is returned. + * + * @param obj + * (input) An asl_object_t. + * @result Returns the next message (an object of type ASL_TYPE_MSG or ASL_TYPE_QUERY) from the object, + * which should be of type ASL_TYPE_CLIENT, ASL_TYPE_LIST, ASL_TYPE_STORE, or ASL_TYPE_FILE. + * Returns NULL when there are no more messages or if obj is not a type that holds messages. + */ +asl_object_t asl_next(asl_object_t obj) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +/*! + * Iterate backwards through messages in an asl_object_t. + * The asl_object_t object maintains an internal position index for the underlying + * collection of ASL messages, whether the asl_object_t represents a list, a + * data file, or an ASL database. The position index is moved backward and the + * "previous" message is returned. + * + * @param data + * (input) An asl_object_t. + * @result Returns the previous message (an object of type ASL_TYPE_MSG or ASL_TYPE_QUERY) from the object, + * which should be of type ASL_TYPE_CLIENT, ASL_TYPE_LIST, ASL_TYPE_STORE, or ASL_TYPE_FILE. + * Returns NULL when there are no more messages or if obj is not a type that holds messages. + */ +asl_object_t asl_prev(asl_object_t obj) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +/*! + * Reset internal interation index in an asl_object_t. + * + * @param obj + * (input) An object of type ASL_TYPE_CLIENT, ASL_TYPE_LIST, ASL_TYPE_STORE, or ASL_TYPE_FILE. + * @param position + * (input) Use 0 to position the internal interation index at the beginning of the asl_object_t object, + * and SIZE_MAX to position it at the end. Other values of position may cause unpredictable behavior. + */ +void asl_reset_iteration(asl_object_t obj, size_t position) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +/*! + * Searches an asl_object_t. + * The search is controlled by a list of queries, and returns a list with matching messages. + * A message is returned if it matches any of the queries in the query list. + * A NULL querylist matches anything. + * + * The caller may provide a starting ASL message ID, a direction, and a count. + * A start ID value of 0 means that matching should commence at the beginning of the target obj. + * A value of SIZE_MAX indicates that matching should commence at the end (most recent message) + * in the target. If a non-zero count value is supplied, the routine will return when it has + * found that many messages, or it has checked all messages. If a non-zero duration is supplied, + * the routine will return after the specified time (in microseconds). + * If both count and duration are non-zero, the routine will return when the desired number of + * items has been matched or when the specified duration has been exceeded, whichever occurs first. + * The search direction may be ASL_MATCH_DIRECTION_FORWARD or ASL_MATCH_DIRECTION_REVERSE. + * The routine sets the value of the out parameter last to be an index of the last message + * checked while matching. To fetch matching messages in batches (using a small count or + * duration value), the start value for each iteration should be set to (last + 1) if searching + * forward, or (last - 1)for reverse search. + * + * @param data + * (input) An asl_object_t object. + * @param querylist + * (input) An asl_object_t object containing zero or more queries. + * @param last + * (output) An internal position index of the last message checked while matching in the asl_object_t object. + * @param start + * (input) A position index specifying where matching should commence. + * @param count + * (input) The maximum number of messages to be returned in the res output list (zero indicates no limit). + * @param duration + * (input) A limit (in microseconds) on the time to be spent searching for results. Zero indicates no time limit. + * @param direction + * (input) ASL_MATCH_DIRECTION_FORWARD or ASL_MATCH_DIRECTION_REVERSE. + * @result Returns an ASL object containing messages matching the querylist, or NULL if there are no matches. + */ +asl_object_t asl_match(asl_object_t data, asl_object_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); __END_DECLS diff --git a/libsystem_asl.tproj/include/asl_client.h b/libsystem_asl.tproj/include/asl_client.h new file mode 100644 index 0000000..e0383aa --- /dev/null +++ b/libsystem_asl.tproj/include/asl_client.h @@ -0,0 +1,101 @@ +/* + * 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, + * 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@ + */ + +#ifndef __ASL_CLIENT_H__ +#define __ASL_CLIENT_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define CLIENT_FLAG_WRITE_SYS 0x00000001 +#define CLIENT_FLAG_WRITE_STORE 0x00000002 +#define CLIENT_FLAG_WRITE_FILE 0x00000004 +#define CLIENT_FLAG_READ_SYS 0x00000100 +#define CLIENT_FLAG_READ_STORE 0x00000200 +#define CLIENT_FLAG_READ_FILE 0x00000400 + +typedef struct +{ + int fd; + uint32_t encoding; + uint32_t filter; + char *mfmt; + char *tfmt; +} asl_out_file_t; + +typedef struct asl_client_s +{ + uint32_t asl_type; //ASL OBJECT HEADER + int32_t refcount; //ASL OBJECT HEADER + uint32_t flags; + uint32_t options; + pid_t pid; + uid_t uid; + gid_t gid; + asl_msg_t *kvdict; + uint32_t filter; + int notify_token; + int notify_master_token; + uint32_t out_count; + asl_out_file_t *out_list; + asl_file_t *aslfile; + uint64_t aslfileid; + asl_store_t *store; + uint32_t reserved1; + void *reserved2; +} asl_client_t; + +__BEGIN_DECLS + +const asl_jump_table_t *asl_client_jump_table(void); + +asl_client_t *asl_client_open(const char *ident, const char *facility, uint32_t opts) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +asl_client_t *asl_client_open_from_file(int descriptor, const char *ident, const char *facility) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +asl_client_t *asl_client_retain(asl_client_t *client) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +void asl_client_release(asl_client_t *client) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +int asl_client_set_filter(asl_client_t *client, int filter) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +ASL_STATUS asl_client_add_output_file(asl_client_t *client, int descriptor, const char *mfmt, const char *tfmt, int filter, int text_encoding) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +int asl_client_set_output_file_filter(asl_client_t *client, int fd, int filter) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +ASL_STATUS asl_client_remove_output_file(asl_client_t *client, int descriptor) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +int asl_client_log_descriptor(asl_client_t *client, asl_msg_t *msg, int level, int descriptor, uint32_t fd_type) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +asl_msg_t *asl_client_kvdict(asl_client_t *client) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +int asl_client_log(asl_client_t *client, asl_msg_t *msg, int level, const char *format, ...) __printflike(4, 5) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +int asl_client_vlog(asl_client_t *client, asl_msg_t *msg, int level, const char *format, va_list ap) __printflike(4, 0) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +ASL_STATUS asl_client_send(asl_client_t *client, asl_msg_t *msg) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +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); + +__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 722e860..3b29a4a 100644 --- a/libsystem_asl.tproj/include/asl_core.h +++ b/libsystem_asl.tproj/include/asl_core.h @@ -2,7 +2,7 @@ #define __ASL_CORE_H__ /* - * Copyright (c) 2007-2011 Apple Inc. All rights reserved. + * Copyright (c) 2007-2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,16 +26,11 @@ #include #include +#include +#include #include -typedef struct -{ - uint32_t encoding; - size_t delta; - size_t bufsize; - size_t cursor; - char *buf; -} asl_string_t; +typedef uint32_t ASL_STATUS; #define ASL_STATUS_OK 0 #define ASL_STATUS_INVALID_ARG 1 @@ -52,6 +47,7 @@ typedef struct #define ASL_STATUS_WRITE_ONLY 12 #define ASL_STATUS_MATCH_FAILED 13 #define ASL_STATUS_NO_RECORDS 14 +#define ASL_STATUS_INVALID_TYPE 15 #define ASL_STATUS_FAILED 9999 #define ASL_REF_NULL 0xffffffffffffffffLL @@ -83,14 +79,19 @@ typedef struct #define ASL_QUERY_MATCH_FALSE 0x40000000 #define ASL_QUERY_MATCH_ERROR 0x20000000 -#define ASL_ENCODE_MASK 0x0000000f -#define ASL_STRING_VM 0x80000000 -#define ASL_STRING_LEN 0x40000000 +#define ASL_SERVICE_NAME "com.apple.system.logger" -#define ASL_STRING_MIG 0xc0000002 +#define ASL_PLACE_DATABASE 0 +#define ASL_PLACE_ARCHIVE 1 + +#define ASL_PLACE_DATABASE_DEFAULT "/var/log/asl" +#define ASL_PLACE_ARCHIVE_DEFAULT "/var/log/asl.archive" + +mach_port_t asl_core_get_service_port(int reset) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); uint32_t asl_core_string_hash(const char *str, uint32_t len) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); const char *asl_core_error(uint32_t code) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); +const char *asl_core_level_to_string(uint32_t level) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); uint32_t asl_core_check_access(int32_t msgu, int32_t msgg, int32_t readu, int32_t readg, uint16_t flags) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); uint64_t asl_core_htonq(uint64_t n) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); uint64_t asl_core_ntohq(uint64_t n)__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); @@ -98,17 +99,8 @@ uint64_t asl_core_new_msg_id(uint64_t start) __OSX_AVAILABLE_STARTING(__MAC_10_5 char *asl_core_encode_buffer(const char *in, uint32_t len) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); int32_t asl_core_decode_buffer(const char *in, char **buf, uint32_t *len) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); -asl_string_t *asl_string_new(uint32_t encoding) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); -char *asl_string_free_return_bytes(asl_string_t *str) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); -void asl_string_free(asl_string_t *str) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); -char *asl_string_bytes(asl_string_t *str) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); -size_t asl_string_length(asl_string_t *str) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); -size_t asl_string_allocated_size(asl_string_t *str) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); -asl_string_t *asl_string_append(asl_string_t *str, const char *app) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); -asl_string_t *asl_string_append_asl_key(asl_string_t *str, const char *app) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); -asl_string_t *asl_string_append_op(asl_string_t *str, uint32_t op) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); -asl_string_t *asl_string_append_no_encoding(asl_string_t *str, const char *app) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); -asl_string_t *asl_string_append_char_no_encoding(asl_string_t *str, const char c) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); -asl_string_t *asl_string_append_xml_tag(asl_string_t *str, const char *tag, const char *s) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); +time_t asl_core_parse_time(const char *in, uint32_t *tlen) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +const char *asl_filesystem_path(uint32_t place) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); #endif /* __ASL_CORE_H__ */ diff --git a/libsystem_asl.tproj/include/asl_file.h b/libsystem_asl.tproj/include/asl_file.h index d550d8d..e3d38ab 100644 --- a/libsystem_asl.tproj/include/asl_file.h +++ b/libsystem_asl.tproj/include/asl_file.h @@ -28,7 +28,11 @@ #include #include #include +#include +#include #include +#include +#include #define DB_HEADER_LEN 80 #define DB_HEADER_COOKIE_OFFSET 0 @@ -36,7 +40,8 @@ #define DB_HEADER_FIRST_OFFSET 16 #define DB_HEADER_TIME_OFFSET 24 #define DB_HEADER_CSIZE_OFFSET 32 -#define DB_HEADER_LAST_OFFSET 36 +#define DB_HEADER_FILTER_MASK_OFFSET 36 +#define DB_HEADER_LAST_OFFSET 37 /* * Magic Cookie for database files. @@ -47,10 +52,11 @@ #define DB_VERSION 2 #define DB_VERSION_LEGACY_1 1 -#define ASL_FILE_FLAG_READ_ONLY 0x00000001 -#define ASL_FILE_FLAG_UNLIMITED_CACHE 0x00000002 -#define ASL_FILE_FLAG_PRESERVE_MSG_ID 0x00000004 -#define ASL_FILE_FLAG_LEGACY_STORE 0x00000008 +#define ASL_FILE_FLAG_READ 0x00000001 +#define ASL_FILE_FLAG_WRITE 0x00000002 +#define ASL_FILE_FLAG_UNLIMITED_CACHE 0x00000004 +#define ASL_FILE_FLAG_PRESERVE_MSG_ID 0x00000008 +#define ASL_FILE_FLAG_LEGACY_STORE 0x00000010 #define ASL_FILE_TYPE_MSG 0 #define ASL_FILE_TYPE_STR 1 @@ -60,6 +66,9 @@ #define ASL_FILE_POSITION_NEXT 2 #define ASL_FILE_POSITION_LAST 3 +/* flags for asl_file_filter */ +#define ASL_FILE_FILTER_FLAG_KEEP_MATCHES 0x00000001 + /* NB CACHE_SIZE must be > 1 */ #define CACHE_SIZE 256 @@ -69,8 +78,8 @@ /* * The first record (header) in the database has the format: * - * | 12 | 4 | 8 | 8 | 4 | 8 | 36 | (80 bytes) - * | Cookie | Vers | First | Time | String cache size | Last | Zero | + * | 12 | 4 | 8 | 8 | 4 | 8 | 1 | 35 | (80 bytes) + * | Cookie | Vers | First | Time | String cache size | Last | Mask | Zero | * * MSG records have the format: * @@ -95,11 +104,14 @@ typedef struct file_string_s char str[]; } file_string_t; -typedef struct +typedef struct asl_file_s { + uint32_t asl_type; //ASL OBJECT HEADER + int32_t refcount; //ASL OBJECT HEADER uint32_t flags; uint32_t version; - uint32_t string_count; + uint32_t string_cache_count; + uint32_t msg_count; file_string_t *string_list; uint64_t first; uint64_t last; @@ -119,32 +131,42 @@ typedef struct asl_file_list_s struct asl_file_list_s *next; } asl_file_list_t; +__BEGIN_DECLS + +const asl_jump_table_t *asl_file_jump_table(void); + asl_file_list_t *asl_file_list_add(asl_file_list_t *list, asl_file_t *f) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); void asl_file_list_close(asl_file_list_t *list) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); +asl_file_t *asl_file_retain(asl_file_t *s) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +void asl_file_release(asl_file_t *s) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + uint32_t asl_file_open_write(const char *path, mode_t mode, uid_t uid, gid_t gid, asl_file_t **s) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); uint32_t asl_file_close(asl_file_t *s) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); -uint32_t asl_file_save(asl_file_t *s, aslmsg msg, uint64_t *mid) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); +uint32_t asl_file_save(asl_file_t *s, asl_msg_t *msg, uint64_t *mid) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); uint32_t asl_file_open_read(const char *path, asl_file_t **s) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); -uint32_t asl_file_fetch(asl_file_t *s, uint64_t mid, aslmsg *msg) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); +uint32_t asl_file_fetch(asl_file_t *s, uint64_t mid, asl_msg_t **msg) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); uint32_t asl_file_read_set_position(asl_file_t *s, uint32_t pos) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); -uint32_t asl_file_fetch_next(asl_file_t *s, aslmsg *msg) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); -uint32_t asl_file_fetch_previous(asl_file_t *s, aslmsg *msg) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); +uint32_t asl_file_fetch_next(asl_file_t *s, asl_msg_t **msg) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); +uint32_t asl_file_fetch_previous(asl_file_t *s, asl_msg_t **msg) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); -uint32_t asl_file_match(asl_file_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); -uint32_t asl_file_list_match_timeout(asl_file_list_t *list, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, uint32_t usec) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_3_2); -uint32_t asl_file_list_match(asl_file_list_t *list, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); +asl_msg_list_t *asl_file_match(asl_file_t *s, asl_msg_list_t *query, uint64_t *last, uint64_t start, uint32_t count, uint32_t duration, int32_t direction) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); +asl_msg_list_t *asl_file_list_match(asl_file_list_t *list, asl_msg_list_t *query, uint64_t *last, uint64_t start, uint32_t count, uint32_t duration, int32_t direction) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); void *asl_file_list_match_start(asl_file_list_t *list, uint64_t start_id, int32_t direction) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); -uint32_t asl_file_list_match_next(void *token, aslresponse query, aslresponse *res, uint32_t count) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); +uint32_t asl_file_list_match_next(void *token, asl_msg_list_t *query, asl_msg_list_t **res, uint32_t count) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); void asl_file_list_match_end(void *token) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); size_t asl_file_size(asl_file_t *s) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); uint64_t asl_file_ctime(asl_file_t *s) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); uint32_t asl_file_compact(asl_file_t *s, const char *path, mode_t mode, uid_t uid, gid_t gid) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); +uint32_t asl_file_filter(asl_file_t *s, const char *path, asl_msg_list_t *filter, uint32_t flags, mode_t mode, uid_t uid, gid_t gid, uint32_t *dstcount, void (*aux_callback)(const char *auxfile)) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +uint32_t asl_file_filter_level(asl_file_t *s, const char *path, uint32_t keep_mask, mode_t mode, uid_t uid, gid_t gid, uint32_t *dstcount, void (*aux_callback)(const char *auxfile)) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +__END_DECLS #endif /* __ASL_FILE_H__ */ diff --git a/libsystem_asl.tproj/include/asl_legacy1.h b/libsystem_asl.tproj/include/asl_legacy1.h index a2efcde..7d6839f 100644 --- a/libsystem_asl.tproj/include/asl_legacy1.h +++ b/libsystem_asl.tproj/include/asl_legacy1.h @@ -60,6 +60,8 @@ #include #include #include +#include +#include #include typedef struct @@ -79,7 +81,7 @@ typedef struct uint32_t asl_legacy1_open(const char *path, asl_legacy1_t **s) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); uint32_t asl_legacy1_close(asl_legacy1_t *s) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); -uint32_t asl_legacy1_fetch(asl_legacy1_t *s, uint64_t msgid, aslmsg *msg) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); -uint32_t asl_legacy1_match(asl_legacy1_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); +uint32_t asl_legacy1_fetch(asl_legacy1_t *s, uint64_t msgid, asl_msg_t **msg) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); +uint32_t asl_legacy1_match(asl_legacy1_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last, uint64_t start, uint32_t count, int32_t direction) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); #endif /*__ASL_LEGACY1_H__*/ diff --git a/libsystem_asl.tproj/include/asl_msg.h b/libsystem_asl.tproj/include/asl_msg.h index 9540471..104cd9d 100644 --- a/libsystem_asl.tproj/include/asl_msg.h +++ b/libsystem_asl.tproj/include/asl_msg.h @@ -25,13 +25,14 @@ #define __ASL_MSG_H__ #include +#include #include -#include +#include #define IndexNull ((uint32_t)-1) -#define ASL_MSG_PAGE_DATA_SIZE 800 -#define ASL_MSG_PAGE_SLOTS 24 +#define ASL_MSG_PAGE_DATA_SIZE 830 +#define ASL_MSG_PAGE_SLOTS 25 #define ASL_MSG_OFFSET_MASK 0x3fff #define ASL_MSG_KV_MASK 0xc000 @@ -60,7 +61,8 @@ #define ASL_STD_KEY_MSG_ID 0x8010 #define ASL_STD_KEY_EXPIRE 0x8011 #define ASL_STD_KEY_OPTION 0x8012 -#define ASL_STD_KEY_LAST ASL_STD_KEY_OPTION +#define ASL_STD_KEY_FREE_NOTE 0x8013 +#define ASL_STD_KEY_LAST ASL_STD_KEY_FREE_NOTE #define ASL_MT_KEY_BASE 0x8100 #define ASL_MT_KEY_DOMAIN 0x8101 @@ -82,26 +84,23 @@ typedef struct asl_msg_s { - uint32_t type; - int32_t refcount; + uint32_t asl_type; //ASL OBJECT HEADER + int32_t refcount; //ASL OBJECT HEADER uint32_t count; 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]; - uint32_t op[ASL_MSG_PAGE_SLOTS]; + uint16_t op[ASL_MSG_PAGE_SLOTS]; char data[ASL_MSG_PAGE_DATA_SIZE]; } asl_msg_t; -typedef struct __aslresponse -{ - uint32_t count; - uint32_t curr; - asl_msg_t **msg; -} asl_msg_list_t; +__BEGIN_DECLS -#define asl_search_result_t asl_msg_list_t +const asl_jump_table_t *asl_msg_jump_table(void); +/* new/retain/release */ asl_msg_t *asl_msg_new(uint32_t type) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); asl_msg_t *asl_msg_retain(asl_msg_t *msg) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); void asl_msg_release(asl_msg_t *msg) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); @@ -109,22 +108,28 @@ void asl_msg_release(asl_msg_t *msg) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHO int asl_msg_set_key_val(asl_msg_t *msg, const char *key, const char *val) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); int asl_msg_set_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32_t op) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); void asl_msg_unset(asl_msg_t *msg, const char *key) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); +void asl_msg_unset_index(asl_msg_t *msg, uint32_t n) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); asl_msg_t *asl_msg_copy(asl_msg_t *msg) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); asl_msg_t *asl_msg_merge(asl_msg_t *target, asl_msg_t *msg) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); -int asl_msg_lookup(asl_msg_t *msg, const char *key, const char **valout, uint32_t *opout) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); -uint32_t asl_msg_fetch(asl_msg_t *msg, uint32_t n, const char **keyout, const char **valout, uint32_t *opout) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); +int asl_msg_lookup(asl_msg_t *msg, const char *key, const char **valout, uint16_t *opout) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); +uint32_t asl_msg_fetch(asl_msg_t *msg, uint32_t n, const char **keyout, const char **valout, uint16_t *opout) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); +const char *asl_msg_get_val_for_key(asl_msg_t *msg, const char *key) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); uint32_t asl_msg_type(asl_msg_t *msg) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); uint32_t asl_msg_count(asl_msg_t *msg) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); char *asl_msg_to_string(asl_msg_t *in, uint32_t *len) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0); -char *asl_list_to_string(asl_search_result_t *, uint32_t *) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); -asl_search_result_t *asl_list_from_string(const char *buf) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); +asl_msg_t *asl_msg_from_string(const char *buf) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_7_0); char *asl_format_message(asl_msg_t *msg, const char *msg_fmt, const char *time_fmt, uint32_t text_encoding, uint32_t *outlen) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); asl_string_t *asl_msg_to_string_raw(uint32_t encoding, asl_msg_t *msg, const char *tfmt) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); +asl_string_t * asl_string_append_asl_msg(asl_string_t *str, asl_msg_t *msg) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +__END_DECLS #endif /* __ASL_MSG_H__ */ diff --git a/libsystem_asl.tproj/include/asl_msg_list.h b/libsystem_asl.tproj/include/asl_msg_list.h new file mode 100644 index 0000000..f0a7f07 --- /dev/null +++ b/libsystem_asl.tproj/include/asl_msg_list.h @@ -0,0 +1,75 @@ +/* + * 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, + * 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@ + */ + +#ifndef __ASL_MSG_LIST_H__ +#define __ASL_MSG_LIST_H__ + +#include +#include +#include +#include +#include + +typedef struct asl_msg_list_s +{ + uint32_t asl_type; //ASL OBJECT HEADER + int32_t refcount; //ASL OBJECT HEADER + uint32_t count; + uint32_t curr; + asl_msg_t **msg; +} asl_msg_list_t; + +__BEGIN_DECLS + +const asl_jump_table_t *asl_msg_list_jump_table(void); + +char *asl_msg_list_to_string(asl_msg_list_t *list, uint32_t *len) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +asl_string_t *asl_msg_list_to_asl_string(asl_msg_list_t *list, uint32_t encoding) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +asl_msg_list_t *asl_msg_list_from_string(const char *buf) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +asl_msg_list_t *asl_msg_list_new(void) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +asl_msg_list_t *asl_msg_list_retain(asl_msg_list_t *list) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +void asl_msg_list_release(asl_msg_list_t *list) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +asl_msg_list_t *asl_msg_list_new_count(uint32_t n) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +void asl_msg_list_insert(asl_msg_list_t *list, uint32_t x, void *obj) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +void asl_msg_list_append(asl_msg_list_t *list, void *obj) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +void asl_msg_list_prepend(asl_msg_list_t *list, void *obj) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +size_t asl_msg_list_count(asl_msg_list_t *list) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +asl_msg_t *asl_msg_list_get_index(asl_msg_list_t *list, size_t index) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +void asl_msg_list_remove_index(asl_msg_list_t *list, size_t index) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +asl_msg_t *asl_msg_list_next(asl_msg_list_t *list) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +asl_msg_t *asl_msg_list_prev(asl_msg_list_t *list) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +void asl_msg_list_reset_iteration(asl_msg_list_t *list, size_t position) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +asl_msg_list_t *asl_msg_list_search(asl_msg_list_t *list, asl_msg_t *query) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +asl_msg_list_t *asl_msg_list_match(asl_msg_list_t *list, 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); + +asl_msg_list_t *asl_msg_search(asl_msg_t *msg, asl_msg_t *query) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +uint32_t asl_msg_match(asl_msg_t *msg, asl_msg_list_t *querylist, asl_msg_list_t **res, size_t *last, size_t start, size_t count, int32_t direction) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +int asl_msg_cmp_list(asl_msg_t *msg, asl_msg_list_t *list) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); + +__END_DECLS + +#endif /* __ASL_MSG_LIST_H__ */ diff --git a/libsystem_asl.tproj/include/asl_object.h b/libsystem_asl.tproj/include/asl_object.h new file mode 100644 index 0000000..3e78284 --- /dev/null +++ b/libsystem_asl.tproj/include/asl_object.h @@ -0,0 +1,78 @@ +#ifndef __ASL_OBJECT_H__ +#define __ASL_OBJECT_H__ + +/* + * Copyright (c) 2007-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, + * 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 + +/* generic object pointer */ +typedef struct _asl_object_s +{ + uint32_t asl_type; //ASL OBJECT HEADER + int32_t refcount; //ASL OBJECT HEADER + char asl_data[]; +} asl_object_private_t; + +#define ASL_OBJECT_HEADER_SIZE 8 + +typedef struct asl_jump_table_s +{ + asl_object_private_t * (*alloc)(uint32_t type); + void (*dealloc)(asl_object_private_t *obj); + int (*set_key_val_op)(asl_object_private_t *obj, const char *key, const char *val, uint16_t op); + void (*unset_key)(asl_object_private_t *obj, const char *key); + int (*get_val_op_for_key)(asl_object_private_t *obj, const char *key, const char **val, uint16_t *op); + int (*get_key_val_op_at_index)(asl_object_private_t *obj, size_t n, const char **key, const char **val, uint16_t *op); + size_t (*count)(asl_object_private_t *obj); + asl_object_private_t *(*next)(asl_object_private_t *obj); + asl_object_private_t *(*prev)(asl_object_private_t *obj); + asl_object_private_t *(*get_object_at_index)(asl_object_private_t *obj, size_t n); + void (*set_iteration_index)(asl_object_private_t *obj, size_t n); + void (*remove_object_at_index)(asl_object_private_t *obj, size_t n); + void (*append)(asl_object_private_t *obj, asl_object_private_t *newobj); + void (*prepend)(asl_object_private_t *obj, asl_object_private_t *newobj); + asl_object_private_t *(*search)(asl_object_private_t *obj, asl_object_private_t *query); + asl_object_private_t *(*match)(asl_object_private_t *obj, asl_object_private_t *querylist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t dir); +} asl_jump_table_t; + +__BEGIN_DECLS + +int asl_object_set_key_val_op(asl_object_private_t *obj, const char *key, const char *val, uint16_t op); +void asl_object_unset_key(asl_object_private_t *obj, const char *key); +int asl_object_get_key_value_op(asl_object_private_t *obj, const char *key, const char **val, uint16_t *op); +size_t asl_object_count(asl_object_private_t *obj); +asl_object_private_t *asl_object_next(asl_object_private_t *obj); +asl_object_private_t *asl_object_prev(asl_object_private_t *obj); +asl_object_private_t *asl_object_get_object_at_index(asl_object_private_t *obj, size_t n); +void asl_object_set_iteration_index(asl_object_private_t *obj, size_t n); +void 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); +void asl_object_prepend(asl_object_private_t *obj, asl_object_private_t *newobj); +asl_object_private_t *asl_object_search(asl_object_private_t *obj, asl_object_private_t *query); +asl_object_private_t *asl_object_match(asl_object_private_t *obj, asl_object_private_t *querylist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t dir); + +__END_DECLS + +#endif /* __ASL_OBJECT_H__ */ diff --git a/libsystem_asl.tproj/include/asl_private.h b/libsystem_asl.tproj/include/asl_private.h index 6007ab0..dcac0a4 100644 --- a/libsystem_asl.tproj/include/asl_private.h +++ b/libsystem_asl.tproj/include/asl_private.h @@ -24,14 +24,19 @@ #ifndef __ASL_PRIVATE_H__ #define __ASL_PRIVATE_H__ +#include #include #include #include +#include #include #include -#include "asl_file.h" -#include "asl_msg.h" #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 @@ -44,58 +49,44 @@ #define ASL_OPT_IGNORE "ignore" #define ASL_OPT_STORE "store" +#define ASL_OPT_CONTROL "control" + +/* File and Store Open Option */ +#define ASL_OPT_OPEN_READ 0x80000000 #define ASL_STORE_LOCATION_FILE 0 #define ASL_STORE_LOCATION_MEMORY 1 #define ASL_OPT_SYSLOG_LEGACY 0x00010000 -#define ASL_KEY_SENDER_MACH_UUID "Sender_Mach_UUID" +#define ASL_KEY_FREE_NOTE "ASLFreeNotify" + +/* + * Private types + */ +#define ASL_TYPE_STRING 6 +#define ASL_TYPE_COUNT 7 /* SPI to enable ASL filter tunneling using asl_set_filter() */ #define ASL_FILTER_MASK_TUNNEL 0x100 -typedef struct -{ - int fd; - uint32_t encoding; - uint32_t filter; - char *mfmt; - char *tfmt; -} asl_out_file_t; - -typedef struct __aslclient -{ - uint32_t options; - struct sockaddr_un server; - int sock; - pid_t pid; - uid_t uid; - gid_t gid; - char *name; - char *facility; - uint32_t filter; - int notify_token; - int notify_master_token; - uint32_t out_count; - asl_out_file_t *out_list; - asl_file_t *aslfile; - uint64_t aslfileid; - uint32_t reserved1; - void *reserved2; - int32_t refcount; -} asl_client_t; +#define NOQUOTA_FILE_PATH "/etc/asl/.noquota" __BEGIN_DECLS -int asl_add_output(aslclient asl, int fd, const char *msg_fmt, const char *time_fmt, uint32_t text_encoding) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); -int asl_remove_output(aslclient asl, int fd) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); int asl_store_location() __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); -int asl_get_filter(aslclient asl, int *local, int *master, int *remote, int *active) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); char *asl_remote_notify_name() __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); -int asl_trigger_aslmanager(void) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); -aslmsg _asl_server_control_query(void) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +int asl_syslog_faciliy_name_to_num(const char *name) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); +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); + +/* EXCLUSIVLY FOR USE BY DEV TOOLS */ +/* DO NOT USE THIS INTERFACE OTHERWISE */ + +uint32_t asl_store_match_timeout(void *ignored, void *query_v1, void **result_v1, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, uint32_t usec) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); __END_DECLS + #endif /* __ASL_PRIVATE_H__ */ diff --git a/libsystem_asl.tproj/include/asl_store.h b/libsystem_asl.tproj/include/asl_store.h index 5905877..b266cb5 100644 --- a/libsystem_asl.tproj/include/asl_store.h +++ b/libsystem_asl.tproj/include/asl_store.h @@ -28,23 +28,21 @@ #include #include #include -#include "asl_file.h" +#include +#include #include +#include +#include #include -#if TARGET_IPHONE_SIMULATOR -extern const char *_path_asl_store(void); -extern const char *_path_asl_archive(void); - -#define PATH_ASL_STORE _path_asl_store() -#define PATH_ASL_ARCHIVE _path_asl_archive() -#else -#define PATH_ASL_STORE "/var/log/asl" -#define PATH_ASL_ARCHIVE "/var/log/asl.archive" -#endif +#define PATH_ASL_STORE (asl_filesystem_path(ASL_PLACE_DATABASE)) +#define PATH_ASL_ARCHIVE (asl_filesystem_path(ASL_PLACE_ARCHIVE)) #define FILE_ASL_STORE_DATA "StoreData" +#define ASL_STORE_FLAG_NO_ACLS 0x00000001 +#define ASL_STORE_FLAG_NO_TTL 0x00000002 + #define FILE_CACHE_SIZE 64 #define FILE_CACHE_TTL 300 @@ -58,8 +56,11 @@ typedef struct asl_file_t *f; } asl_cached_file_t; -typedef struct +typedef struct asl_store_s { + uint32_t asl_type; //ASL OBJECT HEADER + int32_t refcount; //ASL OBJECT HEADER + uint64_t curr; char *base_dir; FILE *storedata; uint64_t next_id; @@ -69,24 +70,34 @@ typedef struct time_t start_tomorrow; time_t last_write; size_t max_file_size; + uint32_t flags; } asl_store_t; +__BEGIN_DECLS + +const asl_jump_table_t *asl_store_jump_table(void); + uint32_t asl_store_open_write(const char *basedir, asl_store_t **s) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); uint32_t asl_store_open_read(const char *basedir, asl_store_t **s) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); uint32_t asl_store_close(asl_store_t *s) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); -uint32_t asl_store_statistics(asl_store_t *s, aslmsg *msg) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); +asl_store_t *asl_store_retain(asl_store_t *s) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +void asl_store_release(asl_store_t *s) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); +uint32_t asl_store_statistics(asl_store_t *s, asl_msg_t **msg) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); + +uint32_t asl_store_set_flags(asl_store_t *s, uint32_t flags) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); -uint32_t asl_store_save(asl_store_t *s, aslmsg msg) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); +uint32_t asl_store_save(asl_store_t *s, asl_msg_t *msg) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); -uint32_t asl_store_match(asl_store_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); -uint32_t asl_store_match_timeout(asl_store_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, uint32_t usec) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_3_2); +asl_msg_list_t *asl_store_match(asl_store_t *s, asl_msg_list_t *query, uint64_t *last, uint64_t start, uint32_t count, uint32_t duration, int32_t direction) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); uint32_t asl_store_match_start(asl_store_t *s, uint64_t start_id, int32_t direction) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); -uint32_t asl_store_match_next(asl_store_t *s, aslresponse query, aslresponse *res, uint32_t count) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); +uint32_t asl_store_match_next(asl_store_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint32_t count) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); uint32_t asl_store_max_file_size(asl_store_t *s, size_t max) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); uint32_t asl_store_sweep_file_cache(asl_store_t *s) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_3_2); -uint32_t asl_store_open_aux(asl_store_t *s, aslmsg msg, int *fd, char **url) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); +uint32_t asl_store_open_aux(asl_store_t *s, asl_msg_t *msg, int *fd, char **url) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); + +__END_DECLS #endif /* __ASL_STORE_H__ */ diff --git a/libsystem_asl.tproj/include/asl_string.h b/libsystem_asl.tproj/include/asl_string.h new file mode 100644 index 0000000..28da85a --- /dev/null +++ b/libsystem_asl.tproj/include/asl_string.h @@ -0,0 +1,57 @@ +#ifndef __ASL_STRING_H__ +#define __ASL_STRING_H__ + +/* + * Copyright (c) 2007-2013 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@ + */ + +#define ASL_ENCODE_MASK 0x0000000f +#define ASL_STRING_VM 0x80000000 +#define ASL_STRING_LEN 0x40000000 +#define ASL_STRING_MIG 0xc0000002 + +typedef struct +{ + uint32_t asl_type; //ASL OBJECT HEADER + int32_t refcount; //ASL OBJECT HEADER + uint32_t encoding; + size_t delta; + size_t bufsize; + size_t cursor; + char *buf; +} asl_string_t; + +asl_string_t *asl_string_new(uint32_t encoding) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); +asl_string_t *asl_string_retain(asl_string_t *str) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); +void asl_string_release(asl_string_t *str) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); +char *asl_string_release_return_bytes(asl_string_t *str) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); +char *asl_string_bytes(asl_string_t *str) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); +size_t asl_string_length(asl_string_t *str) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); +size_t asl_string_allocated_size(asl_string_t *str) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); +asl_string_t *asl_string_append(asl_string_t *str, const char *app) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); +asl_string_t *asl_string_append_asl_key(asl_string_t *str, const char *app) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); +asl_string_t *asl_string_append_op(asl_string_t *str, uint32_t op) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); +asl_string_t *asl_string_append_no_encoding(asl_string_t *str, const char *app) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); +asl_string_t *asl_string_append_char_no_encoding(asl_string_t *str, const char c) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); +asl_string_t *asl_string_append_xml_tag(asl_string_t *str, const char *tag, const char *s) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_1); + +#endif /* __ASL_STRING_H__ */ diff --git a/libsystem_asl.tproj/man/asl.3 b/libsystem_asl.tproj/man/asl.3 index ef93ed9..f2fdda0 100644 --- a/libsystem_asl.tproj/man/asl.3 +++ b/libsystem_asl.tproj/man/asl.3 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2005-2012 Apple Inc. +.\" Copyright (c) 2005-2013 Apple Inc. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -32,19 +32,36 @@ .Sh NAME .Nm asl_add_log_file , .Nm asl_add_outout_file , +.Nm asl_append , .Nm asl_close , .Nm asl_close_auxiliary_file , +.Nm asl_count , .Nm asl_create_auxiliary_file , +.Nm asl_decode_buffer , +.Nm asl_encode_buffer , +.Nm asl_fetch_key_val_op , +.Nm asl_format , .Nm asl_free , .Nm asl_get , +.Nm asl_get_index , +.Nm asl_get_type , .Nm asl_key , .Nm asl_log , .Nm asl_log_auxiliary_location , .Nm asl_log_descriptor , +.Nm asl_match , .Nm asl_new , +.Nm asl_next , .Nm asl_open , .Nm asl_open_from_file , +.Nm asl_open_path , +.Nm asl_prepend , +.Nm asl_prev , +.Nm asl_release , +.Nm asl_remove_index , .Nm asl_remove_log_file , +.Nm asl_reset_iteration , +.Nm asl_retain , .Nm asl_search , .Nm asl_send , .Nm asl_set , @@ -61,12 +78,12 @@ .\" .Ft int .Fo asl_add_log_file -.Fa "aslclient asl" +.Fa "asl_object_t client" .Fa "int descriptor" .Fc .Ft int .Fo asl_add_output_file -.Fa "aslclient asl" +.Fa "asl_object_t client" .Fa "int descriptor" .Fa "const char *msg_fmt" .Fa "const char *time_fmt" @@ -74,149 +91,411 @@ .Fa "int text_encoding" .Fc .Ft void -.Fo asl_close -.Fa "aslclient asl" +.Fo asl_append +.Fa "asl_object_t obj" +.Fa "asl_object_t msg" .Fc +.Pp .Ft void +.Fo asl_close +.Fa "asl_object_t obj" +.Fc +.Ft int .Fo asl_close_auxiliary_file .Fa "int descriptor" .Fc -.Ft void +.Ft size_t +.Fo asl_count +.Fa "asl_object_t obj" +.Fc +.Ft int .Fo asl_create_auxiliary_file -.Fa "aslmsg msg" +.Fa "asl_object_t msg" .Fa "const char *title" .Fa "const char *uti" .Fa "int *out_descriptor" .Fc -.Ft void +.Ft int +.Fo asl_decode_buffer +.Fa "const char *in" +.Fa "char **buf" +.Fa "size_t *len" +.Fc +.Ft char * +.Fo asl_encode_buffer +.Fa "const char *in" +.Fa "size_t len" +.Fc +.Ft int +.Fo asl_fetch_key_val_op +.Fa "asl_object_t msg" +.Fa "uint32_t n" +.Fa "const char **key" +.Fa "const char **val" +.Fa "uint32_t *op" +.Fc +.Ft char * +.Fo asl_format +.Fa "asl_object_t msg" +.Fa "const char *msg_fmt" +.Fa "const char *time_fmt" +.Fa "uint32_t text_encoding" +.Fc +.Ft [DEPRECATED] void .Fo asl_free -.Fa "aslmsg msg" +.Fa "asl_object_t obj" .Fc .Ft const char * .Fo asl_get -.Fa "aslmsg msg" +.Fa "asl_object_t msg" .Fa "const char *key" .Fc +.Ft asl_object_t +.Fo asl_get_index +.Fa "asl_object_t list" +.Fa "size_t index" +.Fc +.Ft uint32_t +.Fo asl_get_type +.Fa "asl_object_t obj" +.Fc .Ft const char * .Fo asl_key -.Fa "aslmsg msg" +.Fa "asl_object_t msg" .Fa "uint32_t n" .Fc .Ft int .Fo asl_log -.Fa "aslclient asl" -.Fa "aslmsg msg" +.Fa "asl_object_t obj" +.Fa "asl_object_t msg" .Fa "int level" .Fa "const char *format" .Fa "..." .Fc -.Ft void +.Ft int .Fo asl_log_auxiliary_location -.Fa "aslmsg msg" +.Fa "asl_object_t msg" .Fa "const char *title" .Fa "const char *uti" .Fa "const char *url" .Fc .Ft int .Fo asl_log_descriptor -.Fa "aslclient asl" -.Fa "aslmsg msg" +.Fa "asl_object_t client" +.Fa "asl_object_t msg" .Fa "int level" .Fa "int descriptor" .Fa "uint32_t fd_type" .Fc -.Ft aslmsg +.Ft int +.Fo asl_log_message +.Fa "int level" +.Fa "const char *format" +.Fa "..." +.Fc +.Ft asl_object_t +.Fo asl_match +.Fa "asl_object_t obj" +.Fa "asl_object_t querylist" +.Fa "size_t *last" +.Fa "size_t start" +.Fa "size_t count" +.Fa "uint32_t duration" +.Fa "int32_t direction" +.Fc +.Ft asl_object_t .Fo asl_new .Fa "uint32_t type" .Fc -.Ft aslclient +.Ft asl_object_t +.Fo asl_next +.Fa "asl_object_t obj" +.Fc +.Ft asl_object_t .Fo asl_open .Fa "const char *ident" .Fa "const char *facility" .Fa "uint32_t opts" .Fc -.Ft aslclient +.Ft asl_object_t .Fo asl_open_from_file .Fa "int descriptor" .Fa "const char *ident" .Fa "const char *facility" .Fc +.Ft asl_object_t +.Fo asl_open_path +.Fa "const char *path" +.Fa "uint32_t opts" +.Fc +.Ft void +.Fo asl_prepend +.Fa "asl_object_t obj" +.Fa "asl_object_t msg" +.Fc +.Ft asl_object_t +.Fo asl_prev +.Fa "asl_object_t obj" +.Fc +.Ft void +.Fo asl_release +.Fa "asl_object_t obj" +.Fc +.Ft void +.Fo asl_remove_index +.Fa "asl_object_t list" +.Fa "size_t index" +.Fc .Ft int .Fo asl_remove_log_file -.Fa "aslclient asl" +.Fa "asl_object_t asl" .Fa "int descriptor" .Fc -.Ft aslresponse +.Ft void +.Fo asl_reset_iteration +.Fa "asl_object_t obj" +.Fa "size_t position" +.Fc +.Ft asl_object_t +.Fo asl_retain +.Fa "asl_object_t obj" +.Fc +.Ft asl_object_t .Fo asl_search -.Fa "aslclient asl" -.Fa "aslmsg msg" +.Fa "asl_object_t obj" +.Fa "asl_object_t query" .Fc .Ft int .Fo asl_send -.Fa "aslclient asl" -.Fa "aslmsg msg" +.Fa "asl_object_t obj" +.Fa "asl_object_t msg" .Fc .Ft int .Fo asl_set -.Fa "aslmsg msg" +.Fa "asl_object_t msg" .Fa "const char *key" .Fa "const char *value" .Fc .Ft int .Fo asl_set_filter -.Fa "aslclient asl" +.Fa "asl_object_t asl" .Fa "int filter" .Fc .Ft int .Fo asl_set_output_file_filter -.Fa "aslclient asl" +.Fa "asl_object_t asl" .Fa "int descriptor" .Fa "int filter" .Fc .Ft int .Fo asl_set_query -.Fa "aslmsg msg" +.Fa "asl_object_t msg" .Fa "const char *key" .Fa "const char *value" .Fa "uint32_t op" .Fc .Ft int .Fo asl_unset -.Fa "aslmsg msg" +.Fa "asl_object_t msg" .Fa "const char *key" .Fc .Ft int .Fo asl_vlog -.Fa "aslclient asl" -.Fa "aslmsg msg" +.Fa "asl_object_t obj" +.Fa "asl_object_t msg" .Fa "int level" .Fa "const char *format" .Fa "va_list ap" .Fc -.Ft void +.Ft [DEPRECATED] void .Fo aslresponse_free -.Fa "aslresponse r" +.Fa "asl_object_t obj" .Fc -.Ft aslmsg +.Ft [DEPRECATED] asl_object_t .Fo aslresponse_next -.Fa "aslresponse r" +.Fa "asl_object_t obj" .Fc .Sh DESCRIPTION -These routines provide an interface to the Apple System Log facility. -They are intended to be a replacement for the -.Xr syslog 3 -API, which will continue to be supported for backwards compatibility. -The new API allows client applications -to create flexible, structured messages and send them to the +These routines provide an interface to the Apple System Log facility and to various +data bearing memory objects, files, and storage directories. +.Pp +The API allows client applications to create and manipulate +flexible, structured messages, send them to the .Nm syslogd server, where they may undergo additional processing. Messages received by the server are saved in a data store (subject to input filtering constraints). +.Pp +Log messages may also be written directly to the filesystem from the ASL library. +This output may go to plain text files, to ASL-format data files, or to ASL databases. +.Pp This API permits clients to create queries -and search the message data store for matching messages. +and search the system ASL database, ASL-format files, or other ASL databases for matching messages. +.Pp +Clients that simply need to send messages to the ASL server may do so using +.Fn asl_log_message . +Other routines allow for more complex logging tasks. .Pp An introduction to the concepts underlying this interface follows the interface summary below. .Ss INTERFACE SUMMARY +.Fo asl_log_message +.Fa level +.Fa format +.Fa "..." +.Fc +sends a message to the ASL server +.Nm syslogd . +.Fa level +is an integer between 7 (ASL_LEVEL_DEBUG) and 0 (ASL_LEVEL_EMERG), +indicating the priority of the message. +Note that message priority levels are used as the basis of filtering +messages in several places in the ASL system. +In general, messages with level ASL_LEVEL_DEBUG and ASL_LEVEL_INFO are often excluded from long-term storage, +or have shorter time-to-live durations. +.Pp +.Fa format +is a printf-like format string. +In addition to the conversion specifications supported by +.Nm printf , +.Fn asl_log_message +supports the +.Dq %m +conversion, which is converted to the current error string returned by the +.Nm strerror +function for the current value of +.Fa errno . +.Pp +.Fn asl_log_message +is a simplified version of the +.Fn asl_log +interface. +It uses the default (NULL) ASL client handle. +This interface is thread-safe, although callers will contend for a mutex lock when using this routine. +Applications that log from multiple threads or dispatch queues may experience undesired performance +characteristics when using this routine. +The use of +.Fn asl_open +and +.Fn asl_log , +.Fn asl_vlog , +or +.Fn asl_send +is advised for applications that log from multiple threads. +.Pp +.Fo asl_log +.Fa obj +.Fa msg +.Fa level +.Fa format +.Fa "..." +.Fc +prepares a message, normally to be sent to the ASL server +.Nm syslogd . +The first parameter, +.Fa obj , +may be an asl_object_t of any type. +It is typically of type ASL_TYPE_CLIENT. +In this case the settings and options associated with the ASL client handle +.Fa obj +are used when preparing the message. +The client may direct the ASL library to +print copies of the message to various output files as well as sending it to the ASL server. +Filter settings in the client may further direct the library in selecting where the message +will be sent, and may in fact prevent the message from being sent to the ASL server at all. +ASL client handles are created using +.Fn asl_open +and are described extensively below. +.Pp +ASL message are dictionaries. +The +.Fn asl_log +routine combines information carried in the ASL client handle +.Fa client +and the ASL message dictionary +.Fa msg , +together with the +.Fa format +string and the associated arguments to construct a final message to be sent +to the ASL server and/or to be written to output files. +In general, the ASL client handle will provide the values for the +ASL_KEY_SENDER and ASL_KEY_FACILITY keys. +If +.Fa msg +is non-NULL, it may override the values for ASL_KEY_SENDER and ASL_KEY_FACILITY, +and it may supply additional key/value pairs. +The +.Fa format +string and it's associated arguments are used to construct a string value for the +ASL_KEY_MSG key in the final log message dictionary. +.Pp +If the +.Fa obj +parameter is of a type other than ASL_TYPE_CLIENT, then +.Fn asl_log +creates a message as if it were to be sent to +.Nm syslogd , +but rather than sending the message, it stores the message in the +.Fa obj +provided. +If +.Fa obj +is of type ASL_TYPE_FILE or ASL_TYPE_STORE that has been opened for writing, +then the message is saved to the file or ASL data store. +If +.Fa obj +is of type ASL_TYPE_LIST, then the message is appended to the list. +If +.Fa obj +is of type ASL_TYPE_MSG, then the message key/value pairs constructed by +.Fn asl_log +are merged with +.Fa obj . +In a merge operation, existing keys and values in +.Fa obj +are preserved. +New values in the +.Fn asl_log +message are attached. +Although this routine works for type ASL_TYPE_QUERY, +new key/value pairs are attached with an operation value of zero. +.Pp +The ASL_PREFILTER_LOG(obj, msg, level, format, ...) macro may be used in +place of +.Fn asl_log +when +.Fa obj +is of type ASL_TYPE_CLIENT. +The macro avoids processing the variable argument list in those cases where +the message would be filtered out due to filter settings, would not be +written to a log file associated with the asl_object_t, or would not be +written to stderr. +The macro may provide a performance benefit for some applications. +Details on filter setting, additional log files, and asl_object_t options +are described below in this manual. +.Pp +.Fo asl_vlog +.Fa obj +.Fa msg +.Fa level +.Fa format +.Fa ap +.Fc +is similar to +.Fn asl_log +except that it takes a va_list argument. +.Pp +.Fo asl_send +.Fa obj +.Fa msg +.Fc +is similar to +.Fn asl_log , +except the value for ASL_KEY_MESSAGE is taken from +.Ar msg +rather than being constructed using a +.Fn printf +style syntax. +.Pp .Fo asl_open .Fa ident .Fa facility @@ -228,6 +507,17 @@ Messages sent using this handle will default to having the string as the value associated with the ASL_KEY_SENDER key, and the value .Ar facility associated with the ASL_KEY_FACILITY key. +If +.Ar ident +is NULL, the library uses the sending process name. +If +.Ar facility +is NULL, the library will use the +.Dq user +facility for processes with non-zero UID, and +.Dq daemon +for processes with zero UID. +.Pp Several options are available, as described in the .Sx CLIENT HANDLES section. @@ -242,27 +532,82 @@ strings and the options from the parameter. Client handles also contain various filter, file descriptor, and control data. .Pp -The state information in a client handle is not protected by any locking or thread synchronization mechanism. +The state information in a client handle is not protected by locking or thread synchronization mechanisms, +except for one special case where NULL is used as a client handle. +That special case is described below. +.Pp It is not safe for two or more threads to use a single client handle simultaneously. -Multi-threaded applications should generally create one client handle for each thread that logs messages. +Multi-threaded applications should generally create one client handle for each thread +or serial dispatch queue that logs messages. A client handle may only be safely shared amongst multiple threads if the application uses locks or some synchronization strategy to ensure single-threaded access. .Pp As a special case, the ASL library allows the use of NULL in place of a client handle. In this case, the library uses an internal structure which contains its own lock. -Multiple threads may safely use NULL, although there may be contention for the lock. +Multiple threads may safely use NULL in place of an ASL client handle, +although there may be contention for the lock. .Pp Applications that use libdispatch may use NULL in place of a client handle, although this may cause undesirable synchronization behavior and degraded performance because of lock contention. A better design is often to use one or more serial dispatch queues specifically for logging. Each such serial queue should use a separate client handle. .Pp +.Fo asl_open_path +.Fa path +.Fa opts +.Fc +opens an ASL data store or ASL data file for read or write access. +Returns an object of type ASL_TYPE_STORE or ASL_TYPE_FILE, +depending on the input parameters. +By default, the ASL store or file is opened for reading. +The routine checks the filesystem type of +.Fa path , +and returns an object of type ASL_TYPE_STORE for an ASL data store (a directory in the filesystem) +or an object of type ASL_TYPE_FILE for an ASL data file. +If +.Fa path +is NULL, the system's ASL database (/var/log/asl) is opened. +.Pp +If the ASL_OPT_OPEN_WRITE option is specified, an existing file or database is +opened for writing. +New messages may be added to the file or database using +.Fn asl_log , +.Fn asl_vlog , +.Fn asl_send , +or +.Fn asl_append . +Existing messages in the store or file may not be deleted or modified. +.Pp +If the path does not exist in the filesystem, +.Fn asl_open_path +will create a new data store if ASL_OPT_CREATE_STORE is set in the options, +The file will be created with the user's effective UID and GID as owner and group. +The mode will be 0644. +If a different mode, UID, or GID is desired, an empty file or directory may be +pre-created with the desired settings. +.Pp .Fo asl_close .Fa asl .Fc closes the client handle .Ar asl and releases its associated resources. +.Fn asl_release +may also be used to close a client handle. +.Pp +.Fo asl_set_filter +.Fa asl +.Fa f +.Fc +sets a filter for messages being sent to the server. +The filter is a bitmask representing priority levels. +Only messages having a priority level with a corresponding bit set in the filter mask are sent to the +.Nm syslogd +server. +The filter does not control writes to additional files associated with the client handle using +.Fn asl_add_output_file . +.Fn asl_set_filter +returns the previous filter value. .Pp .Fo asl_add_output_file .Fa asl @@ -343,9 +688,7 @@ The message is formatted as an XML dictionary: .Pp A NULL value for .Ar msg_fmt -causes the library to use the -.Dq std -format. +causes the library to use the ASL_MSG_FMT_STD format. .Pp Custom format strings may contain a mix of characters that are directly copied to the output line and variables, which are a dollar sign @@ -387,6 +730,11 @@ Formats a Level value as a string, for example .Dq Warning , and so on. Note that $(Level) or $Level formats the value as an integer 0 through 7. +.It $((Level)(char)) +Formats a Level value as a single character from the set +.Dq PACEWNID , +for levels 0 through 7. +These are abbreviations for Panic, Alert, Critical, Error, Warning, Notice, Info, and Debug. .It $((Time)(sec)) Formats a Time value as the number of seconds since the Epoch. .It $((Time)(raw)) @@ -505,7 +853,7 @@ where NN is the character's hexadecimal value. Values that do not contain legal UTF8 are encoded in base-64 and printed as data objects. .El .Pp -.Nm asl_add_output_file +.Fn asl_add_output_file Returns 0 on success, non-zero on failure. .Pp .Pp @@ -534,25 +882,66 @@ Returns the previous filter value. removes a file descriptor from the set of file descriptors associated with a client handle. Returns 0 on success, non-zero on failure. .Pp +.Fo asl_format +.Fa msg +.Fa msg_fmt +.Fa time_fmt +.Fa text_encoding +.Fc +formats the +.Fa msg +object using the message format string, time format string, and text encoding specified. +Message formatting is described above for the +.Fn asl_add_output_file +routine. +The caller must free the returned character string. +.Pp .Fo asl_new .Fa type .Fc -allocates and returns an aslmsg structure, or NULL in the case of a failure in the library. +allocates and returns an asl_object_t structure, or NULL in the case of a failure in the library. The .Ar type -argument must be ASL_TYPE_MSG or ASL_TYPE_QUERY. +argument should be ASL_TYPE_MSG, ASL_TYPE_QUERY, or ASL_TYPE_LIST. +.Pp +.Fo asl_get_type +.Fa obj +.Fc +Returns the type of the object +.Fa obj , +or ASL_TYPE_UNDEF if the object is not a recognized type. +.Pp +.Fo asl_retain +.Fa obj +.Fc +Increments an internal reference count for +.Fa obj . +ASL objects are created with a reference count of 1. +Objects returned by ASL routines should be retained if they are used outside +of the immediate scope of the call that returned them. +.Pp +.Fo asl_release +.Fa obj +.Fc +Decrements the internal reference count for +.Fa obj . +It frees the object and its associated resources when the reference count becomes zero. .Pp +.Em DEPRECATED .Fo asl_free -.Fa msg +.Fa obj .Fc -frees an aslmsg and releases resources associated with the structure. +This interface is deprecated in favor of +.Fn asl_release . +It is implemented as a call to +.Fn asl_release . .Pp .Fo asl_set .Fa msg .Fa key .Fa value .Fc -creates a new key and value in an aslmsg structure, or replaces the value of an existing key. +creates a new key and value in an asl_object_t structure, or replaces the value of an existing key. Returns 0 on success, non-zero on failure. .Pp .Fo asl_set_query @@ -567,7 +956,7 @@ It is similar to except that it takes an additional .Ar op (operation) argument. -Creates a new (key, op, value) triple in an aslmsg structure, +Creates a new (key, op, value) triple in an asl_object_t structure, or replaces the value and operation for an existing key. See the .Sx SEARCHING @@ -578,14 +967,14 @@ Returns 0 on success, non-zero on failure. .Fa msg .Fa key .Fc -removes a key and its associated value from an aslmsg structure. +removes a key and its associated value from an asl_object_t structure. Returns 0 on success, non-zero on failure. .Pp .Fo asl_key .Fa msg .Fa n .Fc -returns the nth key in an aslmsg (beginning at zero), +returns the nth key in an asl_object_t (beginning at zero), allowing an application to iterate through the keys. Returns NULL if .Ar n @@ -598,88 +987,179 @@ indexes beyond the number of keys in .Fc returns the value associated with .Ar key -in the aslmsg +in the asl_object_t .Ar msg . Returns NULL if .Ar msg does not contain . Ar key . .Pp -.Fo asl_set_filter -.Fa asl -.Fa f +.Fo asl_fetch_key_val_op +.Fa msg +.Fa n +.Fa key +.Fa val +.Fa op .Fc -sets a filter for messages being sent to the server. -The filter is a bitmask representing priority levels. -Only messages having a priority level with a corresponding bit set in the filter mask are sent to the -.Nm syslogd -server. -The filter does not control writes to additional files associated with the client handle using -.Fn asl_add_log_file . -Returns the previous filter value. +Returns, in the +.Fa key , +.Fa val , +and +.Fa op +output parameters, the key, value, and operation (for ASL_TYPE_QUERY) at index +.Fa n +in the given object +.Fa msg . +The input +.Fa msg +should be of type ASL_TYPE_MSG or ASL_TYPE_QUERY. +Returns 0 on success, or non-zero otherwise. +Any of the output parameters may be NULL, in which case that parameter value will not +be returned. .Pp -.Fo asl_log -.Fa asl +.Fo asl_count +.Fa obj +.Fc +returns a count of the number of elements contained in +.Fa obj . +For objects of type ASL_TYPE_MSG or ASL_TYPE_QUERY, +this is the number of dictionary keys. +For ASL_TYPE_LIST, it is the number of items in the list. +For ASL_TYPE_FILE, returns the number of messages contained in the file. +Returns zero for ASL_TYPE_STORE and ASL_TYPE_CLIENT. +.Pp +.Fo asl_append +.Fa obj .Fa msg -.Fa level -.Fa format -.Fa args... .Fc -sends a log to the server (subject to filtering, see -.Fn asl_set_filter -above) and to any file descriptors associated with the client handle -.Ar asl . -The -.Ar msg -argument may contain any keys and values, which will be formatted as part of the log message. -The value for ASL_KEY_LEVEL is supplied by the -.Ar level -argument. -The value for ASL_KEY_MESSAGE is computed from -.Ar format -and the associated arguments -.Ar args... . -Normal -.Fn printf -style argument processing is applied to the format and the arguments. -The format may also contain -.Dq %m -which will be substituted with the string value corresponding to the current -.Em errno . +appends the +.Fa msg +object, which is typically of type ASL_TYPE_MSG or ASL_TYPE_QUERY, to the target +.Fa obj . +The target +.Fa obj +is typically a type that contains a collection of messages, +i.e. ASL_TYPE_LIST, ASL_TYPE_FILE, ASL_TYPE_STORE, or ASL_TYPE_CLIENT +(where the collection is the system ASL database). +.Fn asl_append +appends the +.Fa msg +object to the end of the target +.Fa obj . .Pp -The ASL_PREFILTER_LOG(asl, msg, level, format, ...) macro may be used in -place of -.Fn asl_log . -The macro avoids processing the variable argument list in those cases where -the message would be filtered out due to filter settings, would not be -written to a log file associated with the aslclient, or would not be -written to stderr. -The macro may provide a performance benefit for some applications. -Details on filter setting, additional log files, and aslclient options -are described below in this manual. +If +.Fa msg +is of type ASL_TYPE_LIST and +.Fa obj +is of type ASL_TYPE_LIST, ASL_TYPE_FILE, ASL_TYPE_STORE, or ASL_TYPE_CLIENT, +the each message in the +.Fa msg +list is appended in sequence to the the target +.Fa obj . .Pp -.Fo asl_vlog -.Fa asl +If both +.Fa msg +and +.Fa obj +are of type ASL_TYPE_MSG or ASL_TYPE_QUERY, then the message dictionary from +.Fa msg +is merged with +.Fa obj . +Existing keys in +.Fa obj +are preserved. +For keys that are in +.Fa msg +that are not in +.Fa obj , +the key and its value and operation are added to +.Fa obj . +.Pp +.Fo asl_prepend +.Fa obj .Fa msg -.Fa level -.Fa format -.Fa ap .Fc is similar to -.Fn asl_log -except that it takes a va_list argument. -.Pp -.Fo asl_send -.Fa asl +.Fn asl_append , +except that the +.Fa msg +object is prepended to the target +.Fa obj. +In the case where both parameters are of type ASL_TYPE_MSG or ASL_TYPE_QUERY, +all keys from .Fa msg +are copied to +.Fa obj . +Existing keys are not preserved. +.Pp +.Fo asl_next +.Fa obj +.Fc +returns the next item in the target +.Fa obj , +which may be of type ASL_TYPE_LIST, ASL_TYPE_FILE, ASL_TYPE_STORE, or of type ASL_TYPE_CLIENT +in which case the routine fetches messages consecutively from the system ASL database. +Returned objects are of type ASL_TYPE_MSG, or of type ASL_TYPE_QUERY if the target object is a +list containing query objects. +Returns NULL when there are no more objects to return from the target. +.Pp +.Fo asl_prev +.Fa obj .Fc is similar to -.Fn asl_log , -except the value for ASL_KEY_MESSAGE is taken from -.Ar msg -rather than being constructed using a -.Fn printf -style syntax. +.Fn asl_next , +except that it returns objects in reverse order. +Objects that contain messages have an internal index for the +.Dq current +item. +.Fn asl_next +and +.Fn asl_prev +simply return the current item and move the index forward or backward. +The index position can be set using +.Fn asl_reset_iteration . +.Pp +.Fo asl_reset_iteration +.Fa obj +.Fa position +.Fc +sets the current position index used be +.Fn asl_next +and +.Fn asl_prev . +The value of +.Fa position +may be zero to set the position index for +.Fa obj +at the beginning of its contents, +or it may be SIZE_MAX to set the position index for +.Fa obj +at the end of its contents. +For objects of type ASL_TYPE_LIST, the position index is an actual index into the list. +For other message containing objects, the index is an ID number which may not be sequential. +.Pp +.Fo asl_get_index +.Fa list +.Fa index +.Fc +returns the object at position +.Fa index +in the target +.Fa list +object, which must be of type ASL_TYPE_LIST. +Returns NULL if the index is out of range or if +.Fa list +is not a list type. +.Pp +.Fo asl_remove_index +.Fa list +.Fa index +.Fc +removes the object at position +.Fa index +from the target +.Fa list +object, which must be of type ASL_TYPE_LIST. .Pp .Fo asl_log_descriptor .Fa asl @@ -694,8 +1174,8 @@ is retained by ASL and must still be closed by the caller by calling .Fn asl_close if the caller loses reference to it. .Ar msg -is copied by ASL and similarly must still be freed by the caller by calling -.Fn asl_free +is copied by ASL and similarly must still be releaser by the caller by calling +.Fn asl_release if the caller loses reference to it. Any changes made to it after calling .Fn asl_log_descriptor() are not applicable to the message used. @@ -726,36 +1206,128 @@ to stdout or stderr to ASL by passing STDOUT_FILENO or STDERR_FILENO as .Ar descriptor . .Pp .Fo asl_search -.Fa asl -.Fa msg +.Fa obj +.Fa query .Fc -searches for messages that match the keys and values in -.Ar msg , +searches messages in the +.Fa obj +object for messages that match the keys and values in +.Fa query , subject to matching operations associated with those keys and values. +The return returns an object of type ASL_TYPE_LIST containing matching messages, +or NULL if no matches are found. The -.Ar msg +.Ar query argument should be constructed using .Fn asl_set_query . See the .Sx SEARCHING section for details on constructing queries. -Returns an aslresponse structure that contains matching log messages. -NULL is returned in case of error or if there are no matching messages in the ASL database. .Pp +The +.Fa obj +parameter may be any ASL object. +For type ASL_TYPE_CLIENT, the main ASL system database is searched. +If the object type is ASL_TYPE_STORE or ASL_TYPE_FILE, +then the corresponding data store or data file is searched. +For ASL_TYPE_LIST, matches are found in a message list. +If +.Fa obj +is of type ASL_TYPE_MSG and query is of type ASL_TYPE_QUERY, +.Fa obj +is matched against the query, +and a list containing +.Fa obj +is returned if the match succeeds. +If both +.Fa obj +and +.Fa query +are objects of type ASL_TYPE_MSG or both are of type ASL_TYPE_QUERY, +they are tested for exact match. +A list containing +.Fa obj +is returned if the match is exact. +If +.Fa obj +is of type ASL_TYPE_QUERY and +.Fa query +is of type ASL_TYPE_MSG, the routine returns NULL. +.Pp +.Fo asl_match +.Fa obj +.Fa querylist +.Fa last +.Fa start +.Fa count +.Fa duration +.Fa direction +.Fc +is similar to +.Fn asl_search , +but allows more advanced searching of ASL objects. +The +.Fa obj +parameter may be of any type, as with +.Fn asl_search . +The +.Fa querylist +parameter must be an object of type ASL_TYPE_LIST, +containing zero or more objects of type ASL_TYPE_QUERY. +A NULL +.Fa querylist +or a list containing zero objects matches all messages in the target +.Fa obj. +.Pp +The caller may provide a starting ASL message ID, a direction, and a count. +A +.Fa start +ID value of 0 means that matching should commence at the beginning of the target +.Fa obj . +A value of SIZE_MAX indicates that matching should commence at the end (most recent message) +in the target. +If a non-zero +.Fa count +value is supplied, the routine will return when it has found that many messages, +or it has checked all messages. +If a non-zero +.Fa duration +is supplied, the routine will return after the specified time (in microseconds). +If both +.Fa count +and +.Fa duration +are non-zero, the routine will return when the desired number of items has been matched +or when the specified duration has been exceeded, whichever occurs first. +The search direction may be ASL_MATCH_DIRECTION_FORWARD or ASL_MATCH_DIRECTION_REVERSE. +The routine sets the value of the out parameter +.Fa last +to be an index of the last message checked while matching. +To fetch matching messages in batches (using a small count or duration value), the +.Fa start +value for each iteration should be set to +.Fa last ++ 1 if searching forward, or +.Fa last +- 1 for reverse search. +.Pp +.Em DEPRECATED .Fo aslresponse_next .Fa r .Fc -iterates over an aslresponse structure returned by -.Fn asl_search . -Each call returns the next aslmsg in the response. -Returns NULL when there are no further messages. +This interface is deprecated in favor of +.Fn asl_next . +It is implemented as a call to +.Fn asl_next . .Pp +.Em DEPRECATED .Fo aslresponse_free .Fa r .Fc -frees the aslresponse structure -.Ar r -and all of its associated resources. +This interface is deprecated in favor of +.Fn asl_release . +It is implemented as a call to +.Fn asl_release . .Pp .Fo asl_create_auxiliary_file .Fa msg @@ -818,8 +1390,7 @@ The .Nm Console application will display the message with a link to the file. This allows a client to save data in an auxiliary file, but unlike -.Fo asl_create_auxiliary_file -.Fc , +.Fn asl_create_auxiliary_file , the life-cycle of this file must be managed by some external system. The file will not be removed when the corresponding log message expired from the ASL data store. .Pp @@ -831,11 +1402,9 @@ The file will not be removed when the corresponding log message expired from the creates a client handle for an open file descriptor .Fa descriptor . This routine may be used in conjunction with -.Fo asl_create_auxiliary_file -.Fc +.Fn asl_create_auxiliary_file or -.Fo asl_log_auxiliary_location -.Fc +.Fn asl_log_auxiliary_location to save ASL format log messages in an auxiliary file. The UTI type .Dq com.apple.asl-file @@ -872,8 +1441,53 @@ Note that messages with ReadUID or ReadGID values will simply be saved to the fi and will not effect read access to either the message or the file itself. Similarly, messages with ASLExpireTime values will be saved, but will not effect the life-cycle of either the individual messages or the file. +.Pp +.Fo asl_encode_buffer +.Fa in +.Fa len +.Fc +is a utility routine for encoding arbitrary data buffers. +ASL message dictionary keys and values are nul-terminated C strings. +If an application wishes to include arbitrary data which may contain zero bytes, +the data buffer must first be encoded in a manner that eliminates any embedded zeros. +The +.Fn asl_encode_buffer +routine will encode an arbitrary data buffer at the address +.Fa in +containing +.Fa len +bytes (octets) of data. +The output of the routine is a nul-terminated C string. +The encoded string may be decoded using the companion +.Fn asl_decode_buffer +routine. +.Pp +This utility is used by the ASL server +.Nm syslogd +to encode the value associated with ASL_KEY_AUX_DATA in an ASL_TYPE_MSG object. +An ASL_KEY_AUX_DATA key/value pair is used to hold the data written to a file descriptor +created by +.Fn asl_create_auxiliary_file +on iOS systems, where the ASL database is stored in memory. +.Pp +.Fo asl_decode_buffer +.Fa in +.Fa buf +.Fa len +.Fc +decodes a C string previously created by +.Fn asl_encode_buffer +back into a buffer, possibly containing embedded zero bytes (octets). +The routine allocates memory for the buffer and returns a pointer in an output +.Fa buf +parameter. +The caller is responsible for freeing the buffer. +.Pp +This routine should be used to decode the value associated with an +ASL_KEY_AUX_DATA key in an ASL_TYPE_MSG object. +.Pp .Ss MESSAGES -At the core of this API is the aslmsg structure. +At the core of this API is the asl_object_t structure. Although the structure is opaque and may not be directly manipulated, it contains a list of key/value pairs. All keys and values are NUL-character terminated C language strings. @@ -882,7 +1496,7 @@ UTF-8 encoding may be used for non-ASCII characters. Message structures are generally used to send log messages, and are created thusly: .Pp - aslmsg m = asl_new(ASL_TYPE_MSG); + asl_object_t m = asl_new(ASL_TYPE_MSG); .Pp Another message type, ASL_TYPE_QUERY, is used to create queries when searching the data store. @@ -892,7 +1506,7 @@ section. For the remainder of this section, the messages described will be of the ASL_TYPE_MSG variety. .Pp -Each aslmsg contains a default set of keys +Each asl_object_t contains a default set of keys and values that are associated with them. These keys are listed in the asl.h header file. They are: @@ -932,7 +1546,7 @@ server will use a default value of .Dq user if a facility is not set. However, a client may set a facility name as an argument in the -.Nm asl_open +.Fn asl_open call, or by setting a specific value for the ASL_KEY_FACILITY in a message: .Pp asl_set(m, ASL_KEY_FACILITY, "com.somename.greatservice"); @@ -946,48 +1560,27 @@ naming convention to avoid conflicting facility names. Default values are set in the message for each of the keys listed above, except for ASL_KEY_MSG, which may be explicitly set at any time using the -.Nm asl_set +.Fn asl_set routine, or implicitly set at the time the message is sent using the -.Nm asl_log +.Fn asl_log_message , +.Fn asl_log , or -.Nm asl_vlog +.Fn asl_vlog routines. -These two routines also have an integer-level parameter +These three routines also have an integer-level parameter for specifying the log priority. The ASL_KEY_LEVEL value is set accordingly. Finally, the value associated with ASL_KEY_TIME is set in the sending routine. .Pp -Although it may appear that there is significant overhead required -to send a log message using this API, -the opposite is actually true. -A simple -.Dq Hello World -program requires only: -.Pp - #include - ... - asl_log(NULL, NULL, ASL_LEVEL_INFO, "Hello World!"); -.Pp -Both -.Nm asl_log -and -.Nm asl_vlog -will provide the appropriate default values -when passed a NULL aslmsg argument. -.Pp -.Pp -In this example, the aslclient argument is NULL. -This is sufficient for a single-threaded application, -or for an application which only sends log messages from a single thread. When logging from multiple threads, each thread .Em should open a separate client handle using -.Nm asl_open . +.Fn asl_open . The client handle may then be closed when it is no longer required using -.Nm asl_close . -Multiple threads may log messages safely using a NULL aslclient argument, +.Fn asl_release . +Multiple threads may log messages safely using a NULL asl_object_t argument, but the library will use an internal lock, so that in fact only one thread will log at a time. .Pp @@ -997,7 +1590,7 @@ a single message structure may be allocated and set up as .Dq template message of sorts: .Pp - aslmsg m = asl_new(ASL_TYPE_MSG); + asl_object_t m = asl_new(ASL_TYPE_MSG); asl_set(m, ASL_KEY_FACILITY, "com.secrets.r.us"); asl_set(m, "Clearance", "Top Secret"); ... @@ -1010,16 +1603,16 @@ The message structure will carry the values set for the and .Dq Clearance keys so that they are used in each call to -.Nm asl_log , +.Fn asl_log , while the log level and the message text are taken from the calling parameters. .Pp The .Ar format argument to -.Nm asl_log +.Fn asl_log and -.Nm asl_vlog +.Fn asl_vlog is identical to .Xr printf 3 , and may include @@ -1031,28 +1624,28 @@ see .Xr strerror 3 . ) .Pp Key/value pairs may be removed from a message structure with -.Nm asl_unset . +.Fn asl_unset . A message may be freed using -.Nm asl_free . +.Fn asl_release . .Pp The -.Nm asl_send +.Fn asl_send routine is used by -.Nm asl_log +.Fn asl_log and -.Nm asl_vlog +.Fn asl_vlog to transmit a message to the server. This routine sets the value associated with ASL_KEY_TIME and sends the message. It may be called directly if all of a message's key/value pairs have been created using -.Nm asl_set . +.Fn asl_set . .Ss SECURITY Messages that are sent to the .Nm syslogd server may be saved in a message store. The store may be searched using -.Nm asl_search , +.Fn asl_search , as described below. By default, all messages are readable by any user. However, some applications may wish to restrict read access @@ -1098,13 +1691,13 @@ If a single handle must be accessed by multiple dispatch queues, then the application must use locks, semaphores, or some other mechanism to prevent concurrent access to a client handle. .Pp A NULL value may be used in any of the routines -that require an aslclient argument. +that require an asl_object_t argument. In this case, the library will use an internal client handle. This internal handle contains its own lock, allowing multiple threads to safely use the NULL client handle. Note, however, that contention for the lock may cause undesirable synchronization behavior or reduced performance. .Pp The -.Nm asl_open +.Fn asl_open routine may be given an ident argument, which becomes the default value for the ASL_KEY_SENDER key, and a facility argument, @@ -1133,35 +1726,24 @@ connects to the server immediately disables remote-control filter adjustment .El .Pp -ASL_OPT_NO_DELAY makes the client library connect to the -.Nm syslogd -server at the time that -.Nm asl_open -is called, rather than waiting for the first message to be sent. -Opening the connection is quite fast, but some applications may want to avoid any unnecessary delays when calling -.Nm asl_log , -.Nm asl_vlog , -or -.Nm asl_send . -.Pp See the FILTERING section below, and the .Xr syslog 1 for additional details on filter controls. .Pp A client handle is closed and its resources released using -.Nm asl_close . +.Fn asl_close . Note that if additional file descriptors were added to the handle, either using the ASL_OPT_STDERR option or afterwards with the -.Nm asl_add_log_file +.Fn asl_add_log_file routine, those file descriptors are not closed by -.Nm asl_close . +.Fn asl_close . .Ss LOGGING TO ADDITIONAL FILES If a client handle is opened with the ASL_OPT_STDERR option to -.Nm asl_open , +.Fn asl_open , a copy of each log message will be sent to stderr. Additional output streams may be include using -.Nm asl_add_log_file . +.Fn asl_add_log_file . .Pp Messages sent to stderr or other files are printed in the "standard" message format also used as a default format by the @@ -1180,7 +1762,7 @@ A tab character is appended after newlines so that message text is indented. .Pp File descriptors may be removed from the list of outputs associated with a client handle with -.Nm asl_remove_log_file . +.Fn asl_remove_log_file . This routine simply removes the file descriptor from the output list. The file is not closed as a result. .Pp @@ -1191,29 +1773,26 @@ The .Nm syslogd server archives received messages in a data store that may be searched using the -.Nm asl_search , -.Nm aslresponse_next , +.Fn asl_search , +.Fn asl_next , and -.Nm aslresponse_free +.Fn asl_release routines. A query message is created using: .Pp - aslmsg q = asl_new(ASL_TYPE_QUERY); + asl_object_t q = asl_new(ASL_TYPE_QUERY); .Pp Search settings are made in the query using -.Nm asl_set_query . +.Fn asl_set_query . A search is performed on the data store with -.Nm asl_search . -It returns an -.Ft aslresponse -structure. -The caller may then call -.Nm aslresponse_next -to iterate through matching messages. -The -.Ft aslresponse -structure may be freed with -.Nm aslresponse_free . +.Fn asl_search . +It returns an object of type ASL_TYPE_LIST. +The caller may use routines that operate on lists, such as +.Fn asl_next , +.Fn asl_prev , +and +.Fn asl_get_index +to access the matching messages. .Pp Like other messages, ASL_TYPE_QUERY messages contain keys and values. They also associate an operation with each key and value. @@ -1223,8 +1802,7 @@ For example, the following code snippet searches for messages with a Sender value equal to .Dq MyApp . .Pp - aslmsg m; - aslresponse r; + asl_object_t q, r; q = asl_new(ASL_TYPE_QUERY); asl_set_query(q, ASL_KEY_SENDER, "MyApp", ASL_QUERY_OP_EQUAL); r = asl_search(NULL, q); @@ -1284,8 +1862,7 @@ the result will be a logical AND. For example, to find messages from with a priority level less than or equal to .Dq 3 : .Pp - aslmsg q; - aslresponse r; + asl_object_t q, r; q = asl_new(ASL_TYPE_QUERY); asl_set_query(q, ASL_KEY_SENDER, "MyApp", ASL_QUERY_OP_EQUAL); asl_set_query(q, ASL_KEY_LEVEL, "3", @@ -1293,37 +1870,33 @@ with a priority level less than or equal to r = asl_search(NULL, q); .Pp After calling -.Nm asl_search -to get an -.Ft aslresponse -structure, use -.Nm aslresponse_next -to iterate through all matching messages. -To iterate through the keys and values in a message, use -.Nm asl_key -to iterate through the keys, then call -.Nm asl_get -to get the value associated with each key. +.Fn asl_search +to get a list of matching messages, one can use +.Fn asl_next +to iterate through the list, and +.Fn asl_fetch_key_val_op +To iterate through the message dictionary. .Pp - aslmsg q, m; - int i; - const char *key, *val; + asl_object_t q, r; .Pp ... r = asl_search(NULL, q); - while (NULL != (m = aslresponse_next(r))) + while (NULL != (m = asl_next(r))) { - for (i = 0; (NULL != (key = asl_key(m, i))); i++) + int i, n; + n = asl_count(m); + for (i = 0; i < n; i++) { - val = asl_get(m, key); + const char *key, *val; + asl_fetch_key_val_op(m, i, key, val, NULL); ... } } - aslresponse_free(r); + asl_release(r); .Pp .Ss FILTERING AND REMOTE CONTROL Clients may set a filter mask value with -.Nm asl_set_filter . +.Fn asl_set_filter . The mask specifies which messages should be sent to the .Nm syslogd daemon by specifying a yes/no setting for each priority level. @@ -1334,7 +1907,7 @@ are generally only useful for debugging operations. By setting a filter mask, a process can improve performance by avoiding sending messages that are in most cases unnecessary. .Pp -.Nm asl_set_filter returns the previous value of the filter, i.e. the value of the filter before the routine was called. +.Fn asl_set_filter returns the previous value of the filter, i.e. the value of the filter before the routine was called. .Pp As a convenience, the macros ASL_FILTER_MASK(level) and ASL_FILTER_MASK_UPTO(level) may be used to construct a bit mask corresponding to a given priority level, @@ -1346,12 +1919,12 @@ This means that by default, and in the absence of remote-control changes (described below), ASL_LEVEL_DEBUG and ASL_LEVEL_INFO priority level messages are not sent to the -.Mn syslogd +.Nm syslogd server. .Pp Three different filters exist for each application. The first is the filter mask set using -.Nm asl_set_filter +.Fn asl_set_filter as described above. The Apple System Log facility also manages a .Dq master @@ -1387,7 +1960,7 @@ As is the case with the master filter mask, a per-client mask ceases having any effect when if is disabled. .Pp The ASL_OPT_NO_REMOTE option to -.Nm asl_open +.Fn asl_open causes both the master and per-client remote-control masks to be ignored in the library. In that case, only the client's own filter mask diff --git a/libsystem_asl.tproj/src/asl.c b/libsystem_asl.tproj/src/asl.c index 29640c1..745a788 100644 --- a/libsystem_asl.tproj/src/asl.c +++ b/libsystem_asl.tproj/src/asl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2012 Apple Inc. All rights reserved. + * Copyright (c) 2004-2013 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,6 @@ * @APPLE_LICENSE_HEADER_END@ */ -#include #include #include #include @@ -33,8 +32,11 @@ #include #include #include +#include #include #include +#include +#include #include #include #include @@ -49,14 +51,14 @@ #include #include #include +#include #include -#include "asl_core.h" -#include "asl_msg.h" -#include "asl_store.h" -#include "asl_private.h" - -#define streq(A, B) (strcmp(A, B) == 0) -#define strcaseeq(A, B) (strcasecmp(A, B) == 0) +#include +#include +#include +#include +#include +#include #define forever for(;;) @@ -78,24 +80,21 @@ #define QUOTA_MPH 36000 #define QUOTA_MPS 10 #define QUOTA_MSG_INTERVAL 60 - +#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 2 +#define QUOTA_LEVEL_STR "2" /* forward */ -time_t asl_parse_time(const char *); -const char *asl_syslog_faciliy_num_to_name(int n); -static int _asl_send_message(aslclient ac, uint32_t eval, asl_msg_t *msg, const char *mstring); +static ASL_STATUS _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstring); __private_extern__ asl_client_t *_asl_open_default(); -/* private asl_file SPI */ -__private_extern__ uint32_t asl_file_open_write_fd(int fd, asl_file_t **s); - /* notify SPI */ uint32_t notify_register_plain(const char *name, int *out_token); -/* fork handling in syslog.c */ -extern void _syslog_fork_child(); +/* fork handling in asl_fd.c */ +extern void _asl_redirect_fork_child(void); typedef struct { @@ -115,7 +114,6 @@ typedef struct time_t last_send; time_t last_oq_msg; uint32_t quota; - dispatch_once_t port_lookup_once; mach_port_t server_port; char *sender; pthread_mutex_t lock; @@ -124,9 +122,9 @@ typedef struct asl_client_t *asl; } _asl_global_t; +__private_extern__ _asl_global_t _asl_global = {0, -1, -1, -1, 0LL, 0LL, 0LL, 0LL, 0, MACH_PORT_NULL, NULL, PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL}; -#ifndef BUILDING_VARIANT -__private_extern__ _asl_global_t _asl_global = {0, -1, -1, -1, 0LL, 0LL, 0LL, 0LL, 0, 0, MACH_PORT_NULL, NULL, PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL}; +static const char *level_to_number_string[] = {"0", "1", "2", "3", "4", "5", "6", "7"}; #define ASL_SERVICE_NAME "com.apple.system.logger" @@ -147,10 +145,11 @@ _asl_fork_child() _asl_global.last_send = 0; _asl_global.last_oq_msg = 0; - _asl_global.port_lookup_once = 0; _asl_global.server_port = MACH_PORT_NULL; pthread_mutex_init(&(_asl_global.lock), NULL); + + _asl_redirect_fork_child(); } /* @@ -170,7 +169,7 @@ asl_remote_notify_name() return str; } -static int +static ASL_STATUS _asl_notify_open(int do_lock) { char *notify_name; @@ -183,7 +182,7 @@ _asl_notify_open(int do_lock) if (_asl_global.notify_token != -1) { if (do_lock != 0) pthread_mutex_unlock(&_asl_global.lock); - return 0; + return ASL_STATUS_OK; } if (_asl_global.rc_change_token == -1) @@ -208,10 +207,11 @@ _asl_notify_open(int do_lock) if (do_lock != 0) pthread_mutex_unlock(&_asl_global.lock); - if (_asl_global.notify_token == -1) return -1; - return 0; + if (_asl_global.notify_token == -1) return ASL_STATUS_FAILED; + return ASL_STATUS_OK; } +#ifdef UNDEF static void _asl_notify_close() { @@ -236,239 +236,39 @@ _asl_notify_close() pthread_mutex_unlock(&_asl_global.lock); } +#endif static void -_asl_global_init() +_asl_global_init(int reset) { - if (_asl_global.server_port == MACH_PORT_NULL) - { - mach_port_t newport = MACH_PORT_NULL; - char *str = getenv("ASL_DISABLE"); - if ((str == NULL) || strcmp(str, "1")) - { - bootstrap_look_up2(bootstrap_port, ASL_SERVICE_NAME, &newport, 0, BOOTSTRAP_PRIVILEGED_SERVER); - if (newport != MACH_PORT_NULL) - { - if (!OSAtomicCompareAndSwap32Barrier(MACH_PORT_NULL, newport, (int32_t *)&_asl_global.server_port)) - { - mach_port_deallocate(mach_task_self(), newport); - } - } - } - } + _asl_global.server_port = asl_core_get_service_port(reset); } -static void -_asl_global_reset() -{ - mach_port_t tmp = _asl_global.server_port; - _asl_global.server_port = MACH_PORT_NULL; - mach_port_deallocate(mach_task_self(), tmp); -} +#pragma mark - +#pragma mark asl_client -aslclient +asl_object_t asl_open(const char *ident, const char *facility, uint32_t opts) { - char *name, *x; - asl_client_t *asl; - - asl = (asl_client_t *)calloc(1, sizeof(asl_client_t)); - if (asl == NULL) - { - errno = ENOMEM; - return NULL; - } - - asl->options = opts; - - asl->sock = -1; - - _asl_global_init(); - - asl->pid = getpid(); - asl->uid = getuid(); - asl->gid = getgid(); - - asl->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE); - - if (ident != NULL) - { - asl->name = strdup(ident); - if (asl->name == NULL) - { - if (asl->sock >= 0) close(asl->sock); - free(asl); - return NULL; - } - } - else - { - name = *(*_NSGetArgv()); - if (name != NULL) - { - x = strrchr(name, '/'); - if (x != NULL) x++; - else x = name; - asl->name = strdup(x); - if (asl->name == NULL) - { - if (asl->sock >= 0) close(asl->sock); - free(asl); - return NULL; - } - } - } - - asl->facility = NULL; - if (facility != NULL) asl->facility = strdup(facility); - else asl->facility = strdup(asl_syslog_faciliy_num_to_name(LOG_USER)); - if (asl->facility == NULL) - { - if (asl->sock >= 0) close(asl->sock); - if (asl->name != NULL) free(asl->name); - free(asl); - return NULL; - } - - if (!(asl->options & ASL_OPT_NO_REMOTE)) _asl_notify_open(1); - - if (asl->options & ASL_OPT_STDERR) - { - /* only add stderr if it is valid */ - if (fcntl(STDERR_FILENO, F_GETFD) >= 0) - { - asl_add_output_file((aslclient)asl, STDERR_FILENO, ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG), ASL_ENCODE_SAFE); - } - else - { - /* stderr has been closed, ignore ASL_OPT_STDERR flag */ - asl->options &= ~ASL_OPT_STDERR; - } - } + asl_client_t *asl = asl_client_open(ident, facility, opts); + if (asl == NULL) return NULL; - asl->refcount = 1; + _asl_global_init(0); + if (!(opts & ASL_OPT_NO_REMOTE)) _asl_notify_open(1); - return (aslclient)asl; + return (asl_object_t)asl; } -aslclient +asl_object_t asl_open_from_file(int fd, const char *ident, const char *facility) { - char *name, *x; - asl_client_t *asl; - uint32_t status; - - asl = (asl_client_t *)calloc(1, sizeof(asl_client_t)); - if (asl == NULL) - { - errno = ENOMEM; - return NULL; - } - - asl->options = ASL_OPT_NO_REMOTE; - asl->sock = -1; - - asl->pid = getpid(); - asl->uid = getuid(); - asl->gid = getgid(); - - asl->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG); - - if (ident != NULL) - { - asl->name = strdup(ident); - if (asl->name == NULL) - { - free(asl); - return NULL; - } - } - else - { - name = *(*_NSGetArgv()); - if (name != NULL) - { - x = strrchr(name, '/'); - if (x != NULL) x++; - else x = name; - asl->name = strdup(x); - if (asl->name == NULL) - { - free(asl); - return NULL; - } - } - } - - asl->facility = NULL; - if (facility != NULL) asl->facility = strdup(facility); - else asl->facility = strdup(asl_syslog_faciliy_num_to_name(LOG_USER)); - if (asl->facility == NULL) - { - if (asl->name != NULL) free(asl->name); - free(asl); - return NULL; - } - - status = asl_file_open_write_fd(fd, &(asl->aslfile)); - if (status != ASL_STATUS_OK) - { - if (asl->name != NULL) free(asl->name); - if (asl->facility != NULL) free(asl->facility); - free(asl); - return NULL; - } - - asl->aslfileid = 1; - asl->refcount = 1; - - return (aslclient)asl; -} - -__private_extern__ void -asl_client_release(asl_client_t *asl) -{ - uint32_t i; - - if (asl == NULL) return; - - if (OSAtomicDecrement32(&asl->refcount) > 0) return; - - free(asl->name); - free(asl->facility); - - if (asl->sock >= 0) close(asl->sock); - if (!(asl->options & ASL_OPT_NO_REMOTE)) _asl_notify_close(); - - for (i = 0; i < asl->out_count; i++) - { - free(asl->out_list[i].mfmt); - free(asl->out_list[i].tfmt); - } - - free(asl->out_list); - - memset(asl, 0, sizeof(asl_client_t)); - free(asl); + return (asl_object_t)asl_client_open_from_file(fd, ident, facility); } void -asl_close(aslclient ac) -{ - asl_client_release((asl_client_t *)ac); -} - -__private_extern__ asl_client_t * -asl_client_retain(asl_client_t *asl) +asl_close(asl_object_t obj) { - int32_t new; - - if (asl == NULL) return NULL; - - new = OSAtomicIncrement32(&asl->refcount); - assert(new >= 1); - - return asl; + asl_release(obj); } __private_extern__ asl_client_t * @@ -482,7 +282,7 @@ _asl_open_default() * since asl_open(xxx, yyy, 0) calls _asl_notify_open(1) * which locks _asl_global.lock. */ - _asl_global.asl = asl_open(NULL, NULL, ASL_OPT_NO_REMOTE); + _asl_global.asl = (asl_client_t *)asl_open(NULL, NULL, ASL_OPT_NO_REMOTE); /* Reset options to clear ASL_OPT_NO_REMOTE bit */ if (_asl_global.asl != NULL) _asl_global.asl->options = 0; @@ -499,14 +299,14 @@ _asl_open_default() * Log messages will be written to this file as well as to the server. */ int -asl_add_output_file(aslclient ac, int fd, const char *mfmt, const char *tfmt, int filter, int text_encoding) +asl_add_output_file(asl_object_t client, int fd, const char *mfmt, const char *tfmt, int filter, int text_encoding) { - uint32_t i; - int use_global_lock; + int status, use_global_lock = 0; asl_client_t *asl; - use_global_lock = 0; - asl = (asl_client_t *)ac; + if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1; + + asl = (asl_client_t *)client; if (asl == NULL) { asl = _asl_open_default(); @@ -515,63 +315,23 @@ asl_add_output_file(aslclient ac, int fd, const char *mfmt, const char *tfmt, in use_global_lock = 1; } - for (i = 0; i < asl->out_count; i++) - { - if (asl->out_list[i].fd == fd) - { - /* update message format, time format, filter, and text encoding */ - free(asl->out_list[i].mfmt); - asl->out_list[i].mfmt = NULL; - if (mfmt != NULL) asl->out_list[i].mfmt = strdup(mfmt); - - free(asl->out_list[i].tfmt); - asl->out_list[i].tfmt = NULL; - if (tfmt != NULL) asl->out_list[i].tfmt = strdup(tfmt); - - asl->out_list[i].encoding = text_encoding; - asl->out_list[i].filter = filter; - - if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock); - return 0; - } - } - - if (asl->out_count == 0) - { - asl->out_list = (asl_out_file_t *)calloc(1, sizeof(asl_out_file_t)); - } - else - { - asl->out_list = (asl_out_file_t *)reallocf(asl->out_list, (1 + asl->out_count) * sizeof(asl_out_file_t)); - } - - if (asl->out_list == NULL) - { - if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock); - return -1; - } - - asl->out_list[asl->out_count].fd = fd; - asl->out_list[asl->out_count].encoding = text_encoding; - asl->out_list[asl->out_count].filter = filter; - if (mfmt != NULL) asl->out_list[asl->out_count].mfmt = strdup(mfmt); - if (tfmt != NULL) asl->out_list[asl->out_count].tfmt = strdup(tfmt); - - asl->out_count++; + status = asl_client_add_output_file(asl, fd, mfmt, tfmt, filter, text_encoding); if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock); - return 0; + return (status == ASL_STATUS_OK) ? 0 : -1; } +/* returns previous filter value or -1 on error */ int -asl_set_output_file_filter(aslclient ac, int fd, int filter) +asl_set_output_file_filter(asl_object_t client, int fd, int filter) { - uint32_t i, last; - int use_global_lock; + uint32_t last; + int use_global_lock = 0; asl_client_t *asl; - use_global_lock = 0; - asl = (asl_client_t *)ac; + if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1; + + asl = (asl_client_t *)client; if (asl == NULL) { asl = _asl_open_default(); @@ -580,18 +340,7 @@ asl_set_output_file_filter(aslclient ac, int fd, int filter) use_global_lock = 1; } - last = 0; - - for (i = 0; i < asl->out_count; i++) - { - if (asl->out_list[i].fd == fd) - { - /* update filter */ - last = asl->out_list[i].filter; - asl->out_list[i].filter = filter; - break; - } - } + last = asl_client_set_output_file_filter(asl, fd, filter); if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock); return last; @@ -599,29 +348,30 @@ asl_set_output_file_filter(aslclient ac, int fd, int filter) /* SPI - Deprecated */ int -asl_add_output(aslclient ac, int fd, const char *mfmt, const char *tfmt, uint32_t text_encoding) +asl_add_output(asl_object_t client, int fd, const char *mfmt, const char *tfmt, uint32_t text_encoding) { - return asl_add_output_file(ac, fd, mfmt, tfmt, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG), text_encoding); + return asl_add_output_file(client, fd, mfmt, tfmt, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG), text_encoding); } +/* SPI - Deprecated */ int -asl_add_log_file(aslclient ac, int fd) +asl_add_log_file(asl_object_t client, int fd) { - return asl_add_output_file(ac, fd, ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG), ASL_ENCODE_SAFE); + return asl_add_output_file(client, fd, ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG), ASL_ENCODE_SAFE); } /* * asl_remove_output: stop writing log messages to the given file descriptor */ int -asl_remove_output_file(aslclient ac, int fd) +asl_remove_output_file(asl_object_t client, int fd) { - uint32_t i; - int x, use_global_lock; + int status, use_global_lock = 0; asl_client_t *asl; - use_global_lock = 0; - asl = (asl_client_t *)ac; + if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1; + + asl = (asl_client_t *)client; if (asl == NULL) { asl = _asl_open_default(); @@ -630,79 +380,34 @@ asl_remove_output_file(aslclient ac, int fd) use_global_lock = 1; } - if (asl->out_count == 0) - { - if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock); - return 0; - } - - x = -1; - for (i = 0; i < asl->out_count; i++) - { - if (asl->out_list[i].fd == fd) - { - x = i; - break; - } - } - - if (x == -1) - { - if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock); - return 0; - } - - free(asl->out_list[x].mfmt); - free(asl->out_list[x].tfmt); - - for (i = x + 1; i < asl->out_count; i++, x++) - { - asl->out_list[x] = asl->out_list[i]; - } - - asl->out_count--; - - if (asl->out_count == 0) - { - free(asl->out_list); - asl->out_list = NULL; - } - else - { - asl->out_list = (asl_out_file_t *)reallocf(asl->out_list, asl->out_count * sizeof(asl_out_file_t)); - - if (asl->out_list == NULL) - { - asl->out_count = 0; - if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock); - return -1; - } - } + status = asl_client_remove_output_file(asl, fd); if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock); - return 0; + return (status == ASL_STATUS_OK) ? 0 : -1; } int -asl_remove_output(aslclient ac, int fd) +asl_remove_output(asl_object_t client, int fd) { - return asl_remove_output_file(ac, fd); + return asl_remove_output_file(client, fd); } int -asl_remove_log_file(aslclient ac, int fd) +asl_remove_log_file(asl_object_t client, int fd) { - return asl_remove_output_file(ac, fd); + return asl_remove_output_file(client, fd); } +/* returns previous filter value or -1 on error */ int -asl_set_filter(aslclient ac, int f) +asl_set_filter(asl_object_t client, int f) { - int last, use_global_lock; + int last, use_global_lock = 0; asl_client_t *asl; - use_global_lock = 0; - asl = (asl_client_t *)ac; + if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1; + + asl = (asl_client_t *)client; if (asl == NULL) { asl = _asl_open_default(); @@ -711,13 +416,16 @@ asl_set_filter(aslclient ac, int f) use_global_lock = 1; } - last = asl->filter; - asl->filter = f; + last = asl_client_set_filter(asl, f); if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock); return last; } + +#pragma mark - +#pragma mark message sending + /* * Evaluate client / message / level to determine what to do with a message. * Checks filters, tunneling, and log files. Returns EVAL_IGNORE if the message @@ -729,39 +437,44 @@ asl_set_filter(aslclient ac, int f) * EVAL_FILE - will write to file */ uint32_t -_asl_evaluate_send(aslclient ac, aslmsg msg, int slevel) +_asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel) { - asl_client_t *asl = (asl_client_t *)ac; + asl_client_t *asl; + asl_msg_t *msg = (asl_msg_t *)m; uint32_t level, lmask, filter, status, tunnel; - int check, out; + int check; uint64_t v64; const char *val; + 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); + } + + asl = (asl_client_t *)client; if (asl == NULL) { asl = _asl_open_default(); if (asl == NULL) return EVAL_IGNORE; } - check = ASL_LEVEL_DEBUG; - if (slevel >= 0) check = slevel; - - val = asl_get((aslmsg)msg, ASL_KEY_LEVEL); - if (val != NULL) check = atoi(val); - - if (check < ASL_LEVEL_EMERG) check = ASL_LEVEL_EMERG; - else if (check > ASL_LEVEL_DEBUG) check = ASL_LEVEL_DEBUG; - level = check; - - out = check; - - if (asl->aslfile != NULL) return (out | EVAL_ASLFILE); + if (asl->aslfile != NULL) return (level | EVAL_ASLFILE); lmask = ASL_FILTER_MASK(level); filter = asl->filter & 0xff; tunnel = (asl->filter & ASL_FILTER_MASK_TUNNEL) >> 8; - + if (!(asl->options & ASL_OPT_NO_REMOTE)) { pthread_mutex_lock(&_asl_global.lock); @@ -790,7 +503,6 @@ _asl_evaluate_send(aslclient ac, aslmsg msg, int slevel) } pthread_mutex_unlock(&_asl_global.lock); - /* master filter overrides local filter */ if (_asl_global.master_filter != 0) { @@ -808,11 +520,11 @@ _asl_evaluate_send(aslclient ac, aslmsg msg, int slevel) if ((filter != 0) && ((filter & lmask) != 0)) { - out |= EVAL_SEND; - if (tunnel != 0) out |= EVAL_TUNNEL; - if (asl->out_count > 0) out |= EVAL_FILE; + level |= EVAL_SEND; + if (tunnel != 0) level |= EVAL_TUNNEL; + if (asl->out_count > 0) level |= EVAL_FILE; - return out; + return level; } if ((asl->options & ASL_OPT_SYSLOG_LEGACY) && (filter != 0) && ((filter & lmask) == 0)) @@ -820,43 +532,29 @@ _asl_evaluate_send(aslclient ac, aslmsg msg, int slevel) return EVAL_IGNORE; } - if (asl->out_count > 0) return (out | EVAL_FILE); + if (asl->out_count > 0) return (level | EVAL_FILE); return EVAL_IGNORE; } -#endif /* BUILDING_VARIANT */ - /* * _asl_lib_vlog * Internal routine used by asl_vlog. - * msg: an aslmsg + * msg: an asl messsage * eval: log level and send flags for the message * format: A formating string * ap: va_list for the format * returns 0 for success, non-zero for failure */ -static int -_asl_lib_vlog(aslclient ac, uint32_t eval, aslmsg msg, const char *format, va_list ap) +static 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; int status; char *str, *fmt, estr[NL_TEXTMAX]; uint32_t i, len, elen, expand; - asl_client_t *asl; - - asl = (asl_client_t *)ac; - if (asl == NULL) - { - /* - * Initialize _asl_global so that asl_new will have global data. - * Not strictly necessary, but helps performance. - */ - asl = _asl_open_default(); - if (asl == NULL) return -1; - } - if (format == NULL) return -1; + if (format == NULL) return ASL_STATUS_INVALID_ARG; /* insert strerror for %m */ len = 0; @@ -893,7 +591,7 @@ _asl_lib_vlog(aslclient ac, uint32_t eval, aslmsg msg, const char *format, va_li if (fmt == NULL) { if (estr != NULL) free(estr); - return -1; + return ASL_STATUS_NO_MEMORY; } len = 0; @@ -927,9 +625,9 @@ _asl_lib_vlog(aslclient ac, uint32_t eval, aslmsg msg, const char *format, va_li vasprintf(&str, fmt, ap); if (expand != 0) free(fmt); - if (str == NULL) return -1; + if (str == NULL) return ASL_STATUS_NO_MEMORY; - status = _asl_send_message(ac, eval, (asl_msg_t *)msg, str); + status = _asl_send_message(obj, eval, (asl_msg_t *)msg, str); free(str); return status; @@ -938,40 +636,41 @@ _asl_lib_vlog(aslclient ac, uint32_t eval, aslmsg msg, const char *format, va_li /* * asl_vlog * Similar to asl_log, but take a va_list instead of a list of arguments. - * msg: an aslmsg + * msg: an asl message * level: the log level of the associated message * format: A formating string * ap: va_list for the format * returns 0 for success, non-zero for failure */ int -asl_vlog(aslclient ac, aslmsg msg, int level, const char *format, va_list ap) +asl_vlog(asl_object_t client, asl_object_t msg, int level, const char *format, va_list ap) { - uint32_t eval = _asl_evaluate_send(ac, msg, level); + uint32_t eval = _asl_evaluate_send(client, msg, level); if (eval == EVAL_IGNORE) return 0; - return _asl_lib_vlog(ac, eval, msg, format, ap); + ASL_STATUS status = _asl_lib_vlog(client, eval, msg, format, ap); + return (status == ASL_STATUS_OK) ? 0 : -1; } /* * _asl_lib_log * SPI used by ASL_PREFILTER_LOG. Converts format arguments to a va_list and * forwards the call to _asl_lib_vlog. - * msg: an aslmsg + * msg: an asl message * eval: log level and send flags for the message * format: A formating string * ... args for format * returns 0 for success, non-zero for failure */ int -_asl_lib_log(aslclient ac, uint32_t eval, aslmsg msg, const char *format, ...) +_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; va_list ap; va_start(ap, format); - status = _asl_lib_vlog(ac, eval, msg, format, ap); + status = _asl_lib_vlog(client, eval, msg, format, ap); va_end(ap); return status; @@ -980,41 +679,64 @@ _asl_lib_log(aslclient ac, uint32_t eval, aslmsg msg, const char *format, ...) /* * asl_log * Processes an ASL log message. - * msg: an aslmsg + * msg: an asl message * level: the log level of the associated message * format: A formating string * ... args for format * returns 0 for success, non-zero for failure */ int -asl_log(aslclient ac, aslmsg msg, int level, const char *format, ...) +asl_log(asl_object_t client, asl_object_t msg, int level, const char *format, ...) { - int status; - uint32_t eval = _asl_evaluate_send(ac, msg, level); + ASL_STATUS status; + 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(ac, eval, msg, format, ap); + status = _asl_lib_vlog(client, eval, msg, format, ap); va_end(ap); - return status; + return (status == ASL_STATUS_OK) ? 0 : -1; } -#ifndef BUILDING_VARIANT +/* + * asl_log_message + * Like asl_log, supplies NULL client and msg. + * level: the log level of the associated message + * format: A formating string + * ... args for format + * returns 0 for success, non-zero for failure + */ +int +asl_log_message(int level, const char *format, ...) +{ + int status; + 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); + + return (status == ASL_STATUS_OK) ? 0 : -1; +} /* * asl_get_filter: gets the values for the local, master, and remote filters, * and indicates which one is active. */ int -asl_get_filter(aslclient ac, int *local, int *master, int *remote, int *active) +asl_get_filter(asl_object_t client, int *local, int *master, int *remote, int *active) { asl_client_t *asl, *asl_default; int l, m, r, x; int status, check; uint64_t v64; + if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT)) return -1; + l = 0; m = 0; r = 0; @@ -1022,7 +744,7 @@ asl_get_filter(aslclient ac, int *local, int *master, int *remote, int *active) asl_default = _asl_open_default(); - asl = (asl_client_t *)ac; + asl = (asl_client_t *)client; if (asl == NULL) asl = asl_default; if (asl != NULL) l = asl->filter & 0xff; @@ -1070,105 +792,83 @@ asl_get_filter(aslclient ac, int *local, int *master, int *remote, int *active) return 0; } -static int -_asl_send_message(aslclient ac, uint32_t eval, asl_msg_t *msg, const char *mstring) +/* + * Sets Host, PID, UID, GID, 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) { - uint32_t i, len, level, lmask, outstatus; - const char *val; - char *name, *x; - time_t tick; - struct timeval tval; - int status; - asl_client_t *asl; - int use_global_lock; - kern_return_t kstatus; char aux_val[64]; char aux_host[_POSIX_HOST_NAME_MAX]; asl_msg_t *aux; + int status; + unsigned int osacount = 1; + os_activity_t osaid = 0; - if (eval == EVAL_IGNORE) return 0; - - level = eval & LEVEL_MASK; - eval &= EVAL_MASK; - lmask = ASL_FILTER_MASK(level); - - use_global_lock = 0; - asl = (asl_client_t *)ac; - if (asl == NULL) - { - asl = _asl_open_default(); - if (asl == NULL) return -1; - use_global_lock = 1; - } - - if (asl->aslfile != NULL) use_global_lock = 1; - - /* - * Time, TimeNanoSec, Host, PID, UID, and GID values get set here. - * Also sets Sender & Facility (if unset) and "ASLOption store" if remote control is active. - */ aux = asl_msg_new(ASL_TYPE_MSG); + if (aux == NULL) return NULL; - if (mstring != NULL) asl_msg_set_key_val(aux, ASL_KEY_MSG, mstring); - - snprintf(aux_val, sizeof(aux_val), "%u", level); - asl_msg_set_key_val(aux, ASL_KEY_LEVEL, aux_val); - - memset(&tval, 0, sizeof(struct timeval)); + /* Level */ + if (level <= 7) asl_msg_set_key_val(aux, ASL_KEY_LEVEL, level_to_number_string[level]); - status = gettimeofday(&tval, NULL); - if (status == 0) + /* Time and TimeNanoSec */ + if (tv != NULL) { - snprintf(aux_val, sizeof(aux_val), "%lu", tval.tv_sec); + snprintf(aux_val, sizeof(aux_val), "%lu", tv->tv_sec); asl_msg_set_key_val(aux, ASL_KEY_TIME, aux_val); - snprintf(aux_val, sizeof(aux_val), "%d", tval.tv_usec * 1000); + + snprintf(aux_val, sizeof(aux_val), "%d", tv->tv_usec * 1000); asl_msg_set_key_val(aux, ASL_KEY_TIME_NSEC, aux_val); } - else - { - tick = time(NULL); - snprintf(aux_val, sizeof(aux_val), "%lu", tick); - asl_msg_set_key_val(aux, ASL_KEY_TIME, aux_val); - } + /* 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); - } + 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); - /* - * Set Sender if needed - */ - status = asl_msg_lookup((asl_msg_t *)msg, ASL_KEY_SENDER, &val, NULL); - if ((status != 0) || (val == NULL)) + /* OSActivityID */ + if (os_activity_get_active(&osaid, &osacount) == 1) { - if ((ac != NULL) && (ac->name != NULL)) - { - /* Use the Sender name from the client handle */ - asl_msg_set_key_val(aux, ASL_KEY_SENDER, ac->name); - } - else + snprintf(aux_val, sizeof(aux_val), "0x%016llx", (uint64_t)osaid); + asl_msg_set_key_val(aux, ASL_KEY_OS_ACTIVITY_ID, aux_val); + } + + /* Sender */ + if (sstr == 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); + if ((status != 0) || (sstr == NULL)) { - /* Get the value for ASL_KEY_SENDER from cache */ + sstr = NULL; + + /* See if the global cache has a value for ASL_KEY_SENDER */ if (_asl_global.sender == NULL) { - name = *(*_NSGetArgv()); + /* Get the process name with _NSGetArgv */ + char *name = *(*_NSGetArgv()); if (name != NULL) { - x = strrchr(name, '/'); + char *x = strrchr(name, '/'); if (x != NULL) x++; else x = name; + /* Set the cache value */ pthread_mutex_lock(&_asl_global.lock); if (_asl_global.sender == NULL) _asl_global.sender = strdup(x); pthread_mutex_unlock(&_asl_global.lock); @@ -1180,34 +880,141 @@ _asl_send_message(aslclient ac, uint32_t eval, asl_msg_t *msg, const char *mstri } } - /* - * Set Facility - */ - status = asl_msg_lookup((asl_msg_t *)msg, ASL_KEY_FACILITY, &val, NULL); - if ((status != 0) || (val == NULL)) + if (sstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_SENDER, sstr); + + /* Facility */ + if (fstr == NULL) { - if ((ac != NULL) && (ac->facility != NULL)) - { - /* Use the Facility name from the client handle */ - asl_msg_set_key_val(aux, ASL_KEY_FACILITY, ac->facility); - } + status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_FACILITY, &fstr, NULL); + if (status != 0) fstr = NULL; } - /* Set "ASLOption store" if tunneling */ + if (fstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_FACILITY, fstr); + + return aux; +} + +#ifdef NOTDEF +/* + * Possibly useful someday... + */ +asl_msg_t * +asl_prepared_message(asl_client_t *asl, asl_msg_t *msg) +{ + uint32_t i, len, level, outstatus; + const char *val, *sstr, *fstr; + struct timeval tval = {0, 0}; + int status; + asl_msg_t *out; + + if (asl == NULL) + { + asl = _asl_open_default(); + if (asl == NULL) return NULL; + } + + status = gettimeofday(&tval, NULL); + if (status != 0) + { + time_t tick = time(NULL); + tval.tv_sec = tick; + tval.tv_usec = 0; + } + + val = NULL; + status = asl_msg_lookup(msg, ASL_KEY_LEVEL, &val, NULL); + if (status != 0) val = NULL; + + level = ASL_LEVEL_DEBUG; + if (val != NULL) level = atoi(val); + if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG; + + sstr = NULL; + status = asl_msg_lookup(msg, ASL_KEY_SENDER, &sstr, NULL); + if (status != 0) sstr = NULL; + + fstr = NULL; + status = asl_msg_lookup(msg, ASL_KEY_FACILITY, &fstr, NULL); + if (status != 0) fstr = NULL; + + out = asl_base_msg(asl, level, &tval, sstr, fstr, NULL); + out = asl_msg_merge(out, msg); + + return out; +} +#endif + +static ASL_STATUS +_asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstr) +{ + uint32_t i, len, level, lmask, outstatus, objtype; + const char *sstr, *fstr; + struct timeval tval = {0, 0}; + int status; + int use_global_lock = 0; + kern_return_t kstatus; + asl_msg_t *sendmsg; + asl_msg_t *qd_msg = NULL; + asl_client_t *asl = NULL; + static dispatch_once_t noquota_once; + + if (eval == EVAL_IGNORE) return ASL_STATUS_OK; + if (obj == NULL) + { + asl = _asl_open_default(); + if (asl == NULL) return ASL_STATUS_FAILED; + use_global_lock = 1; + objtype = ASL_TYPE_CLIENT; + } + else + { + objtype = asl_get_type(obj); + if (objtype == ASL_TYPE_CLIENT) asl = (asl_client_t *)obj; + else asl = _asl_open_default(); + } + + level = 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; + + status = gettimeofday(&tval, NULL); + if (status != 0) + { + time_t tick = time(NULL); + tval.tv_sec = tick; + tval.tv_usec = 0; + } + + sstr = NULL; + status = asl_msg_lookup(msg, ASL_KEY_SENDER, &sstr, NULL); + if (status != 0) sstr = NULL; + + fstr = NULL; + status = asl_msg_lookup(msg, ASL_KEY_FACILITY, &fstr, NULL); + if (status != 0) fstr = NULL; + + sendmsg = asl_base_msg(asl, level, &tval, sstr, fstr, mstr); + if (sendmsg == NULL) return ASL_STATUS_FAILED; + + /* Set "ASLOption store" if tunneling */ if (eval & EVAL_TUNNEL) { - val = asl_get((aslmsg)msg, ASL_KEY_OPTION); - if (val == NULL) + const char *val = NULL; + status = asl_msg_lookup(msg, ASL_KEY_OPTION, &val, NULL); + if ((status != 0) || (val == NULL)) { - asl_msg_set_key_val(aux, ASL_KEY_OPTION, ASL_OPT_STORE); + asl_msg_set_key_val(sendmsg, ASL_KEY_OPTION, ASL_OPT_STORE); } else { - char *aux_option = NULL; - asprintf(&aux_option, "%s %s", ASL_OPT_STORE, val); - asl_msg_set_key_val(aux, ASL_KEY_OPTION, aux_option); - free(aux_option); + char *option = NULL; + asprintf(&option, "%s %s", ASL_OPT_STORE, val); + asl_msg_set_key_val(sendmsg, ASL_KEY_OPTION, option); + free(option); } } @@ -1215,7 +1022,15 @@ _asl_send_message(aslclient ac, uint32_t eval, asl_msg_t *msg, const char *mstri if (use_global_lock != 0) pthread_mutex_lock(&_asl_global.lock); - aux = asl_msg_merge(aux, msg); + sendmsg = asl_msg_merge(sendmsg, msg); + + if (objtype != ASL_TYPE_CLIENT) + { + asl_append(obj, (asl_object_t)sendmsg); + asl_msg_release(sendmsg); + if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock); + return ASL_STATUS_OK; + } /* * If there is an aslfile this is a stand-alone file client. @@ -1225,23 +1040,51 @@ _asl_send_message(aslclient ac, uint32_t eval, asl_msg_t *msg, const char *mstri { outstatus = ASL_STATUS_FAILED; - if (aux != NULL) + if (sendmsg != NULL) { - outstatus = asl_file_save(asl->aslfile, (aslmsg)aux, &(asl->aslfileid)); + outstatus = asl_file_save(asl->aslfile, sendmsg, &(asl->aslfileid)); asl->aslfileid++; } - asl_msg_release(aux); + asl_msg_release(sendmsg); if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock); return outstatus; } - _asl_global_init(); + _asl_global_init(0); outstatus = 0; - /* manage quota */ - if ((eval & EVAL_TUNNEL) == 0) + /* + * ASL message quota + * Quotas are disabled if: + * - a remote control filter is in place (EVAL_TUNNEL) + * - 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 + * expensive to stat() for every log message. + */ + + 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"))) + { + _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); + } + } + + if (((eval & EVAL_TUNNEL) == 0) && (_asl_global.quota != UINT32_MAX)) { time_t last_send = _asl_global.last_send; time_t last_oq = _asl_global.last_oq_msg; @@ -1289,14 +1132,25 @@ _asl_send_message(aslclient ac, uint32_t eval, asl_msg_t *msg, const char *mstri if (eval & EVAL_QUOTA) { - asl_msg_set_key_val(aux, ASL_KEY_LEVEL, QUOTA_LEVEL); - asl_msg_set_key_val(aux, ASL_KEY_MSG, QUOTA_MSG); + asl_msg_set_key_val(sendmsg, ASL_KEY_LEVEL, QUOTA_LEVEL_STR); + asl_msg_set_key_val(sendmsg, ASL_KEY_MSG, QUOTA_MSG); } - send_str = asl_msg_to_string_raw(ASL_STRING_MIG, aux, "raw"); + if (qd_msg != NULL) + { + send_str = asl_msg_to_string_raw(ASL_STRING_MIG, qd_msg, "raw"); + len = asl_string_length(send_str); + vmsize = asl_string_allocated_size(send_str); + str = asl_string_release_return_bytes(send_str); + if (len != 0) kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)str, len); + 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); vmsize = asl_string_allocated_size(send_str); - str = asl_string_free_return_bytes(send_str); + str = asl_string_release_return_bytes(send_str); if (len != 0) { @@ -1305,12 +1159,10 @@ _asl_send_message(aslclient ac, uint32_t eval, asl_msg_t *msg, const char *mstri if (kstatus != KERN_SUCCESS) { /* retry once if the call failed */ - _asl_global_reset(); - _asl_global_init(); + _asl_global_init(1); kstatus = _asl_server_message(_asl_global.server_port, (caddr_t)str, len); if (kstatus != KERN_SUCCESS) { - _asl_global_reset(); vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize); outstatus = -1; } @@ -1319,7 +1171,7 @@ _asl_send_message(aslclient ac, uint32_t eval, asl_msg_t *msg, const char *mstri else if (vmsize >0) vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize); } - if ((aux != NULL) && (asl->out_count > 0)) + if ((sendmsg != NULL) && (asl->out_count > 0)) { /* write to file descriptors */ for (i = 0; i < asl->out_count; i++) @@ -1329,7 +1181,7 @@ _asl_send_message(aslclient ac, uint32_t eval, asl_msg_t *msg, const char *mstri char *str; len = 0; - str = asl_format_message(aux, asl->out_list[i].mfmt, asl->out_list[i].tfmt, asl->out_list[i].encoding, &len); + str = asl_format_message(sendmsg, asl->out_list[i].mfmt, asl->out_list[i].tfmt, asl->out_list[i].encoding, &len); if (str == NULL) continue; status = write(asl->out_list[i].fd, str, len - 1); @@ -1345,7 +1197,7 @@ _asl_send_message(aslclient ac, uint32_t eval, asl_msg_t *msg, const char *mstri } } - asl_msg_release(aux); + asl_msg_release(sendmsg); if (use_global_lock != 0) pthread_mutex_unlock(&_asl_global.lock); @@ -1354,26 +1206,29 @@ _asl_send_message(aslclient ac, uint32_t eval, asl_msg_t *msg, const char *mstri /* * asl_send: send a message - * This routine may be used instead of asl_log() or asl_vlog() if asl_set() + * This routine may be used instead of asl_log() or asl_vlog() if asl_set() * has been used to set all of a message's attributes. * eval: hints about what to do with the message - * msg: an aslmsg + * msg: an asl message * returns 0 for success, non-zero for failure */ -int -asl_send(aslclient ac, aslmsg msg) +__private_extern__ ASL_STATUS +asl_client_internal_send(asl_object_t obj, asl_object_t msg) { - int status = 0; - uint32_t eval = _asl_evaluate_send(ac, msg, -1); - if (eval != 0) status = _asl_send_message(ac, eval, (asl_msg_t *)msg, NULL); + int status = ASL_STATUS_OK; + uint32_t eval = _asl_evaluate_send(obj, msg, -1); + if (eval != 0) status = _asl_send_message(obj, eval, (asl_msg_t *)msg, NULL); return status; } -static int +#pragma mark - +#pragma mark auxiliary files and URLs + +static ASL_STATUS _asl_aux_save_context(asl_aux_context_t *ctx) { - if (ctx == NULL) return -1; + if (ctx == NULL) return ASL_STATUS_FAILED; pthread_mutex_lock(&_asl_global.lock); @@ -1381,14 +1236,15 @@ _asl_aux_save_context(asl_aux_context_t *ctx) if (_asl_global.aux_ctx == NULL) { _asl_global.aux_count = 0; - return -1; + pthread_mutex_unlock(&_asl_global.lock); + return ASL_STATUS_FAILED; } _asl_global.aux_ctx[_asl_global.aux_count++] = ctx; pthread_mutex_unlock(&_asl_global.lock); - return 0; + return ASL_STATUS_OK; } /* @@ -1398,7 +1254,7 @@ _asl_aux_save_context(asl_aux_context_t *ctx) * Identifier specified. Output parameter out_fd will contain the file descriptor of the * new auxiliary file. */ -static int +static ASL_STATUS _asl_auxiliary(asl_msg_t *msg, const char *title, const char *uti, const char *url, int *out_fd) { asl_msg_t *aux; @@ -1416,50 +1272,34 @@ _asl_auxiliary(asl_msg_t *msg, const char *title, const char *uti, const char *u aux = asl_msg_new(ASL_TYPE_MSG); - if (title != NULL) - { - asl_msg_set_key_val(aux, ASL_KEY_AUX_TITLE, title); - } - - if (uti == NULL) - { - asl_msg_set_key_val(aux, ASL_KEY_AUX_UTI, "public.data"); - } - else - { - asl_msg_set_key_val(aux, ASL_KEY_AUX_UTI, uti); - } - - if (url != NULL) - { - asl_msg_set_key_val(aux, ASL_KEY_AUX_URL, url); - } + if (url != NULL) asl_msg_set_key_val(aux, ASL_KEY_AUX_URL, url); + if (title != NULL) asl_msg_set_key_val(aux, ASL_KEY_AUX_TITLE, title); + if (uti == NULL) asl_msg_set_key_val(aux, ASL_KEY_AUX_UTI, "public.data"); + else asl_msg_set_key_val(aux, ASL_KEY_AUX_UTI, uti); aux = asl_msg_merge(aux, msg); /* if (out_fd == NULL), this is from asl_log_auxiliary_location */ if (out_fd == NULL) { - uint32_t eval = _asl_evaluate_send(NULL, (aslmsg)aux, -1); + uint32_t eval = _asl_evaluate_send(NULL, (asl_object_t)aux, -1); status = _asl_send_message(NULL, eval, aux, NULL); asl_msg_release(aux); return status; } where = asl_store_location(); - if (where == ASL_STORE_LOCATION_MEMORY) { /* create a pipe */ - asl_aux_context_t *ctx = (asl_aux_context_t *)calloc(1, sizeof(asl_aux_context_t)); - if (ctx == NULL) return -1; + if (ctx == NULL) return ASL_STATUS_FAILED; status = pipe(fdpair); if (status < 0) { free(ctx); - return -1; + return ASL_STATUS_FAILED; } /* give read end to dispatch_io_read */ @@ -1469,16 +1309,16 @@ _asl_auxiliary(asl_msg_t *msg, const char *title, const char *uti, const char *u ctx->fd = fdpair[1]; status = _asl_aux_save_context(ctx); - if (status != 0) + if (status != ASL_STATUS_OK) { close(fdpair[0]); close(fdpair[1]); dispatch_release(sem); free(ctx); - return -1; + return ASL_STATUS_FAILED; } - pipe_q = dispatch_queue_create("PipeQ", NULL); + pipe_q = dispatch_queue_create("ASL_AUX_PIPE_Q", NULL); pipe_channel = dispatch_io_create(DISPATCH_IO_STREAM, fd, pipe_q, ^(int err){ close(fd); }); @@ -1501,7 +1341,7 @@ _asl_auxiliary(asl_msg_t *msg, const char *title, const char *uti, const char *u encoded = asl_core_encode_buffer(bytes, len); asl_msg_set_key_val(aux, ASL_KEY_AUX_DATA, encoded); free(encoded); - eval = _asl_evaluate_send(NULL, (aslmsg)aux, -1); + eval = _asl_evaluate_send(NULL, (asl_object_t)aux, -1); _asl_send_message(NULL, eval, aux, NULL); asl_msg_release(aux); dispatch_release(md); @@ -1516,22 +1356,22 @@ _asl_auxiliary(asl_msg_t *msg, const char *title, const char *uti, const char *u } }); - return 0; + return ASL_STATUS_OK; } - _asl_global_init(); - if (_asl_global.server_port == MACH_PORT_NULL) return -1; + _asl_global_init(0); + if (_asl_global.server_port == MACH_PORT_NULL) return ASL_STATUS_FAILED; send_str = asl_msg_to_string_raw(ASL_STRING_MIG, aux, "raw"); len = asl_string_length(send_str); vmsize = asl_string_allocated_size(send_str); - str = asl_string_free_return_bytes(send_str); + str = asl_string_release_return_bytes(send_str); if (len == 0) { asl_msg_release(aux); vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize); - return -1; + return ASL_STATUS_FAILED; } status = 0; @@ -1542,15 +1382,13 @@ _asl_auxiliary(asl_msg_t *msg, const char *title, const char *uti, const char *u if (kstatus != KERN_SUCCESS) { /* retry once if the call failed */ - _asl_global_reset(); - _asl_global_init(); + _asl_global_init(1); kstatus = _asl_server_create_aux_link(_asl_global.server_port, (caddr_t)str, len, &fileport, &newurl, &newurllen, &status); if (kstatus != KERN_SUCCESS) { - _asl_global_reset(); vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize); asl_msg_release(aux); - return -1; + return ASL_STATUS_FAILED; } } @@ -1569,7 +1407,7 @@ _asl_auxiliary(asl_msg_t *msg, const char *title, const char *uti, const char *u if (fileport == MACH_PORT_NULL) { asl_msg_release(aux); - return -1; + return ASL_STATUS_FAILED; } fd = fileport_makefd(fileport); @@ -1601,22 +1439,25 @@ _asl_auxiliary(asl_msg_t *msg, const char *title, const char *uti, const char *u } int -asl_create_auxiliary_file(aslmsg msg, const char *title, const char *uti, int *out_fd) +asl_create_auxiliary_file(asl_object_t msg, const char *title, const char *uti, int *out_fd) { if (out_fd == NULL) return -1; - return _asl_auxiliary((asl_msg_t *)msg, title, uti, NULL, out_fd); + ASL_STATUS status = _asl_auxiliary((asl_msg_t *)msg, title, uti, NULL, out_fd); + return (status == ASL_STATUS_OK) ? 0 : -1; } int -asl_log_auxiliary_location(aslmsg msg, const char *title, const char *uti, const char *url) +asl_log_auxiliary_location(asl_object_t msg, const char *title, const char *uti, const char *url) { - return _asl_auxiliary((asl_msg_t *)msg, title, uti, url, NULL); + ASL_STATUS status = _asl_auxiliary((asl_msg_t *)msg, title, uti, url, NULL); + return (status == ASL_STATUS_OK) ? 0 : -1; } /* * Close an auxiliary file. * Sends the cached auxiliary message to syslogd. + * Returns 0 on success, -1 on error. */ int asl_close_auxiliary_file(int fd) @@ -1673,7 +1514,7 @@ asl_close_auxiliary_file(int fd) if (aux_msg != NULL) { - uint32_t eval = _asl_evaluate_send(NULL, (aslmsg)aux_msg, -1); + uint32_t eval = _asl_evaluate_send(NULL, (asl_object_t)aux_msg, -1); if (_asl_send_message(NULL, eval, aux_msg, NULL) != ASL_STATUS_OK) status = -1; asl_msg_release(aux_msg); } @@ -1687,201 +1528,13 @@ asl_close_auxiliary_file(int fd) return status; } -/* - * asl_search: Search for messages matching the criteria described - * by the aslmsg. The caller should set the attributes to match using - * asl_set_query() or asl_set(). The operatoin ASL_QUERY_OP_EQUAL is - * used for attributes set with asl_set(). - * a: an aslmsg - * returns: a set of messages that can be iterated over using aslresp_next(), - * and the values can be retrieved using aslresp_get. - */ - -/* - * This routine searches the ASL datastore on disk (/var/log/asl). - * It is called my asl_search if syslogd is not running or if syslogd - * indicates that an in-memory store is not being used. - */ -static aslresponse -_asl_search_store(aslclient ac, aslmsg a) -{ - asl_search_result_t query, *out; - asl_msg_t *q, *qlist[1]; - uint32_t status, op; - uint64_t last_id, start_id; - asl_store_t *store; - const char *val; - - if (a == NULL) return NULL; - - q = (asl_msg_t *)a; - - /* check for "ASLMessageId >[=] n" and set start_id */ - start_id = 0; - val = NULL; - - status = asl_msg_lookup(q, ASL_KEY_MSG_ID, &val, &op); - if ((status == 0) && (val != NULL) && (op & ASL_QUERY_OP_GREATER)) - { - if (op & ASL_QUERY_OP_EQUAL) start_id = atoll(val); - else start_id = atoll(val) + 1; - } - - store = NULL; - status = asl_store_open_read(NULL, &store); - if (status != 0) return NULL; - if (store == NULL) return NULL; - - out = NULL; - last_id = 0; - - qlist[0] = (asl_msg_t *)a; - memset(&query, 0, sizeof(asl_search_result_t)); - query.count = 1; - query.msg = qlist; - - status = asl_store_match(store, &query, &out, &last_id, start_id, 0, 1); - asl_store_close(store); - - return out; -} - -static uint32_t -_asl_search_concat_results(asl_search_result_t *batch, asl_search_result_t **out) -{ - uint32_t i, j; - - if (out == NULL) return ASL_STATUS_FAILED; - - /* nothing to do if batch is NULL or contains no messages */ - if (batch == NULL) return 0; - if (batch->count == 0) - { - aslresponse_free(batch); - return 0; - } - - if (*out == NULL) *out = (asl_search_result_t *)calloc(1, sizeof(asl_search_result_t)); - if (*out == NULL) - { - aslresponse_free(batch); - return ASL_STATUS_FAILED; - } +#pragma mark - - if ((*out)->count == 0) - { - (*out)->msg = (asl_msg_t **)calloc(batch->count, sizeof(asl_msg_t *)); - } - else - { - (*out)->msg = (asl_msg_t **)reallocf((*out)->msg, ((*out)->count + batch->count) * sizeof(asl_msg_t *)); - } - - if ((*out)->msg == NULL) - { - aslresponse_free(batch); - free(*out); - *out = NULL; - return ASL_STATUS_FAILED; - } - - for (i = 0, j = (*out)->count; i < batch->count; i++, j++) (*out)->msg[j] = batch->msg[i]; - - (*out)->count += batch->count; - free(batch->msg); - free(batch); - return ASL_STATUS_OK; -} - -static aslresponse -_asl_search_memory(aslclient ac, aslmsg a) -{ - asl_search_result_t *batch, *out; - char *qstr, *str, *res; - uint32_t len, reslen, status; - uint64_t cmax, qmin; - kern_return_t kstatus; - caddr_t vmstr; - - if (a == NULL) return 0; - - _asl_global_init(); - if (_asl_global.server_port == MACH_PORT_NULL) return NULL; - - len = 0; - qstr = asl_msg_to_string((asl_msg_t *)a, &len); - - str = NULL; - if (qstr == NULL) - { - asprintf(&str, "0\n"); - len = 3; - } - else - { - asprintf(&str, "1\n%s\n", qstr); - len += 3; - free(qstr); - } - - if (str == NULL) return NULL; - - /* - * Fetch a batch of results each time through the loop. - * Fetching small batches rebuces the load on syslogd. - */ - out = NULL; - qmin = 0; - cmax = 0; - - forever - { - 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); - - status = 0; - kstatus = _asl_server_query_2(_asl_global.server_port, vmstr, len, qmin, FETCH_BATCH, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status); - if (kstatus != KERN_SUCCESS) - { - /* retry once if the call failed */ - _asl_global_reset(); - _asl_global_init(); - kstatus = _asl_server_query_2(_asl_global.server_port, vmstr, len, qmin, FETCH_BATCH, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status); - if (kstatus != KERN_SUCCESS) - { - _asl_global_reset(); - break; - } - } - - if (res == NULL) break; - - batch = asl_list_from_string(res); - vm_deallocate(mach_task_self(), (vm_address_t)res, reslen); - - status = _asl_search_concat_results(batch, &out); - if (status != ASL_STATUS_OK) break; - if ((out == NULL) || (out->count < FETCH_BATCH)) break; - - if (cmax >= qmin) qmin = cmax + 1; - } - - free(str); - - return out; -} - -aslmsg +asl_msg_t * _asl_server_control_query(void) { - asl_search_result_t *list = NULL; - char *qstr, *res; + asl_msg_list_t *list = NULL; + char *res; uint32_t len, reslen, status; uint64_t cmax, qmin; kern_return_t kstatus; @@ -1889,7 +1542,7 @@ _asl_server_control_query(void) asl_msg_t *m = NULL; static const char ctlstr[] = "1\nQ [= ASLOption control]\n"; - _asl_global_init(); + _asl_global_init(0); if (_asl_global.server_port == MACH_PORT_NULL) return NULL; len = strlen(ctlstr) + 1; @@ -1909,21 +1562,22 @@ _asl_server_control_query(void) if (kstatus != KERN_SUCCESS) { /* retry once if the call failed */ - _asl_global_reset(); - _asl_global_init(); + _asl_global_init(1); kstatus = _asl_server_query_2(_asl_global.server_port, vmstr, len, qmin, FETCH_BATCH, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status); - if (kstatus != KERN_SUCCESS) _asl_global_reset(); } - - list = asl_list_from_string(res); + + list = asl_msg_list_from_string(res); vm_deallocate(mach_task_self(), (vm_address_t)res, reslen); if (list == NULL) return NULL; if (list->count > 0) m = asl_msg_retain(list->msg[0]); - aslresponse_free((aslresponse)list); - return (aslmsg)m; + asl_msg_list_release(list); + return m; } +/* + * Returns ASL_STORE_LOCATION_FILE or ASL_STORE_LOCATION_MEMORY + */ int asl_store_location() { @@ -1932,7 +1586,7 @@ asl_store_location() uint32_t reslen, status; uint64_t cmax; - _asl_global_init(); + _asl_global_init(0); if (_asl_global.server_port == MACH_PORT_NULL) return ASL_STORE_LOCATION_FILE; res = NULL; @@ -1944,345 +1598,82 @@ asl_store_location() if (kstatus != KERN_SUCCESS) { /* retry once if the call failed */ - _asl_global_reset(); - _asl_global_init(); + _asl_global_init(1); kstatus = _asl_server_query_2(_asl_global.server_port, NULL, 0, 0, -1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status); } /* res should never be returned, but just to be certain we don't leak VM ... */ if (res != NULL) vm_deallocate(mach_task_self(), (vm_address_t)res, reslen); - if (kstatus != KERN_SUCCESS) - { - _asl_global_reset(); - return ASL_STORE_LOCATION_FILE; - } - + if (kstatus != KERN_SUCCESS) return ASL_STORE_LOCATION_FILE; if (status == ASL_STATUS_OK) return ASL_STORE_LOCATION_MEMORY; return ASL_STORE_LOCATION_FILE; } -aslresponse -asl_search(aslclient ac, aslmsg a) -{ - int where; - asl_search_result_t *out; - - _asl_global_init(); - - where = asl_store_location(); - if (where == ASL_STORE_LOCATION_FILE) out = _asl_search_store(ac, a); - else out = _asl_search_memory(ac, a); - - return out; -} - -int -asl_syslog_faciliy_name_to_num(const char *name) -{ - if (name == NULL) return -1; - - if (strcaseeq(name, "auth")) return LOG_AUTH; - if (strcaseeq(name, "authpriv")) return LOG_AUTHPRIV; - if (strcaseeq(name, "cron")) return LOG_CRON; - if (strcaseeq(name, "daemon")) return LOG_DAEMON; - if (strcaseeq(name, "ftp")) return LOG_FTP; - if (strcaseeq(name, "install")) return LOG_INSTALL; - if (strcaseeq(name, "kern")) return LOG_KERN; - if (strcaseeq(name, "lpr")) return LOG_LPR; - if (strcaseeq(name, "mail")) return LOG_MAIL; - if (strcaseeq(name, "netinfo")) return LOG_NETINFO; - if (strcaseeq(name, "remoteauth")) return LOG_REMOTEAUTH; - if (strcaseeq(name, "news")) return LOG_NEWS; - if (strcaseeq(name, "security")) return LOG_AUTH; - if (strcaseeq(name, "syslog")) return LOG_SYSLOG; - if (strcaseeq(name, "user")) return LOG_USER; - if (strcaseeq(name, "uucp")) return LOG_UUCP; - if (strcaseeq(name, "local0")) return LOG_LOCAL0; - if (strcaseeq(name, "local1")) return LOG_LOCAL1; - if (strcaseeq(name, "local2")) return LOG_LOCAL2; - if (strcaseeq(name, "local3")) return LOG_LOCAL3; - if (strcaseeq(name, "local4")) return LOG_LOCAL4; - if (strcaseeq(name, "local5")) return LOG_LOCAL5; - if (strcaseeq(name, "local6")) return LOG_LOCAL6; - if (strcaseeq(name, "local7")) return LOG_LOCAL7; - if (strcaseeq(name, "launchd")) return LOG_LAUNCHD; - - return -1; -} - -const char * -asl_syslog_faciliy_num_to_name(int n) -{ - if (n < 0) return NULL; - - if (n == LOG_AUTH) return "auth"; - if (n == LOG_AUTHPRIV) return "authpriv"; - if (n == LOG_CRON) return "cron"; - if (n == LOG_DAEMON) return "daemon"; - if (n == LOG_FTP) return "ftp"; - if (n == LOG_INSTALL) return "install"; - if (n == LOG_KERN) return "kern"; - if (n == LOG_LPR) return "lpr"; - if (n == LOG_MAIL) return "mail"; - if (n == LOG_NETINFO) return "netinfo"; - if (n == LOG_REMOTEAUTH) return "remoteauth"; - if (n == LOG_NEWS) return "news"; - if (n == LOG_AUTH) return "security"; - if (n == LOG_SYSLOG) return "syslog"; - if (n == LOG_USER) return "user"; - if (n == LOG_UUCP) return "uucp"; - if (n == LOG_LOCAL0) return "local0"; - if (n == LOG_LOCAL1) return "local1"; - if (n == LOG_LOCAL2) return "local2"; - if (n == LOG_LOCAL3) return "local3"; - if (n == LOG_LOCAL4) return "local4"; - if (n == LOG_LOCAL5) return "local5"; - if (n == LOG_LOCAL6) return "local6"; - if (n == LOG_LOCAL7) return "local7"; - if (n == LOG_LAUNCHD) return "launchd"; - - return NULL; -} - -/* - * utility for converting a time string into a time_t - * we only deal with the following formats: - * Canonical form YYYY.MM.DD hh:mm:ss UTC - * ctime() form Mth dd hh:mm:ss (e.g. Aug 25 09:54:37) - * absolute form - # seconds since the epoch (e.g. 1095789191) - * relative time - seconds before or after now (e.g. -300, +43200) - * relative time - days/hours/minutes/seconds before or after now (e.g. -1d, +6h, +30m, -10s) - */ - -#define CANONICAL_TIME_REX "^[0-9][0-9][0-9][0-9].[01]?[0-9].[0-3]?[0-9][ ]+[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9][ ]+UTC$" -#define CTIME_REX "^[adfjmnos][aceopu][bcglnprtvy][ ]+[0-3]?[0-9][ ]+[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9]$" -#define ABSOLUTE_TIME_REX "^[0-9]+[s]?$" -#define RELATIVE_TIME_REX "^[\\+-\\][0-9]+[smhdw]?$" - -#define SECONDS_PER_MINUTE 60 -#define SECONDS_PER_HOUR 3600 -#define SECONDS_PER_DAY 86400 -#define SECONDS_PER_WEEK 604800 - -static regex_t rex_canon, rex_ctime, rex_abs, rex_rel; -static int reg_status = 0; - -/* - * We use the last letter in the month name to determine - * the month number (0-11). There are two collisions: - * Jan and Jun both end in n - * Mar and Apr both end in r - * In these cases we check the second letter. - * - * The MTH_LAST array maps the last letter to a number. - */ -static const int8_t MTH_LAST[] = {-1, 1, 11, -1, -1, -1, 7, -1, -1, -1, -1, 6, -1, 5, -1, 8, -1, 3, -1, 9, -1, 10, -1, -1, 4, -1}; - -static int -_month_num(char *s) -{ - int i; - int8_t v8; - - v8 = -1; - if (s[2] > 90) v8 = s[2] - 'a'; - else v8 = s[2] - 'A'; - - if ((v8 < 0) || (v8 > 25)) return -1; - - v8 = MTH_LAST[v8]; - if (v8 < 0) return -1; - - i = v8; - if ((i == 5) && ((s[1] == 'a') || (s[1] == 'A'))) return 0; - if ((i == 3) && ((s[1] == 'a') || (s[1] == 'A'))) return 2; - return i; -} - -time_t -asl_parse_time(const char *in) +asl_object_t +asl_open_path(const char *path, uint32_t opts) { - int len, y; - struct tm t; - time_t tick, delta, factor; - char *str, *p, *x; - static dispatch_once_t once; - - if (in == NULL) return -1; - - dispatch_once(&once, ^{ - int status; - int rflags = REG_EXTENDED | REG_NOSUB | REG_ICASE; - - memset(&rex_canon, 0, sizeof(regex_t)); - status = regcomp(&rex_canon, CANONICAL_TIME_REX, rflags); - if (status != 0) reg_status = -1; - - memset(&rex_ctime, 0, sizeof(regex_t)); - status = regcomp(&rex_ctime, CTIME_REX, rflags); - if (status != 0) reg_status = -1; - - memset(&rex_abs, 0, sizeof(regex_t)); - status = regcomp(&rex_abs, ABSOLUTE_TIME_REX, rflags); - if (status != 0) reg_status = -1; + struct stat sb; + asl_file_t *fout = NULL; + asl_store_t *sout = NULL; - memset(&rex_rel, 0, sizeof(regex_t)); - status = regcomp(&rex_rel, RELATIVE_TIME_REX, rflags); - if (status != 0) reg_status = -1; - }); - - if (reg_status < 0) return -1; - - len = strlen(in) + 1; + if (opts == 0) opts = ASL_OPT_OPEN_READ; - if (regexec(&rex_abs, in, 0, NULL, 0) == 0) + if (opts & ASL_OPT_OPEN_READ) { - /* - * Absolute time (number of seconds since the epoch) - */ - str = strdup(in); - if (str == NULL) return -1; - - if ((str[len-2] == 's') || (str[len-2] == 'S')) str[len-2] = '\0'; - - tick = atol(str); - free(str); - - return tick; - } - else if (regexec(&rex_rel, in, 0, NULL, 0) == 0) - { - /* - * Reletive time (number of seconds before or after right now) - */ - str = strdup(in); - if (str == NULL) return -1; + if (path == NULL) + { + if (asl_store_open_read(ASL_PLACE_DATABASE_DEFAULT, &sout) != ASL_STATUS_OK) return NULL; + return (asl_object_t)sout; + } - factor = 1; + memset(&sb, 0, sizeof(struct stat)); + if (stat(path, &sb) < 0) return NULL; - if ((str[len-2] == 's') || (str[len-2] == 'S')) + if (sb.st_mode & S_IFREG) { - str[len-2] = '\0'; + if (asl_file_open_read(path, &fout) != ASL_STATUS_OK) return NULL; + return (asl_object_t)fout; } - else if ((str[len-2] == 'm') || (str[len-2] == 'M')) + else if (sb.st_mode & S_IFDIR) { - str[len-2] = '\0'; - factor = SECONDS_PER_MINUTE; + if (asl_store_open_read(path, &sout) != ASL_STATUS_OK) return NULL; + return (asl_object_t)sout; } - else if ((str[len-2] == 'h') || (str[len-2] == 'H')) + + return NULL; + } + else if (opts & ASL_OPT_OPEN_WRITE) + { + if (path == NULL) return NULL; + + memset(&sb, 0, sizeof(struct stat)); + if (stat(path, &sb) < 0) { - str[len-2] = '\0'; - factor = SECONDS_PER_HOUR; + if (errno != ENOENT) return NULL; + + if (opts & ASL_OPT_CREATE_STORE) + { + if (asl_store_open_write(path, &sout) != ASL_STATUS_OK) return NULL; + return (asl_object_t)fout; + } + else + { + if (asl_file_open_write(path, 0644, geteuid(), getegid(), &fout) != ASL_STATUS_OK) return NULL; + return (asl_object_t)fout; + } } - else if ((str[len-2] == 'd') || (str[len-2] == 'D')) + else if (sb.st_mode & S_IFREG) { - str[len-2] = '\0'; - factor = SECONDS_PER_DAY; + if (asl_file_open_write(path, 0644, geteuid(), getegid(), &fout) != ASL_STATUS_OK) return NULL; + return (asl_object_t)fout; } - else if ((str[len-2] == 'w') || (str[len-2] == 'W')) + else if (sb.st_mode & S_IFDIR) { - str[len-2] = '\0'; - factor = SECONDS_PER_WEEK; + if (asl_store_open_write(path, &sout) != ASL_STATUS_OK) return NULL; + return (asl_object_t)sout; } - - tick = time(NULL); - delta = factor * atol(str); - tick += delta; - - free(str); - - return tick; - } - else if (regexec(&rex_canon, in, 0, NULL, 0) == 0) - { - memset(&t, 0, sizeof(struct tm)); - str = strdup(in); - if (str == NULL) return -1; - - /* Get year */ - x = str; - p = strchr(x, '.'); - *p = '\0'; - t.tm_year = atoi(x) - 1900; - - /* Get month */ - x = p + 1; - p = strchr(x, '.'); - *p = '\0'; - t.tm_mon = atoi(x) - 1; - - /* Get day */ - x = p + 1; - p = strchr(x, ' '); - *p = '\0'; - t.tm_mday = atoi(x); - - /* Get hour */ - for (x = p + 1; *x == ' '; x++); - p = strchr(x, ':'); - *p = '\0'; - t.tm_hour = atoi(x); - - /* Get minutes */ - x = p + 1; - p = strchr(x, ':'); - *p = '\0'; - t.tm_min = atoi(x); - - /* Get seconds */ - x = p + 1; - p = strchr(x, ' '); - *p = '\0'; - t.tm_sec = atoi(x); - - free(str); - return timegm(&t); - } - else if (regexec(&rex_ctime, in, 0, NULL, 0) == 0) - { - /* We assume it's in the current year */ - memset(&t, 0, sizeof(struct tm)); - tick = time(NULL); - gmtime_r(&tick, &t); - y = t.tm_year; - - memset(&t, 0, sizeof(struct tm)); - str = strdup(in); - if (str == NULL) return -1; - - t.tm_year = y; - t.tm_mon = _month_num(str); - if (t.tm_mon < 0) return -1; - - for (x = strchr(str, ' '); *x == ' '; x++); - p = strchr(x, ' '); - *p = '\0'; - t.tm_mday = atoi(x); - - /* Get hour */ - for (x = p + 1; *x == ' '; x++); - p = strchr(x, ':'); - *p = '\0'; - t.tm_hour = atoi(x); - - /* Get minutes */ - x = p + 1; - p = strchr(x, ':'); - *p = '\0'; - t.tm_min = atoi(x); - - /* Get seconds */ - x = p + 1; - t.tm_sec = atoi(x); - - t.tm_isdst = -1; - - free(str); - return mktime(&t); } - return -1; + return NULL; } - -#endif /* BUILDING_VARIANT */ diff --git a/libsystem_asl.tproj/src/asl_client.c b/libsystem_asl.tproj/src/asl_client.c new file mode 100644 index 0000000..4dd77db --- /dev/null +++ b/libsystem_asl.tproj/src/asl_client.c @@ -0,0 +1,584 @@ +/* + * Copyright (c) 2013 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 + +#define PUBLIC_OPT_MASK 0x000000ff + +/* private asl_file SPI */ +__private_extern__ ASL_STATUS asl_file_open_write_fd(int descriptor, asl_file_t **s); + +/* private asl SPI */ +__private_extern__ ASL_STATUS asl_client_internal_send(asl_object_t client, asl_object_t msg); + +#pragma mark - +#pragma mark asl_client_t + +static void +_asl_client_free_internal(asl_client_t *client) +{ + uint32_t i; + + if (client == NULL) return; + + if (client->kvdict != NULL) asl_msg_release(client->kvdict); + client->kvdict = NULL; + + if (client->aslfile != NULL) asl_file_close(client->aslfile); + client->aslfile = NULL; + + for (i = 0; i < client->out_count; i++) + { + free(client->out_list[i].mfmt); + free(client->out_list[i].tfmt); + } + + free(client->out_list); + client->out_list = NULL; + + free(client); +} + +asl_client_t * +asl_client_open(const char *ident, const char *facility, uint32_t opts) +{ + asl_client_t *client = (asl_client_t *)calloc(1, sizeof(asl_client_t)); + if (client == NULL) + { + errno = ENOMEM; + return NULL; + } + + client->asl_type = ASL_TYPE_CLIENT; + client->refcount = 1; + + client->kvdict = asl_msg_new(ASL_TYPE_MSG); + if (client->kvdict == NULL) + { + asl_client_release(client); + errno = ENOMEM; + return NULL; + } + + client->options = opts & PUBLIC_OPT_MASK; + + client->pid = getpid(); + client->uid = getuid(); + client->gid = getgid(); + + if (ident != NULL) + { + asl_msg_set_key_val(client->kvdict, ASL_KEY_SENDER, ident); + } + else + { + char *name = *(*_NSGetArgv()); + if (name != NULL) + { + char *x = strrchr(name, '/'); + if (x != NULL) x++; + else x = name; + asl_msg_set_key_val(client->kvdict, ASL_KEY_SENDER, x); + } + } + + if (facility != NULL) + { + asl_msg_set_key_val(client->kvdict, ASL_KEY_FACILITY, facility); + } + else if (client->uid == 0) + { + asl_msg_set_key_val(client->kvdict, ASL_KEY_FACILITY, asl_syslog_faciliy_num_to_name(LOG_DAEMON)); + } + else + { + asl_msg_set_key_val(client->kvdict, ASL_KEY_FACILITY, asl_syslog_faciliy_num_to_name(LOG_USER)); + } + + client->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE); + + if (client->options & ASL_OPT_STDERR) + { + /* only add stderr if it is valid */ + if (fcntl(STDERR_FILENO, F_GETFD) >= 0) + { + asl_client_add_output_file(client, fileno(stderr), ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG), ASL_ENCODE_SAFE); + } + else + { + /* stderr has been closed, ignore ASL_OPT_STDERR flag */ + client->options &= ~ASL_OPT_STDERR; + } + } + + return client; +} + +asl_client_t * +asl_client_open_from_file(int descriptor, const char *ident, const char *facility) +{ + uint32_t status; + asl_client_t *client = asl_client_open(ident, facility, 0); + if (client == NULL) return NULL; + + client->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG); + + status = asl_file_open_write_fd(descriptor, &(client->aslfile)); + if (status != ASL_STATUS_OK) + { + _asl_client_free_internal(client); + return NULL; + } + + client->aslfileid = 1; + + return client; +} + +asl_client_t * +asl_client_retain(asl_client_t *client) +{ + if (client == NULL) return NULL; + asl_retain((asl_object_t)client); + return client; +} + +void +asl_client_release(asl_client_t *client) +{ + if (client == NULL) return; + asl_release((asl_object_t)client); +} + +#pragma mark - +#pragma mark database access + +ASL_STATUS +asl_client_send(asl_client_t *client, asl_msg_t *msg) +{ + return asl_client_internal_send((asl_object_t)client, (asl_object_t)msg); +} + +static asl_msg_list_t * +_do_server_match(asl_msg_list_t *qlist, size_t *last, size_t start, size_t count, uint32_t duration, int dir) +{ + char *str, *res = NULL; + uint32_t len, reslen, status; + uint64_t last64, start64, count64; + kern_return_t kstatus; + asl_msg_list_t *out; + caddr_t vmstr; + mach_port_t asl_server_port = asl_core_get_service_port(0); + + if (asl_server_port == MACH_PORT_NULL) return NULL; + + str = NULL; + if (qlist == NULL) + { + asprintf(&str, "0\n"); + len = 3; + } + else + { + str = asl_msg_list_to_string(qlist, &len); + } + + if (str == NULL) return NULL; + + kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE); + if (kstatus != KERN_SUCCESS) return NULL; + + memmove(vmstr, str, len); + free(str); + + last64 = 0; + start64 = start; + count64 = count; + + kstatus = _asl_server_match(asl_server_port, vmstr, len, start64, count64, duration, dir, (caddr_t *)&res, &reslen, &last64, (int *)&status); + *last = last64; + + out = asl_msg_list_from_string(res); + vm_deallocate(mach_task_self(), (vm_address_t)res, reslen); + + return out; +} + +static asl_msg_list_t * +_do_server_search(asl_msg_t *q) +{ + asl_msg_list_t *out; + char *qstr, *str, *res = NULL; + uint32_t len, reslen = 0, status = ASL_STATUS_OK; + uint64_t cmax = 0; + kern_return_t kstatus; + caddr_t vmstr; + mach_port_t asl_server_port = asl_core_get_service_port(0); + + if (asl_server_port == MACH_PORT_NULL) return NULL; + + len = 0; + qstr = asl_msg_to_string(q, &len); + + str = NULL; + if (qstr == NULL) + { + asprintf(&str, "0\n"); + len = 3; + } + else + { + asprintf(&str, "1\n%s\n", qstr); + len += 3; + free(qstr); + } + + if (str == NULL) return NULL; + + kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE); + if (kstatus != KERN_SUCCESS) return NULL; + + memmove(vmstr, str, len); + free(str); + + kstatus = _asl_server_query_2(asl_server_port, vmstr, len, 0, 0, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status); + if (kstatus != KERN_SUCCESS) return NULL; + + out = asl_msg_list_from_string(res); + vm_deallocate(mach_task_self(), (vm_address_t)res, reslen); + + return out; +} + +static asl_msg_list_t * +_do_store_match(asl_msg_list_t *qlist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t direction) +{ + asl_msg_list_t *out; + uint32_t status; + uint64_t l64 = 0, s64; + asl_store_t *store = NULL; + + uint32_t len; + char *str = asl_msg_list_to_string(qlist, &len); + free(str); + + status = asl_store_open_read(NULL, &store); + if (status != 0) return NULL; + if (store == NULL) return NULL; + + s64 = start; + out = asl_store_match(store, qlist, &l64, s64, count, duration, direction); + *last = l64; + + asl_store_close(store); + + return out; +} + +static asl_msg_list_t * +_do_store_search(asl_msg_t *query) +{ + asl_msg_list_t *out, *qlist = NULL; + uint32_t status; + uint16_t op; + uint64_t last = 0, start = 0; + asl_store_t *store = NULL; + const char *val = NULL; + + /* check for "ASLMessageId >[=] n" and set start_id */ + status = asl_msg_lookup(query, ASL_KEY_MSG_ID, &val, &op); + if ((status == 0) && (val != NULL) && (op & ASL_QUERY_OP_GREATER)) + { + if (op & ASL_QUERY_OP_EQUAL) start = atoll(val); + else start = atoll(val) + 1; + } + + status = asl_store_open_read(NULL, &store); + if (status != 0) return NULL; + if (store == NULL) return NULL; + + if (query != NULL) + { + qlist = asl_msg_list_new(); + asl_msg_list_append(qlist, query); + } + + out = asl_store_match(store, qlist, &last, start, 0, 0, 1); + asl_store_close(store); + + asl_msg_list_release(qlist); + return out; +} + +asl_msg_list_t * +asl_client_match(asl_client_t *client, asl_msg_list_t *qlist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t direction) +{ + if (asl_store_location() == ASL_STORE_LOCATION_FILE) return _do_store_match(qlist, last, start, count, duration, direction); + return _do_server_match(qlist, last, start, count, duration, direction); +} + +asl_msg_list_t * +asl_client_search(asl_client_t *client, asl_msg_t *query) +{ + if (asl_store_location() == ASL_STORE_LOCATION_FILE) return _do_store_search(query); + return _do_server_search(query); +} + + +#pragma mark - +#pragma mark output control + +/* returns last filter value, or -1 on error */ +int +asl_client_set_filter(asl_client_t *client, int filter) +{ + int last; + + if (client == NULL) return -1; + last = client->filter; + client->filter = filter; + return last; +} + +ASL_STATUS +asl_client_add_output_file(asl_client_t *client, int descriptor, const char *mfmt, const char *tfmt, int filter, int text_encoding) +{ + uint32_t i; + + if (client == NULL) return ASL_STATUS_FAILED; + + for (i = 0; i < client->out_count; i++) + { + if (client->out_list[i].fd == descriptor) + { + /* update message format, time format, filter, and text encoding */ + free(client->out_list[i].mfmt); + client->out_list[i].mfmt = NULL; + if (mfmt != NULL) client->out_list[i].mfmt = strdup(mfmt); + + free(client->out_list[i].tfmt); + client->out_list[i].tfmt = NULL; + if (tfmt != NULL) client->out_list[i].tfmt = strdup(tfmt); + + client->out_list[i].encoding = text_encoding; + client->out_list[i].filter = filter; + + return ASL_STATUS_OK; + } + } + + if (client->out_count == 0) client->out_list = NULL; + client->out_list = (asl_out_file_t *)reallocf(client->out_list, (1 + client->out_count) * sizeof(asl_out_file_t)); + + if (client->out_list == NULL) return ASL_STATUS_FAILED; + + 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; + if (mfmt != NULL) client->out_list[client->out_count].mfmt = strdup(mfmt); + if (tfmt != NULL) client->out_list[client->out_count].tfmt = strdup(tfmt); + + client->out_count++; + + return ASL_STATUS_OK; +} + +/* returns last filter value, or -1 on error */ +int +asl_client_set_output_file_filter(asl_client_t *client, int descriptor, int filter) +{ + uint32_t i; + int last = 0; + + if (client == NULL) return -1; + + for (i = 0; i < client->out_count; i++) + { + if (client->out_list[i].fd == descriptor) + { + /* update filter */ + last = client->out_list[i].filter; + client->out_list[i].filter = filter; + break; + } + } + + return last; +} + +ASL_STATUS +asl_client_remove_output_file(asl_client_t *client, int descriptor) +{ + uint32_t i; + int x; + + if (client == NULL) return ASL_STATUS_INVALID_ARG; + + if (client->out_count == 0) return ASL_STATUS_OK; + + x = -1; + for (i = 0; i < client->out_count; i++) + { + if (client->out_list[i].fd == descriptor) + { + x = i; + break; + } + } + + if (x == -1) return ASL_STATUS_OK; + + free(client->out_list[x].mfmt); + free(client->out_list[x].tfmt); + + for (i = x + 1; i < client->out_count; i++, x++) + { + client->out_list[x] = client->out_list[i]; + } + + client->out_count--; + + if (client->out_count == 0) + { + free(client->out_list); + client->out_list = NULL; + } + else + { + client->out_list = (asl_out_file_t *)reallocf(client->out_list, client->out_count * sizeof(asl_out_file_t)); + + if (client->out_list == NULL) + { + client->out_count = 0; + return ASL_STATUS_FAILED; + } + } + + return ASL_STATUS_OK; +} + +#pragma mark - +#pragma mark dictionary access + +asl_msg_t * +asl_client_kvdict(asl_client_t *client) +{ + if (client == NULL) return NULL; + return client->kvdict; +} + +#pragma mark - +#pragma mark asl_object support + +static void +_jump_dealloc(asl_object_private_t *obj) +{ + _asl_client_free_internal((asl_client_t *)obj); +} + +static void +_jump_append(asl_object_private_t *obj, asl_object_private_t *newobj) +{ + int type = asl_get_type((asl_object_t)newobj); + + if (type == ASL_TYPE_LIST) + { + asl_msg_t *msg; + asl_msg_list_reset_iteration((asl_msg_list_t *)newobj, 0); + while (NULL != (msg = asl_msg_list_next((asl_msg_list_t *)newobj))) + { + if (asl_client_internal_send((asl_object_t)obj, (asl_object_t)msg) != ASL_STATUS_OK) return; + } + } + else if ((type == ASL_TYPE_MSG) || (type == ASL_TYPE_QUERY)) + { + asl_client_internal_send((asl_object_t)obj, (asl_object_t)newobj); + } +} + +static asl_object_private_t * +_jump_search(asl_object_private_t *obj, asl_object_private_t *query) +{ + int type = asl_get_type((asl_object_t)query); + if ((query != NULL) && (type != ASL_TYPE_MSG) && (type != ASL_TYPE_QUERY)) return NULL; + + return (asl_object_private_t *)asl_client_search((asl_client_t *)obj, (asl_msg_t *)query); +} + +static asl_object_private_t * +_jump_match(asl_object_private_t *obj, asl_object_private_t *qlist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t dir) +{ + asl_msg_list_t *out = NULL; + int type = asl_get_type((asl_object_t)qlist); + + if ((qlist != NULL) && (type != ASL_TYPE_LIST)) return NULL; + + out = asl_client_match((asl_client_t *)obj, (asl_msg_list_t *)qlist, last, start, count, duration, dir); + return (asl_object_private_t *)out; +} + +__private_extern__ const asl_jump_table_t * +asl_client_jump_table() +{ + static const asl_jump_table_t jump = + { + .alloc = NULL, + .dealloc = &_jump_dealloc, + .set_key_val_op = NULL, + .unset_key = NULL, + .get_val_op_for_key = NULL, + .get_key_val_op_at_index = NULL, + .count = NULL, + .next = NULL, + .prev = NULL, + .get_object_at_index = NULL, + .set_iteration_index = NULL, + .remove_object_at_index = NULL, + .append = &_jump_append, + .prepend = NULL, + .search = &_jump_search, + .match = &_jump_match + }; + + return &jump; +} + diff --git a/libsystem_asl.tproj/src/asl_core.c b/libsystem_asl.tproj/src/asl_core.c index b363d2d..3ae25de 100644 --- a/libsystem_asl.tproj/src/asl_core.c +++ b/libsystem_asl.tproj/src/asl_core.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2011 Apple Inc. All rights reserved. + * Copyright (c) 2007-2013 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -23,21 +23,38 @@ #include #include +#include +#include +#include #include #include #include #include #include #include - +#include +#include #include #include #include #include #include +#include -#define ASL_STRING_QUANTUM 256 -static const char *cvis_7_13 = "abtnvfr"; +const char *ASL_LEVEL_TO_STRING[] = +{ + ASL_STRING_EMERG, + ASL_STRING_ALERT, + ASL_STRING_CRIT, + ASL_STRING_ERR, + ASL_STRING_WARNING, + ASL_STRING_NOTICE, + ASL_STRING_INFO, + ASL_STRING_DEBUG +}; + +static char *asl_filesystem_path_database = NULL; +static char *asl_filesystem_path_archive = NULL; /* * Message ID generation @@ -58,6 +75,44 @@ static pthread_mutex_t core_lock = PTHREAD_MUTEX_INITIALIZER; c -= a; c -= b; c ^= (b>>15); \ } +/* + * Get ASL server mach port. + * reset != 0 flushes cached port. + * reset < 0 returns MACH_PORT_NULL + */ +mach_port_t +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; + server_port = MACH_PORT_NULL; + mach_port_deallocate(mach_task_self(), tmp); + } + + if (reset < 0) return MACH_PORT_NULL; + + if (server_port != MACH_PORT_NULL) return server_port; + + tmp = MACH_PORT_NULL; + char *str = getenv("ASL_DISABLE"); + if ((str != NULL) && (!strcmp(str, "1"))) return MACH_PORT_NULL; + + kstatus = bootstrap_look_up2(bootstrap_port, ASL_SERVICE_NAME, &tmp, 0, BOOTSTRAP_PRIVILEGED_SERVER); + if ((kstatus != KERN_SUCCESS) || (tmp == MACH_PORT_NULL)) return MACH_PORT_NULL; + + if (!OSAtomicCompareAndSwap32Barrier(MACH_PORT_NULL, tmp, (int32_t *)&server_port)) + { + mach_port_deallocate(mach_task_self(), tmp); + } + + return server_port; +} + /* * Hash is used to improve string search. */ @@ -140,7 +195,14 @@ asl_core_error(uint32_t code) return "Operation Failed"; } -static uint32_t +const char * +asl_core_level_to_string(uint32_t level) +{ + if (level > ASL_LEVEL_DEBUG) return "invalid"; + return ASL_LEVEL_TO_STRING[level]; +} + +static ASL_STATUS asl_core_check_user_access(int32_t msgu, int32_t readu) { /* -1 means anyone may read */ @@ -152,7 +214,7 @@ asl_core_check_user_access(int32_t msgu, int32_t readu) return ASL_STATUS_ACCESS_DENIED; } -static uint32_t +static ASL_STATUS asl_core_check_group_access(int32_t msgg, int32_t readu, int32_t readg) { int check; @@ -175,7 +237,7 @@ asl_core_check_group_access(int32_t msgg, int32_t readu, int32_t readg) return ASL_STATUS_ACCESS_DENIED; } -uint32_t +ASL_STATUS asl_core_check_access(int32_t msgu, int32_t msgg, int32_t readu, int32_t readg, uint16_t flags) { uint16_t uset, gset; @@ -261,6 +323,49 @@ asl_core_new_msg_id(uint64_t start) return out; } +const char * +asl_filesystem_path(uint32_t place) +{ + static dispatch_once_t once; + + dispatch_once(&once, ^{ + char *asl_var_log = NULL; + const char *const_asl_var_log = "/var/log"; + +#if TARGET_IPHONE_SIMULATOR + asl_var_log = getenv("SIMULATOR_LOG_ROOT"); +#endif + + if (asl_var_log != NULL) const_asl_var_log = (const char *)asl_var_log; + + asprintf(&asl_filesystem_path_database, "%s/asl", const_asl_var_log); + asprintf(&asl_filesystem_path_archive, "%s/asl.archive", const_asl_var_log); + }); + + switch (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: + { + return NULL; + } + } + + return NULL; +} + +#pragma mark - +#pragma mark data buffer encoding + /* * asl_core_encode_buffer * encode arbitrary data as a C string without embedded zero (nul) characters @@ -277,7 +382,7 @@ asl_core_new_msg_id(uint64_t start) * The output string is preceded by L[0] L[1], and is nul terminated. * The output length is 2 + n + N(L[0]) + N(L[1]) + 1 * where N(x) is the number of occurrences of x in the input string. - * The worst case occurs when all characters are equally frequent, + * The worst case occurs when all characters are equally frequent, * In that case the output size will less that 1% larger than the input. */ char * @@ -439,462 +544,582 @@ asl_core_decode_buffer(const char *in, char **buf, uint32_t *len) return 0; } -/* asl_string_t support */ - -asl_string_t * -asl_string_new(uint32_t encoding) -{ - asl_string_t *str = (asl_string_t *)calloc(1, sizeof(asl_string_t)); - if (str == NULL) return NULL; +#pragma mark - +#pragma mark time parsing - str->encoding = encoding; - str->delta = ASL_STRING_QUANTUM; - if (encoding & ASL_STRING_VM) str->delta = PAGE_SIZE; - str->bufsize = 0; - str->cursor = 0; - - if (encoding & ASL_STRING_LEN) asl_string_append_no_encoding(str, " 0 "); - return str; -} - -void -asl_string_free(asl_string_t *str) -{ - if (str == NULL) return; +/* + * utility for converting a time string into a time_t + * we only deal with the following formats: + * dotted form YYYY.MM.DD hh:mm:ss UTC + * ctime() form Mth dd hh:mm:ss (e.g. Aug 25 09:54:37) + * absolute form - # seconds since the epoch (e.g. 1095789191) + * relative time - seconds before or after now (e.g. -300, +43200) + * relative time - days/hours/minutes/seconds before or after now (e.g. -1d, +6h, +30m, -10s) + * ISO8601 - YYYY[-]MM[-]DDTHH[:]MM[:]SS optionally followed by Z or +/-HH[[:]MM] + */ - if (str->encoding & ASL_STRING_VM) - { - vm_deallocate(mach_task_self(), (vm_address_t)str->buf, str->bufsize); - } - else - { - free(str->buf); - } +/* + * light(er)-weight replcaement (in place of regex) for asl_core_parse_time + */ - free(str); -} +#define MFLAG_INCLUDE 0x00000001 +#define MFLAG_EXCLUDE 0x00000002 -char * -asl_string_free_return_bytes(asl_string_t *str) -{ - char *out; - if (str == NULL) return NULL; +#define DIGITS "0123456789" +#define WHITESPACE " " - out = str->buf; - free(str); - return out; -} +#define SECONDS_PER_MINUTE 60 +#define SECONDS_PER_HOUR 3600 +#define SECONDS_PER_DAY 86400 +#define SECONDS_PER_WEEK 604800 -char * -asl_string_bytes(asl_string_t *str) +/* + * Match between mincount and maxcount characters in or not in mset. + * maxcount == 0 means no limit. + * + */ +bool +asl_core_str_match(const char *target, const char *mset, uint32_t mincount, uint32_t maxcount, uint32_t flags, uint32_t *length) { - if (str == NULL) return NULL; - return str->buf; + 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); } -/* length includes trailing nul */ -size_t -asl_string_length(asl_string_t *str) +bool +asl_core_str_match_char(const char *target, const char c, uint32_t mincount, uint32_t flags, uint32_t *length) { - if (str == NULL) return 0; - if (str->cursor == 0) return 0; - - return str->cursor + 1; + 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); } -size_t -asl_string_allocated_size(asl_string_t *str) +uint32_t +asl_core_str_to_uint32(const char *target, uint32_t length) { - if (str == NULL) return 0; - return str->bufsize; + uint32_t i, d, out = 0; + + for (i = 0; i < length; i++) + { + d = target[i] - '0'; + out = (out * 10) + d; + } + + return out; } -static int -_asl_string_grow(asl_string_t *str, size_t len) +static bool +asl_core_str_match_absolute_or_relative_time(const char *target, time_t *tval, uint32_t *tlen) { - size_t newlen = 0; - - if (str == NULL) return -1; - if (len == 0) return 0; - - if (str->bufsize == 0) - { - newlen = ((len + str->delta - 1) / str->delta) * str->delta; - } - else + uint32_t len; + int32_t val, sign = 1; + 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) { - /* used size is (str->cursor + 1) including tailiing nul */ - if (len <= (str->bufsize - (str->cursor + 1))) return 0; - - /* really this is ((str->cursor + 1) + len + (str->delta - 1)) */ - newlen = ((str->cursor + len + str->delta) / str->delta) * str->delta; + /* relative time */ + start = time(NULL); + if (*p == '-') sign = -1; } - - if (str->encoding & ASL_STRING_VM) - { - kern_return_t kstatus; - vm_address_t new = 0; - - kstatus = vm_allocate(mach_task_self(), &new, newlen, TRUE); - if (kstatus != KERN_SUCCESS) - { - new = 0; - newlen = 0; - return -1; - } - if (str->buf != NULL) - { - memcpy((void *)new, str->buf, str->bufsize); - vm_deallocate(mach_task_self(), (vm_address_t)str->buf, str->bufsize); - } - - str->buf = (char *)new; - str->bufsize = newlen; - } - else + /* [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') { - str->buf = reallocf(str->buf, newlen); - if (str->buf == NULL) - { - str->cursor = 0; - str->bufsize = 0; - return -1; - } - - str->bufsize = newlen; + test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len); + if (!test) return false; } - - return 0; + + if (tlen != NULL) *tlen = p - target; + if (tval != NULL) *tval = start + (sign * val); + + return true; } -asl_string_t * -asl_string_append_char_no_encoding(asl_string_t *str, const char c) +static int +_month_num(const char *s) { - size_t len; + if (!strncasecmp(s, "jan", 3)) return 0; + if (!strncasecmp(s, "feb", 3)) return 1; + if (!strncasecmp(s, "mar", 3)) return 2; + if (!strncasecmp(s, "apr", 3)) return 3; + if (!strncasecmp(s, "may", 3)) return 4; + if (!strncasecmp(s, "jun", 3)) return 5; + if (!strncasecmp(s, "jul", 3)) return 6; + if (!strncasecmp(s, "aug", 3)) return 7; + if (!strncasecmp(s, "sep", 3)) return 8; + if (!strncasecmp(s, "oct", 3)) return 9; + if (!strncasecmp(s, "nov", 3)) return 10; + if (!strncasecmp(s, "dec", 3)) return 11; + return -1; - if (str == NULL) return NULL; +} +/* + * Match ctime() format - Mth [D]D [h]h:mm:ss + */ +bool +asl_core_str_match_c_time(const char *target, time_t *tval, uint32_t *tlen) +{ + uint32_t len, y; + bool test; + 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; - 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) + + /* 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') { - char tmp[11]; - snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10); - memcpy(str->buf, tmp, 10); + test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len); + if (!test) return false; } - - return str; + + t.tm_isdst = -1; + + if (tlen != NULL) *tlen = p - target; + if (tval != NULL) *tval = mktime(&t); + + return true; } -asl_string_t * -asl_string_append_no_encoding(asl_string_t *str, const char *app) +/* + * Match YYYY.[M]M.[D]D [h]h:mm:ss UTC + */ +static bool +asl_core_str_match_dotted_time(const char *target, time_t *tval, uint32_t *tlen) { - size_t len, applen; - - if (str == NULL) return NULL; - if (app == NULL) return str; - - applen = strlen(app); - len = applen; - if (str->bufsize == 0) len++; - - if (_asl_string_grow(str, len) < 0) return str; - - memcpy(str->buf + str->cursor, app, applen); - - str->cursor += applen; - str->buf[str->cursor] = '\0'; - - if (str->encoding & ASL_STRING_LEN) + uint32_t len; + 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); + if (!test) return false; + t.tm_mon = asl_core_str_to_uint32(p, len); + 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') { - char tmp[11]; - snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10); - memcpy(str->buf, tmp, 10); + test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len); + if (!test) return false; } - - return str; + + if (tlen != NULL) *tlen = p - target; + if (tval != NULL) *tval = timegm(&t); + + return true; } -static asl_string_t * -asl_string_append_internal(asl_string_t *str, const char *app, int encode_space) +/* + * Match YYYY[-]MM[-]DD[Tt]hh[:]hh[:]ss[Zz] or YYYY[-]MM[-]DD[Tt]hh[:]hh[:]ss[+-][H]H[[:]MM] + */ +static bool +asl_core_str_match_iso_8601_time(const char *target, time_t *tval, uint32_t *tlen) { - uint8_t x; + uint32_t len; + bool test; const char *p; - - if (str == NULL) return NULL; - if (app == NULL) return str; - - switch (str->encoding & ASL_ENCODE_MASK) + 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); + if (!test) return false; + t.tm_mon = asl_core_str_to_uint32(p, len); + 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')) { - case ASL_ENCODE_NONE: - { - return asl_string_append_no_encoding(str, app); - } - case ASL_ENCODE_SAFE: - { - /* minor encoding to reduce the likelyhood of spoof attacks */ - const char *p; + t.tm_isdst = -1; + + if (tlen != NULL) *tlen = p - target; + if (tval != NULL) *tval = mktime(&t); + + return true; + } - for (p = app; *p != '\0'; p++) - { - if ((*p == 10) || (*p == 13)) - { - asl_string_append_no_encoding(str, "\n\t"); - } - else if (*p == 8) - { - asl_string_append_no_encoding(str, "^H"); - } - else - { - asl_string_append_char_no_encoding(str, *p); - } - } - - return str; - } - case ASL_ENCODE_ASL: - { - for (p = app; *p != '\0'; p++) - { - int meta = 0; - - x = *p; - - /* Meta chars get \M prefix */ - if (x >= 128) - { - /* except meta-space, which is \240 */ - if (x == 160) - { - asl_string_append_no_encoding(str, "\\240"); - continue; - } - - asl_string_append_no_encoding(str, "\\M"); - x &= 0x7f; - meta = 1; - } - - /* space is either ' ' or \s */ - if (x == 32) - { - if (encode_space == 0) - { - asl_string_append_char_no_encoding(str, ' '); - continue; - } - - asl_string_append_no_encoding(str, "\\s"); - continue; - } - - /* \ is escaped */ - if ((meta == 0) && (x == 92)) - { - asl_string_append_no_encoding(str, "\\\\"); - 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, "\\]"); - continue; - } - - /* DEL is \^? */ - if (x == 127) - { - if (meta == 0) - { - asl_string_append_char_no_encoding(str, '\\'); - } - - asl_string_append_no_encoding(str, "^?"); - continue; - } - - /* 33-126 are printable (add a '-' prefix for meta) */ - if ((x >= 33) && (x <= 126)) - { - if (meta == 1) - { - asl_string_append_char_no_encoding(str, '-'); - } - - asl_string_append_char_no_encoding(str, x); - 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)) - { - asl_string_append_char_no_encoding(str, '\\'); - asl_string_append_char_no_encoding(str, cvis_7_13[x - 7]); - continue; - } - - /* 0 - 31 are ^@ - ^_ (non-meta get a leading \) */ - if (x <= 31) - { - if (meta == 0) - { - asl_string_append_char_no_encoding(str, '\\'); - } - - 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); - } - - return str; - } - case ASL_ENCODE_XML: - { - for (p = app; *p != '\0'; p++) - { - x = *p; - - if (x == '&') - { - asl_string_append_no_encoding(str, "&"); - } - else if (x == '<') - { - asl_string_append_no_encoding(str, "<"); - } - else if (x == '>') - { - asl_string_append_no_encoding(str, ">"); - } - else if (x == '"') - { - asl_string_append_no_encoding(str, """); - } - else if (x == '\'') - { - asl_string_append_no_encoding(str, "'"); - } - else if (iscntrl(x)) - { - char tmp[8]; - snprintf(tmp, sizeof(tmp), "&#x%02hhx;", x); - asl_string_append_no_encoding(str, tmp); - } - else - { - asl_string_append_char_no_encoding(str, x); - } - } - } - default: + /* 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) */ + p += len; + if (*p != '\0') { - return str; + 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; } - - return str; -} - -asl_string_t * -asl_string_append(asl_string_t *str, const char *app) -{ - return asl_string_append_internal(str, app, 0); + + 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') + { + 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; } -asl_string_t * -asl_string_append_asl_key(asl_string_t *str, const char *app) +time_t +asl_core_parse_time(const char *in, uint32_t *tlen) { - return asl_string_append_internal(str, app, 1); -} + time_t tval = 0; + uint32_t inlen; + + if (tlen != NULL) *tlen = 0; -asl_string_t * -asl_string_append_op(asl_string_t *str, uint32_t op) -{ - char opstr[8]; - uint32_t i; + if (in == NULL) return -1; - if (str == NULL) return NULL; + /* + * 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; - if (op == ASL_QUERY_OP_NULL) + /* leading plus or minus means it must be a relative time */ + if ((in[0] == '+') || (in[0] == '-')) { - return asl_string_append_char_no_encoding(str, '.'); + if (asl_core_str_match_absolute_or_relative_time(in, &tval, tlen)) return tval; + return -1; } - i = 0; - if (op & ASL_QUERY_OP_CASEFOLD) opstr[i++] = 'C'; - - if (op & ASL_QUERY_OP_REGEX) opstr[i++] = 'R'; - - if (op & ASL_QUERY_OP_NUMERIC) opstr[i++] = 'N'; - - if (op & ASL_QUERY_OP_PREFIX) + /* leading alphabetic char means it must be ctime() format */ + if (((in[0] >= 'a') && (in[0] <= 'z')) || ((in[0] >= 'A') && (in[0] <= 'Z'))) { - if (op & ASL_QUERY_OP_SUFFIX) opstr[i++] = 'S'; - else opstr[i++] = 'A'; + if (asl_core_str_match_c_time(in, &tval, tlen)) return tval; + return -1; } - if (op & ASL_QUERY_OP_SUFFIX) opstr[i++] = 'Z'; - switch (op & ASL_QUERY_OP_TRUE) + /* only absolute, dotted, or iso8601 formats at this point */ + + /* one to for chars means it must be absolute */ + if (inlen < 5) { - case ASL_QUERY_OP_EQUAL: - opstr[i++] = '='; - break; - case ASL_QUERY_OP_GREATER: - opstr[i++] = '>'; - break; - case ASL_QUERY_OP_GREATER_EQUAL: - opstr[i++] = '>'; - opstr[i++] = '='; - break; - case ASL_QUERY_OP_LESS: - opstr[i++] = '<'; - break; - case ASL_QUERY_OP_LESS_EQUAL: - opstr[i++] = '<'; - opstr[i++] = '='; - break; - case ASL_QUERY_OP_NOT_EQUAL: - opstr[i++] = '!'; - break; - case ASL_QUERY_OP_TRUE: - opstr[i++] = 'T'; - break; - default: - break; + if (asl_core_str_match_absolute_or_relative_time(in, &tval, tlen)) return tval; + return -1; } - if (i == 0) + /* check for dot */ + if (in[4] == '.') { - return asl_string_append_char_no_encoding(str, '.'); + if (asl_core_str_match_dotted_time(in, &tval, tlen)) return tval; + return -1; } - opstr[i] = '\0'; - return asl_string_append_no_encoding(str, opstr); + /* 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; } -asl_string_t * -asl_string_append_xml_tag(asl_string_t *str, const char *tag, const char *s) +/* + * asl_parse_time is old SPI used all over the place. + */ +time_t +asl_parse_time(const char *in) { - asl_string_append_no_encoding(str, "\t\t<"); - asl_string_append_no_encoding(str, tag); - asl_string_append_no_encoding(str, ">"); - asl_string_append_internal(str, s, 0); - asl_string_append_no_encoding(str, "\n"); - return str; + return asl_core_parse_time(in, NULL); } diff --git a/libsystem_asl.tproj/src/asl_fd.c b/libsystem_asl.tproj/src/asl_fd.c index af60ccf..f801364 100644 --- a/libsystem_asl.tproj/src/asl_fd.c +++ b/libsystem_asl.tproj/src/asl_fd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Apple Inc. All rights reserved. + * Copyright (c) 2013 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -29,21 +29,19 @@ #include #include #include +#include #include #include #include #include -/* asl.c */ -__private_extern__ void asl_client_release(asl_client_t *asl); -__private_extern__ asl_client_t *asl_client_retain(asl_client_t *asl); - #define BUF_SIZE 512 static dispatch_queue_t redirect_serial_q; static dispatch_group_t read_source_group; -typedef struct { +typedef struct +{ int level; asl_client_t *asl; asl_msg_t *msg; @@ -58,7 +56,8 @@ typedef struct { static asl_redirect_t *redirect_descriptors = NULL; static int n_redirect_descriptors = 0; -/* Read from the FD until there is no more to read and redirect to ASL. +/* + * Read from the FD until there is no more to read and redirect to ASL. * Preconditions: * 1: called from the appropriate serial queue for operating on * redirect_descriptors @@ -69,12 +68,15 @@ static int n_redirect_descriptors = 0; * were processed. If the pipe is still open, the number of read bytes * is returned. */ -static inline int _read_redirect(int descriptor, int flush) { +static inline int +_read_redirect(int descriptor, int flush) +{ int total_read = 0; int nbytes; asl_redirect_t *aslr = &redirect_descriptors[descriptor]; - while ((nbytes = read(descriptor, aslr->w, BUF_SIZE - (aslr->w - aslr->buf) - 1)) > 0) { + while ((nbytes = read(descriptor, aslr->w, BUF_SIZE - (aslr->w - aslr->buf) - 1)) > 0) + { char *s, *p; /* Increment our returned number read */ @@ -85,18 +87,20 @@ static inline int _read_redirect(int descriptor, int flush) { aslr->w[0] = '\0'; /* One line at a time */ - for (p = aslr->buf; p < aslr->w; p = s + 1) { + for (p = aslr->buf; p < aslr->w; p = s + 1) + { /* Find null or \n */ - for (s=p; *s && *s != '\n'; s++); + for (s = p; *s && *s != '\n'; s++); - if (*s == '\n') { - *s='\0'; - } + if (*s == '\n') *s='\0'; - if (s < aslr->w || aslr->buf == p) { + if (s < aslr->w || aslr->buf == p) + { /* Either the first of multiple messages or one message which is larger than our buffer */ asl_log((aslclient)aslr->asl, (aslmsg)aslr->msg, aslr->level, "%s", p); - } else { + } + else + { /* We reached the end of the buffer, move this chunk to the start. */ memmove(aslr->buf, p, BUF_SIZE - (p - aslr->buf)); aslr->w = aslr->buf + (s - p); @@ -104,34 +108,38 @@ static inline int _read_redirect(int descriptor, int flush) { } } - if (p == aslr->w) { + if (p == aslr->w) + { /* Start writing at the beginning in the case where we cleared the buffer */ aslr->w = aslr->buf; } } /* Flush if requested or we're at EOF */ - if (flush || nbytes == 0) { - if (aslr->w > aslr->buf) { + if (flush || nbytes == 0) + { + if (aslr->w > aslr->buf) + { *aslr->w = '\0'; asl_log((aslclient)aslr->asl, (aslmsg)aslr->msg, aslr->level, "%s", aslr->buf); } } - if (nbytes == 0) - return EOF; + if (nbytes == 0) return EOF; return total_read; } -static void read_from_source(void *_source) { +static void +read_from_source(void *_source) +{ dispatch_source_t source = (dispatch_source_t)_source; int descriptor = dispatch_source_get_handle(source); - if (_read_redirect(descriptor, 0) == EOF) { - dispatch_source_cancel(source); - } + if (_read_redirect(descriptor, 0) == EOF) dispatch_source_cancel(source); } -static void cancel_source(void *_source) { +static void +cancel_source(void *_source) +{ dispatch_source_t source = (dispatch_source_t)_source; int descriptor = dispatch_source_get_handle(source); asl_redirect_t *aslr = &redirect_descriptors[descriptor]; @@ -150,24 +158,37 @@ static void cancel_source(void *_source) { dispatch_group_leave(read_source_group); } +__attribute__ ((visibility ("hidden"))) +void +_asl_redirect_fork_child(void) +{ + if (redirect_descriptors) { + free(redirect_descriptors); + n_redirect_descriptors = 0; + redirect_descriptors = NULL; + } +} -static void redirect_atexit(void) { +static void +redirect_atexit(void) +{ int i; /* stdout is linebuffered, so flush the buffer */ - if (redirect_descriptors[STDOUT_FILENO].buf) - fflush(stdout); + if (redirect_descriptors[STDOUT_FILENO].buf) fflush(stdout); /* Cancel all of our dispatch sources, so they flush to ASL */ - for (i=0; i < n_redirect_descriptors; i++) + for (i = 0; i < n_redirect_descriptors; i++) { if (redirect_descriptors[i].read_source) dispatch_source_cancel(redirect_descriptors[i].read_source); + } /* Wait at least three seconds for our sources to flush to ASL */ dispatch_group_wait(read_source_group, dispatch_time(DISPATCH_TIME_NOW, 3LL * NSEC_PER_SEC)); } -static void asl_descriptor_init(void *ctx __unused) +static void +asl_descriptor_init(void *ctx __unused) { assert((redirect_descriptors = calloc(16, sizeof(*redirect_descriptors))) != NULL); n_redirect_descriptors = 16; @@ -181,50 +202,57 @@ static void asl_descriptor_init(void *ctx __unused) atexit(redirect_atexit); } -static int asl_log_from_descriptor(aslclient ac, aslmsg am, int level, int descriptor) { +static int +asl_log_from_descriptor(aslclient ac, aslmsg am, int level, int descriptor) +{ int err __block = 0; static dispatch_once_t once_control; dispatch_once_f(&once_control, NULL, asl_descriptor_init); asl_client_t *asl = (asl_client_t *)ac; asl_msg_t *msg = (asl_msg_t *)am; - if (descriptor < 0) - return EBADF; + if (descriptor < 0) return EBADF; - if (msg != NULL) { + if (msg != NULL) + { msg = asl_msg_copy(msg); - if (msg == NULL) - return ENOMEM; + if (msg == NULL) return ENOMEM; } dispatch_sync(redirect_serial_q, ^{ dispatch_source_t read_source; /* Reallocate if we need more space */ - if (descriptor >= n_redirect_descriptors) { + if (descriptor >= n_redirect_descriptors) + { size_t new_n = 1 << (fls(descriptor) + 1); asl_redirect_t *new_array = realloc(redirect_descriptors, new_n * sizeof(*redirect_descriptors)); - if (!new_array) { + if (!new_array) + { err = errno; return; } + redirect_descriptors = new_array; memset(redirect_descriptors + n_redirect_descriptors, 0, (new_n - n_redirect_descriptors) * sizeof(*redirect_descriptors)); n_redirect_descriptors = new_n; } /* If we're already listening on it, return error. */ - if (redirect_descriptors[descriptor].buf != NULL) { + if (redirect_descriptors[descriptor].buf != NULL) + { err = EBADF; return; } /* Initialize our buffer */ redirect_descriptors[descriptor].buf = (char *)malloc(BUF_SIZE); - if (redirect_descriptors[descriptor].buf == NULL) { + if (redirect_descriptors[descriptor].buf == NULL) + { err = errno; return; } + redirect_descriptors[descriptor].w = redirect_descriptors[descriptor].buf; /* Store our ASL settings */ @@ -245,39 +273,41 @@ static int asl_log_from_descriptor(aslclient ac, aslmsg am, int level, int descr dispatch_resume(read_source); }); - if (err) { - asl_msg_release(msg); - } + if (err) asl_msg_release(msg); return err; } -int asl_log_descriptor(aslclient ac, aslmsg am, int level, int descriptor, uint32_t fd_type) { +int +asl_log_descriptor(aslclient ac, aslmsg am, int level, int descriptor, uint32_t fd_type) +{ int pipepair[2]; int retval; int oerrno = errno; - if (fd_type == ASL_LOG_DESCRIPTOR_READ) - return asl_log_from_descriptor(ac, am, level, descriptor); + if (fd_type == ASL_LOG_DESCRIPTOR_READ) return asl_log_from_descriptor(ac, am, level, descriptor); assert(fd_type == ASL_LOG_DESCRIPTOR_WRITE); /* Create pipe */ - if (pipe(pipepair) == -1) { + if (pipe(pipepair) == -1) + { retval = errno; errno = oerrno; return retval; } /* Close the read descriptor but not the write descriptor on exec */ - if (fcntl(pipepair[0], F_SETFD, FD_CLOEXEC) == -1) { + if (fcntl(pipepair[0], F_SETFD, FD_CLOEXEC) == -1) + { retval = errno; errno = oerrno; return retval; } /* Replace the existing descriptor */ - if (dup2(pipepair[1], descriptor) == -1) { + if (dup2(pipepair[1], descriptor) == -1) + { close(pipepair[0]); close(pipepair[1]); retval = errno; @@ -286,8 +316,7 @@ int asl_log_descriptor(aslclient ac, aslmsg am, int level, int descriptor, uint3 } /* If we capture STDOUT_FILENO, make sure we linebuffer stdout */ - if (descriptor == STDOUT_FILENO) - setlinebuf(stdout); + if (descriptor == STDOUT_FILENO) setlinebuf(stdout); /* Close the duplicate descriptors since they've been reassigned */ close(pipepair[1]); diff --git a/libsystem_asl.tproj/src/asl_file.c b/libsystem_asl.tproj/src/asl_file.c index bf43c7b..ceef2c9 100644 --- a/libsystem_asl.tproj/src/asl_file.c +++ b/libsystem_asl.tproj/src/asl_file.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2011 Apple Inc. All rights reserved. + * Copyright (c) 2007-2013 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,9 @@ */ #include +#include #include +#include #include #include #include @@ -40,11 +42,7 @@ #include #include -extern time_t asl_parse_time(const char *str); -extern int asl_msg_cmp(aslmsg a, aslmsg b); - #define forever for(;;) -#define MILLION 1000000 /* * MSG and STR records have (at least) a type (uint16_t) and a length (uint32_t) @@ -140,7 +138,7 @@ _asl_put_64(uint64_t i, char *h) memcpy(h, &x, 8); } -static uint32_t +static ASL_STATUS asl_file_read_uint32(asl_file_t *s, off_t off, uint32_t *out) { uint32_t status, val; @@ -161,7 +159,7 @@ asl_file_read_uint32(asl_file_t *s, off_t off, uint32_t *out) return ASL_STATUS_OK; } -static uint32_t +static ASL_STATUS asl_file_read_uint64(asl_file_t *s, off_t off, uint64_t *out) { uint32_t status; @@ -183,16 +181,40 @@ asl_file_read_uint64(asl_file_t *s, off_t off, uint64_t *out) return ASL_STATUS_OK; } -uint32_t +asl_file_t * +asl_file_retain(asl_file_t *s) +{ + if (s == NULL) return NULL; + asl_retain((asl_object_t)s); + return s; +} + +void +asl_file_release(asl_file_t *s) +{ + if (s == NULL) return; + asl_release((asl_object_t)s); +} + +ASL_STATUS asl_file_close(asl_file_t *s) +{ + if (s == NULL) return ASL_STATUS_OK; + asl_release((asl_object_t)s); + return ASL_STATUS_OK; +} + +static void +_asl_file_free_internal(asl_file_t *s) { file_string_t *x; - if (s == NULL) return ASL_STATUS_OK; + if (s == NULL) return; if (s->version == 1) { - return asl_legacy1_close((asl_legacy1_t *)s->legacy); + asl_legacy1_close((asl_legacy1_t *)s->legacy); + return; } while (s->string_list != NULL) @@ -207,11 +229,9 @@ asl_file_close(asl_file_t *s) memset(s, 0, sizeof(asl_file_t)); free(s); - - return ASL_STATUS_OK; } -__private_extern__ uint32_t +__private_extern__ ASL_STATUS asl_file_open_write_fd(int fd, asl_file_t **s) { time_t now; @@ -225,6 +245,9 @@ asl_file_open_write_fd(int fd, asl_file_t **s) out = (asl_file_t *)calloc(1, sizeof(asl_file_t)); if (out == NULL) return ASL_STATUS_NO_MEMORY; + out->asl_type = ASL_TYPE_FILE; + out->refcount = 1; + out->store = fdopen(fd, "w+"); if (out->store == NULL) { @@ -345,7 +368,7 @@ asl_file_create_return: #endif } -uint32_t +ASL_STATUS asl_file_open_write(const char *path, mode_t mode, uid_t uid, gid_t gid, asl_file_t **s) { int i, status, fd; @@ -363,6 +386,10 @@ asl_file_open_write(const char *path, mode_t mode, uid_t uid, gid_t gid, asl_fil /* must be a plain file */ if (!S_ISREG(sb.st_mode)) return ASL_STATUS_INVALID_STORE; + /* + * If the file exists, we go with the existing mode, uid, and gid. + */ + if (sb.st_size == 0) { fd = open(path, O_RDWR | O_EXCL, mode); @@ -372,10 +399,12 @@ asl_file_open_write(const char *path, mode_t mode, uid_t uid, gid_t gid, asl_fil } else { - /* XXX Check that mode, uid, and gid are correct */ out = (asl_file_t *)calloc(1, sizeof(asl_file_t)); if (out == NULL) return ASL_STATUS_NO_MEMORY; + out->asl_type = ASL_TYPE_FILE; + out->refcount = 1; + out->store = fopen(path, "r+"); if (out->store == NULL) { @@ -467,7 +496,10 @@ asl_file_open_write(const char *path, mode_t mode, uid_t uid, gid_t gid, asl_fil return ASL_STATUS_FAILED; } - /* the file does not exist */ + /* + * If the file does not exist, we set the mode, uid, and gid. + */ + fd = asl_file_create(path, uid, gid, mode); if (fd < 0) return ASL_STATUS_FAILED; @@ -477,12 +509,12 @@ asl_file_open_write(const char *path, mode_t mode, uid_t uid, gid_t gid, asl_fil return aslstatus; } -uint32_t +ASL_STATUS asl_file_compact(asl_file_t *s, const char *path, mode_t mode, uid_t uid, gid_t gid) { asl_file_t *new; struct stat sb; - aslmsg m; + asl_msg_t *m; uint64_t xid; uint32_t status; @@ -512,14 +544,148 @@ asl_file_compact(asl_file_t *s, const char *path, mode_t mode, uid_t uid, gid_t xid = 0; status = asl_file_save(new, m, &xid); - asl_free(m); + asl_msg_release(m); } asl_file_close(new); return status; } -static uint32_t +ASL_STATUS +asl_file_filter(asl_file_t *s, const char *path, asl_msg_list_t *filter, uint32_t flags, mode_t mode, uid_t uid, gid_t gid, uint32_t *dstcount, void (*aux_callback)(const char *auxfile)) +{ + asl_file_t *new; + struct stat sb; + asl_msg_t *m; + uint64_t xid = 0; + uint32_t status, n = 0; + uint32_t matchflag = flags & ASL_FILE_FILTER_FLAG_KEEP_MATCHES; + + if (dstcount != NULL) *dstcount = n; + + if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (path == NULL) return ASL_STATUS_INVALID_ARG; + + if (s->version == 1) return ASL_STATUS_FAILED; + + memset(&sb, 0, sizeof(struct stat)); + + if (stat(path, &sb) == 0) return ASL_STATUS_FAILED; + if (errno != ENOENT) return ASL_STATUS_FAILED; + + status = asl_file_read_set_position(s, ASL_FILE_POSITION_FIRST); + if (status != ASL_STATUS_OK) return status; + + new = NULL; + status = asl_file_open_write(path, mode, uid, gid, &new); + if (status != ASL_STATUS_OK) return status; + new->flags = ASL_FILE_FLAG_UNLIMITED_CACHE | ASL_FILE_FLAG_PRESERVE_MSG_ID; + + while ((status == ASL_STATUS_OK) && (s->cursor != 0)) + { + m = NULL; + status = asl_file_fetch_next(s, &m); + if (status != ASL_STATUS_OK) break; + + /* + * asl_msg_cmp_list is supposed to return 1 for a match, 0 otherwise, + * but just to be sure we only get a 1 or zero, we do an extra test. + */ + uint32_t msgmatch = (asl_msg_cmp_list(m, filter) == 0) ? 0 : 1; + if (msgmatch == matchflag) + { + status = asl_file_save(new, m, &xid); + if (status == ASL_STATUS_OK) n++; + } + else if (aux_callback != NULL) + { + /* check for ASL_KEY_AUX_URL and pass it to callback */ + const char *auxval = asl_msg_get_val_for_key(m, ASL_KEY_AUX_URL); + if (auxval != NULL) aux_callback(auxval); + } + + asl_msg_release(m); + } + + asl_file_close(new); + if (dstcount != NULL) *dstcount = n; + return status; +} + +ASL_STATUS +asl_file_filter_level(asl_file_t *s, const char *path, uint32_t keep_mask, mode_t mode, uid_t uid, gid_t gid, uint32_t *dstcount, void (*aux_callback)(const char *auxfile)) +{ + asl_file_t *new; + struct stat sb; + asl_msg_t *m; + uint64_t xid = 0; + uint32_t status, n = 0; + uint8_t kmcur, kmnew; + + if (dstcount != NULL) *dstcount = n; + + if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (path == NULL) return ASL_STATUS_INVALID_ARG; + + if (s->version == 1) return ASL_STATUS_FAILED; + + memset(&sb, 0, sizeof(struct stat)); + + if (stat(path, &sb) == 0) return ASL_STATUS_FAILED; + if (errno != ENOENT) return ASL_STATUS_FAILED; + + kmnew = keep_mask; + + /* get current filter mask in file's header */ + status = fseeko(s->store, DB_HEADER_FILTER_MASK_OFFSET, SEEK_SET); + if (status != 0) return ASL_STATUS_READ_FAILED; + fread(&kmcur, 1, 1, s->store); + + status = asl_file_read_set_position(s, ASL_FILE_POSITION_FIRST); + if (status != ASL_STATUS_OK) return status; + + new = NULL; + status = asl_file_open_write(path, mode, uid, gid, &new); + if (status != ASL_STATUS_OK) return status; + + new->flags = ASL_FILE_FLAG_UNLIMITED_CACHE | ASL_FILE_FLAG_PRESERVE_MSG_ID; + + while ((status == ASL_STATUS_OK) && (s->cursor != 0)) + { + m = NULL; + status = asl_file_fetch_next(s, &m); + if (status != ASL_STATUS_OK) break; + if (m == NULL) continue; + const char *lval = asl_msg_get_val_for_key(m, ASL_KEY_LEVEL); + if (lval == NULL) continue; + uint32_t level_bit = 0x01 << atoi(lval); + + if (level_bit & keep_mask) + { + status = asl_file_save(new, m, &xid); + if (status == ASL_STATUS_OK) n++; + } + else if (aux_callback != NULL) + { + /* check for ASL_KEY_AUX_URL and pass it to callback */ + const char *auxval = asl_msg_get_val_for_key(m, ASL_KEY_AUX_URL); + if (auxval != NULL) aux_callback(auxval); + } + + asl_msg_release(m); + } + + kmnew = kmcur & kmnew; + status = fseeko(new->store, DB_HEADER_FILTER_MASK_OFFSET, SEEK_SET); + if (status != 0) return ASL_STATUS_READ_FAILED; + fwrite(&kmnew, 1, 1, new->store); + + asl_file_close(new); + if (dstcount != NULL) *dstcount = n; + return status; +} + +static ASL_STATUS asl_file_string_encode(asl_file_t *s, const char *str, uint64_t *out) { uint32_t i, hash, len, x32; @@ -531,6 +697,7 @@ asl_file_string_encode(asl_file_t *s, const char *str, uint64_t *out) char *p; if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (s->store == NULL) return ASL_STATUS_INVALID_STORE; if (str == NULL) return ASL_STATUS_INVALID_ARG; len = strlen(str); @@ -604,7 +771,7 @@ asl_file_string_encode(asl_file_t *s, const char *str, uint64_t *out) s->string_list = sx; - if (((s->flags & ASL_FILE_FLAG_UNLIMITED_CACHE) == 0) && (s->string_count == CACHE_SIZE)) + 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; @@ -622,7 +789,7 @@ asl_file_string_encode(asl_file_t *s, const char *str, uint64_t *out) } else { - s->string_count++; + s->string_cache_count++; } *out = off; @@ -630,11 +797,11 @@ asl_file_string_encode(asl_file_t *s, const char *str, uint64_t *out) } /* - * Encode an aslmsg as a record structure. + * Encode an asl_msg_t *as a record structure. * Creates and caches strings. */ -uint32_t -asl_file_save(asl_file_t *s, aslmsg in, uint64_t *mid) +ASL_STATUS +asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid) { char *buf, *p; uint32_t i, len, x, status; @@ -646,9 +813,10 @@ asl_file_save(asl_file_t *s, aslmsg in, uint64_t *mid) const char *key, *val; if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (s->store == NULL) return ASL_STATUS_INVALID_STORE; if (in == NULL) return ASL_STATUS_INVALID_MESSAGE; - if (s->flags & ASL_FILE_FLAG_READ_ONLY) return ASL_STATUS_READ_ONLY; + if (s->flags & ASL_FILE_FLAG_READ) return ASL_STATUS_READ_ONLY; msg = (asl_msg_t *)in; @@ -677,7 +845,7 @@ asl_file_save(asl_file_t *s, aslmsg in, uint64_t *mid) } else if (!strcmp(key, ASL_KEY_TIME)) { - if (val != NULL) r.time = asl_parse_time(val); + if (val != NULL) r.time = asl_core_parse_time(val, NULL); } else if (!strcmp(key, ASL_KEY_TIME_NSEC)) { @@ -992,7 +1160,7 @@ asl_file_save(asl_file_t *s, aslmsg in, uint64_t *mid) return ASL_STATUS_OK; } -static uint32_t +static ASL_STATUS asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outlen) { char ils[9]; @@ -1004,13 +1172,15 @@ asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outle uint16_t type; off_t off; - *out = NULL; - *outlen = 0; - if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (s->store == NULL) return ASL_STATUS_INVALID_STORE; if (out == NULL) return ASL_STATUS_INVALID_ARG; + if (outlen == NULL) return ASL_STATUS_INVALID_ARG; if (where == 0) return ASL_STATUS_INVALID_ARG; + *out = NULL; + *outlen = 0; + inls = 0; x64 = asl_core_htonq(where); memcpy(&inls, &x64, 1); @@ -1057,6 +1227,7 @@ asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outle if (status != 1) { free(*out); + *out = NULL; return ASL_STATUS_READ_FAILED; } @@ -1065,7 +1236,7 @@ asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outle } static uint16_t -asl_file_fetch_helper_16(asl_file_t *s, char **p, aslmsg m, const char *key) +asl_file_fetch_helper_16(asl_file_t *s, char **p, asl_msg_t *m, const char *key) { uint16_t out; char str[256]; @@ -1076,13 +1247,13 @@ asl_file_fetch_helper_16(asl_file_t *s, char **p, aslmsg m, const char *key) if ((m == NULL) || (key == NULL)) return out; snprintf(str, sizeof(str), "%hu", out); - asl_set(m, key, str); + asl_msg_set_key_val(m, key, str); return out; } static uint32_t -asl_file_fetch_helper_32(asl_file_t *s, char **p, aslmsg m, const char *key, int ignore, uint32_t ignoreval) +asl_file_fetch_helper_32(asl_file_t *s, char **p, asl_msg_t *m, const char *key, int ignore, uint32_t ignoreval) { uint32_t out, doit; char str[256]; @@ -1097,14 +1268,14 @@ asl_file_fetch_helper_32(asl_file_t *s, char **p, aslmsg m, const char *key, int if (doit != 0) { snprintf(str, sizeof(str), "%u", out); - asl_set(m, key, str); + asl_msg_set_key_val(m, key, str); } return out; } static uint64_t -asl_file_fetch_helper_64(asl_file_t *s, char **p, aslmsg m, const char *key) +asl_file_fetch_helper_64(asl_file_t *s, char **p, asl_msg_t *m, const char *key) { uint64_t out; char str[256]; @@ -1115,13 +1286,13 @@ asl_file_fetch_helper_64(asl_file_t *s, char **p, aslmsg m, const char *key) if ((m == NULL) || (key == NULL)) return out; snprintf(str, sizeof(str), "%llu", out); - asl_set(m, key, str); + asl_msg_set_key_val(m, key, str); return out; } static uint64_t -asl_file_fetch_helper_str(asl_file_t *s, char **p, aslmsg m, const char *key, uint32_t *err) +asl_file_fetch_helper_str(asl_file_t *s, char **p, asl_msg_t *m, const char *key, uint32_t *err) { uint64_t out; char *val; @@ -1138,26 +1309,27 @@ asl_file_fetch_helper_str(asl_file_t *s, char **p, aslmsg m, const char *key, ui if (err != NULL) *err = status; if ((status == ASL_STATUS_OK) && (val != NULL)) { - asl_set(m, key, val); + asl_msg_set_key_val(m, key, val); free(val); } return out; } -static uint32_t -asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, aslmsg *msg) +static ASL_STATUS +asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, asl_msg_t **msg) { char *buf, *p, *k, *v; file_record_t r; uint32_t i, status, len, buflen, kvn; uint64_t x64, kv; - aslmsg out; + asl_msg_t *out; off_t off; if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (s->store == NULL) return ASL_STATUS_INVALID_STORE; if (msg == NULL) return ASL_STATUS_INVALID_ARG; - if ((s->flags & ASL_FILE_FLAG_READ_ONLY) == 0) return ASL_STATUS_WRITE_ONLY; + if ((s->flags & ASL_FILE_FLAG_READ) == 0) return ASL_STATUS_WRITE_ONLY; buf = NULL; buflen = 0; @@ -1179,8 +1351,12 @@ asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, aslmsg *msg) return ASL_STATUS_READ_FAILED; } - out = asl_new(ASL_TYPE_MSG); - if (out == NULL) return ASL_STATUS_NO_MEMORY; + out = asl_msg_new(ASL_TYPE_MSG); + if (out == NULL) + { + free(buf); + return ASL_STATUS_NO_MEMORY; + } memset(&r, 0, sizeof(file_record_t)); p = buf; @@ -1209,7 +1385,7 @@ asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, aslmsg *msg) if (status != ASL_STATUS_OK) { - asl_free(out); + asl_msg_release(out); free(buf); s->cursor = 0; s->cursor_xid = 0; @@ -1220,14 +1396,17 @@ asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, aslmsg *msg) for (i = 0; i < kvn; i++) { - kv = _asl_get_64(p); - p += sizeof(uint64_t); k = NULL; + v = NULL; len = 0; + + kv = _asl_get_64(p); + p += sizeof(uint64_t); + status = asl_file_fetch_object(s, kv, &k, &len); if (status != ASL_STATUS_OK) { - asl_free(out); + asl_msg_release(out); free(buf); s->cursor = 0; s->cursor_xid = 0; @@ -1236,7 +1415,6 @@ asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, aslmsg *msg) kv = _asl_get_64(p); p += sizeof(uint64_t); - v = NULL; len = 0; if (kv != 0) @@ -1244,7 +1422,8 @@ asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, aslmsg *msg) status = asl_file_fetch_object(s, kv, &v, &len); if (status != ASL_STATUS_OK) { - asl_free(out); + free(k); + asl_msg_release(out); free(buf); s->cursor = 0; s->cursor_xid = 0; @@ -1254,10 +1433,11 @@ asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, aslmsg *msg) if ((status == ASL_STATUS_OK) && (k != NULL)) { - asl_set(out, k, v); - if (v != NULL) free(v); - free(k); + asl_msg_set_key_val(out, k, v); } + + free(k); + free(v); } r.prev = asl_file_fetch_helper_64(s, &p, NULL, NULL); /* 116 */ @@ -1318,7 +1498,7 @@ asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, aslmsg *msg) status = fseeko(s->store, off, SEEK_SET); if (status != 0) { - asl_free(out); + asl_msg_release(out); s->cursor = 0; s->cursor_xid = 0; return ASL_STATUS_READ_FAILED; @@ -1327,7 +1507,7 @@ asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, aslmsg *msg) status = fread(&x64, sizeof(uint64_t), 1, s->store); if (status != 1) { - asl_free(out); + asl_msg_release(out); s->cursor = 0; s->cursor_xid = 0; return ASL_STATUS_READ_FAILED; @@ -1340,7 +1520,7 @@ asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, aslmsg *msg) return ASL_STATUS_OK; } -uint32_t +ASL_STATUS asl_file_open_read(const char *path, asl_file_t **s) { asl_file_t *out; @@ -1393,8 +1573,11 @@ asl_file_open_read(const char *path, asl_file_t **s) return ASL_STATUS_NO_MEMORY; } + out->asl_type = ASL_TYPE_FILE; + out->refcount = 1; + out->store = f; - out->flags = ASL_FILE_FLAG_READ_ONLY; + out->flags = ASL_FILE_FLAG_READ; out->version = vers; if (legacy != NULL) @@ -1455,7 +1638,7 @@ asl_file_open_read(const char *path, asl_file_t **s) return ASL_STATUS_OK; } -static uint32_t +static ASL_STATUS asl_file_read_set_position_first(asl_file_t *s) { uint32_t status; @@ -1472,8 +1655,8 @@ asl_file_read_set_position_first(asl_file_t *s) return status; } -static uint32_t -asl_file_read_set_position_last(asl_file_t *s) +static ASL_STATUS +asl_file_read_set_position_last(asl_file_t *s, int do_count) { uint64_t next; uint32_t status; @@ -1488,7 +1671,7 @@ asl_file_read_set_position_last(asl_file_t *s) * Note that s->last may be zero if the file is empty. */ - if (s->last != 0) + if ((s->last != 0) && (do_count == 0)) { s->cursor = s->last; off = s->last + RECORD_COMMON_LEN + sizeof(uint64_t); @@ -1501,6 +1684,7 @@ asl_file_read_set_position_last(asl_file_t *s) /* start at the first record and iterate */ s->cursor = s->first; s->cursor_xid = 0; + s->msg_count = 0; forever { @@ -1514,6 +1698,8 @@ asl_file_read_set_position_last(asl_file_t *s) /* detect bogus next pointer */ if (((next + MSG_RECORD_FIXED_LENGTH) > s->file_size) || (next <= s->cursor)) next = 0; + s->msg_count++; + if (next == 0) { if (s->cursor == 0) return ASL_STATUS_OK; @@ -1527,7 +1713,7 @@ asl_file_read_set_position_last(asl_file_t *s) } } -uint32_t +ASL_STATUS asl_file_read_set_position(asl_file_t *s, uint32_t pos) { uint64_t next; @@ -1538,7 +1724,7 @@ asl_file_read_set_position(asl_file_t *s, uint32_t pos) if (s->version == 1) return ASL_STATUS_FAILED; if (pos == ASL_FILE_POSITION_FIRST) return asl_file_read_set_position_first(s); - if (pos == ASL_FILE_POSITION_LAST) return asl_file_read_set_position_last(s); + if (pos == ASL_FILE_POSITION_LAST) return asl_file_read_set_position_last(s, 0); off = 0; @@ -1587,8 +1773,8 @@ asl_file_read_set_position(asl_file_t *s, uint32_t pos) return status; } -uint32_t -asl_file_fetch_next(asl_file_t *s, aslmsg *msg) +ASL_STATUS +asl_file_fetch_next(asl_file_t *s, asl_msg_t **msg) { if (s == NULL) return ASL_STATUS_INVALID_STORE; if (s->version == 1) return ASL_STATUS_FAILED; @@ -1596,8 +1782,8 @@ asl_file_fetch_next(asl_file_t *s, aslmsg *msg) return asl_file_fetch_pos(s, s->cursor, 1, msg); } -uint32_t -asl_file_fetch_previous(asl_file_t *s, aslmsg *msg) +ASL_STATUS +asl_file_fetch_previous(asl_file_t *s, asl_msg_t **msg) { if (s == NULL) return ASL_STATUS_INVALID_STORE; if (s->version == 1) return ASL_STATUS_FAILED; @@ -1605,17 +1791,17 @@ asl_file_fetch_previous(asl_file_t *s, aslmsg *msg) return asl_file_fetch_pos(s, s->cursor, -1, msg); } -uint32_t -asl_file_fetch(asl_file_t *s, uint64_t mid, aslmsg *msg) +ASL_STATUS +asl_file_fetch(asl_file_t *s, uint64_t mid, asl_msg_t **msg) { uint32_t status; if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (msg == NULL) return ASL_STATUS_INVALID_ARG; - if ((s->flags & ASL_FILE_FLAG_READ_ONLY) == 0) return ASL_STATUS_WRITE_ONLY; + if ((s->flags & ASL_FILE_FLAG_READ) == 0) return ASL_STATUS_WRITE_ONLY; if (s->version == 1) { + if (msg == NULL) return ASL_STATUS_OK; return asl_legacy1_fetch((asl_legacy1_t *)s->legacy, mid, msg); } @@ -1644,6 +1830,7 @@ asl_file_fetch(asl_file_t *s, uint64_t mid, aslmsg *msg) if (s->cursor_xid != mid) return ASL_STATUS_INVALID_ID; + if (msg == NULL) return ASL_STATUS_OK; return asl_file_fetch_pos(s, s->cursor, 1, msg); } @@ -1651,20 +1838,20 @@ __private_extern__ uint64_t asl_file_cursor(asl_file_t *s) { if (s == NULL) return 0; - if ((s->flags & ASL_FILE_FLAG_READ_ONLY) == 0) return 0; + if ((s->flags & ASL_FILE_FLAG_READ) == 0) return 0; if (s->version == 1) return 0; return s->cursor_xid; } -__private_extern__ uint32_t -asl_file_match_start(asl_file_t *s, uint64_t start_id, int32_t direction) +__private_extern__ ASL_STATUS +asl_file_match_start(asl_file_t *s, uint64_t start, int32_t direction) { uint32_t status, d; if (s == NULL) return ASL_STATUS_INVALID_STORE; if (s->version == 1) return ASL_STATUS_INVALID_STORE; - if ((s->flags & ASL_FILE_FLAG_READ_ONLY) == 0) return ASL_STATUS_WRITE_ONLY; + if ((s->flags & ASL_FILE_FLAG_READ) == 0) return ASL_STATUS_WRITE_ONLY; d = ASL_FILE_POSITION_NEXT; if (direction < 0) d = ASL_FILE_POSITION_PREVIOUS; @@ -1677,7 +1864,7 @@ asl_file_match_start(asl_file_t *s, uint64_t start_id, int32_t direction) else status = asl_file_read_set_position(s, ASL_FILE_POSITION_LAST); if (status != ASL_STATUS_OK) return status; - while ((status == ASL_STATUS_OK) && (((direction >= 0) && (s->cursor_xid < start_id)) || ((direction < 0) && (s->cursor_xid > start_id)))) + while ((status == ASL_STATUS_OK) && (((direction >= 0) && (s->cursor_xid < start)) || ((direction < 0) && (s->cursor_xid > start)))) { status = asl_file_read_set_position(s, d); } @@ -1685,29 +1872,30 @@ asl_file_match_start(asl_file_t *s, uint64_t start_id, int32_t direction) return status; } -__private_extern__ uint32_t -asl_file_match_next(asl_file_t *s, aslresponse query, aslmsg *msg, uint64_t *last_id, int32_t direction) +__private_extern__ ASL_STATUS +asl_file_match_next(asl_file_t *s, asl_msg_list_t *query, asl_msg_t **msg, uint64_t *last, int32_t direction) { uint32_t status, d, i, do_match, did_match; - aslmsg m; + asl_msg_t *m; if (s == NULL) return ASL_STATUS_INVALID_STORE; if (msg == NULL) return ASL_STATUS_INVALID_ARG; if (s->version == 1) return ASL_STATUS_INVALID_STORE; - if ((s->flags & ASL_FILE_FLAG_READ_ONLY) == 0) return ASL_STATUS_WRITE_ONLY; + if ((s->flags & ASL_FILE_FLAG_READ) == 0) return ASL_STATUS_WRITE_ONLY; if (s->cursor == 0) return ASL_STATUS_NO_RECORDS; *msg = NULL; + do_match = 1; + if (query == NULL) do_match = 0; + else if (query->count == 0) do_match = 0; d = ASL_FILE_POSITION_NEXT; if (direction < 0) d = ASL_FILE_POSITION_PREVIOUS; - if ((query == NULL) || ((query != NULL) && (query->count == 0))) do_match = 0; - m = NULL; - *last_id = s->cursor_xid; + *last = s->cursor_xid; status = asl_file_fetch_pos(s, s->cursor, direction, &m); if (status == ASL_STATUS_ACCESS_DENIED) return ASL_STATUS_MATCH_FAILED; @@ -1722,7 +1910,7 @@ asl_file_match_next(asl_file_t *s, aslresponse query, aslmsg *msg, uint64_t *las for (i = 0; (i < query->count) && (did_match == 0); i++) { - did_match = asl_msg_cmp((aslmsg)(query->msg[i]), m); + did_match = asl_msg_cmp(query->msg[i], m); } } @@ -1733,47 +1921,71 @@ asl_file_match_next(asl_file_t *s, aslresponse query, aslmsg *msg, uint64_t *las } *msg = NULL; - asl_free(m); + asl_msg_release(m); return ASL_STATUS_MATCH_FAILED; } -uint32_t -asl_file_match(asl_file_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction) +asl_msg_list_t * +asl_file_match(asl_file_t *s, asl_msg_list_t *qlist, uint64_t *last, uint64_t start, uint32_t count, uint32_t duration, int32_t direction) { uint32_t status, d, i, do_match, did_match, rescount; - aslmsg m; + asl_msg_t *m; + struct timeval now, finish; + asl_msg_list_t *out = NULL; - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (res == NULL) return ASL_STATUS_INVALID_ARG; - if ((s->flags & ASL_FILE_FLAG_READ_ONLY) == 0) return ASL_STATUS_WRITE_ONLY; + if (s == NULL) return NULL; + if ((s->flags & ASL_FILE_FLAG_READ) == 0) return NULL; if (s->version == 1) { - return asl_legacy1_match((asl_legacy1_t *)s->legacy, query, res, last_id, start_id, count, direction); + asl_legacy1_match((asl_legacy1_t *)s->legacy, qlist, &out, last, start, count, direction); + return out; } do_match = 1; + if (qlist == NULL) do_match = 0; + else if (qlist->count == 0) do_match = 0; + rescount = 0; d = ASL_FILE_POSITION_NEXT; if (direction < 0) d = ASL_FILE_POSITION_PREVIOUS; - if ((query == NULL) || ((query != NULL) && (query->count == 0))) do_match = 0; - /* * find starting point */ status = ASL_STATUS_OK; if (direction >= 0) status = asl_file_read_set_position(s, ASL_FILE_POSITION_FIRST); else status = asl_file_read_set_position(s, ASL_FILE_POSITION_LAST); - if (status != ASL_STATUS_OK) return status; + if (status != ASL_STATUS_OK) return NULL; - while ((status == ASL_STATUS_OK) && (((direction >= 0) && (s->cursor_xid < start_id)) || ((direction < 0) && (s->cursor_xid > start_id)))) + while ((status == ASL_STATUS_OK) && (((direction >= 0) && (s->cursor_xid < start)) || ((direction < 0) && (s->cursor_xid > start)))) { status = asl_file_read_set_position(s, d); } - /* + /* start the timer if a duration was specified */ + memset(&finish, 0, sizeof(struct timeval)); + if (duration != 0) + { + if (gettimeofday(&finish, NULL) == 0) + { + finish.tv_sec += (duration / USEC_PER_SEC); + finish.tv_usec += (duration % USEC_PER_SEC); + if (finish.tv_usec > USEC_PER_SEC) + { + finish.tv_usec -= USEC_PER_SEC; + finish.tv_sec += 1; + } + } + else + { + /* shouldn't happen, but if gettimeofday failed we just run without a timeout */ + memset(&finish, 0, sizeof(struct timeval)); + } + } + + /* * loop through records */ forever @@ -1783,7 +1995,7 @@ asl_file_match(asl_file_t *s, aslresponse query, aslresponse *res, uint64_t *las if (status == ASL_STATUS_ACCESS_DENIED) continue; if (status != ASL_STATUS_OK) break; - *last_id = s->cursor_xid; + *last = s->cursor_xid; did_match = 1; @@ -1791,50 +2003,36 @@ asl_file_match(asl_file_t *s, aslresponse query, aslresponse *res, uint64_t *las { did_match = 0; - for (i = 0; (i < query->count) && (did_match == 0); i++) + for (i = 0; (i < qlist->count) && (did_match == 0); i++) { - did_match = asl_msg_cmp((aslmsg)query->msg[i], m); + did_match = asl_msg_cmp(qlist->msg[i], m); } } if (did_match == 1) { /* append m to res */ - if (*res == NULL) + if (out == NULL) { - *res = (aslresponse)calloc(1, sizeof(aslresponse)); - if (*res == NULL) return ASL_STATUS_NO_MEMORY; - (*res)->msg = (asl_msg_t **)calloc(1, sizeof(aslmsg)); - if ((*res)->msg == NULL) - { - free(*res); - return ASL_STATUS_NO_MEMORY; - } + out = asl_msg_list_new(); + if (out == NULL) return NULL; } - else - { - (*res)->msg = (asl_msg_t **)reallocf((*res)->msg, ((*res)->count + 1) * sizeof(aslmsg)); - if ((*res)->msg == NULL) - { - free(*res); - return ASL_STATUS_NO_MEMORY; - } - } - - (*res)->msg[(*res)->count] = (asl_msg_t *)m; - (*res)->count++; + asl_msg_list_append(out, m); rescount++; if ((count != 0) && (rescount >= count)) break; + + /* check the timer */ + if ((finish.tv_sec != 0) && (gettimeofday(&now, NULL) == 0)) + { + if ((now.tv_sec > finish.tv_sec) || ((now.tv_sec == finish.tv_sec) && (now.tv_usec > finish.tv_usec))) break; + } } - else - { - asl_free(m); - } + + asl_msg_release(m); } - /* NOT REACHED */ - return ASL_STATUS_OK; + return out; } size_t @@ -1933,7 +2131,7 @@ asl_file_list_add(asl_file_list_t *list, asl_file_t *f) } void * -asl_file_list_match_start(asl_file_list_t *list, uint64_t start_id, int32_t direction) +asl_file_list_match_start(asl_file_list_t *list, uint64_t start, int32_t direction) { uint32_t status; asl_file_list_t *n; @@ -1947,7 +2145,7 @@ asl_file_list_match_start(asl_file_list_t *list, uint64_t start_id, int32_t dire for (n = list; n != NULL; n = n->next) { /* init file for the search */ - status = asl_file_match_start(n->file, start_id, direction); + status = asl_file_match_start(n->file, start, direction); if (status != ASL_STATUS_OK) continue; if (n->file->cursor_xid == 0) continue; @@ -1958,14 +2156,14 @@ asl_file_list_match_start(asl_file_list_t *list, uint64_t start_id, int32_t dire return out; } -uint32_t -asl_file_list_match_next(void *token, aslresponse query, aslresponse *res, uint32_t count) +ASL_STATUS +asl_file_list_match_next(void *token, asl_msg_list_t *qlist, asl_msg_list_t **res, uint32_t count) { uint32_t status, rescount; asl_file_list_t *n; - aslmsg m; + asl_msg_t *m; asl_file_match_token_t *work; - uint64_t last_id; + uint64_t last; if (token == NULL) return ASL_STATUS_OK; if (res == NULL) return ASL_STATUS_INVALID_ARG; @@ -1973,15 +2171,15 @@ asl_file_list_match_next(void *token, aslresponse query, aslresponse *res, uint3 work = (asl_file_match_token_t *)token; rescount = 0; - last_id = 0; + last = 0; while ((work->list != NULL) && ((rescount < count) || (count == 0))) { m = NULL; - status = asl_file_match_next(work->list->file, query, &m, &last_id, work->dir); + status = asl_file_match_next(work->list->file, qlist, &m, &last, work->dir); if (m != NULL) { - if (*res == NULL) *res = (aslresponse)calloc(1, sizeof(asl_search_result_t)); + if (*res == NULL) *res = asl_msg_list_new(); if (*res == NULL) { asl_file_list_free(work->list); @@ -1989,19 +2187,8 @@ asl_file_list_match_next(void *token, aslresponse query, aslresponse *res, uint3 return ASL_STATUS_NO_MEMORY; } - if ((*res)->msg == NULL) (*res)->msg = (asl_msg_t **)calloc(1, sizeof(aslmsg)); - else (*res)->msg = (asl_msg_t **)reallocf((*res)->msg, ((*res)->count + 1) * sizeof(aslmsg)); - if ((*res)->msg == NULL) - { - free(*res); - *res = NULL; - asl_file_list_free(work->list); - work->list = NULL; - return ASL_STATUS_NO_MEMORY; - } - - (*res)->msg[(*res)->count] = (asl_msg_t *)m; - (*res)->count++; + asl_msg_list_append(*res, m); + asl_msg_release(m); rescount++; } @@ -2046,24 +2233,24 @@ asl_file_list_match_end(void *token) free(token); } -uint32_t -asl_file_list_match_timeout(asl_file_list_t *list, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, uint32_t usec) +asl_msg_list_t * +asl_file_list_match(asl_file_list_t *list, asl_msg_list_t *qlist, uint64_t *last, uint64_t start, uint32_t count, uint32_t duration, int32_t direction) { uint32_t status, rescount; asl_file_list_t *files, *n; - aslmsg m; + asl_msg_t *m; struct timeval now, finish; + asl_msg_list_t *out = NULL; - if (list == NULL) return ASL_STATUS_INVALID_ARG; - if (res == NULL) return ASL_STATUS_INVALID_ARG; - if (last_id == NULL) return ASL_STATUS_INVALID_ARG; + if (list == NULL) return NULL; + if (last == NULL) return NULL; files = NULL; for (n = list; n != NULL; n = n->next) { /* init file for the search */ - status = asl_file_match_start(n->file, start_id, direction); + status = asl_file_match_start(n->file, start, direction); if (status != ASL_STATUS_OK) continue; if (n->file->cursor_xid == 0) continue; @@ -2073,20 +2260,20 @@ asl_file_list_match_timeout(asl_file_list_t *list, aslresponse query, aslrespons if (files == NULL) { asl_file_list_free(files); - return ASL_STATUS_OK; + return NULL; } /* start the timer if a timeout was specified */ memset(&finish, 0, sizeof(struct timeval)); - if (usec != 0) + if (duration != 0) { if (gettimeofday(&finish, NULL) == 0) { - finish.tv_sec += (usec / MILLION); - finish.tv_usec += (usec % MILLION); - if (finish.tv_usec > MILLION) + finish.tv_sec += (duration / USEC_PER_SEC); + finish.tv_usec += (duration % USEC_PER_SEC); + if (finish.tv_usec > USEC_PER_SEC) { - finish.tv_usec -= MILLION; + finish.tv_usec -= USEC_PER_SEC; finish.tv_sec += 1; } } @@ -2101,28 +2288,18 @@ asl_file_list_match_timeout(asl_file_list_t *list, aslresponse query, aslrespons while ((files != NULL) && ((rescount < count) || (count == 0))) { m = NULL; - status = asl_file_match_next(files->file, query, &m, last_id, direction); + status = asl_file_match_next(files->file, qlist, &m, last, direction); if (m != NULL) { - if (*res == NULL) *res = (aslresponse)calloc(1, sizeof(asl_search_result_t)); - if (*res == NULL) - { - asl_file_list_free(files); - return ASL_STATUS_NO_MEMORY; - } - - if ((*res)->msg == NULL) (*res)->msg = (asl_msg_t **)calloc(1, sizeof(aslmsg)); - else (*res)->msg = (asl_msg_t **)reallocf((*res)->msg, ((*res)->count + 1) * sizeof(aslmsg)); - if ((*res)->msg == NULL) + if (out == NULL) out = asl_msg_list_new(); + if (out == NULL) { - free(*res); - *res = NULL; asl_file_list_free(files); - return ASL_STATUS_NO_MEMORY; + return NULL; } - (*res)->msg[(*res)->count] = (asl_msg_t *)m; - (*res)->count++; + asl_msg_list_append(out, m); + asl_msg_release(m); rescount++; } @@ -2157,11 +2334,168 @@ asl_file_list_match_timeout(asl_file_list_t *list, aslresponse query, aslrespons } asl_file_list_free(files); - return ASL_STATUS_OK; + return out; +} + +#pragma mark - +#pragma mark asl_object support + +static void +_jump_dealloc(asl_object_private_t *obj) +{ + _asl_file_free_internal((asl_file_t *)obj); +} + +static size_t +_jump_count(asl_object_private_t *obj) +{ + asl_file_t *s = (asl_file_t *)obj; + if (s == NULL) return 0; + if ((s->flags & ASL_FILE_FLAG_READ) == 0) return 0; + + uint64_t cursor = s->cursor; + uint64_t cursor_xid = s->cursor_xid; + + if (asl_file_read_set_position_last((asl_file_t *)obj, 1) != ASL_STATUS_OK) return 0; + + s->cursor = cursor; + s->cursor_xid = cursor_xid; + return s->msg_count; +} + +static asl_object_private_t * +_jump_next(asl_object_private_t *obj) +{ + asl_msg_t *msg = NULL; + if (asl_file_fetch_next((asl_file_t *)obj, &msg) != ASL_STATUS_OK) return NULL; + return (asl_object_private_t *)msg; +} + +static asl_object_private_t * +_jump_prev(asl_object_private_t *obj) +{ + asl_msg_t *msg = NULL; + if (asl_file_fetch_previous((asl_file_t *)obj, &msg) != ASL_STATUS_OK) return NULL; + return (asl_object_private_t *)msg; +} + +/* we don't really need to support this, but we are generous */ +static asl_object_private_t * +_jump_get_object_at_index(asl_object_private_t *obj, size_t n) +{ + asl_msg_t *msg = NULL; + uint64_t mid = n; + if (asl_file_fetch((asl_file_t *)obj, mid, &msg) != ASL_STATUS_OK) return NULL; + return (asl_object_private_t *)msg; +} + +static void +_jump_set_iteration_index(asl_object_private_t *obj, size_t n) +{ + asl_file_t *s = (asl_file_t *)obj; + if (s == NULL) return; + if ((s->flags & ASL_FILE_FLAG_READ) == 0) return; + + if (n == 0) + { + asl_file_read_set_position_first(s); + } + else if (n == SIZE_MAX) + { + asl_file_read_set_position_last(s, 0); + } + else + { + /* we don't really need to support this, but we are generous */ + asl_file_fetch(s, n, NULL); + } +} + +static void +_jump_append(asl_object_private_t *obj, asl_object_private_t *newobj) +{ + uint64_t xid; + asl_file_t *s = (asl_file_t *)obj; + int type = asl_get_type((asl_object_t)newobj); + if (s == NULL) return; + if (s->flags & ASL_FILE_FLAG_READ) return; + + if (type == ASL_TYPE_LIST) + { + asl_msg_t *msg; + asl_msg_list_reset_iteration((asl_msg_list_t *)newobj, 0); + while (NULL != (msg = asl_msg_list_next((asl_msg_list_t *)newobj))) + { + if (asl_file_save(s, msg, &xid) != ASL_STATUS_OK) return; + } + } + else if ((type == ASL_TYPE_MSG) || (type == ASL_TYPE_QUERY)) + { + asl_file_save(s, (asl_msg_t *)newobj, &xid); + } +} + +static asl_object_private_t * +_jump_search(asl_object_private_t *obj, asl_object_private_t *query) +{ + asl_file_t *s = (asl_file_t *)obj; + int type = asl_get_type((asl_object_t)query); + asl_msg_list_t *out = NULL; + asl_msg_list_t *ql = NULL; + uint64_t last; + + if (query == NULL) + { + return (asl_object_private_t *)asl_file_match(s, NULL, &last, 0, 0, 0, 1); + } + else if (type == ASL_TYPE_LIST) + { + return (asl_object_private_t *)asl_file_match(s, (asl_msg_list_t *)query, &last, 0, 0, 0, 1); + } + else if ((type == ASL_TYPE_MSG) || (type == ASL_TYPE_QUERY)) + { + ql = asl_msg_list_new(); + asl_msg_list_append(ql, query); + + out = asl_file_match(s, ql, &last, 0, 0, 0, 1); + asl_msg_list_release(ql); + return (asl_object_private_t *)out; + } + + return NULL; +} + +static asl_object_private_t * +_jump_match(asl_object_private_t *obj, asl_object_private_t *qlist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t dir) +{ + uint64_t x; + asl_msg_list_t *out = asl_file_match((asl_file_t *)obj, (asl_msg_list_t *)qlist, &x, start, count, duration, dir); + *last = x; + return (asl_object_private_t *)out; } -uint32_t -asl_file_list_match(asl_file_list_t *list, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction) +__private_extern__ const asl_jump_table_t * +asl_file_jump_table() { - return asl_file_list_match_timeout(list, query, res, last_id, start_id, count, direction, 0); + static const asl_jump_table_t jump = + { + .alloc = NULL, + .dealloc = &_jump_dealloc, + .set_key_val_op = NULL, + .unset_key = NULL, + .get_val_op_for_key = NULL, + .get_key_val_op_at_index = NULL, + .count = &_jump_count, + .next = &_jump_next, + .prev = &_jump_prev, + .get_object_at_index = &_jump_get_object_at_index, + .set_iteration_index = &_jump_set_iteration_index, + .remove_object_at_index = NULL, + .append = &_jump_append, + .prepend = NULL, + .search = &_jump_search, + .match = &_jump_match + }; + + return &jump; } diff --git a/libsystem_asl.tproj/src/asl_legacy1.c b/libsystem_asl.tproj/src/asl_legacy1.c index 8bd9ba1..067d02a 100644 --- a/libsystem_asl.tproj/src/asl_legacy1.c +++ b/libsystem_asl.tproj/src/asl_legacy1.c @@ -83,10 +83,7 @@ #define MSG_OFF_KEY_MSG 69 #define MSG_OFF_KEY_FLAGS 77 -extern time_t asl_parse_time(const char *str); -extern int asl_msg_cmp(aslmsg a, aslmsg b); - -#define asl_msg_list_t asl_search_result_t +extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b); #define Q_NULL 100001 #define Q_FAST 100002 @@ -231,12 +228,12 @@ slotlist_find(asl_legacy1_t *s, uint64_t xid, int32_t direction) if (xid == s->slotlist[top].xid) return top; if (xid == s->slotlist[bot].xid) return bot; - if (direction == 0) return ASL_INDEX_NULL; + if (direction >= 0) return ASL_INDEX_NULL; if (direction < 0) return bot; return top; } -static uint32_t +static ASL_STATUS slotlist_init(asl_legacy1_t *s, uint32_t count) { uint32_t i, si, status, hash, addslot; @@ -299,7 +296,7 @@ slotlist_init(asl_legacy1_t *s, uint32_t count) return ASL_STATUS_OK; } -uint32_t +ASL_STATUS asl_legacy1_open(const char *path, asl_legacy1_t **out) { asl_legacy1_t *s; @@ -351,7 +348,7 @@ asl_legacy1_open(const char *path, asl_legacy1_t **out) return ASL_STATUS_OK; } -uint32_t +ASL_STATUS asl_legacy1_close(asl_legacy1_t *s) { if (s == NULL) return ASL_STATUS_INVALID_STORE; @@ -363,7 +360,7 @@ asl_legacy1_close(asl_legacy1_t *s) return ASL_STATUS_OK; } -static uint32_t +static ASL_STATUS string_fetch_slot(asl_legacy1_t *s, uint32_t slot, char **out) { off_t offset; @@ -444,7 +441,7 @@ string_fetch_slot(asl_legacy1_t *s, uint32_t slot, char **out) return ASL_STATUS_OK; } -static uint32_t +static ASL_STATUS string_fetch_sid(asl_legacy1_t *s, uint64_t sid, char **out) { uint32_t i, len, ref; @@ -483,7 +480,7 @@ string_fetch_sid(asl_legacy1_t *s, uint64_t sid, char **out) } static uint32_t -asl_legacy1_fetch_helper_32(asl_legacy1_t *s, char **p, aslmsg m, const char *key, int ignore, uint32_t ignoreval) +asl_legacy1_fetch_helper_32(asl_legacy1_t *s, char **p, asl_msg_t *m, const char *key, int ignore, uint32_t ignoreval) { uint32_t out, doit; char str[256]; @@ -498,14 +495,14 @@ asl_legacy1_fetch_helper_32(asl_legacy1_t *s, char **p, aslmsg m, const char *ke if (doit != 0) { snprintf(str, sizeof(str), "%u", out); - asl_set(m, key, str); + asl_msg_set_key_val(m, key, str); } return out; } static uint64_t -asl_legacy1_fetch_helper_64(asl_legacy1_t *s, char **p, aslmsg m, const char *key) +asl_legacy1_fetch_helper_64(asl_legacy1_t *s, char **p, asl_msg_t *m, const char *key) { uint64_t out; char str[256]; @@ -516,13 +513,13 @@ asl_legacy1_fetch_helper_64(asl_legacy1_t *s, char **p, aslmsg m, const char *ke if ((m == NULL) || (key == NULL)) return out; snprintf(str, sizeof(str), "%llu", out); - asl_set(m, key, str); + asl_msg_set_key_val(m, key, str); return out; } static uint64_t -asl_legacy1_fetch_helper_str(asl_legacy1_t *s, char **p, aslmsg m, const char *key, uint32_t *err) +asl_legacy1_fetch_helper_str(asl_legacy1_t *s, char **p, asl_msg_t *m, const char *key, uint32_t *err) { uint64_t out; char *val; @@ -538,22 +535,22 @@ asl_legacy1_fetch_helper_str(asl_legacy1_t *s, char **p, aslmsg m, const char *k if (err != NULL) *err = status; if ((status == ASL_STATUS_OK) && (val != NULL)) { - asl_set(m, key, val); + asl_msg_set_key_val(m, key, val); free(val); } return out; } -static uint32_t -msg_fetch(asl_legacy1_t *s, uint32_t slot, aslmsg *out) +static ASL_STATUS +msg_fetch(asl_legacy1_t *s, uint32_t slot, asl_msg_t **out) { off_t offset; uint32_t status, i, n, kvcount, next; uint16_t flags; uint64_t sid; size_t rcount; - aslmsg msg; + asl_msg_t *msg; int fstatus; char *p, tmp[DB_RECORD_LEN], *key, *val; @@ -572,7 +569,7 @@ msg_fetch(asl_legacy1_t *s, uint32_t slot, aslmsg *out) flags = _asl_get_16(tmp + MSG_OFF_KEY_FLAGS); - msg = asl_new(ASL_TYPE_MSG); + msg = asl_msg_new(ASL_TYPE_MSG); if (msg == NULL) return ASL_STATUS_NO_MEMORY; p = tmp + 5; @@ -601,14 +598,14 @@ msg_fetch(asl_legacy1_t *s, uint32_t slot, aslmsg *out) fstatus = fseek(s->db, offset, SEEK_SET); if (fstatus < 0) { - free(out); + asl_msg_release(msg); return ASL_STATUS_READ_FAILED; } rcount = fread(tmp, DB_RECORD_LEN, 1, s->db); if (rcount != 1) { - free(out); + asl_msg_release(msg); return ASL_STATUS_READ_FAILED; } @@ -628,7 +625,7 @@ msg_fetch(asl_legacy1_t *s, uint32_t slot, aslmsg *out) p += 8; if (status == ASL_STATUS_OK) status = string_fetch_sid(s, sid, &val); - if ((status == ASL_STATUS_OK) && (key != NULL)) asl_set(msg, key, val); + if ((status == ASL_STATUS_OK) && (key != NULL)) asl_msg_set_key_val(msg, key, val); if (key != NULL) free(key); if (val != NULL) free(val); @@ -643,7 +640,7 @@ msg_fetch(asl_legacy1_t *s, uint32_t slot, aslmsg *out) } uint32_t -asl_legacy1_fetch(asl_legacy1_t *s, uint64_t msgid, aslmsg *out) +asl_legacy1_fetch(asl_legacy1_t *s, uint64_t msgid, asl_msg_t **out) { uint32_t i, status; @@ -690,18 +687,6 @@ next_search_slot(asl_legacy1_t *s, uint32_t last_si, int32_t direction) return ASL_INDEX_NULL; } -static void -match_worker_cleanup(asl_msg_list_t **res) -{ - uint32_t i; - - if (res != NULL) - { - for (i = 0; i < (*res)->count; i++) asl_free((aslmsg)(*res)->msg[i]); - free(*res); - } -} - /* * Input to asl_legacy1_match is a list of queries. * A record in the store matches if it matches any query (i.e. query list is "OR"ed) @@ -725,12 +710,12 @@ match_worker_cleanup(asl_msg_list_t **res) * * return results. */ -static uint32_t +static ASL_STATUS match_worker(asl_legacy1_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t **idlist, uint32_t *idcount, uint64_t start_id, int32_t count, int32_t direction) { uint32_t mx, si, slot, i, qcount, match, didmatch, status; uint64_t xid; - aslmsg msg; + asl_msg_t *msg; if (s == NULL) return ASL_STATUS_INVALID_STORE; if ((res == NULL) && (idlist == NULL)) return ASL_STATUS_INVALID_ARG; @@ -767,7 +752,7 @@ match_worker(asl_legacy1_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint */ if (res != NULL) { - *res = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t)); + *res = asl_msg_list_new(); if (*res == NULL) return ASL_STATUS_NO_MEMORY; } @@ -798,27 +783,13 @@ match_worker(asl_legacy1_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint { for (i = 0; i < qcount; i++) { - didmatch = asl_msg_cmp((aslmsg)(query->msg[i]), msg); + didmatch = asl_msg_cmp(query->msg[i], msg); if (didmatch == 1) break; } } - if (didmatch == 1) - { - if ((*res)->count == 0) (*res)->msg = (asl_msg_t **)calloc(1, sizeof(asl_msg_t *)); - else (*res)->msg = (asl_msg_t **)reallocf((*res)->msg, (1 + (*res)->count) * sizeof(asl_msg_t *)); - if ((*res)->msg == NULL) - { - match_worker_cleanup(res); - return ASL_STATUS_NO_MEMORY; - } - - (*res)->msg[(*res)->count++] = (asl_msg_t *)msg; - } - else - { - asl_free(msg); - } + if (didmatch == 1) asl_msg_list_append(*res, msg); + asl_msg_release(msg); si = next_search_slot(s, si, direction); } @@ -826,7 +797,7 @@ match_worker(asl_legacy1_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint return status; } -uint32_t +ASL_STATUS asl_legacy1_match(asl_legacy1_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) { uint32_t idcount; diff --git a/libsystem_asl.tproj/src/asl_msg.c b/libsystem_asl.tproj/src/asl_msg.c index f0b0c0d..48ba6ab 100644 --- a/libsystem_asl.tproj/src/asl_msg.c +++ b/libsystem_asl.tproj/src/asl_msg.c @@ -30,16 +30,18 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include #include -#include -#include "asl_msg.h" +#include +#include #define TOKEN_NULL 0 #define TOKEN_OPEN 1 @@ -56,6 +58,8 @@ #define SEC_PER_HOUR 3600 +#define PAGE_OBJECT 1 + #define forever for(;;) #define streq(A, B) (strcmp(A, B) == 0) @@ -64,10 +68,6 @@ #define strcaseeq(A, B) (strcasecmp(A, B) == 0) #define strcaseneq(A, B) (strcasecmp(A, B) != 0) -#ifndef ASL_KEY_OPTION -#define ASL_KEY_OPTION "ASLOption" -#endif - #ifndef ASL_QUERY_OP_FALSE #define ASL_QUERY_OP_FALSE 0 #endif @@ -84,12 +84,15 @@ #define AUX_0_OPTION 0x00000200 #define AUX_0_LEVEL 0x00000400 -extern time_t asl_parse_time(const char *in); - /* from asl_util.c */ int asl_is_utf8(const char *str); uint8_t *asl_b64_encode(const uint8_t *buf, size_t len); +void _asl_msg_dump(FILE *f, const char *comment, asl_msg_t *msg); + +#pragma mark - +#pragma mark standard message keys + static const char *ASLStandardKey[] = { ASL_KEY_TIME, @@ -109,7 +112,8 @@ static const char *ASLStandardKey[] = ASL_KEY_REF_PROC, ASL_KEY_MSG_ID, ASL_KEY_EXPIRE_TIME, - ASL_KEY_OPTION + ASL_KEY_OPTION, + ASL_KEY_FREE_NOTE }; static const char *MTStandardKey[] = @@ -201,6 +205,10 @@ _asl_msg_std_key(const char *s, uint32_t len) { if streq(s, ASL_KEY_EXPIRE_TIME) return ASL_STD_KEY_EXPIRE; } + case 14: + { + if streq(s, ASL_KEY_FREE_NOTE) return ASL_STD_KEY_FREE_NOTE; + } default: { return 0; @@ -210,13 +218,15 @@ _asl_msg_std_key(const char *s, uint32_t len) return 0; } +#pragma mark - +#pragma mark asl_msg + static asl_msg_t * -_asl_msg_make_page() +_asl_msg_make_page(void) { - asl_msg_t *out; int i; + asl_msg_t *out = (asl_msg_t *)calloc(1, sizeof(asl_msg_t)); - out = calloc(1, sizeof(asl_msg_t)); if (out == NULL) return NULL; for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++) @@ -225,9 +235,26 @@ _asl_msg_make_page() out->val[i] = ASL_MSG_SLOT_FREE; } + out->mem_size = sizeof(asl_msg_t); + return out; } +asl_msg_t * +asl_msg_retain(asl_msg_t *msg) +{ + if (msg == NULL) return NULL; + asl_retain((asl_object_t)msg); + return msg; +} + +void +asl_msg_release(asl_msg_t *msg) +{ + if (msg == NULL) return; + asl_release((asl_object_t)msg); +} + static const char * _asl_msg_slot_key(asl_msg_t *page, uint32_t slot) { @@ -236,7 +263,6 @@ _asl_msg_slot_key(asl_msg_t *page, uint32_t slot) 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) @@ -309,27 +335,14 @@ asl_msg_new(uint32_t type) out = _asl_msg_make_page(); if (out == NULL) return NULL; - out->type = type; + out->asl_type = type; out->refcount = 1; return out; } -asl_msg_t * -asl_msg_retain(asl_msg_t *msg) -{ - int32_t new; - - if (msg == NULL) return NULL; - - new = OSAtomicIncrement32Barrier(&msg->refcount); - assert(new >= 1); - - return msg; -} - static void -_asl_msg_free(asl_msg_t *page) +_asl_msg_free_page(asl_msg_t *page) { uint32_t i; char *p; @@ -338,6 +351,12 @@ _asl_msg_free(asl_msg_t *page) for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++) { + if (page->key[i] == 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) { memcpy(&p, page->data + (page->key[i] & ASL_MSG_OFFSET_MASK), sizeof(char *)); @@ -354,27 +373,136 @@ _asl_msg_free(asl_msg_t *page) free(page); } -void -asl_msg_release(asl_msg_t *msg) +uint32_t +asl_msg_type(asl_msg_t *msg) { - int32_t new; - asl_msg_t *next; + if (msg == NULL) return 0; + return msg->asl_type; +} - if (msg == NULL) return; +uint32_t +asl_msg_count(asl_msg_t *msg) +{ + uint32_t total; + + total = 0; + + for (; msg != NULL; msg = msg->next) total += msg->count; + return total; +} + +static void +_asl_msg_dump_kv(FILE *f, asl_msg_t *msg, uint16_t x) +{ + if (x == ASL_MSG_SLOT_FREE) + { + fprintf(f, "-free-"); + return; + } + + if ((x & ASL_MSG_KV_MASK) == ASL_MSG_KV_DICT) + { + switch (x) + { + case ASL_STD_KEY_TIME: fprintf(f, "(dict: Time)"); return; + case ASL_STD_KEY_NANO: fprintf(f, "(dict: Nano)"); return; + case ASL_STD_KEY_HOST: fprintf(f, "(dict: Host)"); return; + case ASL_STD_KEY_SENDER: fprintf(f, "(dict: Sender)"); return; + case ASL_STD_KEY_FACILITY: fprintf(f, "(dict: Facility)"); return; + case ASL_STD_KEY_PID: fprintf(f, "(dict: PID)"); return; + case ASL_STD_KEY_UID: fprintf(f, "(dict: UID)"); return; + case ASL_STD_KEY_GID: fprintf(f, "(dict: GID)"); return; + case ASL_STD_KEY_LEVEL: fprintf(f, "(dict: Level)"); return; + case ASL_STD_KEY_MESSAGE: fprintf(f, "(dict: Message)"); return; + case ASL_STD_KEY_READ_UID: fprintf(f, "(dict: ReadUID)"); return; + case ASL_STD_KEY_READ_GID: fprintf(f, "(dict: ReadGID)"); return; + case ASL_STD_KEY_SESSION: fprintf(f, "(dict: Session)"); return; + case ASL_STD_KEY_REF_PID: fprintf(f, "(dict: PID)"); return; + case ASL_STD_KEY_REF_PROC: fprintf(f, "(dict: RefProc)"); return; + case ASL_STD_KEY_MSG_ID: fprintf(f, "(dict: ASLMessageID)"); return; + case ASL_STD_KEY_EXPIRE: fprintf(f, "(dict: Expire)"); return; + case ASL_STD_KEY_OPTION: fprintf(f, "(dict: ASLOption)"); return; + case ASL_MT_KEY_DOMAIN: fprintf(f, "(dict: com.apple.message.domain)"); return; + case ASL_MT_KEY_SCOPE: fprintf(f, "(dict: com.apple.message.domain_scope)"); return; + case ASL_MT_KEY_RESULT: fprintf(f, "(dict: com.apple.message.result)"); return; + case ASL_MT_KEY_SIG: fprintf(f, "(dict: com.apple.message.signature)"); return; + case ASL_MT_KEY_SIG2: fprintf(f, "(dict: com.apple.message.signature2)"); return; + case ASL_MT_KEY_SIG3: fprintf(f, "(dict: com.apple.message.signature3)"); return; + case ASL_MT_KEY_SUCCESS: fprintf(f, "(dict: com.apple.message.success)"); return; + case ASL_MT_KEY_UUID: fprintf(f, "(dict: com.apple.message.uuid)"); return; + case ASL_MT_KEY_VAL: fprintf(f, "(dict: com.apple.message.value)"); return; + case ASL_MT_KEY_VAL2: fprintf(f, "(dict: com.apple.message.value2)"); return; + case ASL_MT_KEY_VAL3: fprintf(f, "(dict: com.apple.message.value3)"); return; + case ASL_MT_KEY_VAL4: fprintf(f, "(dict: com.apple.message.value4)"); return; + case ASL_MT_KEY_VAL5: fprintf(f, "(dict: com.apple.message.value5)"); return; + } + + fprintf(f, "(dict: -unknown-)"); + return; + } + + if ((x & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) + { + const char *c; + size_t z = x & ASL_MSG_OFFSET_MASK; + memcpy(&c, msg->data + z, sizeof(char *)); + fprintf(f, "(extern: %s)", c); + return; + } + + fprintf(f, "%s", msg->data + x); +} - new = OSAtomicDecrement32Barrier(&msg->refcount); - assert(new >= 0); +void +_asl_msg_dump(FILE *f, const char *comment, asl_msg_t *msg) +{ + int i, page1 = 1; - if (new > 0) return; + if (f == NULL) return; + if (msg == NULL) + { + fprintf(f, "asl_msg %s: NULL\n", comment); + return; + } while (msg != NULL) { - next = msg->next; - _asl_msg_free(msg); - msg = next; + if (page1 == 1) + { + fprintf(f, "asl_msg %s: %p\n", comment, msg); + fprintf(f, " refcount: %u\n", msg->refcount); + fprintf(f, " asl_type: %u\n", msg->asl_type); + page1 = 0; + } + else + { + fprintf(f, " page: %p\n", msg); + } + + fprintf(f, " count: %u\n", msg->count); + fprintf(f, " data_size: %u\n", msg->data_size); + 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++) + { + fprintf(f, " slot[%d]: ", i); + _asl_msg_dump_kv(f, msg, msg->key[i]); + fprintf(f, " "); + _asl_msg_dump_kv(f, msg, msg->val[i]); + fprintf(f, " 0x%04x\n", msg->op[i]); + } + + msg = msg->next; } } +#pragma mark - +#pragma mark fetching contents + +/* + * Find the slot and page for an input key. + */ static uint32_t _asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opage) { @@ -440,67 +568,173 @@ _asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opa } /* - * asl_msg_key: iterate over entries - * initial value of n should be 0 - * after that, the value of n should be previously returned value - * sets the pointers for the next key, value, and op in the msgionary - * returns IndexNull when there are no more entries + * Find page and slot for an "index". */ -static uint32_t -_asl_msg_fetch_internal(asl_msg_t *msg, uint32_t n, const char **keyout, const char **valout, uint32_t *opout, asl_msg_t **outpage, uint32_t *outslot) +static int +_asl_msg_resolve_index(asl_msg_t *msg, uint32_t n, asl_msg_t **page, uint32_t *slot) { - uint32_t slot; - asl_msg_t *page; + uint32_t i, sx; + asl_msg_t *px; + + if (msg == NULL) return -1; + + *slot = IndexNull; + *page = NULL; + + sx = 0; + + /* find page */ + for (px = msg; px != NULL; px = px->next) + { + if (n > (sx + px->count)) + { + sx += px->count; + continue; + } + + *page = px; + + /* find slot */ + for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++) + { + if (px->key[i] != ASL_MSG_SLOT_FREE) + { + if (sx == n) + { + *slot = i; + return 0; + } + + sx++; + } + } + } + + return -1; +} + +/* + * 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. + * The iterator encodes a page number and a slot number. + */ + +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; + asl_msg_t *page = NULL; if (msg == NULL) return IndexNull; - if (outpage != NULL) *outpage = NULL; - if (outslot != NULL) *outslot = IndexNull; - slot = n; - page = msg; + xsn = x >> 24; + xpn = x & 0x00ffffff; + + /* slot number 0xff means we have run out entries */ + if (xsn == 0x000000ff) return IndexNull; - while (slot >= ASL_MSG_PAGE_SLOTS) + page = msg; + for (p = 0; p < xpn; p++) { - if (page->next == NULL) return IndexNull; page = page->next; - slot -= ASL_MSG_PAGE_SLOTS; + if (page == NULL) return IndexNull; } - while (page->key[slot] == ASL_MSG_SLOT_FREE) + 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]); + + /* advance to the next slot */ + forever { - slot++; - n++; + xsn++; - if (slot >= ASL_MSG_PAGE_SLOTS) + if (xsn >= ASL_MSG_PAGE_SLOTS) { - if (page->next == NULL) return IndexNull; + if (page->next == NULL) return 0xff000000; + xsn = 0; page = page->next; - slot = 0; + xpn++; } + + if (page->key[xsn] != ASL_MSG_SLOT_FREE) return ((xsn << 24) | xpn); } - n++; + return IndexNull; +} + +int +asl_msg_lookup(asl_msg_t *msg, const char *key, const char **valout, uint16_t *opout) +{ + uint32_t i, slot; + asl_msg_t *page; + + if (msg == NULL) return -1; + if (valout != NULL) *valout = NULL; + if (opout != NULL) *opout = 0; + + slot = IndexNull; + page = NULL; + + i = _asl_msg_index(msg, key, &slot, &page); + if (i == IndexNull) return -1; - if (keyout != NULL) *keyout = _asl_msg_slot_key(page, slot); if (valout != NULL) *valout = _asl_msg_slot_val(page, slot); - if (opout != NULL) *opout = page->op[slot]; + if (opout != NULL) *opout = (uint32_t)(page->op[slot]); + + return 0; +} + +const char * +asl_msg_get_val_for_key(asl_msg_t *msg, const char *key) +{ + uint32_t slot; + asl_msg_t *page; + + if (msg == NULL) return NULL; + + slot = IndexNull; + page = NULL; - if (outpage != NULL) *outpage = page; - if (outslot != NULL) *outslot = slot; + if (_asl_msg_index(msg, key, &slot, &page) == IndexNull) return NULL; - return n; + return _asl_msg_slot_val(page, slot); } -uint32_t -asl_msg_fetch(asl_msg_t *msg, uint32_t n, const char **keyout, const char **valout, uint32_t *opout) +const char * +asl_msg_key(asl_msg_t *msg, uint32_t n) { - return _asl_msg_fetch_internal(msg, n, keyout, valout, opout, NULL, NULL); + uint32_t slot, i; + asl_msg_t *page; + + if (msg == NULL) return NULL; + + i = 0; + for (page = msg; page != NULL; page = page->next) + { + for (slot = 0; slot < ASL_MSG_PAGE_SLOTS; slot++) + { + if (page->key[slot] != ASL_MSG_SLOT_FREE) + { + if (i == n) return _asl_msg_slot_key(page, slot); + i++; + } + } + } + + return NULL; } +#pragma mark - +#pragma mark adding and replacing contents + 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; + uint64_t klen, vlen; uint16_t kx; asl_msg_t *page, *last; char *extkey, *extval; @@ -512,6 +746,7 @@ _asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32 extval = NULL; keylen = strlen(key); + klen = keylen; kx = _asl_msg_std_key(key, keylen); if (kx == 0) keylen++; @@ -523,6 +758,7 @@ _asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32 if (val != NULL) { vallen = strlen(val) + 1; + vlen = vallen; total += vallen; } @@ -607,6 +843,7 @@ _asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32 { page->key[slot] = page->data_size | ASL_MSG_KV_EXTERN; memcpy(page->data + page->data_size, &extkey, keylen); + page->mem_size += klen; } page->data_size += keylen; @@ -625,13 +862,14 @@ _asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32 { page->val[slot] = page->data_size | ASL_MSG_KV_EXTERN; memcpy(page->data + page->data_size, &extval, vallen); + page->mem_size += vlen; } page->data_size += vallen; } /* set op */ - page->op[slot] = op; + page->op[slot] = (uint16_t)op; /* update page count */ page->count++; @@ -661,7 +899,7 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op) slot = IndexNull; page = NULL; - if ((msg->type == ASL_TYPE_QUERY) || (IndexNull == _asl_msg_index(msg, key, &slot, &page))) + if ((msg->asl_type == ASL_TYPE_QUERY) || (IndexNull == _asl_msg_index(msg, key, &slot, &page))) { /* add key */ return _asl_msg_new_key_val_op(msg, key, val, op); @@ -693,23 +931,28 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op) /* easy case - remove val */ if (val == NULL) { - if (extval != NULL) free(extval); + if (extval != NULL) + { + page->mem_size -= (strlen(extval) + 1); + free(extval); + } + page->val[slot] = ASL_MSG_SLOT_FREE; - if (op != IndexNull) page->op[slot] = op; + if (op != IndexNull) page->op[slot] = (uint16_t)op; return 0; } /* trivial case - internal val doesn't change */ if ((intval != NULL) && (streq(val, intval))) { - if (op != IndexNull) page->op[slot] = op; + if (op != IndexNull) page->op[slot] = (uint16_t)op; return 0; } /* trivial case - external val doesn't change */ if ((extval != NULL) && (streq(val, extval))) { - if (op != IndexNull) page->op[slot] = op; + if (op != IndexNull) page->op[slot] = (uint16_t)op; return 0; } @@ -730,6 +973,7 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op) { page->val[slot] = ASL_MSG_SLOT_FREE; page->data_size -= extvallen; + page->mem_size -= (strlen(extval) + 1); free(extval); extval = NULL; extvallen = 0; @@ -748,7 +992,12 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op) /* check if there is room to change val in place */ if (((extval != NULL) && (newvallen <= extvallen)) || ((extval == NULL) && (newvallen <= intvallen))) { - if (extval != NULL) free(extval); + if (extval != NULL) + { + page->mem_size -= (strlen(extval) + 1); + free(extval); + } + extval = NULL; /* we can re-use the space of the old value */ @@ -760,6 +1009,7 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op) newval = strdup(val); if (newval == NULL) return -1; + page->mem_size += (strlen(newval) + 1); page->val[slot] = i | ASL_MSG_KV_EXTERN; memcpy(page->data + i, &newval, sizeof(char *)); } @@ -770,12 +1020,17 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op) memcpy(page->data + i, val, newvallen); } - if (op != IndexNull) page->op[slot] = op; + if (op != IndexNull) page->op[slot] = (uint16_t)op; return 0; } /* we're done with the old value if it is external - free it now */ - if (extval != NULL) free(extval); + if (extval != NULL) + { + page->mem_size -= (strlen(extval) + 1); + free(extval); + } + extval = NULL; if (newvallen <= (ASL_MSG_PAGE_DATA_SIZE - page->data_size)) @@ -790,6 +1045,7 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op) newval = strdup(val); if (newval == NULL) return -1; + page->mem_size += (strlen(newval) + 1); page->val[slot] = i | ASL_MSG_KV_EXTERN; memcpy(page->data + i, &newval, sizeof(char *)); } @@ -800,7 +1056,7 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op) memcpy(page->data + i, val, newvallen); } - if (op != IndexNull) page->op[slot] = op; + if (op != IndexNull) page->op[slot] = (uint16_t)op; return 0; } @@ -809,6 +1065,7 @@ _asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op) if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) { memcpy(&extval, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *)); + page->mem_size -= (strlen(extval) + 1); free(extval); } @@ -887,13 +1144,80 @@ asl_msg_set_key_val(asl_msg_t *msg, const char *key, const char *val) return asl_msg_set_key_val_op(msg, key, val, 0); } +static void +_asl_msg_unset_page_slot(asl_msg_t *page, uint32_t slot) +{ + char *ext; + + 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) + { + memcpy(&ext, page->data + (page->key[slot] & 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) + { + memcpy(&ext, page->data + (page->val[slot] & 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; + + page->count--; +} + +/* + * asl_msg_unset + * Frees external key and val strings, but does not try to reclaim data space. + */ +void +asl_msg_unset(asl_msg_t *msg, const char *key) +{ + uint32_t i, slot; + asl_msg_t *page; + + if (msg == NULL) return; + if (key == NULL) return; + + slot = IndexNull; + page = NULL; + + i = _asl_msg_index(msg, key, &slot, &page); + if (i == IndexNull) return; + + _asl_msg_unset_page_slot(page, slot); +} + +void +asl_msg_unset_index(asl_msg_t *msg, uint32_t n) +{ + uint32_t slot = IndexNull; + asl_msg_t *page = NULL; + + if (msg == NULL) return; + + if (0 != _asl_msg_resolve_index(msg, n, &page, &slot)) return; + _asl_msg_unset_page_slot(page, slot); +} + +#pragma mark - +#pragma mark copy and merge + /* * Merge a key / val into a message (only ASL_TYPE_MSG). * Adds the key / val if the key is not found. * Does not replace the value if the key is found. */ static void -_asl_msg_merge_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32_t op) +_asl_msg_merge_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint16_t op) { uint32_t i, slot; asl_msg_t *page; @@ -918,21 +1242,23 @@ _asl_msg_merge_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint asl_msg_t * asl_msg_merge(asl_msg_t *target, asl_msg_t *msg) { - uint32_t x, slot, op, isnew = 0; + uint32_t x, type, isnew = 0; + uint16_t op; const char *key, *val; - asl_msg_t *page; if (msg == NULL) return target; + type = asl_get_type((asl_object_t)msg); + if (target == NULL) { isnew = 1; - target = asl_msg_new(msg->type); + target = asl_msg_new(type); } - for (x = _asl_msg_fetch_internal(msg, 0, &key, &val, &op, &page, &slot); x != IndexNull; x = _asl_msg_fetch_internal(msg, x, &key, &val, &op, &page, &slot)) + for (x = asl_msg_fetch(msg, 0, &key, &val, &op); x != IndexNull; x =asl_msg_fetch(msg, x, &key, &val, &op)) { - if (msg->type == ASL_TYPE_MSG) op = 0; + if (type == ASL_TYPE_MSG) op = 0; if (isnew == 1) asl_msg_set_key_val_op(target, key, val, op); else _asl_msg_merge_key_val_op(target, key, val, op); } @@ -941,91 +1267,44 @@ asl_msg_merge(asl_msg_t *target, asl_msg_t *msg) } /* - * Copy msg. - */ -asl_msg_t * -asl_msg_copy(asl_msg_t *msg) -{ - return asl_msg_merge(NULL, msg); -} - -/* - * asl_msg_unset - * Frees external key and val strings, but does not try to reclaim data space. + * replace key/value pairs from msg in target + * Creates a new asl_msg_t if target is NULL. + * Returns target. */ -void -asl_msg_unset(asl_msg_t *msg, const char *key) +static asl_msg_t * +asl_msg_replace(asl_msg_t *target, asl_msg_t *msg) { - uint32_t i, slot; - asl_msg_t *page; - char *ext; + uint32_t x, type; + uint16_t op; + const char *key, *val; - if (msg == NULL) return; - if (key == NULL) return; + if (msg == NULL) return target; - slot = IndexNull; - page = NULL; + type = asl_get_type((asl_object_t)msg); - i = _asl_msg_index(msg, key, &slot, &page); - if (i == IndexNull) return; + if (target == NULL) target = asl_msg_new(type); - if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) + for (x = asl_msg_fetch(msg, 0, &key, &val, &op); x != IndexNull; x =asl_msg_fetch(msg, x, &key, &val, &op)) { - memcpy(&ext, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *)); - free(ext); - } - - if ((page->val[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN) - { - memcpy(&ext, page->data + (page->val[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *)); - free(ext); + if (type == ASL_TYPE_MSG) op = 0; + asl_msg_set_key_val_op(target, key, val, op); } - page->key[slot] = ASL_MSG_SLOT_FREE; - page->val[slot] = ASL_MSG_SLOT_FREE; - page->op[slot] = 0; - - page->count--; + return target; } -int -asl_msg_lookup(asl_msg_t *msg, const char *key, const char **valout, uint32_t *opout) -{ - uint32_t i, slot; - asl_msg_t *page; - - if (valout != NULL) *valout = NULL; - if (opout != NULL) *opout = 0; - - slot = IndexNull; - page = NULL; - - i = _asl_msg_index(msg, key, &slot, &page); - if (i == IndexNull) return -1; - - if (valout != NULL) *valout = _asl_msg_slot_val(page, slot); - if (opout != NULL) *opout = page->op[slot]; - - return 0; -} -uint32_t -asl_msg_type(asl_msg_t *msg) +/* + * Copy msg. + */ +asl_msg_t * +asl_msg_copy(asl_msg_t *msg) { - if (msg == NULL) return 0; - return msg->type; + return asl_msg_merge(NULL, msg); } -uint32_t -asl_msg_count(asl_msg_t *msg) -{ - uint32_t total; - - total = 0; - - for (; msg != NULL; msg = msg->next) total += msg->count; - return total; -} +#pragma mark - +#pragma mark compare and test /* * Compare messages @@ -1033,7 +1312,8 @@ asl_msg_count(asl_msg_t *msg) static int _asl_msg_equal(asl_msg_t *a, asl_msg_t *b) { - uint32_t x, oa, ob; + uint32_t x; + uint16_t oa, ob; const char *key, *va, *vb; if (asl_msg_count(a) != asl_msg_count(b)) return 0; @@ -1046,7 +1326,7 @@ _asl_msg_equal(asl_msg_t *a, asl_msg_t *b) { if (asl_msg_lookup(b, key, &vb, &ob) != 0) return 0; if (strcmp(va, vb)) return 0; - if ((a->type == ASL_TYPE_QUERY) && (oa != ob)) return 0; + if ((a->asl_type == ASL_TYPE_QUERY) && (oa != ob)) return 0; } return 1; @@ -1282,10 +1562,10 @@ _asl_msg_test_time_expression(uint32_t op, const char *q, const char *m) if ((op & ASL_QUERY_OP_PREFIX) || (op & ASL_QUERY_OP_SUFFIX) || (op & ASL_QUERY_OP_REGEX)) return _asl_msg_test_expression(op, q, m); if ((q == NULL) || (m == NULL)) return _asl_msg_test_expression(op, q, m); - tq = asl_parse_time(q); + tq = asl_core_parse_time(q, NULL); if (tq < 0) return _asl_msg_test_expression(op, q, m); - tm = asl_parse_time(m); + tm = asl_core_parse_time(m, NULL); if (tm < 0) return _asl_msg_test_expression(op, q, m); t = op & ASL_QUERY_OP_TRUE; @@ -1337,10 +1617,11 @@ _asl_msg_test_time_expression(uint32_t op, const char *q, const char *m) } /* test a query against a message */ -static int +__private_extern__ int _asl_msg_test(asl_msg_t *q, asl_msg_t *m) { - uint32_t i, t, x, op; + uint32_t i, t, x; + uint16_t op; int cmp; const char *kq, *vq, *vm; @@ -1398,6 +1679,7 @@ _asl_msg_test(asl_msg_t *q, asl_msg_t *m) return 1; } +/* returns 1 if a and b match, 0 otherwise */ int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b) { @@ -1405,11 +1687,35 @@ asl_msg_cmp(asl_msg_t *a, asl_msg_t *b) if (a == NULL) return 0; if (b == NULL) return 0; - if (a->type == b->type) return _asl_msg_equal(a, b); - if (a->type == ASL_TYPE_QUERY) return _asl_msg_test(a, b); + if (a->asl_type == b->asl_type) return _asl_msg_equal(a, b); + if (a->asl_type == ASL_TYPE_QUERY) return _asl_msg_test(a, b); return _asl_msg_test(b, a); } +/* + * Test a message against a query list. + * Returns 1 if msg matches any query in the list, 0 otherwise. + * Returns 1 if the query list is NULL or empty. + */ +int +asl_msg_cmp_list(asl_msg_t *msg, asl_msg_list_t *list) +{ + uint32_t i; + + if (msg == NULL) return 0; + if (list == NULL) return 1; + if (list->count == 0) return 1; + + for (i = 0; i < list->count; i++) + { + if (_asl_msg_test(list->msg[i], msg)) return 1; + } + + return 0; +} + +#pragma mark - +#pragma mark string representation static char * _asl_time_string(const char *infmt, const char *str, const char *nano) @@ -1468,7 +1774,7 @@ _asl_time_string(const char *infmt, const char *str, const char *nano) } tick = 0; - if (str != NULL) tick = asl_parse_time(str); + if (str != NULL) tick = asl_core_parse_time(str, NULL); if ((!strcasecmp(fmt, "lcl")) || (!strcasecmp(fmt, "local"))) { @@ -1533,7 +1839,7 @@ _asl_time_string(const char *infmt, const char *str, const char *nano) { char sep = ' '; if (!strncasecmp(fmt, "iso8601", 7)) sep = 'T'; - + if (NULL == gmtime_r(&tick, &stm)) return NULL; asprintf(&out, "%d-%02d-%02d%c%02d:%02d:%02d%sZ", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, sep, stm.tm_hour, stm.tm_min, stm.tm_sec, nanobuf); return out; @@ -1602,6 +1908,7 @@ _asl_time_string(const char *infmt, const char *str, const char *nano) return out; } + /* called from asl_format_message and _asl_send_message */ __private_extern__ asl_string_t * asl_msg_to_string_raw(uint32_t encoding, asl_msg_t *msg, const char *tfmt) @@ -1665,50 +1972,40 @@ asl_msg_to_string_raw(uint32_t encoding, asl_msg_t *msg, const char *tfmt) return str; } -static asl_string_t * -_asl_string_append_asl_msg(asl_string_t *str, asl_msg_t *msg) +asl_string_t * +asl_string_append_asl_msg(asl_string_t *str, asl_msg_t *msg) { const char *key, *val; - uint32_t i, op, n; + uint32_t i, x; + uint16_t op; if (msg == NULL) return str; - if (msg->type == ASL_TYPE_QUERY) asl_string_append(str, "Q "); + if (msg->asl_type == ASL_TYPE_QUERY) asl_string_append(str, "Q "); i = 0; - n = 0; - - forever + for (x = asl_msg_fetch(msg, 0, &key, &val, &op); x != IndexNull; x = asl_msg_fetch(msg, x, &key, &val, &op)) { - key = NULL; - val = NULL; - - i = asl_msg_fetch(msg, i, &key, &val, &op); - if (key != NULL) - { - if (n != 0) asl_string_append_char_no_encoding(str, ' '); - n++; - - asl_string_append_char_no_encoding(str, '['); + if (i != 0) asl_string_append_char_no_encoding(str, ' '); + i++; - if (msg->type == ASL_TYPE_QUERY) - { - asl_string_append_op(str, op); - asl_string_append_char_no_encoding(str, ' '); - } + asl_string_append_char_no_encoding(str, '['); - asl_string_append_asl_key(str, key); + if (msg->asl_type == ASL_TYPE_QUERY) + { + asl_string_append_op(str, op); + asl_string_append_char_no_encoding(str, ' '); + } - if (val != NULL) - { - asl_string_append_char_no_encoding(str, ' '); - asl_string_append(str, val); - } + asl_string_append_asl_key(str, key); - asl_string_append_char_no_encoding(str, ']'); + if (val != NULL) + { + asl_string_append_char_no_encoding(str, ' '); + asl_string_append(str, val); } - if (i == IndexNull) break; + asl_string_append_char_no_encoding(str, ']'); } return str; @@ -1721,9 +2018,9 @@ asl_msg_to_string(asl_msg_t *msg, uint32_t *len) asl_string_t *str = asl_string_new(ASL_ENCODE_ASL); if (str == NULL) return NULL; - str = _asl_string_append_asl_msg(str, msg); + str = asl_string_append_asl_msg(str, msg); *len = asl_string_length(str); - out = asl_string_free_return_bytes(str); + out = asl_string_release_return_bytes(str); return out; } @@ -2021,7 +2318,7 @@ asl_msg_from_string(const char *buf) out = asl_msg_new(ASL_TYPE_MSG); if (out == NULL) return NULL; - out->type = type; + out->asl_type = type; /* OPEN WORD [WORD [WORD]] CLOSE */ while (k != NULL) @@ -2109,85 +2406,6 @@ asl_msg_from_string(const char *buf) return out; } -char * -asl_list_to_string(asl_search_result_t *list, uint32_t *len) -{ - uint32_t i; - char tmp[16]; - char *out; - asl_string_t *str; - - if (list == NULL) return NULL; - if (list->count == 0) return NULL; - if (list->msg == NULL) return NULL; - - str = asl_string_new(ASL_ENCODE_ASL); - if (str == NULL) return NULL; - - snprintf(tmp, sizeof(tmp), "%u", list->count); - asl_string_append(str, tmp); - asl_string_append_char_no_encoding(str, '\n'); - - for (i = 0; i < list->count; i++) - { - _asl_string_append_asl_msg(str, list->msg[i]); - asl_string_append_char_no_encoding(str, '\n'); - } - - *len = asl_string_length(str); - out = asl_string_free_return_bytes(str); - return out; -} - -asl_search_result_t * -asl_list_from_string(const char *buf) -{ - uint32_t i, n; - const char *p; - asl_search_result_t *out; - asl_msg_t *m; - - if (buf == NULL) return NULL; - p = buf; - - n = atoi(buf); - if (n == 0) return NULL; - - out = (asl_search_result_t *)calloc(1, sizeof(asl_search_result_t)); - if (out == NULL) return NULL; - - out->msg = (asl_msg_t **)calloc(n, sizeof(asl_msg_t *)); - if (out->msg == NULL) - { - free(out); - return NULL; - } - - for (i = 0; i < n; i++) - { - p = strchr(p, '\n'); - if (p == NULL) - { - aslresponse_free((aslresponse)out); - return NULL; - } - - p++; - - m = asl_msg_from_string(p); - if (m == NULL) - { - aslresponse_free((aslresponse)out); - return NULL; - } - - out->msg[i] = (asl_msg_t *)m; - out->count += 1; - } - - return out; -} - static const char * _asl_level_string(int level) { @@ -2202,6 +2420,20 @@ _asl_level_string(int level) return "unknown"; } +static const char * +_asl_level_char(int level) +{ + if (level == ASL_LEVEL_EMERG) return "P"; + if (level == ASL_LEVEL_ALERT) return "A"; + if (level == ASL_LEVEL_CRIT) return "C"; + if (level == ASL_LEVEL_ERR) return "E"; + if (level == ASL_LEVEL_WARNING) return "W"; + if (level == ASL_LEVEL_NOTICE) return "N"; + if (level == ASL_LEVEL_INFO) return "I"; + if (level == ASL_LEVEL_DEBUG) return "D"; + return "?"; +} + /* * Find the value for a key in a message and append a formatted value to str. * kf may be a simple (no embedded white space) key, or one of (key) or ((key)(format)). @@ -2284,6 +2516,11 @@ _asl_string_append_value_for_key_format(asl_string_t *str, asl_msg_t *msg, char mval = _asl_level_string(atoi(mval)); asl_string_append_no_encoding(str, mval); } + else if (!strcmp(fmt, "char")) + { + mval = _asl_level_char(atoi(mval)); + asl_string_append_no_encoding(str, mval); + } else { asl_string_append_no_encoding(str, mval); @@ -2360,7 +2597,7 @@ asl_format_message(asl_msg_t *msg, const char *mfmt, const char *tfmt, uint32_t asl_string_append_char_no_encoding(str, '\n'); *len = asl_string_length(str); - out = asl_string_free_return_bytes(str); + out = asl_string_release_return_bytes(str); return out; } @@ -2377,7 +2614,7 @@ asl_format_message(asl_msg_t *msg, const char *mfmt, const char *tfmt, uint32_t asl_string_append_char_no_encoding(str, '\n'); *len = asl_string_length(str); - out = asl_string_free_return_bytes(str); + out = asl_string_release_return_bytes(str); return out; } @@ -2473,7 +2710,7 @@ asl_format_message(asl_msg_t *msg, const char *mfmt, const char *tfmt, uint32_t asl_string_append_char_no_encoding(str, '\n'); *len = asl_string_length(str); - out = asl_string_free_return_bytes(str); + out = asl_string_release_return_bytes(str); return out; } @@ -2522,7 +2759,7 @@ asl_format_message(asl_msg_t *msg, const char *mfmt, const char *tfmt, uint32_t asl_string_append_char_no_encoding(str, '\n'); *len = asl_string_length(str); - out = asl_string_free_return_bytes(str); + out = asl_string_release_return_bytes(str); return out; } @@ -2638,115 +2875,160 @@ asl_format_message(asl_msg_t *msg, const char *mfmt, const char *tfmt, uint32_t asl_string_append_char_no_encoding(str, '\n'); *len = asl_string_length(str); - out = asl_string_free_return_bytes(str); + out = asl_string_release_return_bytes(str); return out; } -/* - * OLD ASLMSG COMPATIBILITY - */ -const char * -asl_key(aslmsg msg, uint32_t n) +#pragma mark - +#pragma mark asl_object support + +static asl_object_private_t * +_jump_alloc(uint32_t type) { - uint32_t slot, i; - asl_msg_t *page; + return (asl_object_private_t *)asl_msg_new(type); +} - i = 0; - for (page = (asl_msg_t *)msg; page != NULL; page = page->next) +static void +_jump_dealloc(asl_object_private_t *obj) +{ + asl_msg_t *msg = (asl_msg_t *)obj; + while (msg != NULL) { - for (slot = 0; slot < ASL_MSG_PAGE_SLOTS; slot++) - { - if (page->key[slot] != ASL_MSG_SLOT_FREE) - { - if (i == n) return _asl_msg_slot_key(page, slot); - i++; - } - } + asl_msg_t *next = msg->next; + _asl_msg_free_page(msg); + msg = next; } - - return NULL; } -aslmsg -asl_new(uint32_t type) +static int +_jump_set_key_val_op(asl_object_private_t *obj, const char *key, const char *val, uint16_t op) { - return (aslmsg)asl_msg_new(type); + uint32_t op32 = op; + int status = asl_msg_set_key_val_op((asl_msg_t *)obj, key, val, op32); + return (status == ASL_STATUS_OK) ? 0 : -1; } -int -asl_set(aslmsg msg, const char *key, const char *value) +static void +_jump_unset_key(asl_object_private_t *obj, const char *key) { - return asl_msg_set_key_val_op((asl_msg_t *)msg, key, value, IndexNull); + asl_msg_unset((asl_msg_t *)obj, key); } -int -asl_set_query(aslmsg msg, const char *key, const char *value, uint32_t op) +static int +_jump_get_val_op_for_key(asl_object_private_t *obj, const char *key, const char **val, uint16_t *op) { - return asl_msg_set_key_val_op((asl_msg_t *)msg, key, value, op); + return asl_msg_lookup((asl_msg_t *)obj, key, val, op); } -int -asl_unset(aslmsg msg, const char *key) +static int +_jump_get_key_val_op_at_index(asl_object_private_t *obj, size_t n, const char **key, const char **val, uint16_t *op) { - asl_msg_unset((asl_msg_t *)msg, key); + uint32_t slot = IndexNull; + asl_msg_t *page = NULL; + + if (0 != _asl_msg_resolve_index((asl_msg_t *)obj, n, &page, &slot)) return -1; + + 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]; return 0; } -const char * -asl_get(aslmsg msg, const char *key) +static size_t +_jump_count(asl_object_private_t *obj) { - const char *val; - int status; - - val = NULL; - status = asl_msg_lookup((asl_msg_t *)msg, key, &val, NULL); - if (status != 0) return NULL; - return val; + size_t count = asl_msg_count((asl_msg_t *)obj); + return count; } -void -asl_free(aslmsg msg) +static void +_jump_append(asl_object_private_t *obj, asl_object_private_t *newobj) { - asl_msg_release((asl_msg_t *)msg); + int type = asl_get_type((asl_object_t)newobj); + if ((type != ASL_TYPE_QUERY) && (type != ASL_TYPE_MSG)) return; + + asl_msg_merge((asl_msg_t *)obj, (asl_msg_t *)newobj); } -/* aslresponse */ +static void +_jump_prepend(asl_object_private_t *obj, asl_object_private_t *newobj) +{ + if (obj == NULL) return; -/* - * aslresponse_next: Iterate over responses returned from asl_search() - * a: a response returned from asl_search(); - * returns: The next log message (an aslmsg) or NULL on failure - */ -aslmsg -aslresponse_next(aslresponse r) + int type = asl_get_type((asl_object_t)newobj); + if ((type != ASL_TYPE_QUERY) && (type != ASL_TYPE_MSG)) return; + + asl_msg_replace((asl_msg_t *)obj, (asl_msg_t *)newobj); +} + +static asl_object_private_t * +_jump_search(asl_object_private_t *obj, asl_object_private_t *query) { - asl_search_result_t *res; - asl_msg_t *m; + if (obj == NULL) return NULL; - res = (asl_search_result_t *)r; - if (res == NULL) return NULL; + if (query == NULL) + { + /* NULL matches any message */ + asl_msg_list_t *out = asl_msg_list_new(); + asl_msg_list_append(out, obj); + return (asl_object_private_t *)out; + } - if (res->curr >= res->count) return NULL; - m = res->msg[res->curr]; - res->curr++; + if ((query->asl_type != ASL_TYPE_MSG) && (query->asl_type != ASL_TYPE_QUERY)) return NULL; - return (aslmsg)m; + if (asl_msg_cmp((asl_msg_t *)obj, (asl_msg_t *)query) == 1) + { + asl_msg_list_t *out = asl_msg_list_new(); + asl_msg_list_append(out, obj); + return (asl_object_private_t *)out; + } + + return NULL; } -/* - * aslresponse_free: Free a response returned from asl_search() - * a: a response returned from asl_search() - */ -void -aslresponse_free(aslresponse r) +static asl_object_private_t * +_jump_match(asl_object_private_t *obj, asl_object_private_t *qlist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t dir) { - asl_search_result_t *res; - uint32_t i; + if (obj == NULL) return NULL; - res = (asl_search_result_t *)r; - if (res == NULL) return; + if (qlist == NULL) + { + /* NULL matches any message */ + asl_msg_list_t *out = asl_msg_list_new(); + asl_msg_list_append(out, obj); + return (asl_object_private_t *)out; + } - for (i = 0; i < res->count; i++) asl_msg_release(res->msg[i]); - free(res->msg); - free(res); + if (asl_msg_cmp_list((asl_msg_t *)obj, (asl_msg_list_t *)qlist) == 0) return NULL; + + asl_msg_list_t *out = asl_msg_list_new(); + asl_msg_list_append(out, obj); + return (asl_object_private_t *)out; +} + + +__private_extern__ const asl_jump_table_t * +asl_msg_jump_table() +{ + static const asl_jump_table_t jump = + { + .alloc = &_jump_alloc, + .dealloc = &_jump_dealloc, + .set_key_val_op = &_jump_set_key_val_op, + .unset_key = &_jump_unset_key, + .get_val_op_for_key = &_jump_get_val_op_for_key, + .get_key_val_op_at_index = &_jump_get_key_val_op_at_index, + .count = &_jump_count, + .next = NULL, + .prev = NULL, + .get_object_at_index = NULL, + .set_iteration_index = NULL, + .remove_object_at_index = NULL, + .append = &_jump_append, + .prepend = &_jump_prepend, + .search = &_jump_search, + .match = &_jump_match + }; + + return &jump; } diff --git a/libsystem_asl.tproj/src/asl_msg_list.c b/libsystem_asl.tproj/src/asl_msg_list.c new file mode 100644 index 0000000..a1e7ce8 --- /dev/null +++ b/libsystem_asl.tproj/src/asl_msg_list.c @@ -0,0 +1,587 @@ +/* + * Copyright (c) 2012-2013 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 + +asl_msg_list_t * +asl_msg_list_new(void) +{ + asl_msg_list_t *out = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t)); + if (out == NULL) return NULL; + + out->asl_type = ASL_TYPE_LIST; + out->refcount = 1; + + return out; +} + +asl_msg_list_t * +asl_msg_list_new_count(uint32_t n) +{ + asl_msg_list_t *out = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t)); + if (out == NULL) return NULL; + + out->asl_type = ASL_TYPE_LIST; + out->refcount = 1; + out->count = n; + + out->msg = (asl_msg_t **)reallocf(out->msg, out->count * sizeof(asl_msg_t *)); + if (out->msg == NULL) + { + free(out); + return NULL; + } + + return out; +} + +asl_msg_list_t * +asl_msg_list_retain(asl_msg_list_t *list) +{ + if (list == NULL) return NULL; + asl_retain((asl_object_t)list); + return list; +} + +void +asl_msg_list_release(asl_msg_list_t *list) +{ + if (list == NULL) return; + asl_release((asl_object_t)list); +} + +char * +asl_msg_list_to_string(asl_msg_list_t *list, uint32_t *len) +{ + uint32_t i; + char tmp[16]; + char *out; + asl_string_t *str; + + if (list == NULL) return NULL; + if (list->count == 0) return NULL; + if (list->msg == NULL) return NULL; + + str = asl_string_new(ASL_ENCODE_ASL); + if (str == NULL) return NULL; + + snprintf(tmp, sizeof(tmp), "%u", list->count); + asl_string_append(str, tmp); + asl_string_append_char_no_encoding(str, '\n'); + + for (i = 0; i < list->count; i++) + { + asl_string_append_asl_msg(str, list->msg[i]); + asl_string_append_char_no_encoding(str, '\n'); + } + + *len = asl_string_length(str); + out = asl_string_release_return_bytes(str); + return out; +} + +asl_string_t * +asl_msg_list_to_asl_string(asl_msg_list_t *list, uint32_t encoding) +{ + uint32_t i; + char tmp[16]; + asl_string_t *str; + + if (list == NULL) return NULL; + if (list->count == 0) return NULL; + if (list->msg == NULL) return NULL; + + str = asl_string_new(encoding); + if (str == NULL) return NULL; + + snprintf(tmp, sizeof(tmp), "%u", list->count); + asl_string_append(str, tmp); + asl_string_append_char_no_encoding(str, '\n'); + + for (i = 0; i < list->count; i++) + { + asl_string_append_asl_msg(str, list->msg[i]); + asl_string_append_char_no_encoding(str, '\n'); + } + + return str; +} + +asl_msg_list_t * +asl_msg_list_from_string(const char *buf) +{ + uint32_t i, n; + const char *p; + asl_msg_list_t *out; + asl_msg_t *m; + + if (buf == NULL) return NULL; + p = buf; + + n = atoi(buf); + if (n == 0) return NULL; + + out = asl_msg_list_new(); + if (out == NULL) return NULL; + + for (i = 0; i < n; i++) + { + p = strchr(p, '\n'); + if (p == NULL) + { + asl_msg_list_release(out); + return NULL; + } + + p++; + + m = asl_msg_from_string(p); + if (m == NULL) + { + asl_msg_list_release(out); + return NULL; + } + + asl_msg_list_append(out, m); + asl_msg_release(m); + } + + return out; +} + +void +asl_msg_list_insert(asl_msg_list_t *list, uint32_t x, void *obj) +{ + uint32_t i, j; + asl_object_private_t *oo = (asl_object_private_t *)obj; + + if (list == NULL) return; + if (obj == NULL) return; + if (list->count == UINT32_MAX) return; + + if (x >= list->count) x = list->count; + + uint32_t type = asl_get_type((asl_object_t)oo); + uint32_t count = 0; + + if ((type == ASL_TYPE_MSG) || (type == ASL_TYPE_QUERY)) count = 1; + else count = asl_object_count(oo); + + if (count == 0) return; + + uint64_t check = list->count; + check += count; + if (check > UINT32_MAX) return; + + list->msg = (asl_msg_t **)reallocf(list->msg, (list->count + count) * sizeof(asl_msg_t *)); + if (list->msg == NULL) + { + list->count = 0; + list->curr = 0; + return; + } + + for (i = list->count, j = i - 1; i > x; i--, j--) list->msg[i] = list->msg[j]; + + asl_object_set_iteration_index(oo, 0); + + if ((type == ASL_TYPE_MSG) || (type == ASL_TYPE_QUERY)) + { + list->msg[x] = (asl_msg_t *)asl_retain((asl_object_t)oo); + } + else + { + for (i = x, j = 0; j < count; i++, j++) list->msg[i] = (asl_msg_t *)asl_object_next(oo); + } + + asl_object_set_iteration_index(oo, 0); + + list->count += count; +} + +void +asl_msg_list_append(asl_msg_list_t *list, void *obj) +{ + asl_msg_list_insert(list, UINT32_MAX, obj); +} + +void +asl_msg_list_prepend(asl_msg_list_t *list, void *obj) +{ + asl_msg_list_insert(list, 0, obj); +} + +size_t +asl_msg_list_count(asl_msg_list_t *list) +{ + if (list == NULL) return 0; + return list->count; +} + +asl_msg_t * +asl_msg_list_get_index(asl_msg_list_t *list, size_t index) +{ + asl_msg_t *out; + + if (list == NULL) return NULL; + if (index >= list->count) return NULL; + if (list->msg == NULL) + { + list->curr = 0; + list->count = 0; + return NULL; + } + + out = list->msg[index]; + return out; +} + +void +asl_msg_list_remove_index(asl_msg_list_t *list, size_t index) +{ + uint32_t i, j; + + if (list == NULL) return; + if (index >= list->count) return; + if (list->msg == NULL) + { + list->curr = 0; + list->count = 0; + return; + } + + asl_msg_release(list->msg[index]); + + for (i = index + 1, j = index; i < list->count; i++) list->msg[j] = list->msg[i]; + list->count--; + + list->msg = (asl_msg_t **)reallocf(list->msg, list->count * sizeof(asl_msg_t *)); + if (list->msg == NULL) + { + list->count = 0; + list->curr = 0; + } +} + +asl_msg_t * +asl_msg_list_next(asl_msg_list_t *list) +{ + asl_msg_t *out; + + if (list == NULL) return NULL; + if (list->curr >= list->count) return NULL; + if (list->msg == NULL) + { + list->curr = 0; + list->count = 0; + return NULL; + } + + out = list->msg[list->curr]; + list->curr++; + return out; +} + +asl_msg_t * +asl_msg_list_prev(asl_msg_list_t *list) +{ + asl_msg_t *out; + + if (list == NULL) return NULL; + if (list->curr == 0) return NULL; + if (list->msg == NULL) + { + list->curr = 0; + list->count = 0; + return NULL; + } + + if (list->curr > list->count) list->curr = list->count; + + list->curr--; + out = list->msg[list->curr]; + return out; +} + +void +asl_msg_list_reset_iteration(asl_msg_list_t *list, size_t position) +{ + if (list == NULL) return; + + if (position > list->count) position = SIZE_MAX; + list->curr = position; +} + +asl_msg_list_t * +asl_msg_list_search(asl_msg_list_t *list, asl_msg_t *query) +{ + uint32_t i; + asl_msg_list_t *out = NULL; + + if (list == NULL) return NULL; + + if (list->msg == NULL) + { + list->curr = 0; + list->count = 0; + return NULL; + } + + for (i = 0; i < list->count; i++) + { + int match = 0; + if (query == NULL) match = 1; + else match = asl_msg_cmp(query, list->msg[i]); + + if (match != 0) + { + if (out == NULL) out = asl_msg_list_new(); + if (out == NULL) return NULL; + asl_msg_list_append(out, list->msg[i]); + } + } + + return out; +} + +asl_msg_list_t * +asl_msg_list_match(asl_msg_list_t *list, asl_msg_list_t *qlist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t direction) +{ + uint32_t i, end, n = 0; + struct timeval now, finish; + asl_msg_list_t *out = NULL; + + if (list == NULL) return NULL; + if (list->msg == NULL) + { + list->curr = 0; + list->count = 0; + return NULL; + } + + /* start the timer if a timeout was specified */ + memset(&finish, 0, sizeof(struct timeval)); + if (duration != 0) + { + if (gettimeofday(&finish, NULL) == 0) + { + finish.tv_sec += (duration / USEC_PER_SEC); + finish.tv_usec += (duration % USEC_PER_SEC); + if (finish.tv_usec > USEC_PER_SEC) + { + finish.tv_usec -= USEC_PER_SEC; + finish.tv_sec += 1; + } + } + else + { + /* shouldn't happen, but if gettimeofday failed we just run without a timeout */ + memset(&finish, 0, sizeof(struct timeval)); + } + } + + end = list->count - 1; + if (direction >= 0) + { + if (start >= list->count) + { + if (last != NULL) *last = list->count; + return 0; + } + + direction = 1; + } + else + { + if (start >= list->count) start = list->count - 1; + end = 0; + direction = -1; + } + + i = start; + + do + { + int match = 0; + if (qlist == NULL) match = 1; + else match = asl_msg_cmp_list(list->msg[i], qlist); + + if (last != NULL) *last = i; + + if (match != 0) + { + if (out == NULL) out = asl_msg_list_new(); + if (out == NULL) return NULL; + + asl_msg_list_append(out, list->msg[i]); + n++; + } + + if (n >= count) return n; + + /* check the timer */ + if ((finish.tv_sec != 0) && (gettimeofday(&now, NULL) == 0)) + { + if ((now.tv_sec > finish.tv_sec) || ((now.tv_sec == finish.tv_sec) && (now.tv_usec > finish.tv_usec))) return n; + } + + i += direction; + } while (i != end); + + return out; +} + +#pragma mark - +#pragma mark asl_object support + +static asl_object_private_t * +_jump_alloc(uint32_t type) +{ + return (asl_object_private_t *)asl_msg_list_new(); +} + +static void +_jump_dealloc(asl_object_private_t *obj) +{ + asl_msg_list_t *list = (asl_msg_list_t *)obj; + + if (list == NULL) return; + if (list->msg != NULL) + { + uint32_t i; + for (i = 0; i < list->count; i++) asl_msg_release(list->msg[i]); + free(list->msg); + } + + free(list); +} + +static size_t +_jump_count(asl_object_private_t *obj) +{ + return asl_msg_list_count((asl_msg_list_t *)obj); +} + +static asl_object_private_t * +_jump_next(asl_object_private_t *obj) +{ + return (asl_object_private_t *)asl_msg_list_next((asl_msg_list_t *)obj); +} + +static asl_object_private_t * +_jump_prev(asl_object_private_t *obj) +{ + return (asl_object_private_t *)asl_msg_list_prev((asl_msg_list_t *)obj); +} + +static asl_object_private_t * +_jump_get_object_at_index(asl_object_private_t *obj, size_t n) +{ + return (asl_object_private_t *)asl_msg_list_get_index((asl_msg_list_t *)obj, n); +} + +static void +_jump_set_iteration_index(asl_object_private_t *obj, size_t n) +{ + asl_msg_list_reset_iteration((asl_msg_list_t *)obj, n); +} + +static void +_jump_remove_object_at_index(asl_object_private_t *obj, size_t n) +{ + asl_msg_list_remove_index((asl_msg_list_t *)obj, n); +} + +static void +_jump_append(asl_object_private_t *obj, asl_object_private_t *newobj) +{ + int type = asl_get_type((asl_object_t)newobj); + if ((type != ASL_TYPE_QUERY) && (type != ASL_TYPE_MSG)) return; + + asl_msg_list_append((asl_msg_list_t *)obj, newobj); +} + +static void +_jump_prepend(asl_object_private_t *obj, asl_object_private_t *newobj) +{ + int type = asl_get_type((asl_object_t)newobj); + if ((type != ASL_TYPE_QUERY) && (type != ASL_TYPE_MSG)) return; + + asl_msg_list_prepend((asl_msg_list_t *)obj, newobj); +} + +static asl_object_private_t * +_jump_search(asl_object_private_t *obj, asl_object_private_t *query) +{ + int type = asl_get_type((asl_object_t)query); + + if ((query != NULL) && (type != ASL_TYPE_QUERY) && (type != ASL_TYPE_MSG)) return NULL; + + asl_msg_list_t *out = asl_msg_list_search((asl_msg_list_t *)obj, (asl_msg_t *)query); + if (out == NULL) return NULL; + return (asl_object_private_t *)out; +} + +static asl_object_private_t * +_jump_match(asl_object_private_t *obj, asl_object_private_t *qlist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t dir) +{ + int type = asl_get_type((asl_object_t)qlist); + + if ((qlist != NULL) && (type != ASL_TYPE_LIST)) return NULL; + + return (asl_object_private_t *)asl_msg_list_match((asl_msg_list_t *)obj, (asl_msg_list_t *)qlist, last, start, count, duration, dir); +} + +__private_extern__ const asl_jump_table_t * +asl_msg_list_jump_table() +{ + static const asl_jump_table_t jump = + { + .alloc = &_jump_alloc, + .dealloc = &_jump_dealloc, + .set_key_val_op = NULL, + .unset_key = NULL, + .get_val_op_for_key = NULL, + .get_key_val_op_at_index = NULL, + .count = &_jump_count, + .next = &_jump_next, + .prev = &_jump_prev, + .get_object_at_index = &_jump_get_object_at_index, + .set_iteration_index = &_jump_set_iteration_index, + .remove_object_at_index = &_jump_remove_object_at_index, + .append = &_jump_append, + .prepend = &_jump_prepend, + .search = &_jump_search, + .match = &_jump_match + }; + + return &jump; +} diff --git a/libsystem_asl.tproj/src/asl_object.c b/libsystem_asl.tproj/src/asl_object.c new file mode 100644 index 0000000..39286bf --- /dev/null +++ b/libsystem_asl.tproj/src/asl_object.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2007-2013 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 + +static const asl_jump_table_t *asl_jump[ASL_TYPE_COUNT]; +static dispatch_once_t asl_object_once; + +static void +_asl_object_init(void) +{ + asl_jump[ASL_TYPE_MSG] = asl_msg_jump_table(); + asl_jump[ASL_TYPE_QUERY] = asl_msg_jump_table(); + asl_jump[ASL_TYPE_LIST] = asl_msg_list_jump_table(); + asl_jump[ASL_TYPE_FILE] = asl_file_jump_table(); + asl_jump[ASL_TYPE_STORE] = asl_store_jump_table(); + asl_jump[ASL_TYPE_CLIENT] = asl_client_jump_table(); +} + +#pragma mark - +#pragma mark asl_object + +int +asl_object_set_key_val_op(asl_object_private_t *obj, const char *key, const char *val, uint16_t op) +{ + if (obj == NULL) return -1; + if (obj->asl_type >= ASL_TYPE_COUNT) return -1; + + dispatch_once(&asl_object_once, ^{ _asl_object_init(); }); + if (asl_jump[obj->asl_type]->set_key_val_op == NULL) return -1; + return asl_jump[obj->asl_type]->set_key_val_op(obj, key, val, op); +} + +void +asl_object_unset_key(asl_object_private_t *obj, const char *key) +{ + if (obj == NULL) return; + if (obj->asl_type >= ASL_TYPE_COUNT) return; + + dispatch_once(&asl_object_once, ^{ _asl_object_init(); }); + if (asl_jump[obj->asl_type]->unset_key == NULL) return; + asl_jump[obj->asl_type]->unset_key(obj, key); +} + +int +asl_object_get_val_op_for_key(asl_object_private_t *obj, const char *key, const char **val, uint16_t *op) +{ + if (obj == NULL) return -1; + if (obj->asl_type >= ASL_TYPE_COUNT) return -1; + + dispatch_once(&asl_object_once, ^{ _asl_object_init(); }); + if (asl_jump[obj->asl_type]->get_val_op_for_key == NULL) return -1; + return asl_jump[obj->asl_type]->get_val_op_for_key(obj, key, val, op); +} + +int +asl_object_get_key_val_op_at_index(asl_object_private_t *obj, size_t n, const char **key, const char **val, uint16_t *op) +{ + if (obj == NULL) return -1; + if (obj->asl_type >= ASL_TYPE_COUNT) return -1; + + dispatch_once(&asl_object_once, ^{ _asl_object_init(); }); + if (asl_jump[obj->asl_type]->get_key_val_op_at_index == NULL) return -1; + return asl_jump[obj->asl_type]->get_key_val_op_at_index(obj, n, key, val, op); +} + +size_t +asl_object_count(asl_object_private_t *obj) +{ + if (obj == NULL) return 0; + if (obj->asl_type >= ASL_TYPE_COUNT) return 0; + + dispatch_once(&asl_object_once, ^{ _asl_object_init(); }); + if (asl_jump[obj->asl_type]->count == NULL) return 0; + return asl_jump[obj->asl_type]->count(obj); +} + +asl_object_private_t * +asl_object_next(asl_object_private_t *obj) +{ + if (obj == NULL) return NULL; + if (obj->asl_type >= ASL_TYPE_COUNT) return NULL; + + dispatch_once(&asl_object_once, ^{ _asl_object_init(); }); + if (asl_jump[obj->asl_type]->next == NULL) return NULL; + return asl_jump[obj->asl_type]->next(obj); +} + +asl_object_private_t * +asl_object_prev(asl_object_private_t *obj) +{ + if (obj == NULL) return NULL; + if (obj->asl_type >= ASL_TYPE_COUNT) return NULL; + + dispatch_once(&asl_object_once, ^{ _asl_object_init(); }); + if (asl_jump[obj->asl_type]->prev == NULL) return NULL; + return asl_jump[obj->asl_type]->prev(obj); +} + +asl_object_private_t * +asl_object_get_object_at_index(asl_object_private_t *obj, size_t n) +{ + if (obj == NULL) return NULL; + if (obj->asl_type >= ASL_TYPE_COUNT) return NULL; + + dispatch_once(&asl_object_once, ^{ _asl_object_init(); }); + if (asl_jump[obj->asl_type]->get_object_at_index == NULL) return NULL; + return asl_jump[obj->asl_type]->get_object_at_index(obj, n); +} + +void +asl_object_set_iteration_index(asl_object_private_t *obj, size_t n) +{ + if (obj == NULL) return; + if (obj->asl_type >= ASL_TYPE_COUNT) return; + + dispatch_once(&asl_object_once, ^{ _asl_object_init(); }); + if (asl_jump[obj->asl_type]->set_iteration_index == NULL) return; + return asl_jump[obj->asl_type]->set_iteration_index(obj, n); +} + +void +asl_object_remove_object_at_index(asl_object_private_t *obj, size_t n) +{ + if (obj == NULL) return; + if (obj->asl_type >= ASL_TYPE_COUNT) return; + + dispatch_once(&asl_object_once, ^{ _asl_object_init(); }); + if (asl_jump[obj->asl_type]->remove_object_at_index == NULL) return; + return asl_jump[obj->asl_type]->remove_object_at_index(obj, n); +} + +void +asl_object_append(asl_object_private_t *obj, asl_object_private_t *newobj) +{ + int type = ASL_TYPE_CLIENT; + + if (obj != NULL) type = obj->asl_type; + if (type >= ASL_TYPE_COUNT) return; + + dispatch_once(&asl_object_once, ^{ _asl_object_init(); }); + if (asl_jump[type]->append == NULL) return; + return asl_jump[type]->append(obj, newobj); +} + +void +asl_object_prepend(asl_object_private_t *obj, asl_object_private_t *newobj) +{ + if (obj == NULL) return; + if (obj->asl_type >= ASL_TYPE_COUNT) return; + + dispatch_once(&asl_object_once, ^{ _asl_object_init(); }); + if (asl_jump[obj->asl_type]->prepend == NULL) return; + return asl_jump[obj->asl_type]->prepend(obj, newobj); +} + +asl_object_private_t * +asl_object_search(asl_object_private_t *obj, asl_object_private_t *query) +{ + /* default to asl_client_search for obj == NULL */ + if (obj == NULL) return (asl_object_private_t *)asl_client_search(NULL, (asl_msg_t *)query); + if (obj->asl_type >= ASL_TYPE_COUNT) return NULL; + + dispatch_once(&asl_object_once, ^{ _asl_object_init(); }); + if (asl_jump[obj->asl_type]->search == NULL) return NULL; + return asl_jump[obj->asl_type]->search(obj, query); +} + +asl_object_private_t * +asl_object_match(asl_object_private_t *obj, asl_object_private_t *qlist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t dir) +{ + /* default to asl_client_match for obj == NULL */ + if (obj == NULL) return (asl_object_private_t *)asl_client_match(NULL, (asl_msg_list_t *)qlist, last, start, count, duration, dir); + if (obj->asl_type >= ASL_TYPE_COUNT) return NULL; + + dispatch_once(&asl_object_once, ^{ _asl_object_init(); }); + if (asl_jump[obj->asl_type]->match == NULL) return NULL; + return asl_jump[obj->asl_type]->match(obj, qlist, last, start, count, duration, dir); +} + +asl_object_t +asl_retain(asl_object_t obj) +{ + asl_object_private_t *oo = (asl_object_private_t *)obj; + if (oo == NULL) return NULL; + + OSAtomicIncrement32Barrier(&(oo->refcount)); + return obj; +} + +void +asl_release(asl_object_t obj) +{ + asl_object_private_t *oo = (asl_object_private_t *)obj; + if (oo == NULL) return; + if (oo->asl_type >= ASL_TYPE_COUNT) return; + + dispatch_once(&asl_object_once, ^{ _asl_object_init(); }); + if (OSAtomicDecrement32Barrier(&(oo->refcount)) != 0) return; + if (asl_jump[oo->asl_type]->dealloc != NULL) asl_jump[oo->asl_type]->dealloc(oo); +} + +asl_object_t +asl_new(uint32_t type) +{ + if (type >= ASL_TYPE_COUNT) return NULL; + + dispatch_once(&asl_object_once, ^{ _asl_object_init(); }); + if (asl_jump[type]->alloc == NULL) return NULL; + asl_object_t out = (asl_object_t)asl_jump[type]->alloc(type); + return out; +} + +#pragma mark - +#pragma mark utilities + +uint32_t +asl_get_type(asl_object_t obj) +{ + asl_object_private_t *oo = (asl_object_private_t *)obj; + + if (oo == NULL) return ASL_TYPE_UNDEF; + return (int)oo->asl_type; +} + +const char * +asl_get_value_for_key(asl_object_t obj, const char *key) +{ + const char *val = NULL; + uint16_t op; + + asl_object_get_val_op_for_key((asl_object_private_t *)obj, key, &val, &op); + return val; +} + +int +asl_set(asl_object_t obj, const char *key, const char *val) +{ + asl_object_private_t *oo = (asl_object_private_t *)obj; + uint16_t op = 0; + + if (oo == NULL) return -1; + if (oo->asl_type == ASL_TYPE_QUERY) op = (uint32_t)-1; + + return asl_object_set_key_val_op(oo, key, val, op); +} + +int +asl_unset_key(asl_object_t obj, const char *key) +{ + asl_object_unset_key((asl_object_private_t *)obj, key); + return 0; +} + +int +asl_set_key_val_op(asl_object_t obj, const char *key, const char *val, uint16_t op) +{ + return asl_object_set_key_val_op((asl_object_private_t *)obj, key, val, op); +} + +size_t +asl_count(asl_object_t obj) +{ + return asl_object_count((asl_object_private_t *)obj); +} + +asl_object_t +asl_get_index(asl_object_t list, size_t index) +{ + return (asl_object_t)asl_object_get_object_at_index((asl_object_private_t *)list, index); +} + +asl_object_t +asl_next(asl_object_t obj) +{ + return (asl_object_t)asl_object_next((asl_object_private_t *)obj); +} + +asl_object_t +asl_prev(asl_object_t obj) +{ + return (asl_object_t)asl_object_prev((asl_object_private_t *)obj); +} + +void +asl_append(asl_object_t a, asl_object_t b) +{ + asl_object_append((asl_object_private_t *)a, (asl_object_private_t *)b); +} + +void +asl_prepend(asl_object_t a, asl_object_t b) +{ + asl_object_prepend((asl_object_private_t *)a, (asl_object_private_t *)b); +} + +/* asl_send is implemented as asl_append */ +int +asl_send(asl_object_t a, asl_object_t b) +{ + asl_object_append((asl_object_private_t *)a, (asl_object_private_t *)b); + return 0; +} + +const char * +asl_key(asl_object_t obj, uint32_t n) +{ + const char *key = NULL; + size_t sn = n; + + if (asl_object_get_key_val_op_at_index((asl_object_private_t *)obj, sn, &key, NULL, NULL) != 0) return NULL; + return key; +} + +const char * +asl_get(asl_object_t obj, const char *key) +{ + const char *val = NULL; + + if (asl_object_get_val_op_for_key((asl_object_private_t *)obj, key, &val, NULL) != 0) return NULL; + return val; +} + +int +asl_fetch_key_val_op(asl_object_t obj, uint32_t n, const char **key, const char **val, uint32_t *op) +{ + uint16_t op16; + size_t sn = n; + int status = asl_object_get_key_val_op_at_index((asl_object_private_t *)obj, sn, key, val, &op16); + if (status != 0) return status; + if (op != NULL) *op = op16; + return 0; +} + +int +asl_set_query(asl_object_t obj, const char *key, const char *val, uint32_t op) +{ + uint16_t op16 = op; + return asl_object_set_key_val_op((asl_object_private_t *)obj, key, val, op16); +} + +int +asl_unset(asl_object_t obj, const char *key) +{ + asl_object_unset_key((asl_object_private_t *)obj, key); + return 0; +} + +void +asl_reset_iteration(asl_object_t obj, size_t position) +{ + asl_object_set_iteration_index((asl_object_private_t *)obj, position); +} + +asl_object_t +asl_search(asl_object_t data, asl_object_t query) +{ + return (asl_object_t)asl_object_search((asl_object_private_t *)data, (asl_object_private_t *)query); +} + +asl_object_t +asl_match(asl_object_t data, asl_object_t qlist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t direction) +{ + return (asl_object_t)asl_object_match((asl_object_private_t *)data, (asl_object_private_t *)qlist, last, start, count, duration, direction); +} + +void +asl_free(asl_object_t obj) +{ + asl_release(obj); +} + +void +aslresponse_free(asl_object_t obj) +{ + asl_release(obj); +} + +asl_object_t +aslresponse_next(asl_object_t obj) +{ + return (asl_object_t)asl_object_next((asl_object_private_t *)obj); +} + +asl_object_t +asl_list_from_string(const char *buf) +{ + return (asl_object_t)asl_msg_list_from_string(buf); +} + +char * +asl_format(asl_object_t obj, const char *msg_fmt, const char *time_fmt, uint32_t text_encoding) +{ + uint32_t len; + uint32_t type = asl_get_type(obj); + if (type != ASL_TYPE_MSG) return NULL; + return asl_format_message((asl_msg_t *)obj, msg_fmt, time_fmt, text_encoding, &len); +} diff --git a/libsystem_asl.tproj/src/asl_store.c b/libsystem_asl.tproj/src/asl_store.c index 0640d8f..08da1a1 100644 --- a/libsystem_asl.tproj/src/asl_store.c +++ b/libsystem_asl.tproj/src/asl_store.c @@ -35,17 +35,9 @@ #include #include -#include - -#if TARGET_IPHONE_SIMULATOR -#include -#include -#endif - -extern time_t asl_parse_time(const char *str); extern uint64_t asl_file_cursor(asl_file_t *s); extern uint32_t asl_file_match_start(asl_file_t *s, uint64_t start_id, int32_t direction); -extern uint32_t asl_file_match_next(asl_file_t *s, aslresponse query, asl_msg_t **msg, uint64_t *last_id, int32_t direction, int32_t ruid, int32_t rgid); +extern uint32_t asl_file_match_next(asl_file_t *s, asl_msg_list_t *qlist, asl_msg_t **msg, uint64_t *last_id, int32_t direction, int32_t ruid, int32_t rgid); extern int asl_file_create(const char *path, uid_t uid, gid_t gid, mode_t mode); #define SECONDS_PER_DAY 86400 @@ -93,7 +85,7 @@ _asl_start_today() * | MAX_ID (uint64_t) | * */ -uint32_t +ASL_STATUS asl_store_open_write(const char *basedir, asl_store_t **s) { asl_store_t *out; @@ -177,6 +169,9 @@ asl_store_open_write(const char *basedir, asl_store_t **s) return ASL_STATUS_NO_MEMORY; } + out->asl_type = ASL_TYPE_STORE; + out->refcount = 1; + if (basedir == NULL) out->base_dir = strdup(PATH_ASL_STORE); else out->base_dir = strdup(basedir); @@ -204,14 +199,23 @@ asl_store_open_write(const char *basedir, asl_store_t **s) } uint32_t -asl_store_statistics(asl_store_t *s, aslmsg *msg) +asl_store_set_flags(asl_store_t *s, uint32_t flags) { - aslmsg out; + if (s == NULL) return 0; + uint32_t oldflags = s->flags; + s->flags = flags; + return oldflags; +} + +ASL_STATUS +asl_store_statistics(asl_store_t *s, asl_msg_t **msg) +{ + asl_msg_t *out; if (s == NULL) return ASL_STATUS_INVALID_STORE; if (msg == NULL) return ASL_STATUS_INVALID_ARG; - out = asl_new(ASL_TYPE_MSG); + out = asl_msg_new(ASL_TYPE_MSG); if (out == NULL) return ASL_STATUS_NO_MEMORY; /* does nothing for now */ @@ -237,6 +241,9 @@ asl_store_open_read(const char *basedir, asl_store_t **s) out = (asl_store_t *)calloc(1, sizeof(asl_store_t)); if (out == NULL) return ASL_STATUS_NO_MEMORY; + out->asl_type = ASL_TYPE_STORE; + out->refcount = 1; + if (basedir == NULL) out->base_dir = strdup(PATH_ASL_STORE); else out->base_dir = strdup(basedir); @@ -279,10 +286,33 @@ asl_store_file_closeall(asl_store_t *s) } } -uint32_t +asl_store_t * +asl_store_retain(asl_store_t *s) +{ + if (s == NULL) return NULL; + asl_retain((asl_object_t)s); + return s; +} + +void +asl_store_release(asl_store_t *s) +{ + if (s == NULL) return; + asl_release((asl_object_t)s); +} + +ASL_STATUS asl_store_close(asl_store_t *s) { if (s == NULL) return ASL_STATUS_OK; + asl_release((asl_object_t)s); + return ASL_STATUS_OK; +} + +static void +_asl_store_free_internal(asl_store_t *s) +{ + if (s == NULL) return; if (s->base_dir != NULL) free(s->base_dir); s->base_dir = NULL; @@ -290,8 +320,6 @@ asl_store_close(asl_store_t *s) if (s->storedata != NULL) fclose(s->storedata); free(s); - - return ASL_STATUS_OK; } /* @@ -330,7 +358,7 @@ asl_store_file_cache_lru(asl_store_t *s, time_t now, uint32_t ignorex) return x; } -uint32_t +ASL_STATUS asl_store_sweep_file_cache(asl_store_t *s) { if (s == NULL) return ASL_STATUS_INVALID_STORE; @@ -384,7 +412,7 @@ asl_store_make_ug_path(const char *dir, const char *base, const char *ext, uid_t return path; } -static uint32_t +static ASL_STATUS asl_store_file_open_write(asl_store_t *s, char *tstring, int32_t ruid, int32_t rgid, time_t bb, asl_file_t **f, time_t now, uint32_t check_cache) { char *path; @@ -483,8 +511,8 @@ asl_store_file_close(asl_store_t *s, asl_file_t *f) } } -uint32_t -asl_store_save(asl_store_t *s, aslmsg msg) +ASL_STATUS +asl_store_save(asl_store_t *s, asl_msg_t *msg) { struct tm ctm; time_t msg_time, now, bb; @@ -508,9 +536,11 @@ asl_store_save(asl_store_t *s, aslmsg msg) trigger_aslmanager = 0; msg_time = 0; - val = asl_get(msg, ASL_KEY_TIME); - if (val == NULL) msg_time = now; - else msg_time = asl_parse_time(val); + val = NULL; + + if (asl_msg_lookup(msg, ASL_KEY_TIME, &val, NULL) != 0) msg_time = now; + else if (val == NULL) msg_time = now; + else msg_time = asl_core_parse_time(val, NULL); if (msg_time >= s->start_tomorrow) { @@ -533,20 +563,26 @@ asl_store_save(asl_store_t *s, aslmsg msg) } } - val = asl_get(msg, ASL_KEY_READ_UID); ruid = -1; - if (val != NULL) ruid = atoi(val); - - val = asl_get(msg, ASL_KEY_READ_GID); rgid = -1; - if (val != NULL) rgid = atoi(val); + if ((s->flags & ASL_STORE_FLAG_NO_ACLS) == 0) + { + val = NULL; + if ((asl_msg_lookup(msg, ASL_KEY_READ_UID, &val, NULL) == 0) && (val != NULL)) ruid = atoi(val); + + val = NULL; + if ((asl_msg_lookup(msg, ASL_KEY_READ_GID, &val, NULL) == 0) && (val != NULL)) rgid = atoi(val); + } bb = 0; - val = asl_get(msg, ASL_KEY_EXPIRE_TIME); - if (val != NULL) + if ((s->flags & ASL_STORE_FLAG_NO_TTL) == 0) { - bb = 1; - msg_time = asl_parse_time(val); + val = NULL; + if ((asl_msg_lookup(msg, ASL_KEY_EXPIRE_TIME, &val, NULL) == 0) && (val != NULL)) + { + bb = 1; + msg_time = asl_core_parse_time(val, NULL); + } } if (fseeko(s->storedata, 0, SEEK_SET) != 0) return ASL_STATUS_WRITE_FAILED; @@ -656,7 +692,7 @@ asl_store_save(asl_store_t *s, aslmsg msg) return status; } -static uint32_t +static ASL_STATUS asl_store_mkdir(asl_store_t *s, const char *dir, mode_t m) { char *tstring = NULL; @@ -701,8 +737,8 @@ asl_store_mkdir(asl_store_t *s, const char *dir, mode_t m) return ASL_STATUS_OK; } -uint32_t -asl_store_open_aux(asl_store_t *s, aslmsg msg, int *out_fd, char **url) +ASL_STATUS +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; @@ -722,20 +758,26 @@ asl_store_open_aux(asl_store_t *s, aslmsg msg, int *out_fd, char **url) msg_time = time(NULL); - val = asl_get(msg, ASL_KEY_READ_UID); ruid = -1; - if (val != NULL) ruid = atoi(val); - - val = asl_get(msg, ASL_KEY_READ_GID); rgid = -1; - if (val != NULL) rgid = atoi(val); + if ((s->flags & ASL_STORE_FLAG_NO_ACLS) == 0) + { + val = NULL; + if ((asl_msg_lookup(msg, ASL_KEY_READ_UID, &val, NULL) == 0) && (val != NULL)) ruid = atoi(val); + + val = NULL; + if ((asl_msg_lookup(msg, ASL_KEY_READ_GID, &val, NULL) == 0) && (val != NULL)) rgid = atoi(val); + } bb = 0; - val = asl_get(msg, ASL_KEY_EXPIRE_TIME); - if (val != NULL) + if ((s->flags & ASL_STORE_FLAG_NO_TTL) == 0) { - bb = 1; - msg_time = asl_parse_time(val); + val = NULL; + if ((asl_msg_lookup(msg, ASL_KEY_EXPIRE_TIME, &val, NULL) == 0) && (val != NULL)) + { + bb = 1; + msg_time = asl_core_parse_time(val, NULL); + } } if (localtime_r((const time_t *)&msg_time, &ctm) == NULL) return ASL_STATUS_FAILED; @@ -808,8 +850,8 @@ asl_store_open_aux(asl_store_t *s, aslmsg msg, int *out_fd, char **url) return status; } -uint32_t -asl_store_match_timeout(asl_store_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, uint32_t usec) +asl_msg_list_t * +asl_store_match(asl_store_t *s, asl_msg_list_t *qlist, uint64_t *last_id, uint64_t start_id, uint32_t count, uint32_t duration, int32_t direction) { DIR *dp; struct dirent *dent; @@ -817,9 +859,9 @@ asl_store_match_timeout(asl_store_t *s, aslresponse query, aslresponse *res, uin asl_file_t *f; char *path; asl_file_list_t *files; + asl_msg_list_t *res; - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (res == NULL) return ASL_STATUS_INVALID_ARG; + if (s == NULL) return NULL; files = NULL; @@ -827,7 +869,7 @@ asl_store_match_timeout(asl_store_t *s, aslresponse query, aslresponse *res, uin * Open all readable files */ dp = opendir(s->base_dir); - if (dp == NULL) return ASL_STATUS_READ_FAILED; + if (dp == NULL) return NULL; while ((dent = readdir(dp)) != NULL) { @@ -846,18 +888,98 @@ asl_store_match_timeout(asl_store_t *s, aslresponse query, aslresponse *res, uin closedir(dp); - status = asl_file_list_match_timeout(files, query, res, last_id, start_id, count, direction, usec); + res = asl_file_list_match(files, qlist, last_id, start_id, count, duration, direction); asl_file_list_close(files); - return status; + return res; } -uint32_t -asl_store_match(asl_store_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction) +/* + * PRIVATE FOR DEV TOOLS SUPPORT + * DO NOT USE THIS INTERFACE OTHERWISE + * + * This is only called by a client that compiled with a 10.9 SDK, but is running + * with an new 10.10 libasl. + * + * Only searches the ASL database, so the store (first parameter) is ignored. + * + * The query and result are old-style message lists. + * + */ +typedef struct +{ + uint32_t count; + uint32_t curr; + void **msg; +} asl_msg_list_v1_t; + +ASL_STATUS +asl_store_match_timeout(void *ignored, void *query_v1, void **result_v1, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, uint32_t usec) { - return asl_store_match_timeout(s, query, res, last_id, start_id, count, direction, 0); + asl_store_t *asldb = NULL; + asl_msg_list_v1_t *listv1; + asl_msg_list_t *qlist = NULL; + uint32_t status, n; + + if (result_v1 == NULL) return ASL_STATUS_FAILED; + *result_v1 = NULL; + + status = asl_store_open_read(NULL, &asldb); + if (status != ASL_STATUS_OK) return status; + + /* convert query_v1 into an asl_msg_list_t */ + listv1 = (asl_msg_list_v1_t *)query_v1; + if (listv1 != NULL) + { + if (listv1->count > 0) qlist = (asl_msg_list_t *)asl_new(ASL_TYPE_LIST); + + for (listv1->curr = 0; listv1->curr < listv1->count; listv1->curr++) + { + asl_append((asl_object_t)qlist, (asl_object_t)listv1->msg[listv1->curr]); + } + } + + asl_msg_list_t *result = asl_store_match(asldb, qlist, last_id, start_id, count, usec, direction); + asl_release((asl_object_t)asldb); + asl_release((asl_object_t)qlist); + + if (result == NULL) return ASL_STATUS_OK; + + n = asl_count((asl_object_t)result); + if (n == 0) + { + asl_release((asl_object_t)result); + return ASL_STATUS_OK; + } + + listv1 = (asl_msg_list_v1_t *)calloc(1, sizeof(asl_msg_list_v1_t)); + if (listv1 == NULL) + { + asl_release((asl_object_t)result); + return ASL_STATUS_NO_MEMORY; + } + + listv1->count = n; + listv1->msg = (void **)calloc(listv1->count, sizeof(void *)); + if (listv1 == NULL) + { + free(listv1); + asl_release((asl_object_t)result); + return ASL_STATUS_NO_MEMORY; + } + + for (listv1->curr = 0; listv1->curr < listv1->count; listv1->curr++) + { + listv1->msg[listv1->curr] = asl_retain(asl_next((asl_object_t)result)); + } + + listv1->curr = 0; + *result_v1 = listv1; + + asl_release((asl_object_t)result); + return ASL_STATUS_OK; } -uint32_t +ASL_STATUS asl_store_match_start(asl_store_t *s, uint64_t start_id, int32_t direction) { DIR *dp; @@ -887,7 +1009,11 @@ asl_store_match_start(asl_store_t *s, uint64_t start_id, int32_t direction) path = NULL; asprintf(&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 */ + /* + * NB asl_file_open_read will fail if path is NULL, + * if it is not an ASL store file, or if it isn't readable. + * We expect that. + */ status = asl_file_open_read(path, &f); if (path != NULL) free(path); if ((status != ASL_STATUS_OK) || (f == NULL)) continue; @@ -903,43 +1029,174 @@ asl_store_match_start(asl_store_t *s, uint64_t start_id, int32_t direction) return ASL_STATUS_OK; } -uint32_t -asl_store_match_next(asl_store_t *s, aslresponse query, aslresponse *res, uint32_t count) +ASL_STATUS +asl_store_match_next(asl_store_t *s, asl_msg_list_t *qlist, asl_msg_list_t **res, uint32_t count) { if (s == NULL) return ASL_STATUS_INVALID_STORE; if (s->work == NULL) return ASL_STATUS_OK; - return asl_file_list_match_next(s->work, query, res, count); + return asl_file_list_match_next(s->work, qlist, res, count); } -#if TARGET_IPHONE_SIMULATOR -const char *_path_asl_store(void) { - static char * path; - static dispatch_once_t once; +#pragma mark - +#pragma mark asl_object support - dispatch_once(&once, ^{ - char *sim_log_dir = getenv("IPHONE_SIMULATOR_LOG_ROOT"); - assert(sim_log_dir); +static void +_jump_dealloc(asl_object_private_t *obj) +{ + _asl_store_free_internal((asl_store_t *)obj); +} - asprintf(&path, "%s/asl", sim_log_dir); - assert(path); - }); +static asl_object_private_t * +_jump_next(asl_object_private_t *obj) +{ + asl_store_t *s = (asl_store_t *)obj; + asl_msg_list_t *list; + asl_msg_t *out = NULL; + uint64_t last = 0; - return path; + if (s == NULL) return NULL; + if (s->curr == SIZE_MAX) return NULL; + + s->curr++; + list = asl_store_match(s, NULL, &last, s->curr, 1, 0, 1); + if (list == NULL) + { + s->curr = SIZE_MAX; + return NULL; + } + + s->curr = last; + out = asl_msg_list_get_index(list, 0); + asl_msg_list_release(list); + + return (asl_object_private_t *)out; } -const char *_path_asl_archive(void) { - static char * path; - static dispatch_once_t once; +static asl_object_private_t * +_jump_prev(asl_object_private_t *obj) +{ + asl_store_t *s = (asl_store_t *)obj; + asl_msg_list_t *list; + asl_msg_t *out = NULL; + uint64_t last = 0; - dispatch_once(&once, ^{ - char *sim_log_dir = getenv("IPHONE_SIMULATOR_LOG_ROOT"); - assert(sim_log_dir); + if (s == NULL) return NULL; + if (s->curr == 0) return NULL; - asprintf(&path, "%s/asl.archive", sim_log_dir); - assert(path); - }); + s->curr--; + if (s->curr == 0) return NULL; - return path; + list = asl_store_match(s, NULL, &last, s->curr, 1, 0, -1); + if (list == NULL) + { + s->curr = 0; + return NULL; + } + + s->curr = last; + out = asl_msg_list_get_index(list, 0); + asl_msg_list_release(list); + + return (asl_object_private_t *)out; +} + +static void +_jump_set_iteration_index(asl_object_private_t *obj, size_t n) +{ + asl_store_t *s = (asl_store_t *)obj; + if (s == NULL) return; + + s->curr = n; +} + +static void +_jump_append(asl_object_private_t *obj, asl_object_private_t *newobj) +{ + asl_store_t *s = (asl_store_t *)obj; + int type = asl_get_type((asl_object_t)newobj); + if (s == NULL) return; + if (s->flags & ASL_FILE_FLAG_READ) return; + + if (type == ASL_TYPE_LIST) + { + asl_msg_t *msg; + asl_msg_list_reset_iteration((asl_msg_list_t *)newobj, 0); + while (NULL != (msg = asl_msg_list_next((asl_msg_list_t *)newobj))) + { + if (asl_store_save(s, msg) != ASL_STATUS_OK) return; + } + } + else if ((type == ASL_TYPE_MSG) || (type == ASL_TYPE_QUERY)) + { + asl_store_save(s, (asl_msg_t *)newobj); + } +} + +static asl_object_private_t * +_jump_search(asl_object_private_t *obj, asl_object_private_t *query) +{ + asl_store_t *s = (asl_store_t *)obj; + int type = asl_get_type((asl_object_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) + { + out = asl_store_match(s, NULL, &last, 0, 0, 0, 1); + } + else if (type == ASL_TYPE_LIST) + { + out = asl_store_match(s, (asl_msg_list_t *)query, &last, 0, 0, 0, 1); + } + else if ((type == ASL_TYPE_MSG) || (type == ASL_TYPE_QUERY)) + { + ql = asl_msg_list_new(); + asl_msg_list_append(ql, query); + + out = asl_store_match(s, ql, &last, 0, 0, 0, 1); + asl_msg_list_release(ql); + } + + if (status != ASL_STATUS_OK) return NULL; + return (asl_object_private_t *)out; +} + +static asl_object_private_t * +_jump_match(asl_object_private_t *obj, asl_object_private_t *qlist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t dir) +{ + uint64_t x; + asl_msg_list_t *out; + + out = asl_store_match((asl_store_t *)obj, (asl_msg_list_t *)qlist, &x, start, count, duration, dir); + *last = x; + return (asl_object_private_t *)out; +} + +__private_extern__ const asl_jump_table_t * +asl_store_jump_table() +{ + static const asl_jump_table_t jump = + { + .alloc = NULL, + .dealloc = &_jump_dealloc, + .set_key_val_op = NULL, + .unset_key = NULL, + .get_val_op_for_key = NULL, + .get_key_val_op_at_index = NULL, + .count = NULL, + .next = &_jump_next, + .prev = &_jump_prev, + .get_object_at_index = NULL, + .set_iteration_index = &_jump_set_iteration_index, + .remove_object_at_index = NULL, + .append = &_jump_append, + .prepend = NULL, + .search = &_jump_search, + .match = &_jump_match + }; + + return &jump; } -#endif diff --git a/libsystem_asl.tproj/src/asl_string.c b/libsystem_asl.tproj/src/asl_string.c new file mode 100644 index 0000000..9ab5221 --- /dev/null +++ b/libsystem_asl.tproj/src/asl_string.c @@ -0,0 +1,532 @@ +/* + * Copyright (c) 2007-2013 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 + +#define ASL_STRING_QUANTUM 256 +static const char *cvis_7_13 = "abtnvfr"; + +asl_string_t * +asl_string_new(uint32_t encoding) +{ + asl_string_t *str = (asl_string_t *)calloc(1, sizeof(asl_string_t)); + if (str == NULL) return NULL; + + str->asl_type = ASL_TYPE_STRING; + str->refcount = 1; + + str->encoding = encoding; + str->delta = ASL_STRING_QUANTUM; + if (encoding & ASL_STRING_VM) str->delta = PAGE_SIZE; + str->bufsize = 0; + str->cursor = 0; + + if (encoding & ASL_STRING_LEN) asl_string_append_no_encoding(str, " 0 "); + return str; +} + +asl_string_t * +asl_string_retain(asl_string_t *str) +{ + if (str == NULL) return NULL; + + OSAtomicIncrement32Barrier(&(str->refcount)); + return str; +} + +void +asl_string_release(asl_string_t *str) +{ + if (str == NULL) return; + if (OSAtomicDecrement32Barrier(&(str->refcount)) != 0) return; + + if (str->encoding & ASL_STRING_VM) + { + vm_deallocate(mach_task_self(), (vm_address_t)str->buf, str->bufsize); + } + else + { + free(str->buf); + } + + free(str); +} + +char * +asl_string_release_return_bytes(asl_string_t *str) +{ + char *out; + if (str == NULL) return NULL; + + if (OSAtomicDecrement32Barrier(&(str->refcount)) != 0) + { + /* string is still retained - copy buf */ + if (str->encoding & ASL_STRING_VM) + { + if (str->bufsize == 0) return NULL; + + vm_address_t new = 0; + kern_return_t kstatus = vm_allocate(mach_task_self(), &new, str->bufsize, TRUE); + if (kstatus != KERN_SUCCESS) return NULL; + + memcpy((void *)new, str->buf, str->bufsize); + return (char *)new; + } + else + { + if (str->cursor == 0) return NULL; + return strdup(str->buf); + } + } + + out = str->buf; + free(str); + return out; +} + +char * +asl_string_bytes(asl_string_t *str) +{ + if (str == NULL) return NULL; + return str->buf; +} + +/* length includes trailing nul */ +size_t +asl_string_length(asl_string_t *str) +{ + if (str == NULL) return 0; + if (str->cursor == 0) return 0; + + return str->cursor + 1; +} + +size_t +asl_string_allocated_size(asl_string_t *str) +{ + if (str == NULL) return 0; + return str->bufsize; +} + +static int +_asl_string_grow(asl_string_t *str, size_t len) +{ + size_t newlen = 0; + + if (str == NULL) return -1; + if (len == 0) return 0; + + if (str->bufsize == 0) + { + newlen = ((len + str->delta - 1) / str->delta) * str->delta; + } + else + { + /* used size is (str->cursor + 1) including tailiing nul */ + if (len <= (str->bufsize - (str->cursor + 1))) return 0; + + /* really this is ((str->cursor + 1) + len + (str->delta - 1)) */ + newlen = ((str->cursor + len + str->delta) / str->delta) * str->delta; + } + + if (str->encoding & ASL_STRING_VM) + { + kern_return_t kstatus; + vm_address_t new = 0; + + kstatus = vm_allocate(mach_task_self(), &new, newlen, TRUE); + if (kstatus != KERN_SUCCESS) + { + new = 0; + newlen = 0; + return -1; + } + + if (str->buf != NULL) + { + memcpy((void *)new, str->buf, str->bufsize); + vm_deallocate(mach_task_self(), (vm_address_t)str->buf, str->bufsize); + } + + str->buf = (char *)new; + str->bufsize = newlen; + } + else + { + str->buf = reallocf(str->buf, newlen); + if (str->buf == NULL) + { + str->cursor = 0; + str->bufsize = 0; + return -1; + } + + str->bufsize = newlen; + } + + return 0; +} + +asl_string_t * +asl_string_append_char_no_encoding(asl_string_t *str, const char c) +{ + size_t len; + + if (str == NULL) return NULL; + + 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) +{ + size_t len, applen; + + if (str == NULL) return NULL; + if (app == NULL) return str; + + applen = strlen(app); + len = applen; + if (str->bufsize == 0) len++; + + if (_asl_string_grow(str, len) < 0) return str; + + memcpy(str->buf + str->cursor, app, applen); + + 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; +} + +static asl_string_t * +asl_string_append_internal(asl_string_t *str, const char *app, int encode_space) +{ + uint8_t x; + const char *p; + + if (str == NULL) return NULL; + if (app == NULL) return str; + + switch (str->encoding & ASL_ENCODE_MASK) + { + case ASL_ENCODE_NONE: + { + return asl_string_append_no_encoding(str, app); + } + case ASL_ENCODE_SAFE: + { + /* minor encoding to reduce the likelyhood of spoof attacks */ + const char *p; + + for (p = app; *p != '\0'; p++) + { + if ((*p == 10) || (*p == 13)) + { + asl_string_append_no_encoding(str, "\n\t"); + } + else if (*p == 8) + { + asl_string_append_no_encoding(str, "^H"); + } + else + { + asl_string_append_char_no_encoding(str, *p); + } + } + + return str; + } + case ASL_ENCODE_ASL: + { + for (p = app; *p != '\0'; p++) + { + int meta = 0; + + x = *p; + + /* Meta chars get \M prefix */ + if (x >= 128) + { + /* except meta-space, which is \240 */ + if (x == 160) + { + asl_string_append_no_encoding(str, "\\240"); + continue; + } + + asl_string_append_no_encoding(str, "\\M"); + x &= 0x7f; + meta = 1; + } + + /* space is either ' ' or \s */ + if (x == 32) + { + if (encode_space == 0) + { + asl_string_append_char_no_encoding(str, ' '); + continue; + } + + asl_string_append_no_encoding(str, "\\s"); + continue; + } + + /* \ is escaped */ + if ((meta == 0) && (x == 92)) + { + asl_string_append_no_encoding(str, "\\\\"); + 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, "\\]"); + continue; + } + + /* DEL is \^? */ + if (x == 127) + { + if (meta == 0) + { + asl_string_append_char_no_encoding(str, '\\'); + } + + asl_string_append_no_encoding(str, "^?"); + continue; + } + + /* 33-126 are printable (add a '-' prefix for meta) */ + if ((x >= 33) && (x <= 126)) + { + if (meta == 1) + { + asl_string_append_char_no_encoding(str, '-'); + } + + asl_string_append_char_no_encoding(str, x); + 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)) + { + asl_string_append_char_no_encoding(str, '\\'); + asl_string_append_char_no_encoding(str, cvis_7_13[x - 7]); + continue; + } + + /* 0 - 31 are ^@ - ^_ (non-meta get a leading \) */ + if (x <= 31) + { + if (meta == 0) + { + asl_string_append_char_no_encoding(str, '\\'); + } + + 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); + } + + return str; + } + case ASL_ENCODE_XML: + { + for (p = app; *p != '\0'; p++) + { + x = *p; + + if (x == '&') + { + asl_string_append_no_encoding(str, "&"); + } + else if (x == '<') + { + asl_string_append_no_encoding(str, "<"); + } + else if (x == '>') + { + asl_string_append_no_encoding(str, ">"); + } + else if (x == '"') + { + asl_string_append_no_encoding(str, """); + } + else if (x == '\'') + { + asl_string_append_no_encoding(str, "'"); + } + else if (iscntrl(x)) + { + char tmp[8]; + snprintf(tmp, sizeof(tmp), "&#x%02hhx;", x); + asl_string_append_no_encoding(str, tmp); + } + else + { + asl_string_append_char_no_encoding(str, x); + } + } + } + default: + { + return str; + } + } + + return str; +} + +asl_string_t * +asl_string_append(asl_string_t *str, const char *app) +{ + return asl_string_append_internal(str, app, 0); +} + +asl_string_t * +asl_string_append_asl_key(asl_string_t *str, const char *app) +{ + return asl_string_append_internal(str, app, 1); +} + +asl_string_t * +asl_string_append_op(asl_string_t *str, uint32_t op) +{ + char opstr[8]; + uint32_t i; + + if (str == NULL) return NULL; + + if (op == ASL_QUERY_OP_NULL) + { + return asl_string_append_char_no_encoding(str, '.'); + } + + i = 0; + if (op & ASL_QUERY_OP_CASEFOLD) opstr[i++] = 'C'; + + if (op & ASL_QUERY_OP_REGEX) opstr[i++] = 'R'; + + if (op & ASL_QUERY_OP_NUMERIC) opstr[i++] = 'N'; + + if (op & ASL_QUERY_OP_PREFIX) + { + if (op & ASL_QUERY_OP_SUFFIX) opstr[i++] = 'S'; + else opstr[i++] = 'A'; + } + if (op & ASL_QUERY_OP_SUFFIX) opstr[i++] = 'Z'; + + switch (op & ASL_QUERY_OP_TRUE) + { + case ASL_QUERY_OP_EQUAL: + opstr[i++] = '='; + break; + case ASL_QUERY_OP_GREATER: + opstr[i++] = '>'; + break; + case ASL_QUERY_OP_GREATER_EQUAL: + opstr[i++] = '>'; + opstr[i++] = '='; + break; + case ASL_QUERY_OP_LESS: + opstr[i++] = '<'; + break; + case ASL_QUERY_OP_LESS_EQUAL: + opstr[i++] = '<'; + opstr[i++] = '='; + break; + case ASL_QUERY_OP_NOT_EQUAL: + opstr[i++] = '!'; + break; + case ASL_QUERY_OP_TRUE: + opstr[i++] = 'T'; + break; + default: + break; + } + + if (i == 0) + { + return asl_string_append_char_no_encoding(str, '.'); + } + + opstr[i] = '\0'; + return asl_string_append_no_encoding(str, opstr); +} + +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_internal(str, s, 0); + asl_string_append_no_encoding(str, "\n"); + return str; +} + diff --git a/libsystem_asl.tproj/src/asl_util.c b/libsystem_asl.tproj/src/asl_util.c index 4127a80..2965f97 100644 --- a/libsystem_asl.tproj/src/asl_util.c +++ b/libsystem_asl.tproj/src/asl_util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2011 Apple Inc. All rights reserved. + * Copyright (c) 2006-2013 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -34,6 +34,7 @@ #include #include #include +#include #include static uint8_t *b64charset = (uint8_t *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -179,10 +180,10 @@ asl_b64_encode(const uint8_t *buf, size_t len) uint8_t *out; uint8_t b; size_t i0, i1, i2, j, outlen; - + if (buf == NULL) return NULL; if (len == 0) return NULL; - + outlen = ((len + 2) / 3) * 4; out = (uint8_t *)malloc(outlen + 1); if (out == NULL) @@ -190,58 +191,126 @@ asl_b64_encode(const uint8_t *buf, size_t len) errno = ENOMEM; return NULL; } - + out[outlen] = 0; - + i0 = 0; i1 = 1; i2 = 2; j = 0; - + while (i2 < len) { b = buf[i0] >> 2; out[j++] = b64charset[b]; - + b = ((buf[i0] & 0x03) << 4) | (buf[i1] >> 4); out[j++] = b64charset[b]; - + b = ((buf[i1] & 0x0f) << 2) | ((buf[i2] & 0xc0) >> 6); out[j++] = b64charset[b]; - + b = buf[i2] & 0x3f; out[j++] = b64charset[b]; - + i0 += 3; i1 = i0 + 1; i2 = i1 + 1; } - + if (i0 < len) { b = buf[i0] >> 2; out[j++] = b64charset[b]; - + b = (buf[i0] & 0x03) << 4; - + if (i1 < len) b |= (buf[i1] >> 4); out[j++] = b64charset[b]; - + if (i1 >= len) { out[j++] = '='; out[j++] = '='; return out; } - + b = (buf[i1] & 0x0f) << 2; out[j++] = b64charset[b]; out[j++] = '='; } - + return out; } +int +asl_syslog_faciliy_name_to_num(const char *name) +{ + if (name == NULL) return -1; + + if (strcaseeq(name, "auth")) return LOG_AUTH; + if (strcaseeq(name, "authpriv")) return LOG_AUTHPRIV; + if (strcaseeq(name, "cron")) return LOG_CRON; + if (strcaseeq(name, "daemon")) return LOG_DAEMON; + if (strcaseeq(name, "ftp")) return LOG_FTP; + if (strcaseeq(name, "install")) return LOG_INSTALL; + if (strcaseeq(name, "kern")) return LOG_KERN; + if (strcaseeq(name, "lpr")) return LOG_LPR; + if (strcaseeq(name, "mail")) return LOG_MAIL; + if (strcaseeq(name, "netinfo")) return LOG_NETINFO; + if (strcaseeq(name, "remoteauth")) return LOG_REMOTEAUTH; + if (strcaseeq(name, "news")) return LOG_NEWS; + if (strcaseeq(name, "security")) return LOG_AUTH; + if (strcaseeq(name, "syslog")) return LOG_SYSLOG; + if (strcaseeq(name, "user")) return LOG_USER; + if (strcaseeq(name, "uucp")) return LOG_UUCP; + if (strcaseeq(name, "local0")) return LOG_LOCAL0; + if (strcaseeq(name, "local1")) return LOG_LOCAL1; + if (strcaseeq(name, "local2")) return LOG_LOCAL2; + if (strcaseeq(name, "local3")) return LOG_LOCAL3; + if (strcaseeq(name, "local4")) return LOG_LOCAL4; + if (strcaseeq(name, "local5")) return LOG_LOCAL5; + if (strcaseeq(name, "local6")) return LOG_LOCAL6; + if (strcaseeq(name, "local7")) return LOG_LOCAL7; + if (strcaseeq(name, "launchd")) return LOG_LAUNCHD; + + return -1; +} + +const char * +asl_syslog_faciliy_num_to_name(int n) +{ + if (n < 0) return NULL; + + if (n == LOG_AUTH) return "auth"; + if (n == LOG_AUTHPRIV) return "authpriv"; + if (n == LOG_CRON) return "cron"; + if (n == LOG_DAEMON) return "daemon"; + if (n == LOG_FTP) return "ftp"; + if (n == LOG_INSTALL) return "install"; + if (n == LOG_KERN) return "kern"; + if (n == LOG_LPR) return "lpr"; + if (n == LOG_MAIL) return "mail"; + if (n == LOG_NETINFO) return "netinfo"; + if (n == LOG_REMOTEAUTH) return "remoteauth"; + if (n == LOG_NEWS) return "news"; + if (n == LOG_AUTH) return "security"; + if (n == LOG_SYSLOG) return "syslog"; + if (n == LOG_USER) return "user"; + if (n == LOG_UUCP) return "uucp"; + if (n == LOG_LOCAL0) return "local0"; + if (n == LOG_LOCAL1) return "local1"; + if (n == LOG_LOCAL2) return "local2"; + if (n == LOG_LOCAL3) return "local3"; + if (n == LOG_LOCAL4) return "local4"; + if (n == LOG_LOCAL5) return "local5"; + if (n == LOG_LOCAL6) return "local6"; + if (n == LOG_LOCAL7) return "local7"; + if (n == LOG_LAUNCHD) return "launchd"; + + return NULL; +} + static xpc_connection_t _create_aslmanager_connection(void) { diff --git a/libsystem_asl.tproj/src/syslog.c b/libsystem_asl.tproj/src/syslog.c index cc4110f..91fb213 100644 --- a/libsystem_asl.tproj/src/syslog.c +++ b/libsystem_asl.tproj/src/syslog.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2010 Apple Inc. All rights reserved. + * Copyright (c) 1999-2013 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -54,6 +54,8 @@ * SUCH DAMAGE. */ +#include + #include #include #include @@ -61,7 +63,8 @@ #include #include #include -#include "asl_private.h" +#include +#include #ifdef __STDC__ #include @@ -117,7 +120,7 @@ void vsyslog(int pri, const char *fmt, va_list ap) { int fac; - aslmsg facmsg; + asl_msg_t *facmsg; const char *facility; facmsg = NULL; @@ -127,8 +130,8 @@ vsyslog(int pri, const char *fmt, va_list ap) facility = asl_syslog_faciliy_num_to_name(fac); if (facility != NULL) { - facmsg = asl_new(ASL_TYPE_MSG); - asl_set(facmsg, ASL_KEY_FACILITY, facility); + facmsg = asl_msg_new(ASL_TYPE_MSG); + asl_msg_set_key_val(facmsg, ASL_KEY_FACILITY, facility); } } @@ -142,11 +145,11 @@ vsyslog(int pri, const char *fmt, va_list ap) asl_set_filter(_sl_asl, _sl_mask); } - asl_vlog(_sl_asl, facmsg, LOG_PRI(pri), fmt, ap); + asl_vlog(_sl_asl, (aslmsg)facmsg, LOG_PRI(pri), fmt, ap); pthread_mutex_unlock(&_sl_lock); - if (facmsg != NULL) asl_free(facmsg); + if (facmsg != NULL) asl_msg_release(facmsg); } #ifndef BUILDING_VARIANT @@ -159,8 +162,7 @@ openlog(const char *ident, int opts, int logfac) pthread_mutex_lock(&_sl_lock); - /* close existing aslclient */ - asl_close(_sl_asl); + if (_sl_asl != NULL) asl_close(_sl_asl); _sl_asl = NULL; free(_sl_ident); @@ -196,7 +198,7 @@ closelog() if (_sl_asl != NULL) asl_close(_sl_asl); _sl_asl = NULL; - if (_sl_ident != NULL) free(_sl_ident); + free(_sl_ident); _sl_ident = NULL; pthread_mutex_unlock(&_sl_lock); @@ -214,6 +216,7 @@ setlogmask(int mask) _sl_mask = mask; oldmask = asl_set_filter(_sl_asl, mask); + if (_sl_opts & LOG_PERROR) asl_set_output_file_filter(_sl_asl, STDERR_FILENO, mask); pthread_mutex_unlock(&_sl_lock); diff --git a/syslog.xcodeproj/project.pbxproj b/syslog.xcodeproj/project.pbxproj index 34418a3..566416b 100644 --- a/syslog.xcodeproj/project.pbxproj +++ b/syslog.xcodeproj/project.pbxproj @@ -11,7 +11,6 @@ isa = PBXAggregateTarget; buildConfigurationList = 3F0552BC1614E58B00F729CC /* Build configuration list for PBXAggregateTarget "libasl_Sim" */; buildPhases = ( - 3FFD4404174862F2007DAC1B /* Delete man pages */, ); dependencies = ( 3FFD440917486329007DAC1B /* PBXTargetDependency */, @@ -34,7 +33,6 @@ isa = PBXAggregateTarget; buildConfigurationList = 3FFD4402174862D0007DAC1B /* Build configuration list for PBXAggregateTarget "executables_Sim" */; buildPhases = ( - 3FFD440517486314007DAC1B /* Delete man pages */, 3F5F5B9C17487ADB00C12281 /* Configuration */, ); dependencies = ( @@ -61,6 +59,14 @@ /* Begin PBXBuildFile section */ 2D30656E150E6EFF00F31A54 /* asl_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D30656C150E6EFF00F31A54 /* asl_common.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, ); }; }; + 2D31F3C817E77F3300F2A60C /* asl_string.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D31F3C417E77F3300F2A60C /* asl_string.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 2D31F3CD17E77F8800F2A60C /* asl_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D31F3C917E77F8800F2A60C /* asl_client.c */; }; + 2D31F3CE17E77F8800F2A60C /* asl_msg_list.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D31F3CA17E77F8800F2A60C /* asl_msg_list.c */; }; + 2D31F3CF17E77F8800F2A60C /* asl_object.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D31F3CB17E77F8800F2A60C /* asl_object.c */; }; + 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 */; }; 2DCF701A150E97C0002D5E8F /* libaslcommon.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 505ACB9D108FD16400197086 /* libaslcommon.a */; }; @@ -87,7 +93,6 @@ 5020A37F1098EEC400982ED6 /* libaslcommon.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 505ACB9D108FD16400197086 /* libaslcommon.a */; }; 5039176F1091408B0001165E /* aslmanager.c in Sources */ = {isa = PBXBuildFile; fileRef = 5039176C1091408B0001165E /* aslmanager.c */; }; 503917B81091410E0001165E /* asl_action.c in Sources */ = {isa = PBXBuildFile; fileRef = 503917A61091410E0001165E /* asl_action.c */; }; - 503917BA1091410E0001165E /* bb_convert.c in Sources */ = {isa = PBXBuildFile; fileRef = 503917A91091410E0001165E /* bb_convert.c */; }; 503917BB1091410E0001165E /* bsd_in.c in Sources */ = {isa = PBXBuildFile; fileRef = 503917AA1091410E0001165E /* bsd_in.c */; }; 503917BC1091410E0001165E /* bsd_out.c in Sources */ = {isa = PBXBuildFile; fileRef = 503917AB1091410E0001165E /* bsd_out.c */; }; 503917BD1091410E0001165E /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 503917AD1091410E0001165E /* daemon.c */; }; @@ -107,8 +112,6 @@ 505ACBA8108FD18400197086 /* asl_ipc.defs in Headers */ = {isa = PBXBuildFile; fileRef = 505ACBA2108FD18400197086 /* asl_ipc.defs */; }; 505ACBA9108FD18400197086 /* asl_memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 505ACBA3108FD18400197086 /* asl_memory.c */; }; 505ACBAA108FD18400197086 /* asl_memory.h in Headers */ = {isa = PBXBuildFile; fileRef = 505ACBA4108FD18400197086 /* asl_memory.h */; }; - 505ACBAB108FD18400197086 /* asl_mini_memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 505ACBA5108FD18400197086 /* asl_mini_memory.c */; }; - 505ACBAC108FD18400197086 /* asl_mini_memory.h in Headers */ = {isa = PBXBuildFile; fileRef = 505ACBA6108FD18400197086 /* asl_mini_memory.h */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -181,7 +184,7 @@ 3F6F44131613AA9300CA9ADB /* Install man3 */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; - dstPath = /usr/share/man/man3; + dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man3"; dstSubfolderSpec = 0; files = ( 3F6F44141613AAA600CA9ADB /* asl.3 in Install man3 */, @@ -193,7 +196,7 @@ 503A82631099037D00B0D08A /* Copy Manpage.8 */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; - dstPath = /usr/share/man/man8/; + dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man8"; dstSubfolderSpec = 0; files = ( 503A82741099045F00B0D08A /* aslmanager.8 in Copy Manpage.8 */, @@ -204,7 +207,7 @@ 503A8285109904FD00B0D08A /* Copy Manpage.1 */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; - dstPath = /usr/share/man/man1/; + dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man1"; dstSubfolderSpec = 0; files = ( 503A82761099049900B0D08A /* syslog.1 in Copy Manpage.1 */, @@ -215,7 +218,7 @@ 503A8286109904FD00B0D08A /* Copy Manpage.8 */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; - dstPath = /usr/share/man/man8/; + dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man8"; dstSubfolderSpec = 0; files = ( 503A8278109904C000B0D08A /* syslogd.8 in Copy Manpage.8 */, @@ -226,7 +229,7 @@ 503A8287109904FD00B0D08A /* Copy Manpages.5 */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; - dstPath = /usr/share/man/man5/; + dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man5"; dstSubfolderSpec = 0; files = ( 503A827A109904E400B0D08A /* asl.conf.5 in Copy Manpages.5 */, @@ -240,9 +243,21 @@ /* 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 = ""; }; + 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 = ""; }; + 2D31F3C417E77F3300F2A60C /* asl_string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_string.h; sourceTree = ""; }; + 2D31F3C917E77F8800F2A60C /* asl_client.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_client.c; sourceTree = ""; }; + 2D31F3CA17E77F8800F2A60C /* asl_msg_list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_msg_list.c; sourceTree = ""; }; + 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; }; 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 = ""; }; + 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 = ""; }; + 3F6B6314185AF66C00F692C5 /* util.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = util.xcconfig; sourceTree = ""; }; 3F6F43CA1613922800CA9ADB /* libsystem_asl.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libsystem_asl.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 3F6F43CF1613A8E300CA9ADB /* asl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl.h; sourceTree = ""; }; 3F6F43D01613A8E300CA9ADB /* asl_core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_core.h; sourceTree = ""; }; @@ -261,6 +276,7 @@ 3F6F43E71613A8E300CA9ADB /* asl_msg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_msg.c; sourceTree = ""; }; 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 = ""; }; 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 = ""; }; @@ -272,7 +288,6 @@ 5039177C109140C30001165E /* syslogd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = syslogd; sourceTree = BUILT_PRODUCTS_DIR; }; 503917A61091410E0001165E /* asl_action.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = asl_action.c; path = syslogd.tproj/asl_action.c; sourceTree = ""; }; 503917A81091410E0001165E /* asl.conf.5 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = asl.conf.5; path = syslogd.tproj/asl.conf.5; sourceTree = ""; }; - 503917A91091410E0001165E /* bb_convert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bb_convert.c; path = syslogd.tproj/bb_convert.c; sourceTree = ""; }; 503917AA1091410E0001165E /* bsd_in.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bsd_in.c; path = syslogd.tproj/bsd_in.c; sourceTree = ""; }; 503917AB1091410E0001165E /* bsd_out.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bsd_out.c; path = syslogd.tproj/bsd_out.c; sourceTree = ""; }; 503917AC1091410E0001165E /* com.apple.syslogd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.syslogd.plist; path = syslogd.tproj/com.apple.syslogd.plist; sourceTree = ""; }; @@ -294,8 +309,6 @@ 505ACBA2108FD18400197086 /* asl_ipc.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = asl_ipc.defs; sourceTree = ""; }; 505ACBA3108FD18400197086 /* asl_memory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_memory.c; sourceTree = ""; }; 505ACBA4108FD18400197086 /* asl_memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_memory.h; sourceTree = ""; }; - 505ACBA5108FD18400197086 /* asl_mini_memory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_mini_memory.c; sourceTree = ""; }; - 505ACBA6108FD18400197086 /* asl_mini_memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_mini_memory.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -352,6 +365,7 @@ 3F6F43CD1613A8E300CA9ADB /* libsystem_asl */, 505ACB9E108FD16400197086 /* Products */, 3FFD43F717485C5B007DAC1B /* xcodeconfig */, + 3F900DB519383950003CA7E6 /* xcodescripts */, 503A82461099029200B0D08A /* libbsm.dylib */, 2D60F61015657D0F00F2E3F9 /* libz.dylib */, ); @@ -375,6 +389,10 @@ children = ( 3F6F43CF1613A8E300CA9ADB /* asl.h */, 3F6F43D01613A8E300CA9ADB /* asl_core.h */, + 2D31F3C117E77F3300F2A60C /* asl_client.h */, + 2D31F3C217E77F3300F2A60C /* asl_msg_list.h */, + 2D31F3C317E77F3300F2A60C /* asl_object.h */, + 2D31F3C417E77F3300F2A60C /* asl_string.h */, 3F6F43D11613A8E300CA9ADB /* asl_file.h */, 3F6F43D21613A8E300CA9ADB /* asl_legacy1.h */, 3F6F43D31613A8E300CA9ADB /* asl_msg.h */, @@ -398,6 +416,10 @@ children = ( 3FE798E316161F2A00D547B0 /* syslog.c */, 3F6F43E21613A8E300CA9ADB /* asl.c */, + 2D31F3C917E77F8800F2A60C /* asl_client.c */, + 2D31F3CA17E77F8800F2A60C /* asl_msg_list.c */, + 2D31F3CB17E77F8800F2A60C /* asl_object.c */, + 2D31F3CC17E77F8800F2A60C /* asl_string.c */, 3F6F43E31613A8E300CA9ADB /* asl_core.c */, 3F6F43E41613A8E300CA9ADB /* asl_fd.c */, 3F6F43E51613A8E300CA9ADB /* asl_file.c */, @@ -409,9 +431,21 @@ path = src; sourceTree = ""; }; + 3F900DB519383950003CA7E6 /* xcodescripts */ = { + isa = PBXGroup; + children = ( + 3F900DB619383950003CA7E6 /* sim-compat-symlink.sh */, + ); + path = xcodescripts; + sourceTree = ""; + }; 3FFD43F717485C5B007DAC1B /* xcodeconfig */ = { isa = PBXGroup; children = ( + 3F6B6311185AF66C00F692C5 /* aslmanager.xcconfig */, + 3F6B6312185AF66C00F692C5 /* base.xcconfig */, + 3F6B6313185AF66C00F692C5 /* syslogd.xcconfig */, + 3F6B6314185AF66C00F692C5 /* util.xcconfig */, 3FFD43F817485C5B007DAC1B /* libasl.xcconfig */, ); path = xcodeconfig; @@ -434,7 +468,6 @@ 503917A61091410E0001165E /* asl_action.c */, 2DB4DA0A125FC69A001CDC45 /* after_install.sh */, 503917A81091410E0001165E /* asl.conf.5 */, - 503917A91091410E0001165E /* bb_convert.c */, 503917AA1091410E0001165E /* bsd_in.c */, 503917AB1091410E0001165E /* bsd_out.c */, 503917AC1091410E0001165E /* com.apple.syslogd.plist */, @@ -482,8 +515,6 @@ 505ACBA2108FD18400197086 /* asl_ipc.defs */, 505ACBA3108FD18400197086 /* asl_memory.c */, 505ACBA4108FD18400197086 /* asl_memory.h */, - 505ACBA5108FD18400197086 /* asl_mini_memory.c */, - 505ACBA6108FD18400197086 /* asl_mini_memory.h */, ); path = aslcommon; sourceTree = ""; @@ -495,7 +526,11 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 2D31F3C517E77F3300F2A60C /* asl_client.h in Headers */, + 2D31F3C817E77F3300F2A60C /* asl_string.h in Headers */, 3F6F43F21613A8E300CA9ADB /* asl.h in Headers */, + 2D31F3C717E77F3300F2A60C /* asl_object.h in Headers */, + 2D31F3C617E77F3300F2A60C /* asl_msg_list.h in Headers */, 3F6F43F31613A8E300CA9ADB /* asl_core.h in Headers */, 3F6F43F41613A8E300CA9ADB /* asl_file.h in Headers */, 3F6F43F51613A8E300CA9ADB /* asl_legacy1.h in Headers */, @@ -511,7 +546,6 @@ files = ( 505ACBA8108FD18400197086 /* asl_ipc.defs in Headers */, 505ACBAA108FD18400197086 /* asl_memory.h in Headers */, - 505ACBAC108FD18400197086 /* asl_mini_memory.h in Headers */, 2D9DEB64150E6FE80059BA61 /* asl_common.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -527,6 +561,7 @@ 3F6F43C71613922800CA9ADB /* Frameworks */, 3F6F43C81613922800CA9ADB /* Headers */, 3F6F44131613AA9300CA9ADB /* Install man3 */, + 3F900DB41938393C003CA7E6 /* Sim compat symlink */, ); buildRules = ( ); @@ -660,35 +695,22 @@ ); runOnlyForDeploymentPostprocessing = 1; shellPath = /bin/sh; - shellScript = "mkdir -p ${DSTROOT}${SDKROOT}/System/Library/LaunchDaemons\nmv ${DSTROOT}/System/Library/LaunchDaemons/* ${DSTROOT}${SDKROOT}/System/Library/LaunchDaemons/\n\nmkdir -p ${DSTROOT}${SDKROOT}/etc\ncp ${SRCROOT}/syslogd.tproj/asl_sim.conf ${DSTROOT}${SDKROOT}/etc/asl.conf\n"; + shellScript = "mkdir -p ${DSTROOT}${INSTALL_PATH_PREFIX}/etc\ncp ${SRCROOT}/syslogd.tproj/asl_sim.conf ${DSTROOT}${INSTALL_PATH_PREFIX}/etc/asl.conf\n"; }; - 3FFD4404174862F2007DAC1B /* Delete man pages */ = { + 3F900DB41938393C003CA7E6 /* Sim compat symlink */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 8; files = ( ); inputPaths = ( + "$(SRCROOT)/xcodescripts/sim-compat-symlink.sh", ); - name = "Delete man pages"; + name = "Sim compat symlink"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 1; - shellPath = /bin/sh; - shellScript = "rm -rf ${DSTROOT}/usr/share/man\n"; - }; - 3FFD440517486314007DAC1B /* Delete man pages */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 8; - files = ( - ); - inputPaths = ( - ); - name = "Delete man pages"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 1; - shellPath = /bin/sh; - shellScript = "rm -rf ${DSTROOT}/usr/share/man"; + shellPath = "/bin/bash -e -x"; + shellScript = ". \"${SCRIPT_INPUT_FILE_0}\""; }; 50A9CB7A10A8D16300AA715E /* after install */ = { isa = PBXShellScriptBuildPhase; @@ -715,7 +737,7 @@ ); runOnlyForDeploymentPostprocessing = 1; shellPath = /bin/sh; - 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"; + 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"; showEnvVarsInLog = 0; }; FCF3762A10D2F47C00C0EC8D /* ShellScript */ = { @@ -738,14 +760,18 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2D31F3CD17E77F8800F2A60C /* asl_client.c in Sources */, 3F6F43FB1613A8E300CA9ADB /* asl.c in Sources */, 3F6F43FC1613A8E300CA9ADB /* asl_core.c in Sources */, + 2D31F3D017E77F8800F2A60C /* asl_string.c in Sources */, 3F6F43FD1613A8E300CA9ADB /* asl_fd.c in Sources */, + 2D31F3CE17E77F8800F2A60C /* asl_msg_list.c in Sources */, 3F6F43FE1613A8E300CA9ADB /* asl_file.c in Sources */, 3F6F43FF1613A8E300CA9ADB /* asl_legacy1.c in Sources */, 3F6F44001613A8E300CA9ADB /* asl_msg.c in Sources */, 3F6F44011613A8E300CA9ADB /* asl_store.c in Sources */, 3F6F44021613A8E300CA9ADB /* asl_util.c in Sources */, + 2D31F3CF17E77F8800F2A60C /* asl_object.c in Sources */, 3F6F440A1613A91E00CA9ADB /* asl_ipc.defs in Sources */, 3FE798E416161F2A00D547B0 /* syslog.c in Sources */, ); @@ -764,7 +790,6 @@ buildActionMask = 2147483647; files = ( 503917B81091410E0001165E /* asl_action.c in Sources */, - 503917BA1091410E0001165E /* bb_convert.c in Sources */, 503917BB1091410E0001165E /* bsd_in.c in Sources */, 503917BC1091410E0001165E /* bsd_out.c in Sources */, 503917BD1091410E0001165E /* daemon.c in Sources */, @@ -790,7 +815,6 @@ files = ( 503A81D81098FA3900B0D08A /* asl_ipc.defs in Sources */, 505ACBA9108FD18400197086 /* asl_memory.c in Sources */, - 505ACBAB108FD18400197086 /* asl_mini_memory.c in Sources */, 2D30656E150E6EFF00F31A54 /* asl_common.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -848,6 +872,7 @@ /* Begin XCBuildConfiguration section */ 1DEB928B08733DD80010E9CD /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 3F6B6312185AF66C00F692C5 /* base.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)"; @@ -883,6 +908,7 @@ "$(inherited)", "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders", ); + "ORDER_FILE[sdk=iphoneos*]" = "${SDK_ROOT}/AppleInternal/OrderFiles/libsystem_asl.order"; }; name = Release; }; @@ -917,6 +943,7 @@ }; 50391768109140460001165E /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 3F6B6311185AF66C00F692C5 /* aslmanager.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CODE_SIGN_IDENTITY = "-"; @@ -924,8 +951,6 @@ DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_DYNAMIC_NO_PIC = NO; - INSTALL_PATH = /usr/sbin; - "INSTALL_PATH[sdk=iphonesimulator*]" = "$(SDKROOT)/usr/sbin"; OTHER_CFLAGS = ( "-Wall", "-DINET6", @@ -937,6 +962,7 @@ }; 5039177E109140C40001165E /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 3F6B6313185AF66C00F692C5 /* syslogd.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CODE_SIGN_IDENTITY = "-"; @@ -948,8 +974,6 @@ "$(inherited)", "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders", ); - INSTALL_PATH = /usr/sbin; - "INSTALL_PATH[sdk=iphonesimulator*]" = "$(SDKROOT)/usr/sbin"; OTHER_CFLAGS = ( "-Wall", "-DINET6", @@ -969,6 +993,7 @@ }; 503917CA1091413E0001165E /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 3F6B6314185AF66C00F692C5 /* util.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = util.tproj/entitlements.plist; @@ -977,8 +1002,6 @@ DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_DYNAMIC_NO_PIC = NO; - INSTALL_PATH = /usr/bin; - "INSTALL_PATH[sdk=iphonesimulator*]" = "$(SDKROOT)/usr/bin"; OTHER_CFLAGS = ( "-Wall", "-DINET6", diff --git a/syslogd.tproj/after_install.sh b/syslogd.tproj/after_install.sh index c2406d9..d54cd6a 100755 --- a/syslogd.tproj/after_install.sh +++ b/syslogd.tproj/after_install.sh @@ -2,13 +2,13 @@ set -e if [ "${RC_ProjectName%_Sim}" != "${RC_ProjectName}" ] ; then - DESTDIR="${DSTROOT}${SDKROOT}"/System/Library/LaunchDaemons PLIST="${SRCROOT}"/syslogd.tproj/com.apple.syslogd_sim.plist else - DESTDIR="${DSTROOT}"/System/Library/LaunchDaemons PLIST="${SRCROOT}"/syslogd.tproj/com.apple.syslogd.plist fi +DESTDIR="${DSTROOT}${INSTALL_PATH_PREFIX}"/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 diff --git a/syslogd.tproj/asl.conf.5 b/syslogd.tproj/asl.conf.5 index 85617b9..5d6e115 100644 --- a/syslogd.tproj/asl.conf.5 +++ b/syslogd.tproj/asl.conf.5 @@ -1,4 +1,4 @@ -.\"Copyright (c) 2004-2011 Apple Inc. All rights reserved. +.\"Copyright (c) 2004-2013 Apple Inc. All rights reserved. .\" .\"@APPLE_LICENSE_HEADER_START@ .\" @@ -49,8 +49,8 @@ Modules may be enabled or disabled independently. Each module may specify its own set of rules for acting on received messages. See the ASL MODULES section for details. .Pp -The files contains four types of lines. -Each type is identified by the first non-whitespace character. +The files contain several types of lines, described below. +Each type is identified by the first non-whitespace character in the line. .Pp .Bl -tag -width "=" -compact .It = @@ -92,7 +92,7 @@ These lines generally have the form: .Pp See the OUTPUT CONFIGURATION SETTINGS section for details. .Pp -Comments lines are ignored. +Comment lines are ignored. .Ss PARAMETER SETTINGS The following parameter-settings are recognized by .Nm syslogd . @@ -263,6 +263,12 @@ Will match any message that has a .Dq Flavor key, regardless of its value. .Pp +Note that space characters and closing square bracket characters (']') are specially processed. +The first space character following the beginning of a key delimits the key. +The first closing square bracket following the beginning of a value delimits the value. +So '[= foo bar\ ]' +will match messages which have a key 'foo' with the value 'bar ', including a trailing space character. +.Pp As a special case, the query .Pp .Dl * @@ -569,7 +575,7 @@ If files are created in different timezones but saved with a non-absolute timest 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 sec +.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. @@ -727,7 +733,7 @@ library if the option has been given. If the total size of all the rotated versions of the file exceeds a value given in an .Dq all_max -option, older version of the rotated file will be deleted to keep the total below the specified limit. +option, older versions of the rotated file will be deleted to keep the total below the specified limit. .Pp Although checkpoint and file rotation operations are normally done automatically, .Nm aslmanager @@ -744,6 +750,33 @@ See the and .Xr syslog 1 manuals for details. +.Pp +Programmatically, an +.Xr asl 3 +message may be sent to syslogd to force it to checkpoint either a single file, +or to checkpoint all files for a particular ASL module. +To checkpoint all files: +.Pp + const char *module_name; +.Pp + //TODO: set module_name + asl_object_t ctl = asl_new(ASL_TYPE_MSG); + asl_set(ctl, ASL_KEY_OPTION, "control"); + asl_log(NULL, ctl, ASL_LEVEL_NOTICE, "@ %s checkpoint", module_name); + asl_release(ctl); +.Pp +To checkpoint just one file: +.Pp + const char *module_name; + const char *file_name; +.Pp + //TODO: set module_name + //TODO: set file_name + asl_object_t ctl = asl_new(ASL_TYPE_MSG); + asl_set(ctl, ASL_KEY_OPTION, "control"); + asl_log(NULL, ctl, ASL_LEVEL_NOTICE, "@ %s checkpoint %s", module_name, file_name); + asl_release(ctl); +.Pp .Ss ASL OUTPUT MODULES .Pp An ASL output module is created by a configuration file in the directory /etc/asl. @@ -751,7 +784,7 @@ The file name is used as the module's name. The format of the file is generally the same as .Nm asl.conf with a few exceptions. -Mdules may not have parameter setting lines for the system parameters listed in the +Modules may not have parameter setting lines for the system parameters listed in the PARAMETER SETTINGS or ASLMANAGER PARAMETER SETTINGS sections, nor may they include .Dq broadcast @@ -837,15 +870,17 @@ may enable or disable modules. .Pp A module may be enabled or disabled by sending an .Xr asl 3 -message as shown in this example, which enables a module named -.Dq com.apple.example : +message as shown in this example: +.Pp + int enable; + const char *module_name; .Pp - #include - aslmsg ctl = asl_new(ASL_TYPE_MSG); + //TODO: set module_name + //TODO: set enable to 0 or 1 + asl_object_t ctl = asl_new(ASL_TYPE_MSG); asl_set(ctl, ASL_KEY_OPTION, "control"); - asl_set(ctl, ASL_KEY_MSG, "@ com.apple.example enable 1"); - asl_send(NULL, ctl); - asl_free(ctl); + asl_log(NULL, ctl, ASL_LEVEL_NOTICE, "@ %s enable %d", module_name, enable); + asl_release(ctl); .Pp A control message may also be sent using .Nm syslog @@ -883,7 +918,7 @@ The debug parameter requires a value of to enable debug output, or a value of .Dq 0 to disable it. -Debug messages saved in an auxiliary file attached to an ASL log message. +Debug messages are saved in an auxiliary file attached to an ASL log message. The file may be inspected by opening the file attachement from the Console utility. .Pp .It store_ttl @@ -901,7 +936,7 @@ The archive parameter requires a value of to enable archiving, or a value of .Dq 0 to disable it. -An option archive directory path may follow the +An optional archive directory path may follow the .Dq 0 or .Dq 1 . diff --git a/syslogd.tproj/asl_action.c b/syslogd.tproj/asl_action.c index fd4d381..b33d582 100644 --- a/syslogd.tproj/asl_action.c +++ b/syslogd.tproj/asl_action.c @@ -22,7 +22,6 @@ */ #include - #include #include #include @@ -46,13 +45,9 @@ #include #define _PATH_WALL "/usr/bin/wall" -#define NOTIFY_PATH_SERVICE "com.apple.system.notify.service.path:0x87:" #define MY_ID "asl_action" -/* XXX add to asl.h */ -#define ASL_KEY_MODULE "ASLModule" - #define MAX_FAILURES 5 #define ACTION_STATUS_ERROR -1 @@ -60,6 +55,22 @@ #define IDLE_CLOSE 300 +#define PRIVATE_FLAG_NO_CLOSE 0x00000001 /* File or Store is closed by a cancellation handler */ + +#define DST_CLOSE_CHECKPOINT 0 +#define DST_CLOSE_DELETED 1 +#define DST_CLOSE_ERROR 2 +#define DST_CLOSE_IDLE 3 +#define DST_CLOSE_SHUTDOWN 4 +static const char *why_str[] = +{ + "checkpoint", + "deleted", + "error", + "idle", + "shutdown" +}; + #define forever for(;;) static dispatch_queue_t asl_action_queue; @@ -67,31 +78,47 @@ static dispatch_source_t checkpoint_timer; static time_t sweep_time = 0; #if TARGET_OS_EMBEDDED +#ifndef CRASH_MOVER_SERVICE +#define CRASH_MOVER_SERVICE "com.apple.crash_mover" +#endif static dispatch_queue_t crashlog_queue; -static dispatch_source_t crashlog_sentinel_src; -static int crashlog_sentinel_fd = -1; static time_t crashmover_state = 0; static int crashmover_token = -1; #endif -typedef struct store_data +typedef struct asl_file_data +{ + uint64_t next_id; + asl_file_t *aslfile; + time_t last_time; + uint32_t flags; + uint32_t pending; + dispatch_source_t monitor; +} asl_action_asl_file_data_t; + +typedef struct asl_store_data { - asl_file_t *store; FILE *storedata; + asl_file_t *aslfile; uint64_t next_id; time_t last_time; + uint32_t flags; + uint32_t pending; uint32_t p_year; uint32_t p_month; uint32_t p_day; - dispatch_source_t monitor; -} asl_action_store_data_t; + dispatch_source_t storedata_monitor; + dispatch_source_t aslfile_monitor; +} asl_action_asl_store_data_t; typedef struct file_data { int fd; - uint32_t last_hash; - uint32_t last_count; + uint32_t flags; time_t last_time; + uint32_t last_count; + uint32_t last_hash; + uint32_t pending; char *last_msg; dispatch_source_t dup_timer; dispatch_source_t monitor; @@ -105,12 +132,13 @@ typedef struct set_param_data static int action_asl_store_count; static bool store_has_logged; -extern void db_save_message(aslmsg m); +extern void db_save_message(asl_msg_t *m); /* forward */ static int _act_file_checkpoint_all(uint32_t force); static void _asl_action_post_process_rule(asl_out_module_t *m, asl_out_rule_t *r); static void _asl_action_close_idle_files(time_t idle_time); +static void _act_dst_close(asl_out_rule_t *r, int why); static void _act_out_set_param(asl_out_module_t *m, char *x, bool eval) @@ -139,6 +167,7 @@ _act_out_set_param(asl_out_module_t *m, char *x, bool eval) if (intval == 0) m->flags &= ~MODULE_FLAG_ENABLED; else m->flags|= MODULE_FLAG_ENABLED; + free_string_list(l); return; } else if (!strcasecmp(l[0], "disable")) @@ -151,6 +180,7 @@ _act_out_set_param(asl_out_module_t *m, char *x, bool eval) if (intval != 0) m->flags &= ~MODULE_FLAG_ENABLED; else m->flags|= MODULE_FLAG_ENABLED; + free_string_list(l); return; } @@ -176,7 +206,7 @@ _act_notify(asl_out_module_t *m, asl_out_rule_t *r) } static void -_act_broadcast(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) +_act_broadcast(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg) { #if !TARGET_OS_EMBEDDED FILE *pw; @@ -193,7 +223,7 @@ _act_broadcast(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) if (strcmp(m->name, ASL_MODULE_NAME)) return; val = r->options; - if (val == NULL) val = asl_get(msg, ASL_KEY_MSG); + if (val == NULL) val = asl_msg_get_val_for_key(msg, ASL_KEY_MSG); if (val == NULL) return; pw = popen(_PATH_WALL, "w"); @@ -209,7 +239,19 @@ _act_broadcast(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) } static void -_act_access_control(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) +_act_set_key(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg) +{ + /* Placeholder */ +} + +static void +_act_unset_key(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg) +{ + /* Placeholder */ +} + +static void +_act_access_control(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg) { int32_t ruid, rgid; char *p; @@ -233,10 +275,10 @@ _act_access_control(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) rgid = atoi(p); } - if (ruid != -1) asl_set(msg, ASL_KEY_READ_UID, r->options); + if (ruid != -1) asl_msg_set_key_val(msg, ASL_KEY_READ_UID, r->options); if (p != NULL) { - if (rgid != -1) asl_set(msg, ASL_KEY_READ_GID, p); + if (rgid != -1) asl_msg_set_key_val(msg, ASL_KEY_READ_GID, p); p--; *p = ' '; } @@ -244,144 +286,696 @@ _act_access_control(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) #if TARGET_OS_EMBEDDED static void -_crashlog_sentinel_init(void) +_crashlog_queue_check(void) +{ + /* + * Check whether the crashlog queue has been suspended for too long. + * We allow the crashlog quque to be suspended for 60 seconds. + * After that, we start logging again. This prevents syslogd from + * filling memory due to a suspended queue. CrashMover really shoud + * take no more than a second or two to finish. + */ + if (crashmover_state == 0) return; + if ((time(NULL) - crashmover_state) <= 60) return; + + asldebug("CrashMover timeout: resuming crashlog queue\n"); + dispatch_resume(crashlog_queue); + crashmover_state = 0; +} +#endif + +/* + * cover routine for asl_out_dst_file_create_open() + */ +static int +_act_file_create_open(asl_out_dst_data_t *dst) +{ + return asl_out_dst_file_create_open(dst, NULL); +} + +/* + * Checks and creates (if required) a directory for an ASL data store. + */ +static int +_asl_dir_create(asl_out_rule_t *r) { - char path[MAXPATHLEN]; + struct stat sb; + int status; + + memset(&sb, 0, sizeof(struct stat)); + status = stat(r->dst->path, &sb); + if (status == 0) + { + /* Store path must be a directory */ + if (!S_ISDIR(sb.st_mode)) + { + asldebug("_asl_dir_create: expected a directory at path %s\n", r->dst->path); + return -1; + } + } + else if (errno == ENOENT) + { + /* Directory doesn't exists - try to create it */ + status = asl_out_mkpath(global.asl_out_module, r); + if (status != 0) + { + asldebug("_asl_dir_create: asl_out_mkpath failed: %s\n", r->dst->path); + return -1; + } + } + else + { + /* Unexpected stat error */ + asldebug("_asl_dir_create: stat error %s\n", strerror(errno)); + return -1; + } - if (crashlog_sentinel_src != NULL) return; + return 0; +} - snprintf(path, sizeof(path), "%s/com.apple.asl.%ld", _PATH_CRASHREPORTER, time(NULL)); +/* + * Close an ASL Directory StoreData file + * - cancel the dispatch source for the file + */ +static void +_asl_dir_storedata_close(asl_out_rule_t *r) +{ + asl_action_asl_store_data_t *as_data = (asl_action_asl_store_data_t *)r->dst->private; + if (as_data->storedata == NULL) return; - crashlog_sentinel_fd = open(path, O_WRONLY | O_CREAT); - if (crashlog_sentinel_fd < 0) + if (as_data->storedata_monitor == NULL) + { + /* + * This should never happen, but _asl_dir_storedata_open allows + * dispatch_source_create to fail silently. If there is no dispatch + * source, we just close the file. + */ + asldebug("close ASL storedata fd %d\n", fileno(as_data->storedata)); + fclose(as_data->storedata); + } + else + { + /* + * The storedata_monitor cancel handler will close the file. + */ + dispatch_source_cancel(as_data->storedata_monitor); + dispatch_release(as_data->storedata_monitor); + + } + + asldebug("_asl_dir_storedata_close %p\n", as_data->storedata); + as_data->storedata = NULL; +} + +/* + * Open an ASL Directory StoreData file + * - check directory existance and create it if necessary + * - check for StoreData file and create it (with given xid) if necessary. + * - create a dispatch source to watch for StoreData file deletion + */ +static int +_asl_dir_storedata_open(asl_out_rule_t *r, uint64_t xid) +{ + struct stat sb; + int status; + char dstpath[MAXPATHLEN]; + + asl_action_asl_store_data_t *as_data = (asl_action_asl_store_data_t *)r->dst->private; + if (as_data->storedata != NULL) return 0; + + status = _asl_dir_create(r); + if (status != 0) + { + asldebug("_asl_dir_storedata_open: No directory at path %s\n", r->dst->path); + return -1; + } + + /* StoreData file is not open */ + snprintf(dstpath, sizeof(dstpath), "%s/%s", r->dst->path, FILE_ASL_STORE_DATA); + + memset(&sb, 0, sizeof(struct stat)); + status = stat(dstpath, &sb); + if (status == 0) + { + /* StoreData file exists */ + as_data->storedata = fopen(dstpath, "r+"); + if (as_data->storedata == NULL) + { + asldebug("_asl_dir_storedata_open: fopen existing %s: %s\n", dstpath, strerror(errno)); + return -1; + } + } + else if (errno == ENOENT) + { + /* + * StoreData file does not exist. + * Create a new StoreData with a given xid. + */ + //TODO: This should return a failure if there are any ASL files. + /* that would require reading the directory, thus a performance hit */ + as_data->storedata = fopen(dstpath, "w+"); + if (as_data->storedata == NULL) + { + asldebug("_asl_dir_storedata_open: fopen new %s: %s\n", dstpath, strerror(errno)); + return -1; + } + + uint64_t xout = asl_core_htonq(xid); + status = fwrite(&xout, sizeof(uint64_t), 1, as_data->storedata); + if (status != 1) + { + asldebug("_asl_dir_storedata_open: storedata write failed %d %s\n", errno, strerror(errno)); + return -1; + } + +#if !TARGET_IPHONE_SIMULATOR + if (chown(dstpath, r->dst->uid[0], r->dst->gid[0]) != 0) + { + asldebug("_asl_dir_storedata_open: chown %d %d new %s: %s\n", dstpath, r->dst->uid[0], r->dst->gid[0], strerror(errno)); + return -1; + } +#endif + } + else + { + /* Unexpected stat error */ + asldebug("_asl_dir_storedata_open: stat error %s\n", strerror(errno)); + return -1; + } + + /* create storedata_monitor */ + int fd = fileno(as_data->storedata); + FILE *sdfp = as_data->storedata; + + as_data->storedata_monitor = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE, asl_action_queue); + if (as_data->storedata_monitor != NULL) + { + dispatch_source_set_event_handler(as_data->storedata_monitor, ^{ + _act_dst_close(r, DST_CLOSE_DELETED); + }); + + dispatch_source_set_cancel_handler(as_data->storedata_monitor, ^{ + asldebug("cancel/close ASL storedata fd %d\n", fd); + fclose(sdfp); + }); + + dispatch_resume(as_data->storedata_monitor); + } + + asldebug("_asl_dir_storedata_open ASL storedata %s fd %d\n", dstpath, fd); + return 0; +} + +/* + * Close an ASL Directory ASL file + * - cancel the dispatch source for the file + * - clears file name and timestamp in asl_action_asl_store_data_t structue + */ +static void +_asl_dir_today_close(asl_out_rule_t *r) +{ + asl_action_asl_store_data_t *as_data = (asl_action_asl_store_data_t *)r->dst->private; + if (as_data->aslfile == NULL) return; + + if (as_data->pending != 0) { char *str = NULL; - asprintf(&str, "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message Sentinel %s create/open failed (%s)]", global.pid, path, strerror(errno)); + 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); internal_log_message(str); free(str); - return; } - close(crashlog_sentinel_fd); + if (as_data->aslfile_monitor == NULL) + { + /* + * This should never happen, but _asl_dir_today_open allows + * dispatch_source_create to fail silently. If there is no dispatch + * source, we just close the file. + */ + asldebug("close ASL fd %d\n", fileno(as_data->aslfile->store)); + asl_file_close(as_data->aslfile); + } + else + { + /* + * The aslfile_monitor cancel handler will close the file. + */ + dispatch_source_cancel(as_data->aslfile_monitor); + dispatch_release(as_data->aslfile_monitor); + as_data->aslfile_monitor = NULL; + } + + as_data->p_year = 0; + as_data->p_month = 0; + as_data->p_day = 0; + + free(r->dst->fname); + r->dst->fname = NULL; + + as_data->aslfile = NULL; +} + +/* + * Check file size. + */ +static int +_act_checkpoint(asl_out_rule_t *r, uint32_t force) +{ + char tmpfname[MAXPATHLEN], *fn; + + if (r == NULL) return 0; + if (r->dst == NULL) return 0; + + fn = r->dst->fname; + if (fn == NULL) + { + if (r->dst->path == NULL) return 0; + asl_make_dst_filename(r->dst, tmpfname, sizeof(tmpfname)); + fn = tmpfname; + } + + if ((force == CHECKPOINT_TEST) && (r->dst->file_max == 0)) return 0; + + if ((r->dst->size == 0) || (r->dst->stamp == 0)) + { + struct stat sb; + + memset(&sb, 0, sizeof(struct stat)); + + if (stat(fn, &sb) < 0) + { + if (errno == ENOENT) return 0; + 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; + r->dst->size = sb.st_size; + } + + if ((force == CHECKPOINT_TEST) && (r->dst->size < r->dst->file_max)) return 0; + + if (r->dst->flags & MODULE_FLAG_BASESTAMP) + { + _act_dst_close(r, DST_CLOSE_CHECKPOINT); + } + else + { + 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); + + _act_dst_close(r, DST_CLOSE_CHECKPOINT); + rename(srcpath, dstpath); + } + + r->dst->stamp = 0; + r->dst->size = 0; + return 1; +} + +/* + * Open today's ASL file in an ASL directory + * - Checks date and closes a currently open file if it has the wrong date + * - Opens today's file + */ +static int +_asl_dir_today_open(asl_out_rule_t *r, const time_t *tick) +{ + int status; + mode_t mask; + struct tm ctm; + time_t now; + + if (r == NULL) return -1; + if (r->dst == NULL) return -1; + + status = _asl_dir_create(r); + if (status != 0) + { + asldebug("_asl_dir_today_open: No directory at path %s\n", r->dst->path); + return -1; + } + + asl_action_asl_store_data_t *as_data = (asl_action_asl_store_data_t *)r->dst->private; + + memset(&ctm, 0, sizeof(struct tm)); + if (tick == NULL) + { + now = time(NULL); + tick = (const time_t *)&now; + } + + if (localtime_r(tick, &ctm) == NULL) + { + asldebug("_asl_dir_today_open: localtime_r error %s\n", strerror(errno)); + return -1; + } + + /* checks file_max and closes if required */ + status = _act_checkpoint(r, CHECKPOINT_TEST); + if (status == 1) trigger_aslmanager(); + + if (as_data->aslfile != NULL) + { + /* Check the date */ + if ((as_data->p_year == ctm.tm_year) && (as_data->p_month == ctm.tm_mon) && (as_data->p_day == ctm.tm_mday)) return 0; + + /* Wrong date, close the current file */ + _asl_dir_today_close(r); + } + + /* Open data file */ + + if (r->dst->flags & MODULE_FLAG_BASESTAMP) + { + char tstamp[32]; + + if (tick == NULL) + { + now = time(NULL); + 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); + } + else + { + asprintf(&(r->dst->fname), "%s/%d.%02d.%02d.asl", r->dst->path, ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); + } + + + if (r->dst->fname == NULL) + { + asldebug("_asl_dir_today_open: asprintf error %s\n", strerror(errno)); + return -1; + } + +#if TARGET_IPHONE_SIMULATOR + uid_t uid = -1; + gid_t gid = -1; +#else + uid_t uid = r->dst->uid[0]; + gid_t gid = r->dst->gid[0]; +#endif + + mask = umask(0); + status = asl_file_open_write(r->dst->fname, (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; + 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; + return -1; + } + + as_data->p_year = ctm.tm_year; + as_data->p_month = ctm.tm_mon; + as_data->p_day = ctm.tm_mday; - crashlog_sentinel_fd = open(path, O_EVTONLY, 0); - if (crashlog_sentinel_fd < 0) + /* create aslfile_monitor */ + int fd = fileno(as_data->aslfile->store); + asl_file_t *aslf = as_data->aslfile; + + as_data->aslfile_monitor = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE, asl_action_queue); + if (as_data->aslfile_monitor != NULL) + { + dispatch_source_set_event_handler(as_data->aslfile_monitor, ^{ + _act_dst_close(r, DST_CLOSE_DELETED); + }); + + dispatch_source_set_cancel_handler(as_data->aslfile_monitor, ^{ + asldebug("cancel/close ASL file fd %d\n", fd); + asl_file_close(aslf); + }); + + dispatch_resume(as_data->aslfile_monitor); + } + + asldebug("_asl_dir_today_open ASL file %s fd %d\n", r->dst->fname, fd); + + return 0; +} + +static void +_asl_file_close(asl_out_rule_t *r) +{ + if (r == NULL) return; + if (r->dst == NULL) return; + + asl_action_asl_file_data_t *af_data = (asl_action_asl_file_data_t *)r->dst->private; + if (af_data->aslfile == NULL) return; + + if (af_data->pending != 0) { char *str = NULL; - asprintf(&str, "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message Sentinel %s event/open failed (%s)]", global.pid, path, strerror(errno)); + 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); internal_log_message(str); free(str); - return; } - crashlog_sentinel_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, (uintptr_t)crashlog_sentinel_fd, DISPATCH_VNODE_DELETE, asl_action_queue); - if (crashlog_sentinel_src == NULL) + if (af_data->monitor == NULL) + { + /* + * This should never happen, but _asl_file_open allows + * dispatch_source_create to fail silently. If there is no dispatch + * source, we just close the file. + */ + asldebug("close ASL fd %d\n", fileno(af_data->aslfile->store)); + asl_file_close(af_data->aslfile); + } + else + { + /* + * The monitor cancel handler will close the file. + */ + dispatch_source_cancel(af_data->monitor); + dispatch_release(af_data->monitor); + af_data->monitor = NULL; + } + + af_data->aslfile = NULL; +} + +static int +_asl_file_open(asl_out_rule_t *r) +{ + int fd, status; + + if (r == NULL) return -1; + if (r->dst == NULL) return -1; + + asl_action_asl_file_data_t *af_data = (asl_action_asl_file_data_t *)r->dst->private; + if (af_data->aslfile != NULL) return 0; + + /* create path if necessary */ + status = asl_out_mkpath(global.asl_out_module, r); + if (status != 0) + { + asldebug("_asl_file_open: asl_out_mkpath %s failed\n", r->dst->path); + return -1; + } + + 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)); + return -1; + } + + close(fd); + + if (r->dst->fname == NULL) return -1; + + status = asl_file_open_write(r->dst->fname, 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)); + return -1; + } + + /* create monitor */ + fd = fileno(af_data->aslfile->store); + asl_file_t *aslf = af_data->aslfile; + + af_data->monitor = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE, asl_action_queue); + if (af_data->monitor != NULL) + { + dispatch_source_set_event_handler(af_data->monitor, ^{ + _act_dst_close(r, DST_CLOSE_DELETED); + }); + + dispatch_source_set_cancel_handler(af_data->monitor, ^{ + asldebug("cancel/close ASL file fd %d\n", fd); + asl_file_close(aslf); + }); + + dispatch_resume(af_data->monitor); + } + + asldebug("_asl_file_open ASL file %s fd %d\n", r->dst->fname, fd); + return 0; +} + +static void +_text_file_close(asl_out_rule_t *r) +{ + asl_action_file_data_t *f_data = (asl_action_file_data_t *)r->dst->private; + if (f_data->fd < 0) return; + + if (f_data->pending != 0) { char *str = NULL; - asprintf(&str, "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message Sentinel %s dispatch_source_create failed]", global.pid, path); + 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); internal_log_message(str); free(str); - close(crashlog_sentinel_fd); - crashlog_sentinel_fd = -1; - return; } - dispatch_source_set_event_handler(crashlog_sentinel_src, ^{ - if (crashmover_state != 0) + if (f_data->monitor == NULL) + { + /* + * This should never happen, but _text_file_open allows + * dispatch_source_create to fail silently. If there is no dispatch + * source, we just close the file. + */ + asldebug("close fd %d\n", f_data->fd); + close(f_data->fd); + } + else + { + /* + * The monitor cancel handler will close the file. + */ + dispatch_source_cancel(f_data->monitor); + dispatch_release(f_data->monitor); + f_data->monitor = NULL; + } + + f_data->fd = -1; +} + +static int +_text_file_open(asl_out_rule_t *r) +{ + asl_action_file_data_t *f_data = (asl_action_file_data_t *)r->dst->private; + + if (f_data->fd < 0) + { + f_data->fd = _act_file_create_open(r->dst); + if (f_data->fd < 0) + { + /* + * lazy path creation: create path and retry + * _act_file_create_open does not create the path + * so we do it here. + */ + int status = asl_out_mkpath(global.asl_out_module, r); + if (status != 0) return -1; + + f_data->fd = _act_file_create_open(r->dst); + } + + if (f_data->fd < 0) return -1; + + f_data->monitor = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, f_data->fd, DISPATCH_VNODE_DELETE, asl_action_queue); + if (f_data->monitor != NULL) + { + int ffd = f_data->fd; + + dispatch_source_set_event_handler(f_data->monitor, ^{ + asldebug("dispatch_source DISPATCH_VNODE_DELETE fd %d\n", ffd); + _act_dst_close(r, DST_CLOSE_DELETED); + }); + + dispatch_source_set_cancel_handler(f_data->monitor, ^{ + asldebug("cancel/close file fd %d\n", ffd); + close(ffd); + }); + + dispatch_resume(f_data->monitor); + } + } + + return 0; +} + +static int +_act_dst_open(asl_out_rule_t *r, const time_t *tick, uint64_t xid) +{ + if (r == NULL) return -1; + if (r->dst == NULL) return -1; + if (r->dst->private == NULL) return -1; + + if (r->action == ACTION_ASL_DIR) + { + if (_asl_dir_today_open(r, tick) != 0) { - asldebug("CrashMover inactive / sentinel deleted: resuming crashlog queue\n"); - dispatch_resume(crashlog_queue); - crashmover_state = 0; + asldebug("_act_dst_open:_asl_dir_today_open %s FAILED!\n", r->dst->path); + return -1; } - if (crashlog_sentinel_src != NULL) + if (_asl_dir_storedata_open(r, xid) != 0) { - dispatch_source_cancel(crashlog_sentinel_src); - dispatch_release(crashlog_sentinel_src); + asldebug("_act_dst_open:_asl_dir_storedata_open %s FAILED! Closing today file\n", r->dst->path); + _asl_dir_today_close(r); + return -1; } - crashlog_sentinel_src = NULL; - - close(crashlog_sentinel_fd); - crashlog_sentinel_fd = -1; - _crashlog_sentinel_init(); - }); - - dispatch_resume(crashlog_sentinel_src); - asldebug("Created CrashLog Sentinel: %s\n", path); -} - -static void -_crashlog_queue_check(void) -{ - /* - * Check whether the crashlog queue has been suspended for too long. - * We allow the crashlog quque to be suspended for 60 seconds. - * After that, we start logging again. This prevents syslogd from - * filling memory due to a suspended queue. CrashMover really shoud - * take no more than a second or two to finish. - */ - if (crashmover_state == 0) return; - if ((time(NULL) - crashmover_state) <= 60) return; - - asldebug("CrashMover timeout: resuming crashlog queue\n"); - dispatch_resume(crashlog_queue); - crashmover_state = 0; + return 0; + } - /* - * crashlog_sentinel_src should never be NULL, but if - * _crashlog_sentinel_init failed for some strange reason, - * it will be NULL here. - */ - if (crashlog_sentinel_src != NULL) + if (r->action == ACTION_ASL_FILE) { - dispatch_source_cancel(crashlog_sentinel_src); - dispatch_release(crashlog_sentinel_src); + return _asl_file_open(r); } - crashlog_sentinel_src = NULL; + if (r->action == ACTION_FILE) + { + return _text_file_open(r); + } - close(crashlog_sentinel_fd); - crashlog_sentinel_fd = -1; - _crashlog_sentinel_init(); + return -1; } -#endif static void -_act_dst_close(asl_out_rule_t *r) +_act_dst_close(asl_out_rule_t *r, int why) { if (r == NULL) return; if (r->dst == NULL) return; if (r->dst->private == NULL) return; - if ((r->action == ACTION_ASL_DIR) || (r->action == ACTION_ASL_FILE)) + if (r->action == ACTION_ASL_DIR) { - asl_action_store_data_t *sdata = (asl_action_store_data_t *)r->dst->private; - if (sdata->store != NULL) asl_file_close(sdata->store); - sdata->store = NULL; - - if (sdata->storedata != NULL) fclose(sdata->storedata); - sdata->storedata = NULL; - - if (sdata->monitor != NULL) - { - dispatch_source_cancel(sdata->monitor); - dispatch_release(sdata->monitor); - sdata->monitor = NULL; - } + asldebug("_act_dst_close: %s ASL DIR %s\n", why_str[why], r->dst->path); + if (why != DST_CLOSE_CHECKPOINT) _asl_dir_storedata_close(r); + _asl_dir_today_close(r); + } + 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); + _asl_file_close(r); } else if (r->action == ACTION_FILE) { - asl_action_file_data_t *fdata = (asl_action_file_data_t *)r->dst->private; - if (fdata->fd >= 0) close(fdata->fd); - fdata->fd = -1; - - if (fdata->monitor != NULL) - { - dispatch_source_cancel(fdata->monitor); - dispatch_release(fdata->monitor); - fdata->monitor = NULL; - } + asldebug("_act_dst_close: %s FILE %s\n", why_str[why], (r->dst->fname == NULL) ? r->dst->path : r->dst->fname); + _text_file_close(r); } } @@ -389,55 +983,35 @@ static uint32_t _act_store_file_setup(asl_out_module_t *m, asl_out_rule_t *r) { uint32_t status; - asl_action_store_data_t *sdata; - char dstpath[MAXPATHLEN]; + asl_action_asl_file_data_t *af_data; if (r == NULL) return ASL_STATUS_INVALID_STORE; if (r->dst == NULL) return ASL_STATUS_INVALID_STORE; if (r->dst->private == NULL) return ASL_STATUS_INVALID_STORE; - sdata = (asl_action_store_data_t *)r->dst->private; - if (sdata->store == NULL) + af_data = (asl_action_asl_file_data_t *)r->dst->private; + if (af_data->aslfile != NULL) { - /* create path if necessary */ - asl_out_mkpath(r); - - int fd = asl_out_dst_file_create_open(r->dst); - if (fd < 0) - { - asldebug("_act_store_file_setup: asl_out_dst_file_create_open failed %d %s\n", errno, strerror(errno)); - return ASL_STATUS_WRITE_FAILED; - } - close(fd); - - asl_make_dst_filename(r->dst, dstpath, sizeof(dstpath)); - status = asl_file_open_write(dstpath, 0, -1, -1, &(sdata->store)); - if (status != ASL_STATUS_OK) return status; - - sdata->monitor = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fileno(sdata->store->store), DISPATCH_VNODE_DELETE, asl_action_queue); - if (sdata->monitor != NULL) - { - dispatch_source_set_event_handler(sdata->monitor, ^{ _act_dst_close(r); }); - dispatch_resume(sdata->monitor); - } + af_data->next_id++; + return ASL_STATUS_OK; + } - status = asl_file_read_set_position(sdata->store, ASL_FILE_POSITION_LAST); - if (status != ASL_STATUS_OK) - { - asldebug("_act_store_file_setup: asl_file_read_set_position failed %d %s\n", status, asl_core_error(status)); - return status; - } + if (_act_dst_open(r, NULL, 0) != 0) return ASL_STATUS_WRITE_FAILED; - sdata->next_id = sdata->store->cursor_xid + 1; - if (fseek(sdata->store->store, 0, SEEK_END) != 0) - { - asldebug("_act_store_file_setup: fseek failed %d %s\n", errno, strerror(errno)); - return ASL_STATUS_WRITE_FAILED; - } + status = asl_file_read_set_position(af_data->aslfile, ASL_FILE_POSITION_LAST); + if (status != ASL_STATUS_OK) + { + asldebug("_act_store_file_setup: asl_file_read_set_position failed %d %s\n", status, asl_core_error(status)); + _act_dst_close(r, DST_CLOSE_ERROR); + return status; } - else + + af_data->next_id = af_data->aslfile->cursor_xid + 1; + if (fseek(af_data->aslfile->store, 0, SEEK_END) != 0) { - sdata->next_id++; + asldebug("_act_store_file_setup: fseek failed %d %s\n", errno, strerror(errno)); + _act_dst_close(r, DST_CLOSE_ERROR); + return ASL_STATUS_WRITE_FAILED; } return ASL_STATUS_OK; @@ -446,224 +1020,102 @@ _act_store_file_setup(asl_out_module_t *m, asl_out_rule_t *r) /* * _act_store_dir_setup * - * Creates store directory if it does not exist - * Creates StoreData file if it does not exist + * Opens StoreData file and today's file * Reads ASL Message ID from StoreData file * Writes ASL Message ID + 1 to StoreData file - * Opens current day file (e.g. "/foo/bar/2012.04.06.asl") */ static uint32_t _act_store_dir_setup(asl_out_module_t *m, asl_out_rule_t *r, time_t tick) { - struct tm ctm; - char *path; - struct stat sb; uint64_t xid; int status; - mode_t mask; - asl_action_store_data_t *sdata; + asl_action_asl_store_data_t *as_data; if (r == NULL) return ASL_STATUS_INVALID_STORE; if (r->dst == NULL) return ASL_STATUS_INVALID_STORE; if (r->dst->private == NULL) return ASL_STATUS_INVALID_STORE; if (r->dst->path == NULL) return ASL_STATUS_INVALID_STORE; - sdata = (asl_action_store_data_t *)r->dst->private; - - /* get / set message id from StoreData file */ - xid = 0; + as_data = (asl_action_asl_store_data_t *)r->dst->private; - if (sdata->storedata == NULL) + if (_act_dst_open(r, NULL, as_data->next_id) != 0) { - memset(&sb, 0, sizeof(struct stat)); - status = stat(r->dst->path, &sb); - if (status == 0) - { - /* must be a directory */ - if (!S_ISDIR(sb.st_mode)) return ASL_STATUS_INVALID_STORE; - } - else if (errno == ENOENT) - { - /* doesn't exist - create it */ - mask = umask(S_IWGRP | S_IWOTH); - status = mkpath_np(r->dst->path, 0755); - if (status == 0) status = chmod(r->dst->path, r->dst->mode); - umask(mask); - - if (status != 0) return ASL_STATUS_WRITE_FAILED; -#if !TARGET_IPHONE_SIMULATOR - if (chown(r->dst->path, r->dst->uid[0], r->dst->gid[0]) != 0) return ASL_STATUS_WRITE_FAILED; -#endif - } - else - { - /* Unexpected stat error */ - return ASL_STATUS_FAILED; - } - - path = NULL; - asprintf(&path, "%s/%s", r->dst->path, FILE_ASL_STORE_DATA); - if (path == NULL) return ASL_STATUS_NO_MEMORY; - - memset(&sb, 0, sizeof(struct stat)); - status = stat(path, &sb); - if (status == 0) - { - /* StoreData exists: open and read last xid */ - sdata->storedata = fopen(path, "r+"); - if (sdata->storedata == NULL) - { - free(path); - return ASL_STATUS_FAILED; - } - - if (fread(&xid, sizeof(uint64_t), 1, sdata->storedata) != 1) - { - free(path); - fclose(sdata->storedata); - sdata->storedata = NULL; - return ASL_STATUS_READ_FAILED; - } - } - else if (errno == ENOENT) - { - /* StoreData does not exist: create it */ - sdata->storedata = fopen(path, "w"); - if (sdata->storedata == NULL) - { - free(path); - return ASL_STATUS_FAILED; - } - -#if !TARGET_IPHONE_SIMULATOR - if (chown(path, r->dst->uid[0], r->dst->gid[0]) != 0) - { - free(path); - return ASL_STATUS_WRITE_FAILED; - } -#endif - } - else - { - /* Unexpected stat error */ - free(path); - return ASL_STATUS_FAILED; - } - - sdata->monitor = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fileno(sdata->storedata), DISPATCH_VNODE_DELETE, asl_action_queue); - if (sdata->monitor != NULL) - { - dispatch_source_set_event_handler(sdata->monitor, ^{ _act_dst_close(r); }); - dispatch_resume(sdata->monitor); - } - - free(path); + asldebug("_act_store_dir_setup: _act_dst_open %s failed\n", r->dst->path); + return ASL_STATUS_WRITE_FAILED; } - else + + /* get / set message id from StoreData file */ + xid = 0; + rewind(as_data->storedata); + if (fread(&xid, sizeof(uint64_t), 1, as_data->storedata) != 1) { - rewind(sdata->storedata); - if (fread(&xid, sizeof(uint64_t), 1, sdata->storedata) != 1) - { - fclose(sdata->storedata); - sdata->storedata = NULL; - return ASL_STATUS_READ_FAILED; - } + asldebug("_act_store_dir_setup: storedata read failed %d %s\n", errno, strerror(errno)); + _act_dst_close(r, DST_CLOSE_ERROR); + return ASL_STATUS_READ_FAILED; } xid = asl_core_ntohq(xid); xid++; - sdata->next_id = xid; + as_data->next_id = xid; xid = asl_core_htonq(xid); - rewind(sdata->storedata); - status = fwrite(&xid, sizeof(uint64_t), 1, sdata->storedata); + rewind(as_data->storedata); + status = fwrite(&xid, sizeof(uint64_t), 1, as_data->storedata); if (status != 1) { - fclose(sdata->storedata); - sdata->storedata = NULL; + asldebug("_act_store_dir_setup: storedata write failed %d %s\n", errno, strerror(errno)); + _act_dst_close(r, DST_CLOSE_ERROR); return ASL_STATUS_WRITE_FAILED; } - memset(&ctm, 0, sizeof(struct tm)); + fflush(as_data->storedata); - if (localtime_r((const time_t *)&tick, &ctm) == NULL) return ASL_STATUS_FAILED; - if ((sdata->store != NULL) && (sdata->p_year == ctm.tm_year) && (sdata->p_month == ctm.tm_mon) && (sdata->p_day == ctm.tm_mday)) + if (fseek(as_data->aslfile->store, 0, SEEK_END) != 0) { - return ASL_STATUS_OK; - } - - if (sdata->store != NULL) asl_file_close(sdata->store); - sdata->store = NULL; - free(r->dst->fname); - r->dst->fname = NULL; - - r->dst->stamp = tick; - - sdata->p_year = ctm.tm_year; - sdata->p_month = ctm.tm_mon; - sdata->p_day = ctm.tm_mday; - - asprintf(&(r->dst->fname), "%s/%d.%02d.%02d.asl", r->dst->path, ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); - if (r->dst->fname == NULL) return ASL_STATUS_NO_MEMORY; - mask = umask(0); - - status = ASL_STATUS_OK; - if (sdata->store == NULL) { -#if TARGET_IPHONE_SIMULATOR - uid_t uid = -1; - gid_t gid = -1; -#else - uid_t uid = r->dst->uid[0]; - gid_t gid = r->dst->gid[0]; -#endif - status = asl_file_open_write(r->dst->fname, (r->dst->mode & 0666), uid, gid, &(sdata->store)); + asldebug("_act_store_dir_setup: aslfile fseek failed %d %s\n", errno, strerror(errno)); + _act_dst_close(r, DST_CLOSE_ERROR); + return ASL_STATUS_FAILED; } - umask(mask); - - if (status != ASL_STATUS_OK) return status; - - if (fseek(sdata->store->store, 0, SEEK_END) != 0) return ASL_STATUS_FAILED; return ASL_STATUS_OK; } static void -_asl_action_store_data_free(asl_action_store_data_t *sdata) +_asl_action_asl_store_data_free(asl_action_asl_store_data_t *as_data) { - if (sdata == NULL) return; - - if (sdata->store != NULL) asl_file_close(sdata->store); - sdata->store = NULL; - - if (sdata->storedata != NULL) fclose(sdata->storedata); - sdata->storedata = NULL; + if (as_data == NULL) return; + free(as_data); +} - free(sdata); +static void +_asl_action_asl_file_data_free(asl_action_asl_file_data_t *af_data) +{ + if (af_data == NULL) return; + free(af_data); } static void -_asl_action_file_data_free(asl_action_file_data_t *fdata) +_asl_action_file_data_free(asl_action_file_data_t *f_data) { - if (fdata == NULL) return; + if (f_data == NULL) return; - if (fdata->dup_timer != NULL) + if (f_data->dup_timer != NULL) { - if (fdata->last_count == 0) + if (f_data->last_count == 0) { /* * The timer exists, but last_count is zero, so the timer is suspended. * Sources must not be released in when suspended. * So we resume it so that we can release it. */ - dispatch_resume(fdata->dup_timer); + dispatch_resume(f_data->dup_timer); } - dispatch_release(fdata->dup_timer); + dispatch_release(f_data->dup_timer); } - free(fdata->last_msg); - if (fdata->fd >= 0) close(fdata->fd); - free(fdata); + free(f_data->last_msg); + free(f_data); } static void @@ -689,18 +1141,22 @@ _asl_action_save_failed(const char *where, asl_out_module_t *m, asl_out_rule_t * internal_log_message(str); free(str); - if (r->action == ACTION_FILE) _asl_action_file_data_free((asl_action_file_data_t *)r->dst->private); - else _asl_action_store_data_free((asl_action_store_data_t *)r->dst->private); + if (r->action == ACTION_ASL_DIR) _asl_action_asl_store_data_free((asl_action_asl_store_data_t *)r->dst->private); + else if (r->action == ACTION_ASL_FILE) _asl_action_asl_file_data_free((asl_action_asl_file_data_t *)r->dst->private); + else if (r->action == ACTION_FILE) _asl_action_file_data_free((asl_action_file_data_t *)r->dst->private); r->dst->private = NULL; r->action = ACTION_NONE; } } +/* + * Save a message in an ASL file. + */ static int -_act_store_file(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) +_act_store_file(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg) { - asl_action_store_data_t *sdata; + asl_action_asl_file_data_t *af_data; uint32_t status; uint64_t mid; @@ -708,29 +1164,25 @@ _act_store_file(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) if (r->dst == NULL) return ACTION_STATUS_ERROR; if (r->dst->private == NULL) return ACTION_STATUS_ERROR; - sdata = (asl_action_store_data_t *)r->dst->private; - - /* check dst for file_max & etc */ - if (r->dst->flags & MODULE_FLAG_ROTATE) - { - if (asl_out_dst_checkpoint(r->dst, CHECKPOINT_TEST) != 0) - { - _act_dst_close(r); - asl_trigger_aslmanager(); - } - } + af_data = (asl_action_asl_file_data_t *)r->dst->private; + if (af_data->pending > 0) af_data->pending--; status = _act_store_file_setup(m, r); if (status == ASL_STATUS_OK) { - sdata->last_time = time(NULL); + af_data->last_time = time(NULL); r->dst->fails = 0; - mid = sdata->next_id; + mid = af_data->next_id; /* save message to file and update dst size */ - status = asl_file_save(sdata->store, msg, &mid); - if (status == ASL_STATUS_OK) r->dst->size = sdata->store->file_size; + status = asl_file_save(af_data->aslfile, msg, &mid); + if (status == ASL_STATUS_OK) + { + r->dst->size = af_data->aslfile->file_size; + + if (_act_checkpoint(r, CHECKPOINT_TEST) == 1) trigger_aslmanager(); + } } if (status != ASL_STATUS_OK) @@ -742,10 +1194,13 @@ _act_store_file(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) return ACTION_STATUS_OK; } +/* + * Save a message in an ASL data store. + */ static int -_act_store_dir(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) +_act_store_dir(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg) { - asl_action_store_data_t *sdata; + asl_action_asl_store_data_t *as_data; uint32_t status; uint64_t mid; const char *val; @@ -755,29 +1210,30 @@ _act_store_dir(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) if (r->dst == NULL) return ACTION_STATUS_ERROR; if (r->dst->private == NULL) return ACTION_STATUS_ERROR; - sdata = (asl_action_store_data_t *)r->dst->private; + as_data = (asl_action_asl_store_data_t *)r->dst->private; + if (as_data->pending > 0) as_data->pending--; - val = asl_get(msg, ASL_KEY_TIME); + val = asl_msg_get_val_for_key(msg, ASL_KEY_TIME); if (val == NULL) return ACTION_STATUS_ERROR; - /* check dst for file_max & etc */ - if (asl_out_dst_checkpoint(r->dst, CHECKPOINT_TEST) != 0) - { - _act_dst_close(r); - asl_trigger_aslmanager(); - } - tick = atol(val); status = _act_store_dir_setup(m, r, tick); if (status == ASL_STATUS_OK) { - sdata->last_time = time(NULL); + as_data->last_time = time(NULL); r->dst->fails = 0; - mid = sdata->next_id; - status = asl_file_save(sdata->store, msg, &mid); - if (status == ASL_STATUS_OK) r->dst->size = sdata->store->file_size; + mid = as_data->next_id; + status = asl_file_save(as_data->aslfile, msg, &mid); + if (status == ASL_STATUS_OK) r->dst->size = as_data->aslfile->file_size; + else asldebug("_act_store_dir asl_file_save FAILED %s\n", asl_core_error(status)); + //TODO: checkpoint here? + /* + * Currently, the checkpoint is in _asl_dir_today_open(). + * Moving it here would be in keeping with the way that + * _act_store_file() and _act_file_final() do checkpoints. + */ } if (status != ASL_STATUS_OK) @@ -790,7 +1246,7 @@ _act_store_dir(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) } static void -_act_store_final(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) +_act_store_final(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg) { if (r->action == ACTION_ASL_DIR) _act_store_dir(m, r, msg); else _act_store_file(m, r, msg); @@ -801,25 +1257,38 @@ _act_store_final(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) * or to an ASL directory (ACTION_ASL_DIR). */ static void -_act_store(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) +_act_store(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg) { if (r == NULL) return; + if (r->dst == NULL) return; if (msg == NULL) return; if (m == NULL) return; if ((m->flags & MODULE_FLAG_ENABLED) == 0) return; - if (r->dst == NULL) return; if (r->dst->flags & MODULE_FLAG_HAS_LOGGED) return; + r->dst->flags |= MODULE_FLAG_HAS_LOGGED; + if (r->action == ACTION_ASL_DIR) + { + asl_action_asl_store_data_t *as_data = (asl_action_asl_store_data_t *)r->dst->private; + if (as_data != NULL) as_data->pending++; + } + else if (r->action == ACTION_ASL_FILE) + { + asl_action_asl_file_data_t *af_data = (asl_action_asl_file_data_t *)r->dst->private; + if (af_data != NULL) af_data->pending++; + } #if TARGET_OS_EMBEDDED if (r->dst->flags & MODULE_FLAG_CRASHLOG) { _crashlog_queue_check(); - asl_msg_retain((asl_msg_t *)msg); + asl_msg_retain(msg); dispatch_async(crashlog_queue, ^{ - _act_store_final(m, r, msg); - asl_msg_release((asl_msg_t *)msg); + dispatch_async(asl_action_queue, ^{ + _act_store_final(m, r, msg); + asl_msg_release(msg); + }); }); return; } @@ -831,7 +1300,7 @@ _act_store(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) static int _send_repeat_msg(asl_out_rule_t *r) { - asl_action_file_data_t *fdata; + asl_action_file_data_t *f_data; char vt[32], *msg; int len, status; time_t now = time(NULL); @@ -840,79 +1309,41 @@ _send_repeat_msg(asl_out_rule_t *r) if (r->dst == NULL) return -1; if (r->dst->private == NULL) return -1; - fdata = (asl_action_file_data_t *)r->dst->private; + f_data = (asl_action_file_data_t *)r->dst->private; - free(fdata->last_msg); - fdata->last_msg = NULL; + free(f_data->last_msg); + f_data->last_msg = NULL; - if (fdata->last_count == 0) return 0; + if (f_data->last_count == 0) return 0; /* stop the timer */ - dispatch_suspend(fdata->dup_timer); + dispatch_suspend(f_data->dup_timer); memset(vt, 0, sizeof(vt)); ctime_r(&now, vt); vt[19] = '\0'; msg = NULL; - asprintf(&msg, "%s --- last message repeated %u time%s ---\n", vt + 4, fdata->last_count, (fdata->last_count == 1) ? "" : "s"); - fdata->last_count = 0; - fdata->last_time = now; + asprintf(&msg, "%s --- last message repeated %u time%s ---\n", vt + 4, f_data->last_count, (f_data->last_count == 1) ? "" : "s"); + f_data->last_count = 0; + f_data->last_time = now; if (msg == NULL) return -1; - if (fdata->fd < 0) fdata->fd = asl_out_dst_file_create_open(r->dst); + if (f_data->fd < 0) f_data->fd = _act_file_create_open(r->dst); len = strlen(msg); - status = write(fdata->fd, msg, len); + status = write(f_data->fd, msg, len); free(msg); if ((status < 0) || (status < len)) { - asldebug("%s: error writing repeat message (%s): %s\n", MY_ID, r->dst->path, strerror(errno)); + asldebug("%s: error writing repeat message (%s): %s\n", MY_ID, r->dst->fname, strerror(errno)); return -1; } return 0; } -static int -_act_file_open(asl_out_module_t *m, asl_out_rule_t *r) -{ - asl_action_file_data_t *fdata; - - if (r == NULL) return -1; - if (r->dst == NULL) return -1; - if (r->dst->private == NULL) return -1; - - fdata = (asl_action_file_data_t *)r->dst->private; - if (fdata->fd < 0) - { - fdata->fd = asl_out_dst_file_create_open(r->dst); - if (fdata->fd < 0) - { - /* - * lazy path creation: create path and retry - * asl_out_dst_file_create_open doesn not create the path - * so we do it here. - */ - asl_out_mkpath(r); - fdata->fd = asl_out_dst_file_create_open(r->dst); - } - - if (fdata->fd >= 0) - { - fdata->monitor = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fdata->fd, DISPATCH_VNODE_DELETE, asl_action_queue); - if (fdata->monitor != NULL) - { - dispatch_source_set_event_handler(fdata->monitor, ^{ _act_dst_close(r); }); - dispatch_resume(fdata->monitor); - } - } - } - - return fdata->fd; -} - static void _start_cycling() { @@ -984,19 +1415,19 @@ _act_file_checkpoint(asl_out_module_t *m, const char *path, uint32_t force) { if (r->dst->flags & MODULE_FLAG_CRASHLOG) { - if (asl_out_dst_checkpoint(r->dst, CHECKPOINT_FORCE) > 0) + if (_act_checkpoint(r, CHECKPOINT_FORCE) > 0) { did_checkpoint = 1; - _act_dst_close(r); + _act_dst_close(r, DST_CLOSE_CHECKPOINT); } } } else { - if (asl_out_dst_checkpoint(r->dst, force) > 0) + if (_act_checkpoint(r, force) > 0) { did_checkpoint = 1; - _act_dst_close(r); + _act_dst_close(r, DST_CLOSE_CHECKPOINT); } } } @@ -1018,20 +1449,28 @@ _act_file_checkpoint_all(uint32_t force) if (_act_file_checkpoint(m, NULL, force) > 0) did_checkpoint = 1; } - asl_trigger_aslmanager(); + trigger_aslmanager(); return did_checkpoint; } +/* + * Save a message in a plain text file. + */ static void -_act_file_final(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) +_act_file_final(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg) { - asl_action_file_data_t *fdata; + asl_action_file_data_t *f_data; int is_dup; uint32_t len, msg_hash = 0; char *str; time_t now; + if (r->dst->private == NULL) return; + + f_data = (asl_action_file_data_t *)r->dst->private; + if (f_data->pending > 0) f_data->pending--; + /* * If print format is std, bsd, or msg, then skip messages with * no ASL_KEY_MSG, or without a value for it. @@ -1039,51 +1478,49 @@ _act_file_final(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) if (r->dst->flags & MODULE_FLAG_STD_BSD_MSG) { const char *msgval = NULL; - if (asl_msg_lookup((asl_msg_t *)msg, ASL_KEY_MSG, &msgval, NULL) != 0) return; + if (asl_msg_lookup(msg, ASL_KEY_MSG, &msgval, NULL) != 0) return; if (msgval == NULL) return; } - fdata = (asl_action_file_data_t *)r->dst->private; - now = time(NULL); is_dup = 0; - str = asl_format_message((asl_msg_t *)msg, r->dst->fmt, r->dst->tfmt, ASL_ENCODE_SAFE, &len); + str = asl_format_message(msg, r->dst->fmt, r->dst->tfmt, ASL_ENCODE_SAFE, &len); if (r->dst->flags & MODULE_FLAG_COALESCE) { - if (fdata->dup_timer == NULL) + if (f_data->dup_timer == NULL) { /* create a timer to flush dups on this file */ - fdata->dup_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, asl_action_queue); - dispatch_source_set_event_handler(fdata->dup_timer, ^{ _send_repeat_msg(r); }); + f_data->dup_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, asl_action_queue); + dispatch_source_set_event_handler(f_data->dup_timer, ^{ _send_repeat_msg(r); }); } - if ((global.bsd_max_dup_time > 0) && (str != NULL) && (fdata->last_msg != NULL)) + if ((global.bsd_max_dup_time > 0) && (str != NULL) && (f_data->last_msg != NULL)) { msg_hash = asl_core_string_hash(str + 16, len - 16); - if ((fdata->last_hash == msg_hash) && (!strcmp(fdata->last_msg, str + 16))) + if ((f_data->last_hash == msg_hash) && (!strcmp(f_data->last_msg, str + 16))) { - if ((now - fdata->last_time) < global.bsd_max_dup_time) is_dup = 1; + if ((now - f_data->last_time) < global.bsd_max_dup_time) is_dup = 1; } } } if (is_dup == 1) { - if (fdata->last_count == 0) + if (f_data->last_count == 0) { /* start the timer */ - dispatch_source_set_timer(fdata->dup_timer, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * global.bsd_max_dup_time), DISPATCH_TIME_FOREVER, 0); - dispatch_resume(fdata->dup_timer); + dispatch_source_set_timer(f_data->dup_timer, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * global.bsd_max_dup_time), DISPATCH_TIME_FOREVER, 0); + dispatch_resume(f_data->dup_timer); } - fdata->last_count++; + f_data->last_count++; } else { - if (_act_file_open(m, r) < 0) + if (_act_dst_open(r, NULL, 0) != 0) { _asl_action_save_failed("_act_file", m, r, ASL_STATUS_FAILED); free(str); @@ -1095,54 +1532,34 @@ _act_file_final(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) } /* - * The current message is not a duplicate. If fdata->last_count > 0 + * The current message is not a duplicate. If f_data->last_count > 0 * we need to write a "last message repeated N times" log entry. * _send_repeat_msg will free last_msg and do nothing if * last_count == 0, but we test and free here to avoid a function call. */ - if (fdata->last_count > 0) + if (f_data->last_count > 0) { _send_repeat_msg(r); } else { - free(fdata->last_msg); - fdata->last_msg = NULL; - } - - /* check dst for file_max & etc */ - if (r->dst->flags & MODULE_FLAG_ROTATE) - { - int ckpt = asl_out_dst_checkpoint(r->dst, CHECKPOINT_TEST); - if (ckpt != 0) - { - _act_dst_close(r); - asl_trigger_aslmanager(); - - if (_act_file_open(m, r) < 0) - { - _asl_action_save_failed("_act_file", m, r, ASL_STATUS_FAILED); - free(str); - return; - } - else - { - r->dst->fails = 0; - } - } + free(f_data->last_msg); + f_data->last_msg = NULL; } - if (str != NULL) fdata->last_msg = strdup(str + 16); + if (str != NULL) f_data->last_msg = strdup(str + 16); - fdata->last_hash = msg_hash; - fdata->last_count = 0; - fdata->last_time = now; + f_data->last_hash = msg_hash; + f_data->last_count = 0; + f_data->last_time = now; if ((str != NULL) && (len > 1)) { /* write line to file and update dst size */ - size_t bytes = write(fdata->fd, str, len - 1); + 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(); } } @@ -1150,8 +1567,10 @@ _act_file_final(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) } static void -_act_file(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) +_act_file(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg) { + asl_action_file_data_t *f_data; + if (r == NULL) return; if (msg == NULL) return; if (m == NULL) return; @@ -1162,15 +1581,19 @@ _act_file(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) if (r->dst->flags & MODULE_FLAG_HAS_LOGGED) return; r->dst->flags |= MODULE_FLAG_HAS_LOGGED; + f_data = (asl_action_file_data_t *)r->dst->private; + if (f_data != NULL) f_data->pending++; #if TARGET_OS_EMBEDDED if (r->dst->flags & MODULE_FLAG_CRASHLOG) { _crashlog_queue_check(); - asl_msg_retain((asl_msg_t *)msg); + asl_msg_retain(msg); dispatch_async(crashlog_queue, ^{ - _act_file_final(m, r, msg); - asl_msg_release((asl_msg_t *)msg); + dispatch_async(asl_action_queue, ^{ + _act_file_final(m, r, msg); + asl_msg_release(msg); + }); }); return; } @@ -1180,19 +1603,20 @@ _act_file(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) } static void -_act_forward(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) +_act_forward(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg) { /* To do: Add a "forward" action to asl.conf */ } static void -_act_control(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) +_act_control(asl_out_module_t *m, asl_out_rule_t *r, asl_msg_t *msg) { const char *p; if (m == NULL) return; if (r == NULL) return; - p = asl_get(msg, ASL_KEY_MODULE); + + p = asl_msg_get_val_for_key(msg, ASL_KEY_MODULE); if (r->options == NULL) return; @@ -1211,7 +1635,7 @@ _act_control(asl_out_module_t *m, asl_out_rule_t *r, aslmsg msg) } static void -_send_to_asl_store(aslmsg msg) +_send_to_asl_store(asl_msg_t *msg) { if ((global.asl_out_module != NULL) && ((global.asl_out_module->flags & MODULE_FLAG_ENABLED) == 0)) return; @@ -1222,7 +1646,7 @@ _send_to_asl_store(aslmsg msg) } static int -_asl_out_process_message(asl_out_module_t *m, aslmsg msg) +_asl_out_process_message(asl_out_module_t *m, asl_msg_t *msg) { asl_out_rule_t *r; @@ -1252,16 +1676,18 @@ _asl_out_process_message(asl_out_module_t *m, aslmsg msg) */ if (r->action == ACTION_CLAIM) { - if ((asl_msg_cmp(r->query, (asl_msg_t *)msg) != 1)) return 0; + if ((asl_msg_cmp(r->query, msg) != 1)) return 0; } - if ((asl_msg_cmp(r->query, (asl_msg_t *)msg) == 1)) + if ((asl_msg_cmp(r->query, msg) == 1)) { if (r->action == ACTION_NONE) continue; else if (r->action == ACTION_IGNORE) return 1; else if (r->action == ACTION_SKIP) return 0; else if (r->action == ACTION_ASL_STORE) _send_to_asl_store(msg); else if (r->action == ACTION_ACCESS) _act_access_control(m, r, msg); + else if (r->action == ACTION_SET_KEY) _act_set_key(m, r, msg); + else if (r->action == ACTION_UNSET_KEY) _act_unset_key(m, r, msg); else if (r->action == ACTION_NOTIFY) _act_notify(m, r); else if (r->action == ACTION_BROADCAST) _act_broadcast(m, r, msg); else if (r->action == ACTION_FORWARD) _act_forward(m, r, msg); @@ -1276,10 +1702,10 @@ _asl_out_process_message(asl_out_module_t *m, aslmsg msg) } void -asl_out_message(aslmsg msg) +asl_out_message(asl_msg_t *msg) { OSAtomicIncrement32(&global.asl_queue_count); - asl_msg_retain((asl_msg_t *)msg); + asl_msg_retain(msg); dispatch_async(asl_action_queue, ^{ int ignore = 0; @@ -1289,7 +1715,7 @@ asl_out_message(aslmsg msg) store_has_logged = false; - p = asl_get(msg, ASL_KEY_MODULE); + p = asl_msg_get_val_for_key(msg, ASL_KEY_MODULE); if (p == NULL) { if ((action_asl_store_count == 0) || (asl_check_option(msg, ASL_OPT_STORE) == 1)) _send_to_asl_store(msg); @@ -1315,7 +1741,10 @@ asl_out_message(aslmsg msg) } } - asl_msg_release((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); + + asl_msg_release(msg); OSAtomicDecrement32(&global.asl_queue_count); if ((now - sweep_time) >= IDLE_CLOSE) @@ -1334,7 +1763,7 @@ _asl_action_profile_test(asl_out_module_t *m, asl_out_rule_t *r) bool eval; /* ident is first message key */ - asl_msg_fetch((asl_msg_t *)r->query, 0, &ident, NULL, NULL); + asl_msg_fetch(r->query, 0, &ident, NULL, NULL); if (ident == NULL) { r->action = ACTION_NONE; @@ -1358,7 +1787,7 @@ _asl_action_file_test(asl_out_module_t *m, asl_out_rule_t *r) bool eval; /* path is first message key */ - asl_msg_fetch((asl_msg_t *)r->query, 0, &path, NULL, NULL); + asl_msg_fetch(r->query, 0, &path, NULL, NULL); if (path == NULL) { r->action = ACTION_NONE; @@ -1502,11 +1931,11 @@ _asl_action_post_process_rule(asl_out_module_t *m, asl_out_rule_t *r) } else if (r->action == ACTION_ASL_DIR) { - if (r->dst->private == NULL) r->dst->private = (asl_action_store_data_t *)calloc(1, sizeof(asl_action_store_data_t)); + if (r->dst->private == NULL) r->dst->private = (asl_action_asl_store_data_t *)calloc(1, sizeof(asl_action_asl_store_data_t)); } else if (r->action == ACTION_ASL_FILE) { - if (r->dst->private == NULL)r->dst->private = (asl_action_store_data_t *)calloc(1, sizeof(asl_action_store_data_t)); + if (r->dst->private == NULL)r->dst->private = (asl_action_asl_file_data_t *)calloc(1, sizeof(asl_action_asl_file_data_t)); } else if (r->action == ACTION_FILE) { @@ -1615,23 +2044,6 @@ _asl_action_configure() if (global.asl_out_module == NULL) global.asl_out_module = asl_out_module_init(); if (global.asl_out_module == NULL) return; - if (global.debug != 0) - { - FILE *dfp; - if (global.debug_file == NULL) dfp = fopen(_PATH_SYSLOGD_LOG, "a"); - else dfp = fopen(global.debug_file, "a"); - if (dfp != NULL) - { - for (m = global.asl_out_module; m != NULL; m = m->next) - { - fprintf(dfp, "module: %s%s\n", (m->name == NULL) ? "" : m->name, (m->flags & MODULE_FLAG_LOCAL) ? " (local)" : ""); - asl_out_module_print(dfp, m); - fprintf(dfp, "\n"); - } - fclose(dfp); - } - } - asldebug("%s: init\n", MY_ID); action_asl_store_count = 0; @@ -1669,10 +2081,6 @@ _asl_action_configure() _act_file_checkpoint_all(CHECKPOINT_TEST); if (checkpoint_timer == NULL) _start_cycling(); } - -#if TARGET_OS_EMBEDDED - if (flags & MODULE_FLAG_CRASHLOG) _crashlog_sentinel_init(); -#endif } int @@ -1684,13 +2092,30 @@ asl_action_init(void) asl_action_queue = dispatch_queue_create("ASL Action Queue", NULL); #if TARGET_OS_EMBEDDED crashlog_queue = dispatch_queue_create("iOS CrashLog Queue", NULL); - notify_register_dispatch(CRASH_MOVER_WILL_START_NOTIFICATION, &crashmover_token, asl_action_queue, ^(int unused){ - if (crashmover_state == 0) + notify_register_dispatch(CRASH_MOVER_SERVICE, &crashmover_token, asl_action_queue, ^(int unused) { + uint64_t cmstate = 0; + uint64_t oldstate = (crashmover_state == 0) ? 0llu : 1llu; + + uint32_t status = notify_get_state(crashmover_token, &cmstate); + if (status == 0) { - asldebug("CrashMover active: suspending crashlog queue and closing files\n"); - crashmover_state = time(NULL); - dispatch_suspend(crashlog_queue); - _asl_action_close_idle_files(0); + if (cmstate != oldstate) + { + crashmover_state = 0; + if (cmstate == 1) crashmover_state = time(NULL); + + if (crashmover_state == 0) + { + asldebug("CrashMover finished\n"); + dispatch_resume(crashlog_queue); + } + else + { + asldebug("CrashMover active: suspending crashlog queue and closing files\n"); + dispatch_suspend(crashlog_queue); + _asl_action_close_idle_files(0); + } + } } }); #endif @@ -1702,7 +2127,7 @@ asl_action_init(void) } /* - * Free a module. + * Close outputs and free modules. */ static void _asl_action_free_modules(asl_out_module_t *m) @@ -1718,24 +2143,35 @@ _asl_action_free_modules(asl_out_module_t *m) { for (r = x->ruleset; r != NULL; r = r->next) { - if ((r->action == ACTION_ASL_FILE) || (r->action == ACTION_ASL_DIR)) + if (r->action == ACTION_ASL_DIR) + { + _act_dst_close(r, DST_CLOSE_SHUTDOWN); + if (r->dst != NULL) + { + _asl_action_asl_store_data_free((asl_action_asl_store_data_t *)r->dst->private); + r->dst->private = NULL; + } + } + else if (r->action == ACTION_ASL_FILE) { + _act_dst_close(r, DST_CLOSE_SHUTDOWN); if (r->dst != NULL) { - _asl_action_store_data_free((asl_action_store_data_t *)r->dst->private); + _asl_action_asl_file_data_free((asl_action_asl_file_data_t *)r->dst->private); r->dst->private = NULL; } } else if (r->action == ACTION_FILE) { + _act_dst_close(r, DST_CLOSE_SHUTDOWN); if (r->dst != NULL) { - asl_action_file_data_t *fdata = (asl_action_file_data_t *)r->dst->private; - if (fdata != NULL) + asl_action_file_data_t *f_data = (asl_action_file_data_t *)r->dst->private; + if (f_data != NULL) { /* flush repeat message if necessary */ - if (fdata->last_count > 0) _send_repeat_msg(r); - _asl_action_file_data_free(fdata); + if (f_data->last_count > 0) _send_repeat_msg(r); + _asl_action_file_data_free(f_data); r->dst->private = NULL; } } @@ -1748,6 +2184,10 @@ _asl_action_free_modules(asl_out_module_t *m) { _asl_action_set_param_data_free((asl_action_set_param_data_t *)r->private); } + else if (r->action == ACTION_SET_FILE) + { + _asl_action_set_param_data_free((asl_action_set_param_data_t *)r->private); + } } } @@ -1758,10 +2198,6 @@ static int _asl_action_close_internal(void) { #if TARGET_OS_EMBEDDED - dispatch_source_cancel(crashlog_sentinel_src); - dispatch_release(crashlog_sentinel_src); - crashlog_sentinel_src = NULL; - close(crashlog_sentinel_fd); if (crashmover_state != 0) { dispatch_resume(crashlog_queue); @@ -1769,7 +2205,7 @@ _asl_action_close_internal(void) } /* wait for the crashlog_queue to flush before _asl_action_free_modules() */ - dispatch_sync(crashlog_queue, ^{ crashlog_sentinel_fd = -1; }); + dispatch_sync(crashlog_queue, ^{ int x = 0; if (x == 1) x = 2; }); #endif _asl_action_free_modules(global.asl_out_module); @@ -1795,24 +2231,34 @@ _asl_action_close_idle_files(time_t idle_time) { if ((r->dst != NULL) && (r->dst->flags & MODULE_FLAG_CRASHLOG)) { - _act_dst_close(r); - if (r->action != ACTION_ASL_DIR) asl_out_dst_checkpoint(r->dst, CHECKPOINT_FORCE); + _act_dst_close(r, DST_CLOSE_IDLE); + //TODO: can r->action even be ACTION_ASL_DIR? + /* if not, we can avoid the extra check here */ + if (r->action != ACTION_ASL_DIR) _act_checkpoint(r, CHECKPOINT_FORCE); + } + } + else if (r->action == ACTION_ASL_DIR) + { + if (r->dst != NULL) + { + asl_action_asl_store_data_t *as_data = (asl_action_asl_store_data_t *)r->dst->private; + if ((as_data != NULL) && (as_data->aslfile != NULL) && (as_data->pending == 0) && ((now - as_data->last_time) >= idle_time)) _act_dst_close(r, DST_CLOSE_IDLE); } } - else if ((r->action == ACTION_ASL_DIR) || (r->action == ACTION_ASL_FILE)) + else if (r->action == ACTION_ASL_FILE) { if (r->dst != NULL) { - asl_action_store_data_t *sdata = (asl_action_store_data_t *)r->dst->private; - if ((sdata != NULL) && (sdata->store != NULL) && ((now - sdata->last_time) >= idle_time)) _act_dst_close(r); + asl_action_asl_file_data_t *af_data = (asl_action_asl_file_data_t *)r->dst->private; + if ((af_data != NULL) && (af_data->aslfile != NULL) && (af_data->pending == 0) && ((now - af_data->last_time) >= idle_time)) _act_dst_close(r, DST_CLOSE_IDLE); } } else if (r->action == ACTION_FILE) { if (r->dst != NULL) { - asl_action_file_data_t *fdata = (asl_action_file_data_t *)r->dst->private; - if ((fdata != NULL) && (fdata->fd >= 0) && ((now - fdata->last_time) >= idle_time)) _act_dst_close(r); + asl_action_file_data_t *f_data = (asl_action_file_data_t *)r->dst->private; + if ((f_data != NULL) && (f_data->fd >= 0) && (f_data->pending == 0) && ((now - f_data->last_time) >= idle_time)) _act_dst_close(r, DST_CLOSE_IDLE); } } } @@ -1881,11 +2327,16 @@ asl_action_control_set_param(const char *s) if (l != NULL) for (count = 0; l[count] != NULL; count++); /* at least 2 parameters (l[0] = module, l[1] = param) required */ - if (count < 2) return -1; + if (count < 2) + { + free_string_list(l); + return -1; + } if (global.asl_out_module == NULL) { asldebug("asl_action_control_set_param: no modules loaded\n"); + free_string_list(l); return -1; } @@ -1896,6 +2347,7 @@ asl_action_control_set_param(const char *s) if (p == NULL) { asldebug("asl_action_control_set_param: memory allocation failed\n"); + free_string_list(l); return -1; } diff --git a/syslogd.tproj/asl_sim.conf b/syslogd.tproj/asl_sim.conf index 5af3ff6..e2cc06a 100644 --- a/syslogd.tproj/asl_sim.conf +++ b/syslogd.tproj/asl_sim.conf @@ -2,14 +2,14 @@ # configuration file for syslogd and aslmanager in the iOS Simulator ## -# redirect com.apple.message.domain to $ENV(IPHONE_SIMULATOR_LOG_ROOT)/DiagnosticMessages -? [T com.apple.message.domain] store_dir $ENV(IPHONE_SIMULATOR_LOG_ROOT)/DiagnosticMessages +# redirect com.apple.message.domain to $ENV(SIMULATOR_LOG_ROOT)/DiagnosticMessages +? [T com.apple.message.domain] store_dir $ENV(SIMULATOR_LOG_ROOT)/DiagnosticMessages -# redirect com.apple.performance* messages to $ENV(IPHONE_SIMULATOR_LOG_ROOT)/performance -? [A= Facility com.apple.performance] store_dir $ENV(IPHONE_SIMULATOR_LOG_ROOT)/performance +# redirect com.apple.performance* messages to $ENV(SIMULATOR_LOG_ROOT)/performance +? [A= Facility com.apple.performance] store_dir $ENV(SIMULATOR_LOG_ROOT)/performance -# redirect com.apple.eventmonitor* messages to $ENV(IPHONE_SIMULATOR_LOG_ROOT)/eventmonitor -? [A= Facility com.apple.eventmonitor] store_dir $ENV(IPHONE_SIMULATOR_LOG_ROOT)/eventmonitor +# 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 @@ -21,14 +21,16 @@ ? [<= Level notice] store # install messages get saved only in install.log -? [= Facility install] file $ENV(IPHONE_SIMULATOR_LOG_ROOT)/install.log format=bsd +? [= Facility install] file $ENV(SIMULATOR_LOG_ROOT)/install.log format=bsd file_max=5M all_max=50M ? [= Facility install] ignore +> $ENV(SIMULATOR_LOG_ROOT)/system.log mode=0640 format=bsd rotate=seq compress file_max=5M all_max=50M + # emergency - notice get saved in system.log -? [<= Level notice] file $ENV(IPHONE_SIMULATOR_LOG_ROOT)/system.log +? [<= Level notice] file $ENV(SIMULATOR_LOG_ROOT)/system.log # Facility auth to level info gets saved in system.log -? [= Facility auth] [<= Level info] file $ENV(IPHONE_SIMULATOR_LOG_ROOT)/system.log +? [= Facility auth] [<= Level info] file $ENV(SIMULATOR_LOG_ROOT)/system.log # Facility authpriv gets saved in system.log -? [= Facility authpriv] file $ENV(IPHONE_SIMULATOR_LOG_ROOT)/system.log +? [= Facility authpriv] file $ENV(SIMULATOR_LOG_ROOT)/system.log diff --git a/syslogd.tproj/bb_convert.c b/syslogd.tproj/bb_convert.c deleted file mode 100644 index 18ee310..0000000 --- a/syslogd.tproj/bb_convert.c +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Copyright (c) 2009-2010 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 - -extern time_t asl_parse_time(const char *); - -#define TEMP_NAME "_TMP_.asl" -#define STORE_DATA_FLAGS 0x00000000 - -#if TARGET_IPHONE_SIMULATOR -const char *store_path; -#else -static const char *store_path = PATH_ASL_STORE; -#endif - -/* - * Cache the output file for BB writes. - * we write messages in the order in which they were generated, - * so we are almost guaranteed to use the cache in most cases. - */ -static asl_file_t *cache_file = NULL; -static uid_t cache_uid = -1; -static uid_t cache_gid = -1; -static time_t cache_bb = 0; - -typedef struct name_list_s -{ - char *name; - struct name_list_s *next; -} name_list_t; - -static name_list_t * -add_to_list(name_list_t *l, const char *name) -{ - 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; - } - - /* 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; -} - -static void -free_list(name_list_t *l) -{ - name_list_t *e; - - while (l != NULL) - { - e = l; - l = l->next; - free(e->name); - free(e); - } - - free(l); -} - -/* find all messages that have an ASLExpireTime key */ -static uint32_t -do_ASLExpireTime_search(asl_store_t *s, asl_search_result_t **out) -{ - asl_search_result_t q, *query, *res; - asl_msg_t *qm[1]; - uint32_t status; - uint64_t mid; - - qm[0] = asl_msg_new(ASL_TYPE_QUERY); - if (qm[0] == NULL) return ASL_STATUS_NO_MEMORY; - - q.count = 1; - q.curr = 0; - q.msg = qm; - query = &q; - - if (asl_msg_set_key_val_op(qm[0], ASL_KEY_EXPIRE_TIME, NULL, ASL_QUERY_OP_TRUE) != 0) - { - asl_msg_release(qm[0]); - return ASL_STATUS_NO_MEMORY; - } - - res = NULL; - mid = 0; - status = asl_store_match(s, query, out, &mid, 0, 0, 1); - - asl_msg_release(qm[0]); - return status; -} - -/* remove all messages that have an ASLExpireTime key */ -static uint32_t -do_ASLExpireTime_filter(const char *name) -{ - aslmsg msg; - asl_file_t *in, *out; - uint32_t status; - uint64_t mid; - char *inpath, *outpath; - struct stat sb; - - if (name == NULL) return ASL_STATUS_INVALID_ARG; - - in = NULL; - inpath = NULL; - asprintf(&inpath, "%s/%s", store_path, name); - if (inpath == NULL) return ASL_STATUS_NO_MEMORY; - - memset(&sb, 0, sizeof(struct stat)); - if (stat(inpath, &sb) < 0) - { - free(inpath); - return ASL_STATUS_INVALID_STORE; - } - - status = asl_file_open_read(inpath, &in); - if (status != ASL_STATUS_OK) - { - free(inpath); - return ASL_STATUS_OK; - } - - out = NULL; - outpath = NULL; - asprintf(&outpath, "%s/%s", store_path, TEMP_NAME); - if (outpath == NULL) - { - asl_file_close(in); - free(inpath); - return ASL_STATUS_NO_MEMORY; - } - - status = asl_file_open_write(outpath, sb.st_mode, sb.st_uid, sb.st_gid, &out); - if (status != ASL_STATUS_OK) - { - asl_file_close(in); - free(inpath); - free(outpath); - return status; - } - - out->flags = ASL_FILE_FLAG_PRESERVE_MSG_ID; - - msg = NULL; - while (asl_file_fetch_next(in, &msg) == ASL_STATUS_OK) - { - if (msg == NULL) break; - - mid = 0; - - if (asl_get(msg, ASL_KEY_EXPIRE_TIME) == NULL) status = asl_file_save(out, msg, &mid); - - asl_free(msg); - msg = NULL; - - if (status != ASL_STATUS_OK) break; - } - - asl_file_close(in); - asl_file_close(out); - - unlink(inpath); - rename(outpath, inpath); - - free(inpath); - free(outpath); - - return status; -} - -/* qsort compare function for sorting by message ID */ -static int -sort_compare(const void *a, const void *b) -{ - const char *va, *vb; - uint64_t na, nb; - - va = asl_get(*(aslmsg *)a, ASL_KEY_MSG_ID); - vb = asl_get(*(aslmsg *)b, ASL_KEY_MSG_ID); - - if (va == NULL) return -1; - if (vb == NULL) return 1; - - na = atoll(va); - nb = atoll(vb); - - if (na < nb) return -1; - if (na > nb) return 1; - return 0; -} - -/* save a message to an appropriately named BB file */ -static uint32_t -save_bb_msg(aslmsg msg) -{ - const char *val; - uid_t u, ruid; - gid_t g, rgid; - struct tm ctm; - time_t msg_time, bb; - char *path, *tstring; - asl_file_t *out; - uint64_t mid; - mode_t m; - uint32_t status; - - if (msg == NULL) return ASL_STATUS_OK; - - val = asl_get(msg, ASL_KEY_EXPIRE_TIME); - if (val == NULL) return ASL_STATUS_INVALID_ARG; - msg_time = asl_parse_time(val); - - val = asl_get(msg, ASL_KEY_READ_UID); - ruid = -1; - if (val != NULL) ruid = atoi(val); - - val = asl_get(msg, ASL_KEY_READ_GID); - rgid = -1; - if (val != NULL) rgid = atoi(val); - - if (localtime_r((const time_t *)&msg_time, &ctm) == NULL) return ASL_STATUS_FAILED; - - /* - * This supports 12 monthy "Best Before" buckets. - * We advance the actual expiry time to day zero of the following month. - * mktime() is clever enough to know that you actually mean the last day - * of the previous month. What we get back from localtime is the last - * day of the month in which the message expires, which we use in the name. - */ - ctm.tm_sec = 0; - ctm.tm_min = 0; - ctm.tm_hour = 0; - ctm.tm_mday = 0; - ctm.tm_mon += 1; - - bb = mktime(&ctm); - - u = 0; - g = 0; - if (ruid != -1) u = ruid; - if (rgid != -1) g = rgid; - - out = NULL; - - if (cache_file != NULL) - { - if ((cache_uid == u) && (cache_gid == g) && (cache_bb == bb)) - { - out = cache_file; - } - else - { - asl_file_close(cache_file); - cache_file = NULL; - cache_uid = -1; - cache_gid = -1; - cache_bb = 0; - } - } - - if (out == NULL) - { - if (localtime_r((const time_t *)&bb, &ctm) == NULL) return ASL_STATUS_FAILED; - - tstring = NULL; - asprintf(&tstring, "%s/BB.%d.%02d.%02d", store_path, ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); - if (tstring == NULL) return ASL_STATUS_NO_MEMORY; - - path = NULL; - m = 0644; - - if (ruid == -1) - { - if (rgid == -1) - { - asprintf(&path, "%s.asl", tstring); - } - else - { - m = 0640; - asprintf(&path, "%s.G%d.asl", tstring, g); - } - } - else - { - if (rgid == -1) - { - m = 0600; - asprintf(&path, "%s.U%d.asl", tstring, u); - } - else - { - m = 0640; - asprintf(&path, "%s.U%d.G%u.asl", tstring, u, g); - } - } - - if (path == NULL) return ASL_STATUS_NO_MEMORY; - - status = asl_file_open_write(path, m, u, g, &out); - free(path); - if (status != ASL_STATUS_OK) return status; - if (out == NULL) return ASL_STATUS_FAILED; - - out->flags = ASL_FILE_FLAG_PRESERVE_MSG_ID; - - cache_file = out; - cache_uid = u; - cache_gid = g; - cache_bb = bb; - } - - status = asl_file_save(out, msg, &mid); - - return status; -} - -static uint32_t -finish_conversion() -{ - FILE *sd; - uint32_t store_flags; - int status; - char *path; - - path = NULL; - asprintf(&path, "%s/%s", store_path, FILE_ASL_STORE_DATA); - - sd = fopen(path, "a"); - free(path); - if (sd == NULL) return ASL_STATUS_WRITE_FAILED; - - store_flags = STORE_DATA_FLAGS; - status = fwrite(&store_flags, sizeof(uint32_t), 1, sd); - fclose(sd); - - if (status != 1) return ASL_STATUS_WRITE_FAILED; - - return ASL_STATUS_OK; -} - -/* - * Utility to convert a data store with LongTTL files into - * a store with Best Before files. - * - * Returns quickly if the data store has already been converted. - * - * Older versions of the data store included messages with non-standard time-to-live - * records in the daily data files (yyyy.mm.dd.asl). When the files expired, aslmanager - * first copied messages with ASLExpireTime keys to a LongTTL file, then deleted the - * original data file. - * - * We now write ASLExpireTime messages to a Best Before file (BB.yyyy.mm.dd.asl) - * and aslmanager just deletes these files after the Best Before date has passed. - * - * If StoreData is bigger than 8 bytes, the store has been converted. Do nothing. - * - * Convert the store: - * Search the store for messages that have an ASLExpireTime. - * Sort by ASLMessageID - * Remove all BB.* files and all LongTTL.* files - * Write the ASLExpireTime messages into a new set of BB files - * Re-write each YMD file without messages that have an ASLExpireTime - * Add a new 4-byte flags field to StoreData - */ - -uint32_t -bb_convert(const char *name) -{ - struct stat sb; - asl_store_t *store; - uint32_t status; - asl_search_result_t *expire_time_records; - DIR *dp; - struct dirent *dent; - int i; - name_list_t *list, *e; - char *path; - - if (name != NULL) store_path = name; - - /* StoreData must exist */ - path = NULL; - asprintf(&path, "%s/%s", store_path, FILE_ASL_STORE_DATA); - if (path == NULL) return ASL_STATUS_NO_MEMORY; - - memset(&sb, 0, sizeof(struct stat)); - i = stat(path, &sb); - free(path); - if (i != 0) return ASL_STATUS_INVALID_STORE; - - /* must be a regular file */ - if (!S_ISREG(sb.st_mode)) return ASL_STATUS_INVALID_STORE; - - /* check is the store has already been converted */ - if (sb.st_size > sizeof(uint64_t)) return ASL_STATUS_OK; - - /* find ASLExpireTime messages */ - status = asl_store_open_read(store_path, &store); - if (status != ASL_STATUS_OK) return status; - - expire_time_records = NULL; - status = do_ASLExpireTime_search(store, &expire_time_records); - - asl_store_close(store); - if (status != ASL_STATUS_OK) return status; - - /* unlink BB.* and LongTTL.* */ - dp = opendir(store_path); - if (dp == NULL) return ASL_STATUS_READ_FAILED; - - while ((dent = readdir(dp)) != NULL) - { - if ((!strncmp(dent->d_name, "BB.", 3)) || (!strncmp(dent->d_name, "LongTTL.", 8))) - { - path = NULL; - asprintf(&path, "%s/%s", store_path, dent->d_name); - if (path == NULL) - { - closedir(dp); - return ASL_STATUS_NO_MEMORY; - } - - unlink(path); - free(path); - } - } - - closedir(dp); - - if ((expire_time_records == NULL) || (expire_time_records->count == 0)) return finish_conversion(); - - /* sort by ASLMessageID */ - qsort(expire_time_records->msg, expire_time_records->count, sizeof(aslmsg), sort_compare); - - /* save the ASLExpireTime messages into a new set of BB files */ - for (i = 0; i < expire_time_records->count; i++) - { - status = save_bb_msg((aslmsg)expire_time_records->msg[i]); - if (status != ASL_STATUS_OK) - { - if (cache_file != NULL) asl_file_close(cache_file); - return status; - } - } - - if (cache_file != NULL) asl_file_close(cache_file); - - aslresponse_free(expire_time_records); - - /* Re-write each YMD file without messages that have an ASLExpireTime */ - dp = opendir(store_path); - if (dp == NULL) return ASL_STATUS_READ_FAILED; - - list = NULL; - - while ((dent = readdir(dp)) != NULL) - { - if ((dent->d_name[0] < '0') || (dent->d_name[0] > '9')) continue; - list = add_to_list(list, dent->d_name); - } - - closedir(dp); - - for (e = list; e != NULL; e = e->next) - { - status = do_ASLExpireTime_filter(e->name); - if (status != ASL_STATUS_OK) - { - free_list(list); - return status; - } - } - - free_list(list); - - return finish_conversion(); -} diff --git a/syslogd.tproj/bsd_in.c b/syslogd.tproj/bsd_in.c index c27ac8b..a1beed7 100644 --- a/syslogd.tproj/bsd_in.c +++ b/syslogd.tproj/bsd_in.c @@ -51,7 +51,7 @@ bsd_in_acceptmsg(int fd) int n; char line[MAXLINE]; struct sockaddr_un sun; - aslmsg m; + asl_msg_t *m; len = sizeof(struct sockaddr_un); n = recvfrom(fd, line, MAXLINE, 0, (struct sockaddr *)&sun, &len); @@ -145,7 +145,7 @@ bsd_in_init() in_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, (uintptr_t)sock, 0, in_queue); dispatch_source_set_event_handler(in_src, ^{ bsd_in_acceptmsg(sock); }); - + dispatch_resume(in_src); return 0; } diff --git a/syslogd.tproj/bsd_out.c b/syslogd.tproj/bsd_out.c index c7c0639..935b01a 100644 --- a/syslogd.tproj/bsd_out.c +++ b/syslogd.tproj/bsd_out.c @@ -416,7 +416,7 @@ _bsd_send_repeat_msg(struct config_rule *r) } static int -_bsd_send(aslmsg msg, struct config_rule *r, char **out, char **fwd, time_t now) +_bsd_send(asl_msg_t *msg, struct config_rule *r, char **out, char **fwd, time_t now) { char *sf, *outmsg; const char *vlevel, *vfacility; @@ -460,10 +460,10 @@ _bsd_send(aslmsg msg, struct config_rule *r, char **out, char **fwd, time_t now) if ((*fwd == NULL) && (r->type == DST_TYPE_SOCK)) { pf = 7; - vlevel = asl_get(msg, ASL_KEY_LEVEL); + vlevel = asl_msg_get_val_for_key(msg, ASL_KEY_LEVEL); if (vlevel != NULL) pf = atoi(vlevel); - fc = asl_syslog_faciliy_name_to_num(asl_get(msg, ASL_KEY_FACILITY)); + fc = asl_syslog_faciliy_name_to_num(asl_msg_get_val_for_key(msg, ASL_KEY_FACILITY)); if (fc > 0) pf |= fc; sf = NULL; @@ -492,7 +492,7 @@ _bsd_send(aslmsg msg, struct config_rule *r, char **out, char **fwd, time_t now) * The kernel printf routine already sends them to /dev/console * so writing them here would cause duplicates. */ - vfacility = asl_get(msg, ASL_KEY_FACILITY); + vfacility = asl_msg_get_val_for_key(msg, ASL_KEY_FACILITY); if ((vfacility != NULL) && (!strcmp(vfacility, FACILITY_KERNEL)) && (r->type == DST_TYPE_CONS)) do_write = 0; if ((do_write == 1) && (r->type == DST_TYPE_FILE) && (is_dup == 1)) { @@ -576,7 +576,7 @@ _bsd_send(aslmsg msg, struct config_rule *r, char **out, char **fwd, time_t now) } static int -_bsd_rule_match(aslmsg msg, struct config_rule *r) +_bsd_rule_match(asl_msg_t *msg, struct config_rule *r) { uint32_t i, test, f; int32_t pri; @@ -596,7 +596,7 @@ _bsd_rule_match(aslmsg msg, struct config_rule *r) if ((test == 0) && (r->pri[i] == -2)) continue; f = 0; - val = asl_get(msg, ASL_KEY_FACILITY); + val = asl_msg_get_val_for_key(msg, ASL_KEY_FACILITY); if (strcmp(r->facility[i], "*") == 0) { @@ -620,7 +620,7 @@ _bsd_rule_match(aslmsg msg, struct config_rule *r) continue; } - val = asl_get(msg, ASL_KEY_LEVEL); + val = asl_msg_get_val_for_key(msg, ASL_KEY_LEVEL); if (val == NULL) continue; pri = atoi(val); @@ -633,7 +633,7 @@ _bsd_rule_match(aslmsg msg, struct config_rule *r) } static int -_bsd_match_and_send(aslmsg msg) +_bsd_match_and_send(asl_msg_t *msg) { struct config_rule *r; char *out, *fwd; @@ -658,7 +658,7 @@ _bsd_match_and_send(aslmsg msg) } void -bsd_out_message(aslmsg msg) +bsd_out_message(asl_msg_t *msg) { if (msg == NULL) return; @@ -732,7 +732,7 @@ bsd_out_init(void) /* start a timer to close idle files */ bsd_idle_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, bsd_out_queue); - dispatch_source_set_event_handler(bsd_idle_timer, ^{ _bsd_close_idle_files(); }); + dispatch_source_set_event_handler(bsd_idle_timer, ^{ _bsd_close_idle_files(); }); dispatch_source_set_timer(bsd_idle_timer, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * CLOSE_ON_IDLE_SEC), NSEC_PER_SEC * CLOSE_ON_IDLE_SEC, 0); dispatch_resume(bsd_idle_timer); }); @@ -775,7 +775,7 @@ _bsd_out_close_internal(void) free(r->facility); } - + TAILQ_REMOVE(&bsd_out_rule, r, entries); free(r); } diff --git a/syslogd.tproj/com.apple.syslogd.plist b/syslogd.tproj/com.apple.syslogd.plist index df73a1d..05ab013 100644 --- a/syslogd.tproj/com.apple.syslogd.plist +++ b/syslogd.tproj/com.apple.syslogd.plist @@ -18,7 +18,7 @@ EnableTransactions POSIXSpawnType - Interactive + Adaptive ProgramArguments