* 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,
* 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 <assert.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#define _PATH_ASL_CONF_LOCAL_DIR "/usr/local/etc/asl"
#endif
+//#define DEBUG_LIST_FILES 1
+
static const char *asl_out_action_name[] =
{
"none ",
#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)
{
int i, len;
if (s == NULL) return l;
- if (l == NULL)
+ if (l == NULL)
{
l = (char **)malloc(2 * sizeof(char *));
if (l == NULL) return NULL;
for (i = 0; l[i] != NULL; i++);
- /* len includes the NULL at the end of the list */
+ /* len includes the NULL at the end of the list */
len = i + 1;
l = (char **)reallocf(l, (len + 1) * sizeof(char *));
return out;
}
-static asl_out_dst_data_t *
-_asl_out_dest_for_path(asl_out_module_t *m, const char *path)
+asl_out_dst_data_t *
+asl_out_dest_for_path(asl_out_module_t *m, const char *path)
{
if (m == NULL) return NULL;
if (path == NULL) return NULL;
asl_out_rule_t *r = m->ruleset;
while (r != NULL)
{
- if ((r->action == ACTION_OUT_DEST) && (r->dst != NULL) && (r->dst->path != NULL) && (!strcmp(r->dst->path, path))) return r->dst;
+ if ((r->action == ACTION_OUT_DEST) && (r->dst != NULL) && (r->dst->path != NULL) && (streq(r->dst->path, path))) return r->dst;
r = r->next;
}
return -1;
}
- dst = _asl_out_dest_for_path(mlist, tmp);
+ dst = asl_out_dest_for_path(mlist, tmp);
if ((dst == NULL) && (flags & MODULE_FLAG_NONSTD_DIR))
{
/* no rule to create a non-standard path component! */
return -1;
}
+int
+asl_make_database_dir(const char *dir, char **out)
+{
+ const char *asldir, *path;
+ char *str = NULL;
+ struct stat sb;
+ int status;
+ mode_t mask;
+
+ if (out != NULL) *out = NULL;
+
+ asldir = asl_filesystem_path(ASL_PLACE_DATABASE);
+ if (asldir == NULL) return -1;
+
+ if (dir == NULL)
+ {
+ /* create the database directory itself */
+ path = asldir;
+ }
+ else
+ {
+ if (strchr(dir, '/') != NULL) return -1;
+
+ asprintf(&str, "%s/%s", asldir, dir);
+ if (str == NULL) return -1;
+ path = str;
+ }
+
+ memset(&sb, 0, sizeof(struct stat));
+
+ status = stat(path, &sb);
+ if (status == 0)
+ {
+ if (S_ISDIR(sb.st_mode))
+ {
+ if (out == NULL) free(str);
+ else *out = str;
+ return 0;
+ }
+
+ free(str);
+ return -1;
+ }
+
+ if (errno != ENOENT)
+ {
+ free(str);
+ return -1;
+ }
+
+ mask = umask(0);
+ status = mkdir(path, 0755);
+ umask(mask);
+
+ if (status == 0)
+ {
+ if (out == NULL) free(str);
+ else *out = str;
+ }
+ else free(str);
+
+ return status;
+}
+
void
asl_make_timestamp(time_t stamp, uint32_t flags, char *buf, size_t len)
{
if (buf == NULL) return;
- if (flags & MODULE_FLAG_STYLE_UTC)
+ if (flags & MODULE_NAME_STYLE_STAMP_UTC)
{
memset(&t, 0, sizeof(t));
gmtime_r(&stamp, &t);
snprintf(buf, len, "%d-%02d-%02dT%02d:%02d:%02dZ", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
}
- else if (flags & MODULE_FLAG_STYLE_UTC_B)
+ else if (flags & MODULE_NAME_STYLE_STAMP_UTC_B)
{
memset(&t, 0, sizeof(t));
gmtime_r(&stamp, &t);
snprintf(buf, len, "%d%02d%02dT%02d%02d%02dZ", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
}
- else if (flags & MODULE_FLAG_STYLE_LCL)
+ else if (flags & MODULE_NAME_STYLE_STAMP_LCL)
{
bool neg = false;
memset(&t, 0, sizeof(t));
else if (m > 0) snprintf(buf, len, "%d-%02d-%02dT%02d:%02d:%02d%c%u:%02u", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, neg ? '-' : '+', h, m);
else snprintf(buf, len, "%d-%02d-%02dT%02d:%02d:%02d%c%u", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, neg ? '-' : '+', h);
}
- else if (flags & MODULE_FLAG_STYLE_LCL_B)
+ else if (flags & MODULE_NAME_STYLE_STAMP_LCL_B)
{
bool neg = false;
memset(&t, 0, sizeof(t));
}
else
{
- snprintf(buf, len, "%c%lu", STYLE_SEC_PREFIX_CHAR, stamp);
+ snprintf(buf, len, "%c%llu", STYLE_SEC_PREFIX_CHAR, (unsigned long long)stamp);
}
}
void
-asl_make_dst_filename(asl_out_dst_data_t *dst, char *buf, size_t len)
+asl_dst_make_current_name(asl_out_dst_data_t *dst, uint32_t xflags, char *buf, size_t len)
{
+ char tstamp[32];
+
if (dst == NULL) return;
if (buf == NULL) return;
- if (dst->flags & (MODULE_FLAG_BASESTAMP | MODULE_FLAG_TYPE_ASL_DIR))
- {
- char tstamp[32];
- const char *name = dst->path;
+ xflags |= dst->flags;
- if (dst->flags & MODULE_FLAG_TYPE_ASL_DIR) name = dst->fname;
+ if (dst->timestamp == 0) dst->timestamp = time(NULL);
+ asl_make_timestamp(dst->timestamp, dst->style_flags, tstamp, sizeof(tstamp));
- if (dst->stamp == 0) dst->stamp = time(NULL);
- asl_make_timestamp(dst->stamp, dst->flags, tstamp, sizeof(tstamp));
- snprintf(buf, len, "%s.%s", name, tstamp);
+ if (xflags & MODULE_FLAG_TYPE_ASL_DIR)
+ {
+ snprintf(buf, len, "%s.%s", dst->current_name, tstamp);
+ }
+ else if (xflags & MODULE_FLAG_BASESTAMP)
+ {
+ if ((dst->dir != NULL) && (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BSE))
+ {
+ snprintf(buf, len, "%s/%s.%s.%s", dst->dir, dst->base, tstamp, dst->ext);
+ }
+ else
+ {
+ snprintf(buf, len, "%s.%s", dst->path, tstamp);
+ }
}
else
{
if (dst->refcount > 0) dst->refcount--;
if (dst->refcount > 0) return;
+ free(dst->dir);
free(dst->path);
- free(dst->fname);
+ free(dst->current_name);
+ free(dst->base);
+ free(dst->ext);
free(dst->rotate_dir);
free(dst->fmt);
#if !TARGET_IPHONE_SIMULATOR
if (dst == NULL) return -1;
if (dst->path == NULL) return -1;
- asl_make_dst_filename(dst, outpath, sizeof(outpath));
- if (dst->fname != NULL) free(dst->fname);
+ asl_dst_make_current_name(dst, 0, outpath, sizeof(outpath));
+ free(dst->current_name);
- dst->fname = strdup(outpath);
- if (dst->fname == NULL) return -1;
+ dst->current_name = strdup(outpath);
+ if (dst->current_name == NULL) return -1;
if (pathp != NULL) *pathp = strdup(outpath);
/* file exists */
fd = open(outpath, O_RDWR | O_APPEND | O_EXCL, 0);
- if (dst->stamp == 0) dst->stamp = sb.st_birthtimespec.tv_sec;
- if (dst->stamp == 0) dst->stamp = sb.st_mtimespec.tv_sec;
+ if (dst->timestamp == 0) dst->timestamp = sb.st_birthtimespec.tv_sec;
+ if (dst->timestamp == 0) dst->timestamp = sb.st_mtimespec.tv_sec;
dst->size = sb.st_size;
+ if ((dst->flags & MODULE_FLAG_BASESTAMP) && (dst->flags & MODULE_FLAG_SYMLINK)) symlink(outpath, dst->path);
return fd;
}
else if (errno != ENOENT)
fd = open(outpath, O_RDWR | O_CREAT | O_EXCL, (dst->mode & 00666));
if (fd < 0) return -1;
- dst->stamp = time(NULL);
+ dst->timestamp = time(NULL);
fd = asl_out_dst_set_access(fd, dst);
if (fd < 0) unlink(outpath);
+ if ((dst->flags & MODULE_FLAG_BASESTAMP) && (dst->flags & MODULE_FLAG_SYMLINK))
+ {
+ /* remove old symlink, make a new link to the "current" file */
+ unlink(dst->path);
+ symlink(outpath, dst->path);
+ }
+
return fd;
}
else
{
/* = param [query] */
- if ((!strncmp(p, "[File ", 6)) || (!strncmp(p, "[File\t", 6))) out->action = ACTION_SET_FILE;
- else if ((!strncmp(p, "[Plist ", 7)) || (!strncmp(p, "[Plist\t", 7))) out->action = ACTION_SET_PLIST;
- else if ((!strncmp(p, "[Profile ", 9)) || (!strncmp(p, "[Profile\t", 9))) out->action = ACTION_SET_PROF;
+ if (streq_len(p, "[File ", 6) || streq_len(p, "[File\t", 6)) out->action = ACTION_SET_FILE;
+ else if (streq_len(p, "[Plist ", 7) || streq_len(p, "[Plist\t", 7)) out->action = ACTION_SET_PLIST;
+ else if (streq_len(p, "[Profile ", 9) || streq_len(p, "[Profile\t", 9)) out->action = ACTION_SET_PROF;
p--;
*p = '\0';
return fmt;
}
-size_t
-asl_str_to_size(char *s)
-{
- size_t len, n, max;
- char x;
-
- if (s == NULL) return 0;
-
- len = strlen(s);
- if (len == 0) return 0;
-
- n = 1;
- x = s[len - 1];
- if (x > 90) x -= 32;
- if (x == 'K') n = 1ll << 10;
- else if (x == 'M') n = 1ll << 20;
- else if (x == 'G') n = 1ll << 30;
-
- max = atoll(s) * n;
- return max;
-}
-
static bool
_dst_path_match(const char *newpath, const char *existingpath)
{
return (strcmp(newpath, trailing) == 0);
}
+static uint32_t
+_parse_stamp_string(const char *in)
+{
+ char buf[16];
+ uint32_t x;
+
+ if (in == NULL) return 0;
+
+ for (x = 0; (((in[x] >= 'a') && (in[x] <= 'z')) || (in[x] == '-')) && (x < 11); x++) buf[x] = in[x];
+ buf[x] = '\0';
+
+ if (streq(buf, "sec") || streq(buf, "seconds")) return MODULE_NAME_STYLE_STAMP_SEC;
+ if (streq(buf, "zulu") || streq(buf, "utc")) return MODULE_NAME_STYLE_STAMP_UTC;
+ if (streq(buf, "utc-b") || streq(buf, "utc-basic")) return MODULE_NAME_STYLE_STAMP_UTC_B;
+ if (streq(buf, "local") || streq(buf, "lcl")) return MODULE_NAME_STYLE_STAMP_LCL;
+ if (streq(buf, "local-b") || streq(buf, "lcl-b") || streq(buf, "local-basic") || streq(buf, "lcl-basic")) return MODULE_NAME_STYLE_STAMP_LCL_B;
+ if (streq(buf, "#") || streq(buf, "seq") || streq(buf, "sequence"))return MODULE_NAME_STYLE_STAMP_SEQ;
+
+ return 0;
+}
+
+/*
+ * Parse a file-rotation naming style.
+ *
+ * Legacy: sec / seconds, utc / date / zulu [-b], local / lcl [-b], # / seq / sequence
+ * We scan the whole line and match to one of these.
+ *
+ * New scheme: 2 or 3 components: base and style, or base, style, and extension.
+ * these define a name format. base is the file name without a leading directory path
+ * and with no extension (e.g. "foo"). style is one of the styles above. extension is
+ * the file name extension (e.g. "log", "txt", etc).
+ *
+ * Examples:
+ * foo.utc.log
+ * foo.log.lcl
+ * foo.seq
+ *
+ * The leading base name may be ommitted (E.G. ".lcl.log", ".log.seq")
+ * If the leading base name AND extension are omitted, it is taken from the path. E.G. ".lcl", ".seq"
+ *
+ * If we get input without a stamp spec, we default to "sec".
+ */
+static int
+_parse_dst_style(asl_out_dst_data_t *dst, const char *in)
+{
+ const char *p, *q;
+ size_t len;
+
+ if ((dst == NULL) || (in == NULL)) return -1;
+
+ /* check for base. or just . for shorthand */
+ p = NULL;
+ if (in[0] == '.')
+ {
+ p = in + 1;
+ }
+ else
+ {
+ if (dst->base == NULL) return -1;
+
+ len = strlen(dst->base);
+ if (streq_len(in, dst->base, len) && (in[len] == '.')) p = in + len + 1;
+ }
+
+ if (p == NULL)
+ {
+ /* input does not start with '.' or base, so this is legacy style */
+ dst->style_flags = _parse_stamp_string(in);
+ if (dst->style_flags == 0) return -1;
+
+ if (dst->ext == NULL) dst->style_flags |= MODULE_NAME_STYLE_FORMAT_BS;
+ else dst->style_flags |= MODULE_NAME_STYLE_FORMAT_BES;
+
+ return 0;
+ }
+
+ /* look for another dot in the name */
+ for (q = p; (*q != '.') && (*q != ' ') && (*q != '\t') && (*q != '\0'); q++);
+ if (*q != '.') q = NULL;
+
+ if (q == NULL)
+ {
+ /* we require a stamp spec, so we are expecting base.stamp */
+ dst->style_flags = _parse_stamp_string(p);
+
+ if (dst->style_flags == 0) return -1;
+
+ /*
+ * We got a valid stamp style ("base.stamp").
+ * Note that we might have skipped the extention if the file name was "foo.log".
+ * That's OK - syslogd writes "foo.log", but the rotated files are e.g. foo.20141018T1745Z.
+ */
+ dst->style_flags |= MODULE_NAME_STYLE_FORMAT_BS;
+ return 0;
+ }
+
+ /* set q to the char past the dot */
+ q++;
+
+ /* either base.stamp.ext or base.ext.stamp */
+ if (dst->ext == NULL) return -1;
+
+ len = strlen(dst->ext);
+ if (streq_len(p, dst->ext, len) && (p[len] == '.'))
+ {
+ /* got base.ext.stamp */
+ dst->style_flags = _parse_stamp_string(q);
+ if (dst->style_flags == 0) return -1;
+
+ dst->style_flags |= MODULE_NAME_STYLE_FORMAT_BES;
+ return 0;
+ }
+
+ /* must be base.stamp.ext */
+ if (strneq_len(q, dst->ext, len)) return -1;
+
+ dst->style_flags = _parse_stamp_string(p);
+ if (dst->style_flags == 0) return -1;
+
+ dst->style_flags |= MODULE_NAME_STYLE_FORMAT_BSE;
+ return 0;
+}
+
static asl_out_dst_data_t *
_asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode)
{
asl_out_rule_t *out, *rule;
asl_out_dst_data_t *dst;
- char *p, *opts, *path;
+ char *p, *dot, *opts, *path;
char **path_parts;
int has_dotdot, recursion_limit;
uint32_t i, flags = 0;
for (i = 0; path_parts[i] != NULL; i++)
{
- if (!strncmp(path_parts[i], "$ENV(", 5))
+ if (streq_len(path_parts[i], "$ENV(", 5))
{
char *p = strchr(path_parts[i], ')');
if (p != NULL) *p = '\0';
}
}
- if ((has_dotdot == 0) && (!strcmp(path_parts[i], ".."))) has_dotdot = 1;
+ if ((has_dotdot == 0) && streq(path_parts[i], "..")) has_dotdot = 1;
}
free_string_list(path_parts);
if (log_root == NULL) log_root = "/tmp/log";
#endif
- if (!strcmp(m->name, ASL_MODULE_NAME))
+ if (streq(m->name, ASL_MODULE_NAME))
{
asprintf(&path, "%s/%s", log_root, t);
}
* Standard log directories get marked so that syslogd
* will create them without explicit rules.
*/
- if (!strncmp(path, PATH_VAR_LOG, PATH_VAR_LOG_LEN)) flags &= ~MODULE_FLAG_NONSTD_DIR;
- else if (!strncmp(path, PATH_LIBRARY_LOGS, PATH_LIBRARY_LOGS_LEN)) flags &= ~MODULE_FLAG_NONSTD_DIR;
+ if (streq_len(path, PATH_VAR_LOG, PATH_VAR_LOG_LEN)) flags &= ~MODULE_FLAG_NONSTD_DIR;
+ else if (streq_len(path, PATH_LIBRARY_LOGS, PATH_LIBRARY_LOGS_LEN)) flags &= ~MODULE_FLAG_NONSTD_DIR;
}
out = (asl_out_rule_t *)calloc(1, sizeof(asl_out_rule_t));
dst->refcount = 1;
dst->path = path;
+
+ p = strrchr(dst->path, '/');
+ if (p != NULL)
+ {
+ *p = '\0';
+ dst->dir = strdup(dst->path);
+ *p = '/';
+ }
+
dst->mode = def_mode;
dst->ttl[LEVEL_ALL] = DEFAULT_TTL;
dst->flags = flags | MODULE_FLAG_COALESCE;
+ /*
+ * Break out base and extension (if present) from path.
+ * Note this only supports a '.' as a separator.
+ */
+ p = strrchr(path, '/');
+ if (p == NULL) p = path;
+ else p++;
+
+ dot = strrchr(path, '.');
+ if (dot != NULL)
+ {
+ *dot = '\0';
+ dst->ext = strdup(dot + 1);
+ }
+
+ dst->base = strdup(p);
+ if (dot != NULL) *dot = '.';
+
while (NULL != (p = next_word_from_string(&opts)))
{
if (KEYMATCH(p, "mode=")) dst->mode = strtol(p+5, NULL, 0);
else if (KEYMATCH(p+9, "false")) dst->flags &= ~MODULE_FLAG_COALESCE;
}
else if (KEYMATCH(p, "compress")) dst->flags |= MODULE_FLAG_COMPRESS;
+ else if (KEYMATCH(p, "activity")) dst->flags |= MODULE_FLAG_ACTIVITY;
else if (KEYMATCH(p, "extern")) dst->flags |= MODULE_FLAG_EXTERNAL;
else if (KEYMATCH(p, "truncate")) dst->flags |= MODULE_FLAG_TRUNCATE;
else if (KEYMATCH(p, "dir")) dst->flags |= MODULE_FLAG_TYPE_ASL_DIR;
else if (KEYMATCH(p, "soft")) dst->flags |= MODULE_FLAG_SOFT_WRITE;
- else if (KEYMATCH(p, "file_max=")) dst->file_max = asl_str_to_size(p+9);
- else if (KEYMATCH(p, "all_max=")) dst->all_max = asl_str_to_size(p+8);
+ else if (KEYMATCH(p, "file_max=")) dst->file_max = asl_core_str_to_size(p+9);
+ else if (KEYMATCH(p, "all_max=")) dst->all_max = asl_core_str_to_size(p+8);
else if (KEYMATCH(p, "style=") || KEYMATCH(p, "rotate="))
{
const char *x = p + 6;
- if (KEYMATCH(p, "rotate=")) x++;
+ if (*p == 'r') x++;
+ if (_parse_dst_style(dst, x) == 0) dst->flags |= MODULE_FLAG_ROTATE;
+ }
+ else if (KEYMATCH(p, "rotate"))
+ {
+ if (dst->ext == NULL) dst->style_flags = MODULE_NAME_STYLE_FORMAT_BS | MODULE_NAME_STYLE_STAMP_SEC;
+ else dst->style_flags = MODULE_NAME_STYLE_FORMAT_BES | MODULE_NAME_STYLE_STAMP_SEC;
dst->flags |= MODULE_FLAG_ROTATE;
-
- if (KEYMATCH(x, "sec") || KEYMATCH(x, "seconds"))
- {
- dst->flags |= MODULE_FLAG_STYLE_SEC;
- }
- else if (KEYMATCH(x, "utc") || KEYMATCH(x, "date") || KEYMATCH(x, "zulu"))
- {
- const char *dash = strchr(x, '-');
- if ((dash != NULL) && (*(dash + 1) == 'b')) dst->flags |= MODULE_FLAG_STYLE_UTC_B;
- else dst->flags |= MODULE_FLAG_STYLE_UTC;
- }
- else if (KEYMATCH(x, "local") || KEYMATCH(x, "lcl"))
- {
- const char *dash = strchr(x, '-');
- if ((dash != NULL) && (*(dash + 1) == 'b')) dst->flags |= MODULE_FLAG_STYLE_LCL_B;
- else dst->flags |= MODULE_FLAG_STYLE_LCL;
- }
- else if (KEYMATCH(x, "#") || KEYMATCH(x, "seq") || KEYMATCH(x, "sequence"))
- {
- dst->flags |= MODULE_FLAG_STYLE_SEQ;
- }
- else
- {
- dst->flags |= MODULE_FLAG_STYLE_SEC;
- }
}
- else if (KEYMATCH(p, "rotate")) dst->flags |= MODULE_FLAG_ROTATE;
else if (KEYMATCH(p, "crashlog"))
{
/* crashlog implies rotation */
{
dst->flags |= MODULE_FLAG_BASESTAMP;
}
+ else if (KEYMATCH(p, "link") || KEYMATCH(p, "symlink"))
+ {
+ dst->flags |= MODULE_FLAG_SYMLINK;
+ }
else if (KEYMATCH(p, "ttl"))
{
char *q = p + 3;
if (*q == '=')
{
- dst->ttl[LEVEL_ALL] = strtol(p+4, NULL, 0);
+ dst->ttl[LEVEL_ALL] = asl_core_str_to_time(p+4, SECONDS_PER_DAY);
}
else if ((*q >= '0') && (*q <= '7') && (*(q+1) == '='))
{
uint32_t x = *q - '0';
- dst->ttl[x] = strtol(p+5, NULL, 0);
+ dst->ttl[x] = asl_core_str_to_time(p+5, SECONDS_PER_DAY);
}
}
#if TARGET_OS_EMBEDDED
/* check for crashreporter files */
- if ((KEYMATCH(dst->path, _PATH_CRASHREPORTER)) || (KEYMATCH(dst->path, _PATH_CRASHREPORTER_MOBILE)))
+ if ((KEYMATCH(dst->path, _PATH_CRASHREPORTER)) || (KEYMATCH(dst->path, _PATH_CRASHREPORTER_MOBILE_1)) || (KEYMATCH(dst->path, _PATH_CRASHREPORTER_MOBILE_2)))
{
dst->flags |= MODULE_FLAG_ROTATE;
dst->flags |= MODULE_FLAG_CRASHLOG;
if (strcmp(dst->fmt, "std") && strcmp(dst->fmt, "bsd")) dst->flags &= ~MODULE_FLAG_COALESCE;
/* note if format is one of std, bsd, or msg */
- if (!strcmp(dst->fmt, "std") || !strcmp(dst->fmt, "bsd") || !strcmp(dst->fmt, "msg")) dst->flags |= MODULE_FLAG_STD_BSD_MSG;
+ if (streq(dst->fmt, "std") || streq(dst->fmt, "bsd") || streq(dst->fmt, "msg")) dst->flags |= MODULE_FLAG_STD_BSD_MSG;
- /* MODULE_FLAG_STYLE_SEQ can not be used with MODULE_FLAG_BASESTAMP */
- if ((dst->flags & MODULE_FLAG_BASESTAMP) && (dst->flags & MODULE_FLAG_STYLE_SEQ))
+ /* MODULE_NAME_STYLE_STAMP_SEQ can not be used with MODULE_FLAG_BASESTAMP */
+ if ((dst->flags & MODULE_FLAG_BASESTAMP) && (dst->flags & MODULE_NAME_STYLE_STAMP_SEQ))
{
- dst->flags &= ~MODULE_FLAG_STYLE_SEQ;
- dst->flags |= MODULE_FLAG_STYLE_SEC;
+ dst->flags &= ~MODULE_NAME_STYLE_STAMP_SEQ;
+ dst->flags |= MODULE_NAME_STYLE_STAMP_SEC;
}
/* set time format for raw output */
- if (!strcmp(dst->fmt, "raw")) dst->tfmt = "sec";
+ if (streq(dst->fmt, "raw")) dst->tfmt = "sec";
/* check for ASL_PLACE_DATABASE_DEFAULT */
- if (!strcmp(dst->path, ASL_PLACE_DATABASE_DEFAULT))
+ if (streq(dst->path, ASL_PLACE_DATABASE_DEFAULT))
{
dst->flags = MODULE_FLAG_TYPE_ASL_DIR;
}
+ /* set file_max to all_max if it is zero */
+ if (dst->file_max == 0) dst->file_max = dst->all_max;
+
out->action = ACTION_OUT_DEST;
out->dst = dst;
if (p == NULL) p = strchr(act, '\t');
if (p != NULL) *p = '\0';
- if (!strcasecmp(act, "ignore")) out->action = ACTION_IGNORE;
- else if (!strcasecmp(act, "skip")) out->action = ACTION_SKIP;
- else if (!strcasecmp(act, "claim")) out->action = ACTION_CLAIM;
- else if (!strcasecmp(act, "notify")) out->action = ACTION_NOTIFY;
- else if (!strcasecmp(act, "file")) out->action = ACTION_FILE;
- else if (!strcasecmp(act, "asl_file")) out->action = ACTION_ASL_FILE;
- else if (!strcasecmp(act, "directory")) out->action = ACTION_ASL_DIR;
- else if (!strcasecmp(act, "dir")) out->action = ACTION_ASL_DIR;
- else if (!strcasecmp(act, "asl_directory")) out->action = ACTION_ASL_DIR;
- else if (!strcasecmp(act, "asl_dir")) out->action = ACTION_ASL_DIR;
- else if (!strcasecmp(act, "store_dir")) out->action = ACTION_ASL_DIR;
- else if (!strcasecmp(act, "store_directory")) out->action = ACTION_ASL_DIR;
- else if (!strcasecmp(act, "control")) out->action = ACTION_CONTROL;
- else if (!strcasecmp(act, "save")) out->action = ACTION_ASL_STORE;
- else if (!strcasecmp(act, "store")) out->action = ACTION_ASL_STORE;
- else if (!strcasecmp(act, "access")) out->action = ACTION_ACCESS;
- else if (!strcasecmp(act, "set")) out->action = ACTION_SET_KEY;
- else if (!strcasecmp(act, "unset")) out->action = ACTION_UNSET_KEY;
- else if (!strcmp(m->name, ASL_MODULE_NAME))
+ if (strcaseeq(act, "ignore")) out->action = ACTION_IGNORE;
+ else if (strcaseeq(act, "skip")) out->action = ACTION_SKIP;
+ else if (strcaseeq(act, "claim")) out->action = ACTION_CLAIM;
+ else if (strcaseeq(act, "notify")) out->action = ACTION_NOTIFY;
+ else if (strcaseeq(act, "file")) out->action = ACTION_FILE;
+ else if (strcaseeq(act, "asl_file")) out->action = ACTION_ASL_FILE;
+ else if (strcaseeq(act, "directory")) out->action = ACTION_ASL_DIR;
+ else if (strcaseeq(act, "dir")) out->action = ACTION_ASL_DIR;
+ else if (strcaseeq(act, "asl_directory")) out->action = ACTION_ASL_DIR;
+ else if (strcaseeq(act, "asl_dir")) out->action = ACTION_ASL_DIR;
+ else if (strcaseeq(act, "store_dir")) out->action = ACTION_ASL_DIR;
+ else if (strcaseeq(act, "store_directory")) out->action = ACTION_ASL_DIR;
+ else if (strcaseeq(act, "control")) out->action = ACTION_CONTROL;
+ else if (strcaseeq(act, "save")) out->action = ACTION_ASL_STORE;
+ else if (strcaseeq(act, "store")) out->action = ACTION_ASL_STORE;
+ else if (strcaseeq(act, "access")) out->action = ACTION_ACCESS;
+ else if (strcaseeq(act, "set")) out->action = ACTION_SET_KEY;
+ else if (strcaseeq(act, "unset")) out->action = ACTION_UNSET_KEY;
+ else if (streq(m->name, ASL_MODULE_NAME))
{
/* actions only allowed in com.apple.asl */
- if (!strcasecmp(act, "broadcast")) out->action = ACTION_BROADCAST;
- else if (!strcasecmp(act, "forward")) out->action = ACTION_FORWARD;
+ if (strcaseeq(act, "broadcast")) out->action = ACTION_BROADCAST;
+ else if (strcaseeq(act, "forward")) out->action = ACTION_FORWARD;
}
if (out->action == ACTION_NONE)
if (out->action == ACTION_ASL_STORE)
{
if (out->options == NULL) out->dst = asl_out_dst_data_retain(_asl_out_module_parse_dst(m, ASL_PLACE_DATABASE_DEFAULT, 0755));
- else if (!strncmp(out->options, ASL_PLACE_DATABASE_DEFAULT, strlen(ASL_PLACE_DATABASE_DEFAULT))) out->dst = asl_out_dst_data_retain(_asl_out_module_parse_dst(m, out->options, 0755));
+ else if (streq_len(out->options, ASL_PLACE_DATABASE_DEFAULT, strlen(ASL_PLACE_DATABASE_DEFAULT))) out->dst = asl_out_dst_data_retain(_asl_out_module_parse_dst(m, out->options, 0755));
else if (out->options != NULL) out->action = ACTION_ASL_FILE;
}
*/
if (out->dst->mode == 010000) out->dst->mode = def_mode;
- if ((out->action == ACTION_FILE) && (out->dst != NULL) && (out->dst->fmt != NULL) && (!strcasecmp(out->dst->fmt, "asl")))
+ if ((out->action == ACTION_FILE) && (out->dst != NULL) && (out->dst->fmt != NULL) && (strcaseeq(out->dst->fmt, "asl")))
{
out->action = ACTION_ASL_FILE;
}
/* coalesce is meaningless for ASL directories */
out->dst->flags &= ~MODULE_FLAG_COALESCE;
- /* no compression at this point */
- out->dst->flags &= ~MODULE_FLAG_COMPRESS;
-
out->dst->flags |= MODULE_FLAG_TYPE_ASL_DIR;
/* set style bits for basestamp asl_dirs */
- if (((out->dst->flags & MODULE_FLAG_STYLE_BITS) == 0) && (out->dst->flags & MODULE_FLAG_BASESTAMP)) out->dst->flags |= MODULE_FLAG_STYLE_LCL_B;
+ if (((out->dst->style_flags & MODULE_NAME_STYLE_STAMP_MASK) == 0) && (out->dst->flags & MODULE_FLAG_BASESTAMP)) out->dst->style_flags |= MODULE_NAME_STYLE_STAMP_LCL_B;
}
/* only ACTION_FILE and ACTION_ASL_FILE may rotate */
{
return _asl_out_module_parse_set_param(m, s);
}
- else if (*s == '>')
+ else if (*s == '>')
{
_asl_out_module_parse_dst(m, s + 1, 010000);
}
for (x = list; x != NULL; x = x->next)
{
- if ((x->name != NULL) && (!strcmp(x->name, name))) return x;
+ if ((x->name != NULL) && (streq(x->name, name))) return x;
}
return NULL;
{
while (NULL != (ent = readdir(d)))
{
- if ((ent->d_name != NULL) && (ent->d_name[0] != '.'))
+ if (ent->d_name[0] != '.')
{
/* merge: skip this file if we already have a module with this name */
if (_asl_out_module_find(*list, ent->d_name) != NULL) continue;
{
x->flags |= flags;
- if (!strcmp(ent->d_name, ASL_MODULE_NAME))
+ if (streq(ent->d_name, ASL_MODULE_NAME))
{
/* com.apple.asl goes at the head of the list */
x->next = *list;
char *asl_conf, *asl_conf_dir, *asl_conf_local_dir;
sim_root_path = getenv("IPHONE_SIMULATOR_ROOT");
- assert(sim_root_path);
+ if (sim_root_path == NULL) return NULL;
sim_resources_path = getenv("IPHONE_SHARED_RESOURCES_DIRECTORY");
- assert(sim_resources_path);
+ if (sim_resources_path == NULL) return NULL;
asprintf(&asl_conf, "%s%s", sim_root_path, _PATH_ASL_CONF);
asprintf(&asl_conf_dir, "%s%s", sim_root_path, _PATH_ASL_CONF_DIR);
asprintf(&out, " %s%s%s%s%s",
asl_out_action_name[r->action],
- (r->query == NULL) ? "" : " ",
+ (r->query == NULL) ? "" : " ",
(r->query == NULL) ? "" : str,
- (r->options == NULL) ? "" : " ",
+ (r->options == NULL) ? "" : " ",
(r->options == NULL) ? "" : r->options);
free(str);
return out;
}
+static const char *
+_stamp_style_name(uint32_t flags)
+{
+ if (flags & MODULE_NAME_STYLE_STAMP_SEC) return "<seconds>";
+ if (flags & MODULE_NAME_STYLE_STAMP_SEQ) return "<sequence>";
+ if (flags & MODULE_NAME_STYLE_STAMP_UTC) return "<utc>";
+ if (flags & MODULE_NAME_STYLE_STAMP_UTC_B) return "<utc-basic>";
+ if (flags & MODULE_NAME_STYLE_STAMP_LCL) return "<local>";
+ if (flags & MODULE_NAME_STYLE_STAMP_LCL_B) return "<local-basic>";
+ return "<unknown>";
+}
+
/*
* Print module
*/
asl_out_rule_t *r, *n;
asl_out_dst_data_t *o;
uint32_t i, ttlnset;
+ char tstr[150];
n = NULL;
for (r = m->ruleset; r != NULL; r = n)
fprintf(f, "%ccompress", c);
c = ' ';
}
- if (o->flags & MODULE_FLAG_STYLE_SEC)
- {
- fprintf(f, "%cseconds", c);
- c = ' ';
- }
- if (o->flags & MODULE_FLAG_STYLE_SEQ)
- {
- fprintf(f, "%csequence", c);
- c = ' ';
- }
- if (o->flags & MODULE_FLAG_STYLE_UTC)
- {
- fprintf(f, "%cutc", c);
- c = ' ';
- }
- if (o->flags & MODULE_FLAG_STYLE_UTC_B)
- {
- fprintf(f, "%cutc-basic", c);
- c = ' ';
- }
- if (o->flags & MODULE_FLAG_STYLE_LCL)
- {
- fprintf(f, "%clocal", c);
- c = ' ';
- }
- if (o->flags & MODULE_FLAG_STYLE_LCL_B)
+ if (o->flags & MODULE_FLAG_BASESTAMP)
{
- fprintf(f, "%clocal-basic", c);
+ fprintf(f, "%cbasestamp", c);
c = ' ';
}
- if (o->flags & MODULE_FLAG_BASESTAMP)
+ if (o->flags & MODULE_FLAG_SYMLINK)
{
- fprintf(f, "%cbasestamp", c);
+ fprintf(f, "%csymlink", c);
c = ' ';
}
if (o->flags & MODULE_FLAG_NONSTD_DIR)
fprintf(f, "%cexternal", c);
c = ' ';
}
+ if (o->flags & MODULE_FLAG_ACTIVITY)
+ {
+ fprintf(f, "%cactivity", c);
+ c = ' ';
+ }
if (o->flags & MODULE_FLAG_CRASHLOG)
{
fprintf(f, "%ccrashlog", c);
}
fprintf(f, "\n");
- fprintf(f, " ttl: %u", o->ttl[LEVEL_ALL]);
+ if (o->flags & MODULE_FLAG_ROTATE)
+ {
+ fprintf(f, " rotatation style: ");
+ if (o->style_flags & MODULE_NAME_STYLE_FORMAT_BS)
+ {
+ fprintf(f, "[base=%s].%s\n", o->base, _stamp_style_name(o->style_flags));
+ }
+ else if (o->style_flags & MODULE_NAME_STYLE_FORMAT_BES)
+ {
+ fprintf(f, "[base=%s].[ext=%s].%s\n", o->base, o->ext, _stamp_style_name(o->style_flags));
+ }
+ else if (o->style_flags & MODULE_NAME_STYLE_FORMAT_BSE)
+ {
+ fprintf(f, "[base=%s].%s.[ext=%s]\n", o->base, _stamp_style_name(o->style_flags), o->ext);
+ }
+ else
+ {
+ fprintf(f, "0x%08x\n", o->style_flags);
+ }
+ }
+
+ asl_core_time_to_str(o->ttl[LEVEL_ALL], tstr, sizeof(tstr));
+ fprintf(f, " ttl: %s\n", tstr);
+
ttlnset = 0;
for (i = 0; (i <= 7) & (ttlnset == 0); i++) if (o->ttl[i] != 0) ttlnset = 1;
- if (ttlnset != 0) for (i = 0; i <= 7; i++) printf(" [%d %d]", i, (o->ttl[i] == 0) ? o->ttl[LEVEL_ALL] : o->ttl[i]);
- fprintf(f, "\n");
+ if (ttlnset != 0)
+ {
+ for (i = 0; i <= 7; i++)
+ {
+ time_t x = o->ttl[i];
+ if (x == 0) x = o->ttl[LEVEL_ALL];
+ asl_core_time_to_str(x, tstr, sizeof(tstr));
+
+ fprintf(f, " [%d %s]", i, tstr);
+ }
+
+ fprintf(f, "\n");
+ }
fprintf(f, " mode: 0%o\n", o->mode);
fprintf(f, " file_max: %lu\n", o->file_max);
}
/*
- * Checks input name for the form base[.stamp][.gz]
- * name == base is allowed if src is true.
+ * Checks input name for one of the forms:
+ * MODULE_NAME_STYLE_FORMAT_BS base (src only) or base.stamp[.gz]
+ * MODULE_NAME_STYLE_FORMAT_BES base.ext (src only) or base.ext.stamp[.gz]
+ * MODULE_NAME_STYLE_FORMAT_BSE base.ext (src only) or base.stamp.ext[.gz]
+ *
+ * name == base[.ext] is allowed if src is true.
* base.gz is not allowed.
* Output parameter stamp must be freed by caller.
*/
bool
-_check_file_name(const char *name, const char *base, bool src, char **stamp)
+_check_file_name(const char *name, const char *base, const char *ext, uint32_t flags, bool src, char **stamp)
{
- size_t baselen, nparts;
- const char *p, *q, *part[2];
+ size_t baselen, extlen;
+ const char *p, *z;
bool isgz = false;
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, "_check_file_name name=%s base=%s ext=%s flags=0x%08x %s\n", name, base, (ext == NULL) ? "(NULL)" : ext, flags, src ? "src" : "dst");
+#endif
+
if (name == NULL) return false;
if (base == NULL) return false;
baselen = strlen(base);
if (baselen == 0) return false;
+ extlen = 0;
+ if (ext != NULL) extlen = strlen(ext);
+
if (stamp != NULL) *stamp = NULL;
- if (strncmp(name, base, baselen)) return false;
+ if (strneq_len(name, base, baselen))
+ {
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " base match failed [%u]\n", __LINE__);
+#endif
+ return false;
+ }
- p = name + baselen;
+ z = strrchr(name, '.');
+ if ((z != NULL) && streq(z, ".gz")) isgz = true;
- /* name == base not allowed (it's the "active" file) */
- if (*p == '\0') return false;
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, "z=%s isgz=%s\n", (z == NULL) ? "NULL" : z, isgz ? "true" : "false");
+#endif
- /* name must be base.something */
- if (*p != '.') return false;
+ p = name + baselen;
- /* maximum of 2 parts (stamp and gz) */
- nparts = 0;
- for (q = p; *q != '\0'; q++)
+ if (flags & MODULE_NAME_STYLE_FORMAT_BS)
{
- if (*q == '.')
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " MODULE_NAME_STYLE_FORMAT_BS\n");
+#endif
+ if (*p == '\0')
{
- if (nparts == 2) return false;
- part[nparts++] = q + 1;
+ /* name == base OK if src is true */
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " name == base %s [%u]\n", src ? "OK" : "failed", __LINE__);
+#endif
+ return src;
}
- }
- if (nparts == 0) return false;
+ /* expecting p == .stamp[.gz] */
+ if (*p != '.')
+ {
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " expecting dot - failed [%u]\n", __LINE__);
+#endif
+ return false;
+ }
- isgz = strcmp(part[nparts - 1], "gz") == 0;
+ p++;
- /* no compressed files in src */
- if (src && isgz) return false;
+ if (p == z)
+ {
+ /* base.gz is not allowed */
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " got base.gz - failed [%u]\n", __LINE__);
+#endif
+ return false;
+ }
- /* expecting base.stamp or base.stamp.gz */
+ /* got base.stamp[.gz] */
+ if (stamp != NULL)
+ {
+ *stamp = strdup(p);
+ char *x = strchr(*stamp, '.');
+ if (x != NULL) *x = '\0';
+ }
- if (nparts == 1)
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " got base.stamp%s - OK\n", isgz ? ".gz" : "");
+#endif
+ return true;
+ }
+ else if (flags & MODULE_NAME_STYLE_FORMAT_BES)
{
- /* compressed files must have a stamp (base.gz is not allowed) */
- if (isgz) return false;
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " MODULE_NAME_STYLE_FORMAT_BES\n");
+#endif
+ if (*p != '.')
+ {
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " expecting dot - failed [%u]\n", __LINE__);
+#endif
+ return false;
+ }
+
+ p++;
+
+ if (strneq_len(p, ext, extlen))
+ {
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " ext match failed [%u]\n", __LINE__);
+#endif
+ return false;
+ }
- /* got base.stamp */
- if (stamp != NULL) *stamp = strdup(part[0]);
+ /* expecting p == .ext[.stamp][.gz] */
+ p += extlen;
+
+ if (*p == '\0')
+ {
+ /* name == base.ext OK if src is true */
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " name == base.ext %s [%u]\n", src ? "OK" : "failed", __LINE__);
+#endif
+ return src;
+ }
+
+ /* expecting p == .stamp[.gz] */
+ if (*p != '.')
+ {
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " expecting dot - failed [%u]\n", __LINE__);
+#endif
+ return false;
+ }
+
+ p++;
+
+ if (p == z)
+ {
+ /* base.ext.gz is not allowed */
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " got base.ext.gz - failed [%u]\n", __LINE__);
+#endif
+ return false;
+ }
+
+ /* got base.ext.stamp[.gz] */
+ if (stamp != NULL)
+ {
+ *stamp = strdup(p);
+ char *x = strchr(*stamp, '.');
+ if (x != NULL) *x = '\0';
+ }
+
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " got base.ext.stamp%s - OK\n", isgz ? ".gz" : "");
+#endif
return true;
}
+ else if (flags & MODULE_NAME_STYLE_FORMAT_BSE)
+ {
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " MODULE_NAME_STYLE_FORMAT_BSE name=%s base=%s ext=%s flags=0x%08x %s\n", name, base, (ext == NULL) ? "(NULL)" : ext, flags, src ? "src" : "dst");
+#endif
- /* expecting base.stamp.gz */
- if (!isgz) return false;
+ if (*p != '.')
+ {
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " expecting dot - failed [%u]\n", __LINE__);
+#endif
+ return false;
+ }
- /* got base.stamp.gz */
- if (stamp != NULL)
- {
- *stamp = strdup(part[0]);
- char *x = strchr(*stamp, '.');
- if (x != NULL) *x = '\0';
+ p++;
+
+ if (streq_len(p, ext, extlen))
+ {
+ p += extlen;
+ if (*p == '\0')
+ {
+ /* name == base.ext OK if src is true */
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " name == base.ext %s [%u]\n", src ? "OK" : "failed", __LINE__);
+#endif
+ return src;
+ }
+ }
+
+ /* expecting p == stamp.ext[.gz] */
+
+ if (isgz)
+ {
+ if (strneq_len(z - extlen, ext, extlen))
+ {
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " ext match (%s) isgz failed [%u]\n", z-extlen, __LINE__);
+#endif
+ return false;
+ }
+ }
+ else
+ {
+ if (strneq_len(z + 1, ext, extlen))
+ {
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " ext match (%s) failed [%u]\n", z, __LINE__);
+#endif
+ return false;
+ }
+ }
+
+ /* got base.stamp.ext[.gz] */
+ if (stamp != NULL)
+ {
+ *stamp = strdup(p);
+ char *x = strchr(*stamp, '.');
+ if (x != NULL) *x = '\0';
+ }
+
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " got base.stamp.ext%s - OK\n", isgz ? ".gz" : "");
+#endif
+ return true;
}
- return true;
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, " unknown format - failed\n");
+#endif
+
+ return false;
}
/*
* Find files in a directory (dir) that all have a common prefix (base).
* Bits in flags further control the search.
*
- * MODULE_FLAG_STYLE_SEQ means a numeric sequence number is expected, although not required.
+ * MODULE_NAME_STYLE_STAMP_SEQ means a numeric sequence number is expected, although not required.
* E.g. foo.log foo.log.0
*
- * MODULE_FLAG_STYLE_SEC also means a numeric sequence number is required following an 'T' character.
+ * MODULE_NAME_STYLE_STAMP_SEC also means a numeric sequence number is required following an 'T' character.
* The numeric value is the file's timestamp in seconds. E.g foo.log.T1335200452
*
- * MODULE_FLAG_STYLE_UTC requires a date/time component as the file's timestamp.
+ * MODULE_NAME_STYLE_STAMP_UTC requires a date/time component as the file's timestamp.
* E.g. foo.2012-04-06T15:30:00Z
*
- * MODULE_FLAG_STYLE_UTC_B requires a date/time component as the file's timestamp.
+ * MODULE_NAME_STYLE_STAMP_UTC_B requires a date/time component as the file's timestamp.
* E.g. foo.20120406T153000Z
*
- * MODULE_FLAG_STYLE_LCL requires a date/time component as the file's timestamp.
+ * MODULE_NAME_STYLE_STAMP_LCL requires a date/time component as the file's timestamp.
* E.g. foo.2012-04-06T15:30:00-7
*
- * MODULE_FLAG_STYLE_LCL_B requires a date/time component as the file's timestamp.
+ * MODULE_NAME_STYLE_STAMP_LCL_B requires a date/time component as the file's timestamp.
* E.g. foo.20120406T153000-07
*/
int
/* check for NULL (no stamp) */
if (stamp == NULL) return STAMP_STYLE_NULL;
- /* check for MODULE_FLAG_STYLE_SEC (foo.T12345678) */
+ /* check for MODULE_NAME_STYLE_STAMP_SEC (foo.T12345678) */
if (stamp[0] == 'T')
{
n = atoi(stamp + 1);
return STAMP_STYLE_SEC;
}
- /* check for MODULE_FLAG_STYLE_SEQ (foo.0 or foo.2.gz) */
+ /* check for MODULE_NAME_STYLE_STAMP_SEQ (foo.0 or foo.2.gz) */
digits = true;
for (i = 0; digits && (stamp[i] != '\0'); i++) digits = (stamp[i] >= '0') && (stamp[i] <= '9');
- if (!digits && (!strcmp(stamp + i, ".gz"))) digits = true;
+ if (!digits && (streq(stamp + i, ".gz"))) digits = true;
if (digits)
{
return STAMP_STYLE_SEQ;
}
- /* check for MODULE_FLAG_STYLE_UTC, UTC_B, LCL, or LCL_B */
+ /* check for MODULE_NAME_STYLE_STAMP_UTC, UTC_B, LCL, or LCL_B */
memset(&t, 0, sizeof(t));
h = m = s = 0;
n = 0;
- if ((flags & MODULE_FLAG_STYLE_UTC) || (flags & MODULE_FLAG_STYLE_LCL))
+ if ((flags & MODULE_NAME_STYLE_STAMP_UTC) || (flags & MODULE_NAME_STYLE_STAMP_LCL))
{
n = sscanf(stamp, "%d-%d-%dT%d:%d:%d%c%u:%u:%u", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &zone, &h, &m, &s);
}
- else if ((flags & MODULE_FLAG_STYLE_UTC_B) || (flags & MODULE_FLAG_STYLE_LCL_B))
+ else if ((flags & MODULE_NAME_STYLE_STAMP_UTC_B) || (flags & MODULE_NAME_STYLE_STAMP_LCL_B))
{
n = sscanf(stamp, "%4d%2d%2dT%2d%2d%2d%c%2u%2u%2u", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &zone, &h, &m, &s);
}
else
{
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, "_parse_stamp_style fail %u\n", __LINE__);
+#endif
return STAMP_STYLE_INVALID;
}
- if (n < 6) return STAMP_STYLE_INVALID;
+ if (n < 6)
+ {
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, "_parse_stamp_style fail %u\n", __LINE__);
+#endif
+ return STAMP_STYLE_INVALID;
+ }
if (n == 6)
{
if (n >= 8) utc_offset += (3600 * h);
if (n >= 9) utc_offset += (60 * m);
if (n == 10) utc_offset += s;
- if (zone == '-') utc_offset *= -1;
+ if (zone == '+') utc_offset *= -1;
}
else if ((zone >= 'A') && (zone <= 'Z'))
{
}
else
{
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, "_parse_stamp_style fail %u\n", __LINE__);
+#endif
return STAMP_STYLE_INVALID;
}
if (tp != NULL) *tp = ftime;
- return STAMP_STYLE_UTC_OR_LCL;
+ return STAMP_STYLE_ISO8601;
}
asl_out_file_list_t *
-asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags)
+asl_list_log_files(const char *dir, const char *base, const char *ext, uint32_t flags, bool src)
{
DIR *d;
struct dirent *ent;
int pstyle, fstyle;
asl_out_file_list_t *out, *x, *y;
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, "asl_list_log_files dir=%s base=%s ext=%s flags=0x%08x %s\n", dir, base, (ext == NULL) ? "(NULL)" : ext, flags, src ? "src" : "dst");
+#endif
+
if (dir == NULL) return NULL;
if (base == NULL) return NULL;
{
char *stamp = NULL;
bool check;
+ bool stat_ok = false;
- if (ent->d_name == NULL) continue;
-
- check = _check_file_name(ent->d_name, base, src, &stamp);
+ check = _check_file_name(ent->d_name, base, ext, flags, src, &stamp);
if (!check) continue;
seq = IndexNull;
if (pstyle == STAMP_STYLE_INVALID) continue;
+ snprintf(path, sizeof(path), "%s/%s", dir, ent->d_name);
+ memset(&sb, 0, sizeof(sb));
+ if (lstat(path, &sb) == 0)
+ {
+ /* ignore symlinks (created for basestamp / symlink files) */
+ stat_ok = true;
+ if ((sb.st_mode & S_IFMT) == S_IFLNK) continue;
+ }
+
fstyle = STAMP_STYLE_NULL;
- if (flags & MODULE_FLAG_STYLE_SEC) fstyle = STAMP_STYLE_SEC;
- else if (flags & MODULE_FLAG_STYLE_SEQ) fstyle = STAMP_STYLE_SEQ;
- else if ((flags & MODULE_FLAG_STYLE_UTC) || (flags & MODULE_FLAG_STYLE_LCL)) fstyle = STAMP_STYLE_UTC_OR_LCL;
- else if ((flags & MODULE_FLAG_STYLE_UTC_B) || (flags & MODULE_FLAG_STYLE_LCL_B)) fstyle = STAMP_STYLE_UTC_OR_LCL;
+ if (flags & MODULE_NAME_STYLE_STAMP_SEC) fstyle = STAMP_STYLE_SEC;
+ else if (flags & MODULE_NAME_STYLE_STAMP_SEQ) fstyle = STAMP_STYLE_SEQ;
+ else if ((flags & MODULE_NAME_STYLE_STAMP_UTC) || (flags & MODULE_NAME_STYLE_STAMP_LCL)) fstyle = STAMP_STYLE_ISO8601;
+ else if ((flags & MODULE_NAME_STYLE_STAMP_UTC_B) || (flags & MODULE_NAME_STYLE_STAMP_LCL_B)) fstyle = STAMP_STYLE_ISO8601;
+
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, "%s %s %u fstyle %u pstyle %u\n", __func__, path, __LINE__, fstyle, pstyle);
+#endif
/*
* accept the file if:
if ((pstyle == STAMP_STYLE_SEC) && src) check = true;
if (pstyle == fstyle) check = true;
- if (!check) continue;
-
+ if (!check)
+ {
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, "%s reject %s at line %u\n", __func__, path, __LINE__);
+#endif
+ continue;
+ }
+
x = (asl_out_file_list_t *)calloc(1, sizeof(asl_out_file_list_t));
if (x == NULL)
{
}
x->name = strdup(ent->d_name);
+ x->stamp = pstyle;
x->ftime = ftime;
x->seq = seq;
- memset(&sb, 0, sizeof(sb));
- snprintf(path, sizeof(path), "%s/%s", dir, ent->d_name);
- if (stat(path, &sb) == 0)
+ if (stat_ok)
{
x->size = sb.st_size;
if (pstyle == STAMP_STYLE_SEQ)
if (pstyle == STAMP_STYLE_SEQ)
{
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, "asl_list_log_files SEQ %s %u %ld\n", path, x->seq, x->ftime);
+#endif
if (out == NULL)
{
out = x;
}
- else if ((x->seq == IndexNull) || ((x->seq < out->seq) && (out->seq != IndexNull)))
+ else if ((x->seq == IndexNull) || ((x->seq > out->seq) && (out->seq != IndexNull)))
{
x->next = out;
out->prev = x;
x->prev = y;
break;
}
- else if ((x->seq < y->next->seq) && (y->next->seq != IndexNull))
+ else if ((x->seq > y->next->seq) && (y->next->seq != IndexNull))
{
x->next = y->next;
y->next = x;
}
else
{
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, "asl_list_log_files TIME %s %ld\n", path, x->ftime);
+#endif
if (out == NULL)
{
out = x;
asl_out_file_list_t *
asl_list_src_files(asl_out_dst_data_t *dst)
{
- char *base;
- uint32_t flags = MODULE_FLAG_STYLE_SEC;
- asl_out_file_list_t *out;
+ uint32_t flags;
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, "asl_list_src_files\n");
+#endif
if (dst == NULL) return NULL;
if (dst->path == NULL) return NULL;
+ if (dst->base == NULL) return NULL;
/*
* MODULE_FLAG_EXTERNAL means some process other than syslogd writes the file.
{
if (S_ISREG(sb.st_mode) && (sb.st_size != 0))
{
- out = (asl_out_file_list_t *)calloc(1, sizeof(asl_out_file_list_t));
+ asl_out_file_list_t *out = (asl_out_file_list_t *)calloc(1, sizeof(asl_out_file_list_t));
if (out != NULL)
{
char *p = strrchr(dst->path, '/');
return NULL;
}
- /*
- * Checkpoint / source format may be one of:
- * MODULE_FLAG_STYLE_SEC (foo.T12345678.log),
- * MODULE_FLAG_STYLE_UTC (foo.20120-06-24T12:34:56Z.log)
- * MODULE_FLAG_STYLE_UTC_B (foo.201200624T123456Z.log)
- * MODULE_FLAG_STYLE_LCL (foo.20120-06-24T12:34:56-7.log)
- * MODULE_FLAG_STYLE_LCL_B (foo.201200624T123456-07.log)
- *
- * MODULE_FLAG_STYLE_SEC format is used for sequenced (MODULE_FLAG_STYLE_SEQ) files.
- * aslmanager converts the file names.
- */
-
- if (dst->flags & MODULE_FLAG_STYLE_UTC) flags = MODULE_FLAG_STYLE_UTC;
- else if (dst->flags & MODULE_FLAG_STYLE_UTC_B) flags = MODULE_FLAG_STYLE_UTC_B;
- else if (dst->flags & MODULE_FLAG_STYLE_LCL) flags = MODULE_FLAG_STYLE_LCL;
- else if (dst->flags & MODULE_FLAG_STYLE_LCL_B) flags = MODULE_FLAG_STYLE_LCL_B;
-
- if ((dst->rotate_dir == NULL) && ((dst->flags & MODULE_FLAG_STYLE_SEQ) == 0) && ((dst->flags & MODULE_FLAG_COMPRESS) == 0))
+ if ((dst->rotate_dir == NULL) && (dst->flags & MODULE_FLAG_BASESTAMP) && ((dst->flags & MODULE_FLAG_COMPRESS) == 0))
{
/* files do not move to a dest dir, get renamed, or get compressed - nothing to do */
return NULL;
}
- base = strrchr(dst->path, '/');
- if (base == NULL) return NULL;
-
- *base = '\0';
- base++;
-
- out = asl_list_log_files(dst->path, base, true, flags);
-
- if (base != NULL) *--base = '/';
+ /*
+ * MODULE_NAME_STYLE_STAMP_SEC format is used for sequenced (MODULE_NAME_STYLE_STAMP_SEQ) files.
+ * aslmanager converts the file names.
+ */
+ flags = dst->style_flags;
+ if (flags & MODULE_NAME_STYLE_STAMP_SEQ)
+ {
+ flags &= ~MODULE_NAME_STYLE_STAMP_SEQ;
+ flags |= MODULE_NAME_STYLE_STAMP_SEC;
+ }
- return out;
+ return asl_list_log_files(dst->dir, dst->base, dst->ext, flags, true);
}
/*
asl_out_file_list_t *
asl_list_dst_files(asl_out_dst_data_t *dst)
{
- char *base, *dst_dir;
- asl_out_file_list_t *out;
+ char *dst_dir;
+#ifdef DEBUG_LIST_FILES
+ fprintf(stderr, "asl_list_dst_files\n");
+#endif
if (dst == NULL) return NULL;
if (dst->path == NULL) return NULL;
-
- base = strrchr(dst->path, '/');
- if (base == NULL) return NULL;
-
- *base = '\0';
- base++;
+ if (dst->base == NULL) return NULL;
dst_dir = dst->rotate_dir;
- if (dst_dir == NULL) dst_dir = dst->path;
-
- out = asl_list_log_files(dst_dir, base, false, dst->flags);
-
- if (base != NULL) *--base = '/';
+ if (dst_dir == NULL) dst_dir = dst->dir;
- return out;
+ return asl_list_log_files(dst_dir, dst->base, dst->ext, dst->style_flags, false);
}
static int
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;
* 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,
* 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 <stdio.h>
#include <xpc/xpc.h>
+#include <asl_msg.h>
#define ASL_MODULE_NAME "com.apple.asl"
#define _PATH_CRASHREPORTER "/Library/Logs/CrashReporter"
-#define _PATH_CRASHREPORTER_MOBILE "/var/mobile/Library/Logs/CrashReporter"
+#define _PATH_CRASHREPORTER_MOBILE_1 "/var/mobile/Library/Logs/CrashReporter"
+#define _PATH_CRASHREPORTER_MOBILE_2 "/private/var/mobile/Library/Logs/CrashReporter"
+#define ASL_INTERNAL_LOGS_DIR "Logs"
#define ASL_SERVICE_NAME "com.apple.system.logger"
#define CRASH_MOVER_WILL_START_NOTIFICATION "CrashMoverWillStart"
-#define DEFAULT_TTL 7 /* days */
#define SECONDS_PER_DAY 86400
+#define DEFAULT_TTL (7 * SECONDS_PER_DAY)
#define ACTION_NONE 0
#define ACTION_SET_PARAM 1
#define MODULE_FLAG_NONSTD_DIR 0x00000020
#define MODULE_FLAG_EXTERNAL 0x00000040
#define MODULE_FLAG_TRUNCATE 0x00000080
-#define MODULE_FLAG_STYLE_SEC 0x00000100 /* foo.T1332799722 (note STYLE_SEC_PREFIX_CHAR) */
-#define MODULE_FLAG_STYLE_SEQ 0x00000200 /* foo.0 */
-#define MODULE_FLAG_STYLE_UTC 0x00000400 /* foo.2012-04-06T13:45:00Z */
-#define MODULE_FLAG_STYLE_UTC_B 0x00000800 /* ("basic utc") foo.20120406T134500Z */
-#define MODULE_FLAG_STYLE_LCL 0x00001000 /* foo.2012-04-06T13:45:00-7 */
-#define MODULE_FLAG_STYLE_LCL_B 0x00002000 /* ("basic local") foo.20120406T134500-7 */
-#define MODULE_FLAG_BASESTAMP 0x00004000 /* base file has timestamp */
-#define MODULE_FLAG_CRASHLOG 0x00008000 /* checkpoint on CrashMoverWillStart notification */
-#define MODULE_FLAG_SOFT_WRITE 0x00010000 /* ignore write failures */
-#define MODULE_FLAG_TYPE_ASL 0x00020000 /* asl format file */
-#define MODULE_FLAG_TYPE_ASL_DIR 0x00040000 /* asl format directory */
-#define MODULE_FLAG_STD_BSD_MSG 0x00080000 /* print format is std, bsd, or msg */
-
-#define MODULE_FLAG_STYLE_BITS (MODULE_FLAG_STYLE_SEC | MODULE_FLAG_STYLE_SEQ | MODULE_FLAG_STYLE_UTC | MODULE_FLAG_STYLE_UTC_B | MODULE_FLAG_STYLE_LCL | MODULE_FLAG_STYLE_LCL_B)
+#define MODULE_FLAG_BASESTAMP 0x00000100 /* base file has timestamp */
+#define MODULE_FLAG_SYMLINK 0x00000200 /* link to basestamp name */
+#define MODULE_FLAG_CRASHLOG 0x00000400 /* checkpoint on CrashMoverWillStart notification */
+#define MODULE_FLAG_SOFT_WRITE 0x00000800 /* ignore write failures */
+#define MODULE_FLAG_TYPE_ASL 0x00001000 /* asl format file */
+#define MODULE_FLAG_TYPE_ASL_DIR 0x00002000 /* asl format directory */
+#define MODULE_FLAG_STD_BSD_MSG 0x00004000 /* print format is std, bsd, or msg */
+#define MODULE_FLAG_ACTIVITY 0x00008000
+
+#define MODULE_NAME_STYLE_FORMAT_MASK 0xf0000000
+#define MODULE_NAME_STYLE_FORMAT_BS 0x10000000 /* base.stamp */
+#define MODULE_NAME_STYLE_FORMAT_BES 0x20000000 /* base.ext.stamp */
+#define MODULE_NAME_STYLE_FORMAT_BSE 0x40000000 /* base.stamp.ext */
+#define MODULE_NAME_STYLE_STAMP_MASK 0x000000ff
+#define MODULE_NAME_STYLE_STAMP_SEC 0x00000001 /* foo.T1332799722 (note STYLE_SEC_PREFIX_CHAR) */
+#define MODULE_NAME_STYLE_STAMP_SEQ 0x00000002 /* foo.0 */
+#define MODULE_NAME_STYLE_STAMP_UTC 0x00000004 /* foo.2012-04-06T13:45:00Z */
+#define MODULE_NAME_STYLE_STAMP_UTC_B 0x00000008 /* ("basic utc") foo.20120406T134500Z */
+#define MODULE_NAME_STYLE_STAMP_LCL 0x00000010 /* foo.2012-04-06T13:45:00-7 */
+#define MODULE_NAME_STYLE_STAMP_LCL_B 0x00000020 /* ("basic local") foo.20120406T134500-7 */
+
+#define STAMP_STYLE_INVALID -1
+#define STAMP_STYLE_NULL 0
+#define STAMP_STYLE_SEC 1
+#define STAMP_STYLE_SEQ 2
+#define STAMP_STYLE_ISO8601 3
+
#define CHECKPOINT_TEST 0x00000000
#define CHECKPOINT_FORCE 0x00000001
#define CHECKPOINT_CRASH 0x00000002
typedef struct
{
+ char *dir;
char *path;
- char *fname;
+ char *current_name;
char *fmt;
- const char *tfmt;
char *rotate_dir;
+ char *base;
+ char *ext;
+ const char *tfmt;
+ uint32_t style_flags;
uint32_t pvt_flags;
uint32_t flags;
uint32_t fails;
size_t file_max;
size_t all_max;
uint32_t refcount;
- time_t stamp;
+ time_t timestamp;
size_t size;
void *private;
} asl_out_dst_data_t;
typedef struct asl_out_file_list_s
{
char *name;
+ uint32_t stamp;
time_t ftime;
uint32_t seq;
size_t size;
char *asl_out_module_rule_to_string(asl_out_rule_t *r);
int asl_out_mkpath(asl_out_module_t *mlist, asl_out_rule_t *r);
+int asl_make_database_dir(const char *dir, char **out);
int asl_out_dst_checkpoint(asl_out_dst_data_t *dst, uint32_t force);
int asl_out_dst_file_create_open(asl_out_dst_data_t *dst, char **pathp);
int asl_out_dst_set_access(int fd, asl_out_dst_data_t *dst);
void asl_make_timestamp(time_t stamp, uint32_t flags, char *buf, size_t len);
-void asl_make_dst_filename(asl_out_dst_data_t *dst, char *buf, size_t len);
+void asl_dst_make_current_name(asl_out_dst_data_t *dst, uint32_t xflags, char *buf, size_t len);
asl_out_dst_data_t *asl_out_dst_data_retain(asl_out_dst_data_t *dst);
void asl_out_dst_data_release(asl_out_dst_data_t *dst);
/* rotated log files */
-asl_out_file_list_t *asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags);
+asl_out_file_list_t *asl_list_log_files(const char *dir, const char *base, const char *ext, uint32_t flags, bool src);
asl_out_file_list_t * asl_list_src_files(asl_out_dst_data_t *dst);
asl_out_file_list_t * asl_list_dst_files(asl_out_dst_data_t *dst);
void asl_out_file_list_free(asl_out_file_list_t *l);
+asl_out_dst_data_t *asl_out_dest_for_path(asl_out_module_t *m, const char *path);
asl_msg_t *configuration_profile_to_asl_msg(const char *ident);
#define DEFAULT_MAX_RECORDS 2000
#define DEFAULT_MAX_STRING_MEMORY 4096000
-#define MEM_STRING_HEADER_SIZE 8
#define forever for(;;)
for (i = 0; i < s->string_count; i++)
{
- size += MEM_STRING_HEADER_SIZE;
- if (((mem_string_t *)s->string_cache[i])->str != NULL) size += (strlen(((mem_string_t *)s->string_cache[i])->str) + 1);
+ size += sizeof(mem_string_t);
+ if (s->string_cache[i]->str != NULL) size += (strlen(s->string_cache[i]->str) + 1);
}
snprintf(str, sizeof(str), "%llu", size);
snprintf(str, sizeof(str), "%u", s->string_count);
asl_msg_set_key_val(out, "StringCount", str);
- snprintf(str, sizeof(str), "%u", s->curr_string_mem);
+ snprintf(str, sizeof(str), "%lu", s->curr_string_mem);
asl_msg_set_key_val(out, "StringMemory", str);
- snprintf(str, sizeof(str), "%u", s->max_string_mem);
+ snprintf(str, sizeof(str), "%lu", s->max_string_mem);
asl_msg_set_key_val(out, "MaxStringMemory", str);
*msg = out;
uint32_t
asl_memory_close(asl_memory_t *s)
{
- uint32_t i;
-
if (s == NULL) return ASL_STATUS_OK;
+
+ dispatch_sync(s->queue, ^{
+ uint32_t i;
- if (s->record != NULL)
- {
- for (i = 0; i < s->record_count; i++)
+ if (s->record != NULL)
{
- if (s->record[i] != NULL) free(s->record[i]);
- s->record[i] = NULL;
- }
+ for (i = 0; i < s->record_count; i++)
+ {
+ free(s->record[i]);
+ s->record[i] = NULL;
+ }
- free(s->record);
- s->record = NULL;
- }
+ free(s->record);
+ s->record = NULL;
+ }
- if (s->buffer_record != NULL) free(s->buffer_record);
+ free(s->buffer_record);
+ s->buffer_record = NULL;
- if (s->string_cache != NULL)
- {
- for (i = 0; i < s->string_count; i++)
+ if (s->string_cache != NULL)
{
- if (s->string_cache[i] != NULL) free(s->string_cache[i]);
- s->string_cache[i] = NULL;
+ for (i = 0; i < s->string_count; i++)
+ {
+ if (s->string_cache[i] != NULL)
+ {
+ free(s->string_cache[i]->str);
+ free(s->string_cache[i]);
+ }
+
+ s->string_cache[i] = NULL;
+ }
+
+ free(s->string_cache);
+ s->string_cache = NULL;
}
+ });
- free(s->string_cache);
- s->string_cache = NULL;
- }
+ dispatch_release(s->queue);
free(s);
out = calloc(1, sizeof(asl_memory_t));
if (out == NULL) return ASL_STATUS_NO_MEMORY;
+ out->queue = dispatch_queue_create("ASL Memory Queue", NULL);
+ if (out->queue == NULL)
+ {
+ free(out);
+ return ASL_STATUS_NO_MEMORY;
+ }
+
out->max_string_mem = max_str_mem;
out->record_count = max_records;
out->record = (mem_record_t **)calloc(max_records, sizeof(mem_record_t *));
if (out->record == NULL)
{
+ dispatch_release(out->queue);
free(out);
return ASL_STATUS_NO_MEMORY;
}
return ASL_STATUS_OK;
}
+static void
+asl_memory_reset(asl_memory_t *s)
+{
+ uint32_t i;
+ if (s == NULL) return;
+
+ /* clear all message records */
+ for (i = 0; i < s->record_count; i++)
+ {
+ memset(s->record[i], 0, sizeof(mem_record_t));
+ }
+
+ /* reset the string cache */
+ if (s->string_cache != NULL)
+ {
+ for (i = 0; i < s->string_count; i++)
+ {
+ if (s->string_cache[i] != NULL)
+ {
+ free(s->string_cache[i]->str);
+ free(s->string_cache[i]);
+ }
+
+ s->string_cache[i] = NULL;
+ }
+
+ free(s->string_cache);
+ s->string_cache = NULL;
+ }
+
+ s->string_count = 0;
+}
+
static mem_string_t *
-mem_string_new(const char *str, uint32_t len, uint32_t hash)
+asl_memory_string_new(const char *str, uint32_t len, uint32_t hash)
{
mem_string_t *out;
- size_t ss;
if (str == NULL) return NULL;
- ss = MEM_STRING_HEADER_SIZE + len + 1;
- out = (mem_string_t *)calloc(1, ss);
+ out = (mem_string_t *)calloc(1, sizeof(mem_string_t));
if (out == NULL) return NULL;
out->hash = hash;
out->refcount = 1;
+ out->str = malloc(len + 1);
+ if (out->str == NULL)
+ {
+ free(out);
+ return NULL;
+ }
+
memcpy(out->str, str, len);
+ out->str[len] = 0;
return out;
}
/*
* Find the first hash greater than or equal to a given hash in the string cache.
- * Return s->string_count if hash is greater that or equal to last hash in the string cache.
+ * Return s->string_count if hash is greater than last hash in the string cache.
* Caller must check if the hashes match or not.
*
* This routine is used both to find strings in the cache and to determine where to insert
if (s->string_count == 0) return 0;
if (s->string_count == 1)
{
- ms = (mem_string_t *)s->string_cache[0];
+ ms = s->string_cache[0];
if (hash < ms->hash) return 0;
return 1;
}
while (range > 1)
{
- ms = (mem_string_t *)s->string_cache[mid];
+ ms = s->string_cache[mid];
if (hash == ms->hash)
{
while (mid > 0)
{
- ms = (mem_string_t *)s->string_cache[mid - 1];
+ ms = s->string_cache[mid - 1];
if (hash != ms->hash) break;
mid--;
}
}
else
{
- ms = (mem_string_t *)s->string_cache[mid];
+ ms = s->string_cache[mid];
if (hash < ms->hash) top = mid;
else bot = mid;
}
mid = bot + (range / 2);
}
- ms = (mem_string_t *)s->string_cache[bot];
+ ms = s->string_cache[bot];
if (hash <= ms->hash) return bot;
- ms = (mem_string_t *)s->string_cache[top];
+ ms = s->string_cache[top];
if (hash <= ms->hash) return top;
return s->string_count;
/* asl_memory_string_cache_search_hash just tells us where to look */
if (where < s->string_count)
{
- while (((mem_string_t *)(s->string_cache[where]))->hash == hash)
+ while (s->string_cache[where]->hash == hash)
{
- if (!strcmp(str, ((mem_string_t *)(s->string_cache[where]))->str))
+ if (!strcmp(str, s->string_cache[where]->str))
{
- ((mem_string_t *)(s->string_cache[where]))->refcount++;
+ s->string_cache[where]->refcount++;
return s->string_cache[where];
}
if (create == 0) return NULL;
/* create a new mem_string_t and insert into the cache at index 'where' */
- if (s->string_count == 0)
- {
- s->string_cache = (void **)calloc(1, sizeof(void *));
- }
- else
- {
- s->string_cache = (void **)reallocf(s->string_cache, (s->string_count + 1) * sizeof(void *));
- for (i = s->string_count; i > where; i--) s->string_cache[i] = s->string_cache[i - 1];
- }
-
+ new = asl_memory_string_new(str, len, hash);
+ if (new == NULL) return NULL;
+
+ s->string_cache = (mem_string_t **)reallocf(s->string_cache, (s->string_count + 1) * sizeof(void *));
if (s->string_cache == NULL)
{
s->string_count = 0;
+ free(new);
return NULL;
}
- new = mem_string_new(str, len, hash);
- if (new == NULL) return NULL;
+ for (i = s->string_count; i > where; i--) s->string_cache[i] = s->string_cache[i - 1];
- s->curr_string_mem += (MEM_STRING_HEADER_SIZE + len + 1);
+ s->curr_string_mem += (sizeof(mem_string_t) + len + 1);
s->string_cache[where] = new;
s->string_count++;
if (m->refcount > 0) return ASL_STATUS_OK;
where = asl_memory_string_cache_search_hash(s, m->hash);
- if (((mem_string_t *)(s->string_cache[where]))->hash != m->hash) return ASL_STATUS_OK;
+ if (s->string_cache[where]->hash != m->hash) return ASL_STATUS_OK;
while (s->string_cache[where] != m)
{
- if (((mem_string_t *)(s->string_cache[where]))->hash != m->hash) return ASL_STATUS_OK;
+ if (s->string_cache[where]->hash != m->hash) return ASL_STATUS_OK;
where++;
if (where >= s->string_count) return ASL_STATUS_OK;
for (i = where + 1; i < s->string_count; i++) s->string_cache[i - 1] = s->string_cache[i];
- s->curr_string_mem -= (MEM_STRING_HEADER_SIZE + strlen(m->str) + 1);
+ if (m->str == NULL) s->curr_string_mem -= sizeof(mem_string_t);
+ else s->curr_string_mem -= (sizeof(mem_string_t) + strlen(m->str) + 1);
+ free(m->str);
free(m);
+
s->string_count--;
if (s->string_count == 0)
return ASL_STATUS_OK;
}
- s->string_cache = (void **)reallocf(s->string_cache, s->string_count * sizeof(void *));
+ s->string_cache = (mem_string_t **)reallocf(s->string_cache, s->string_count * sizeof(void *));
if (s->string_cache == NULL)
{
s->string_count = 0;
v = NULL;
if (val != NULL) v = asl_memory_string_retain(s, val, 1);
- if (r->kvcount == 0)
- {
- r->kvlist = (mem_string_t **)calloc(2, sizeof(mem_string_t *));
- }
- else
- {
- r->kvlist = (mem_string_t **)reallocf(r->kvlist, (r->kvcount + 2) * sizeof(mem_string_t *));
- }
-
+ r->kvlist = (mem_string_t **)reallocf(r->kvlist, (r->kvcount + 2) * sizeof(mem_string_t *));
if (r->kvlist == NULL)
{
asl_memory_record_clear(s, r);
uint32_t
asl_memory_save(asl_memory_t *s, asl_msg_t *msg, uint64_t *mid)
{
- uint32_t status;
- mem_record_t *t;
+ __block uint32_t status;
if (s == NULL) return ASL_STATUS_INVALID_STORE;
if (s->buffer_record == NULL) return ASL_STATUS_INVALID_STORE;
- /* asl_memory_message_encode creates and caches strings */
- status = asl_memory_message_encode(s, msg);
- if (status != ASL_STATUS_OK) return status;
-
- if (*mid != 0)
- {
- s->buffer_record->mid = *mid;
- }
- else
- {
- s->buffer_record->mid = asl_core_new_msg_id(0);
- *mid = s->buffer_record->mid;
- }
-
- /* clear the first record */
- t = s->record[s->record_first];
- asl_memory_record_clear(s, t);
-
- /* add the new record to the record list (swap in the buffer record) */
- s->record[s->record_first] = s->buffer_record;
- s->buffer_record = t;
-
- /* record list is a circular queue */
- s->record_first++;
- if (s->record_first >= s->record_count) s->record_first = 0;
+ dispatch_sync(s->queue, ^{
+ mem_record_t *t;
- /* delete records if too much memory is in use */
- while (s->curr_string_mem > s->max_string_mem)
- {
- asl_memory_record_clear(s, s->record[s->record_first]);
- s->record_first++;
- if (s->record_first >= s->record_count) s->record_first = 0;
- }
+ /* asl_memory_message_encode creates and caches strings */
+ status = asl_memory_message_encode(s, msg);
+ if (status == ASL_STATUS_OK)
+ {
+ uint32_t loop_start_index = s->record_first;
+
+ if (*mid != 0)
+ {
+ s->buffer_record->mid = *mid;
+ }
+ else
+ {
+ s->buffer_record->mid = asl_core_new_msg_id(0);
+ *mid = s->buffer_record->mid;
+ }
+
+ /* clear the first record */
+ t = s->record[s->record_first];
+ asl_memory_record_clear(s, t);
+
+ /* add the new record to the record list (swap in the buffer record) */
+ s->record[s->record_first] = s->buffer_record;
+ s->buffer_record = t;
+
+ /* record list is a circular queue */
+ s->record_first++;
+ if (s->record_first >= s->record_count) s->record_first = 0;
+
+ /* delete records if too much memory is in use */
+ while (s->curr_string_mem > s->max_string_mem)
+ {
+ asl_memory_record_clear(s, s->record[s->record_first]);
+ s->record_first++;
+ if (s->record_first >= s->record_count) s->record_first = 0;
+ if (s->record_first == loop_start_index)
+ {
+ /* The entire ring has been cleared. This should never happen. */
+ asl_memory_reset(s);
+ status = ASL_STATUS_FAILED;
+ break;
+ }
+ }
+ }
+ });
return status;
}
key = NULL;
val = NULL;
- if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) key = r->kvlist[i]->str;
+ if (r->kvlist[i] != NULL) key = r->kvlist[i]->str;
i++;
- if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) val = r->kvlist[i]->str;
+ if (r->kvlist[i] != NULL) val = r->kvlist[i]->str;
if (key != NULL) asl_msg_set_key_val(msg, key, val);
}
uint32_t
asl_memory_fetch(asl_memory_t *s, uint64_t mid, asl_msg_t **msg, int32_t ruid, int32_t rgid)
{
- uint32_t i, status;
+ __block uint32_t status;
if (s == NULL) return ASL_STATUS_INVALID_STORE;
if (msg == NULL) return ASL_STATUS_INVALID_ARG;
- for (i = 0; i < s->record_count; i++)
- {
- if (s->record[i]->mid == 0) break;
+ status = ASL_STATUS_INVALID_ID;
- if (s->record[i]->mid == mid)
+ dispatch_sync(s->queue, ^{
+ uint32_t i;
+
+ for (i = 0; i < s->record_count; i++)
{
- status = asl_core_check_access(s->record[i]->ruid, s->record[i]->rgid, ruid, rgid, s->record[i]->flags);
- if (status != ASL_STATUS_OK) return status;
- return asl_memory_message_decode(s, s->record[i], msg);
+ if (s->record[i]->mid == 0) break;
+
+ if (s->record[i]->mid == mid)
+ {
+ status = asl_core_check_access(s->record[i]->ruid, s->record[i]->rgid, ruid, rgid, s->record[i]->flags);
+ if (status != ASL_STATUS_OK) break;
+
+ status = asl_memory_message_decode(s, s->record[i], msg);
+ break;
+ }
}
- }
+ });
- return ASL_STATUS_INVALID_ID;
+ return status;
}
static mem_record_t *
return status;
}
-uint32_t
-asl_memory_match_restricted_uuid(asl_memory_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t start_id, uint32_t count, uint32_t duration, int32_t direction, int32_t ruid, int32_t rgid, const char *uuid_str)
+static uint32_t
+asl_memory_match_restricted_uuid_internal(asl_memory_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t start_id, uint32_t count, uint32_t duration, int32_t direction, int32_t ruid, int32_t rgid, const char *uuid_str)
{
uint32_t status, i, where, start, j, do_match, did_match, rescount, *qtype;
mem_record_t **qp;
size_t qcount;
struct timeval now, finish;
- if (s == NULL) return ASL_STATUS_INVALID_STORE;
- if (res == NULL) return ASL_STATUS_INVALID_ARG;
-
qp = NULL;
qtype = NULL;
rescount = 0;
return ASL_STATUS_OK;
}
+uint32_t
+asl_memory_match_restricted_uuid(asl_memory_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t start_id, uint32_t count, uint32_t duration, int32_t direction, int32_t ruid, int32_t rgid, const char *uuid_str)
+{
+ __block uint32_t status;
+
+ if (s == NULL) return ASL_STATUS_INVALID_STORE;
+ if (res == NULL) return ASL_STATUS_INVALID_ARG;
+
+ dispatch_sync(s->queue, ^{
+ status = asl_memory_match_restricted_uuid_internal(s, query, res, last_id, start_id, count, duration, direction, ruid, rgid, uuid_str);
+ });
+
+ return status;
+}
+
uint32_t
asl_memory_match(asl_memory_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, int32_t ruid, int32_t rgid)
{
- return asl_memory_match_restricted_uuid(s, query, res, last_id, start_id, count, 0, direction, ruid, rgid, NULL);
+ __block uint32_t status;
+
+ if (s == NULL) return ASL_STATUS_INVALID_STORE;
+ if (res == NULL) return ASL_STATUS_INVALID_ARG;
+
+ dispatch_sync(s->queue, ^{
+ status = asl_memory_match_restricted_uuid_internal(s, query, res, last_id, start_id, count, 0, direction, ruid, rgid, NULL);
+ });
+
+ return status;
}
#define __ASL_MEMORY_H__
#include <stdint.h>
#include <asl.h>
+#include <dispatch/dispatch.h>
typedef struct
{
uint32_t hash;
uint32_t refcount;
- char str[];
+ char *str;
} mem_string_t;
typedef struct
{
uint64_t mid;
uint64_t time;
- uint32_t nano;
- uint8_t unused_0;
- uint8_t level;
- uint16_t flags;
- uint32_t pid;
- uint32_t uid;
- uint32_t gid;
- uint32_t ruid;
- uint32_t rgid;
- uint32_t refpid;
uint64_t os_activity_id;
- uint32_t kvcount;
mem_string_t *host;
mem_string_t *sender;
mem_string_t *sender_mach_uuid;
mem_string_t *refproc;
mem_string_t *session;
mem_string_t **kvlist;
+ uint32_t nano;
+ uint32_t pid;
+ uint32_t uid;
+ uint32_t gid;
+ uint32_t ruid;
+ uint32_t rgid;
+ uint32_t refpid;
+ uint32_t kvcount;
+ uint16_t flags;
+ uint8_t level;
+ uint8_t unused_0;
} mem_record_t;
typedef struct
{
+ mem_string_t **string_cache;
+ mem_record_t **record;
+ mem_record_t *buffer_record;
uint32_t string_count;
- void **string_cache;
uint32_t record_count;
uint32_t record_first;
- mem_record_t **record;
- mem_record_t *buffer_record;
- uint32_t max_string_mem;
- uint32_t curr_string_mem;
+ size_t max_string_mem;
+ size_t curr_string_mem;
+ dispatch_queue_t queue;
} asl_memory_t;
uint32_t asl_memory_open(uint32_t max_records, size_t max_str_mem, asl_memory_t **s);
/*
- * Copyright (c) 2007-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2015 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#include <stdio.h>
-#include <dirent.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <errno.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <servers/bootstrap.h>
-#include <bootstrap_priv.h>
-#include <mach/mach.h>
-#include <copyfile.h>
-#include <fcntl.h>
-#include <zlib.h>
-#include <xpc/xpc.h>
-#include <xpc/private.h>
-#include <os/assumes.h>
-#include <vproc_priv.h>
-#include <asl.h>
-#include <asl_private.h>
-#include <asl_core.h>
-#include <asl_file.h>
-#include <asl_store.h>
-#include "asl_common.h"
-
-#define DEFAULT_MAX_SIZE 150000000
-#define IOBUFSIZE 4096
-
-#define DO_ASLDB 0x00000001
-#define DO_MODULE 0x00000002
-#define DO_CHECKPT 0x00000004
-
-#define DEBUG_FLAG_MASK 0xfffffff0
-#define DEBUG_LEVEL_MASK 0x0000000f
-#define DEBUG_STDERR 0x00000010
-#define DEBUG_ASL 0x00000020
-
-#define AUX_URL_MINE "file:///var/log/asl/"
-#define AUX_URL_MINE_LEN 20
-
-/* length of "file://" */
-#define AUX_URL_PATH_OFFSET 7
-
-extern kern_return_t _asl_server_query
-(
- mach_port_t server,
- caddr_t request,
- mach_msg_type_number_t requestCnt,
- uint64_t startid,
- int count,
- int flags,
- caddr_t *reply,
- mach_msg_type_number_t *replyCnt,
- uint64_t *lastid,
- int *status,
- security_token_t *token
-);
-
-/* global */
-static time_t module_ttl;
-static uint32_t debug;
-static int dryrun;
-static int asl_aux_fd = -1;
-static aslclient aslc;
-static mach_port_t asl_server_port;
-static xpc_connection_t listener;
-static dispatch_queue_t serverq;
-
-typedef struct name_list_s
-{
- char *name;
- size_t size;
- struct name_list_s *next;
-} name_list_t;
-
-static const char *
-keep_str(uint8_t mask)
-{
- static char str[9];
- uint32_t x = 0;
-
- memset(str, 0, sizeof(str));
- if (mask & 0x01) str[x++] = '0';
- if (mask & 0x02) str[x++] = '1';
- if (mask & 0x04) str[x++] = '2';
- if (mask & 0x08) str[x++] = '3';
- if (mask & 0x10) str[x++] = '4';
- if (mask & 0x20) str[x++] = '5';
- if (mask & 0x40) str[x++] = '6';
- if (mask & 0x80) str[x++] = '7';
- if (x == 0) str[x++] = '-';
- return str;
-}
-
-void
-set_debug(int flag, const char *str)
-{
- int level, x;
-
- if (str == NULL) x = ASL_LEVEL_ERR;
- else if (((str[0] == 'L') || (str[0] == 'l')) && ((str[1] >= '0') && (str[1] <= '7')) && (str[2] == '\0')) x = atoi(str+1);
- else if ((str[0] >= '0') && (str[0] <= '7') && (str[1] == '\0')) x = ASL_LEVEL_CRIT + atoi(str);
- else x = ASL_LEVEL_ERR;
-
- if (x <= 0) x = 0;
- else if (x > 7) x = 7;
-
- level = debug & DEBUG_LEVEL_MASK;
- if (x > level) level = x;
-
- debug = debug & DEBUG_FLAG_MASK;
- debug |= flag;
- debug |= level;
-}
-
-void
-debug_log(int level, const char *str, ...)
-{
- va_list v;
-
- if ((debug & DEBUG_STDERR) && (level <= (debug & DEBUG_LEVEL_MASK)))
- {
- va_start(v, str);
- vfprintf(stderr, str, v);
- va_end(v);
- }
-
- if (debug & DEBUG_ASL)
- {
- char *line = NULL;
-
- if (aslc == NULL)
- {
- aslc = asl_open("aslmanager", "syslog", 0);
- asl_msg_t *msg = asl_msg_new(ASL_TYPE_MSG);
-
- asl_msg_set_key_val(msg, ASL_KEY_MSG, "Status Report");
- asl_msg_set_key_val(msg, ASL_KEY_LEVEL, ASL_STRING_NOTICE);
- asl_create_auxiliary_file((asl_object_t)msg, "Status Report", "public.text", &asl_aux_fd);
- asl_msg_release(msg);
- }
-
- va_start(v, str);
- vasprintf(&line, str, v);
- va_end(v);
-
- if (line != NULL) write(asl_aux_fd, line, strlen(line));
- free(line);
- }
-}
-
-__attribute__((noreturn)) static void
-xpc_server_exit(int status)
-{
- xpc_connection_cancel(listener);
- xpc_release(listener);
- dispatch_release(serverq);
- exit(status);
-}
-
-name_list_t *
-add_to_name_list(name_list_t *l, const char *name, size_t size)
-{
- name_list_t *e, *x;
-
- if (name == NULL) return l;
-
- e = (name_list_t *)calloc(1, sizeof(name_list_t));
- if (e == NULL) return NULL;
-
- e->name = strdup(name);
- if (e->name == NULL)
- {
- free(e);
- return NULL;
- }
-
- e->size = size;
-
- /* list is sorted by name (i.e. primarily by timestamp) */
- if (l == NULL) return e;
-
- if (strcmp(e->name, l->name) <= 0)
- {
- e->next = l;
- return e;
- }
-
- for (x = l; (x->next != NULL) && (strcmp(e->name, x->next->name) > 0) ; x = x->next);
-
- e->next = x->next;
- x->next = e;
- return l;
-}
-
-void
-free_name_list(name_list_t *l)
-{
- name_list_t *e;
-
- while (l != NULL)
- {
- e = l;
- l = l->next;
- free(e->name);
- free(e);
- }
-
- free(l);
-}
-/*
- * Copy ASL files by reading and writing each record.
- */
-uint32_t
-copy_asl_file(const char *src, const char *dst, mode_t mode)
-{
- asl_msg_list_t *res;
- asl_file_t *f;
- uint32_t status, i;
- uint64_t mid;
- size_t rcount;
-
- if (src == NULL) return ASL_STATUS_INVALID_ARG;
- if (dst == NULL) return ASL_STATUS_INVALID_ARG;
-
- f = NULL;
- status = asl_file_open_read(src, &f);
- if (status != ASL_STATUS_OK) return status;
-
- res = NULL;
- mid = 0;
-
- res = asl_file_match(f, NULL, &mid, 0, 0, 0, 1);
- asl_file_close(f);
-
- if (res == NULL) return ASL_STATUS_OK;
- rcount = asl_msg_list_count(res);
- if (rcount == 0)
- {
- asl_msg_list_release(res);
- return ASL_STATUS_OK;
- }
-
- f = NULL;
- status = asl_file_open_write(dst, mode, -1, -1, &f);
- if (status != ASL_STATUS_OK) return status;
- if (f == ASL_STATUS_OK) return ASL_STATUS_FAILED;
-
- f->flags = ASL_FILE_FLAG_PRESERVE_MSG_ID;
-
- for (i = 0; i < rcount; i++)
- {
- mid = 0;
- status = asl_file_save(f, asl_msg_list_get_index(res, i), &mid);
- if (status != ASL_STATUS_OK) break;
- }
-
- asl_file_close(f);
- return status;
-}
-
-int
-copy_compress_file(asl_out_dst_data_t *asldst, const char *src, const char *dst)
-{
- int in, out;
- size_t n;
- gzFile gz;
- char buf[IOBUFSIZE];
-
- in = open(src, O_RDONLY, 0);
- if (in < 0) return -1;
-
- out = open(dst, O_WRONLY | O_CREAT, asldst->mode);
- if (out >= 0) out = asl_out_dst_set_access(out, asldst);
- if (out < 0)
- {
- close(in);
- return -1;
- }
-
- gz = gzdopen(out, "w");
- if (gz == NULL)
- {
- close(in);
- close(out);
- return -1;
- }
-
- do {
- n = read(in, buf, sizeof(buf));
- if (n > 0) gzwrite(gz, buf, n);
- } while (n == IOBUFSIZE);
-
- gzclose(gz);
- close(in);
- close(out);
-
- return 0;
-}
-
-void
-filesystem_rename(const char *src, const char *dst)
-{
- int status = 0;
-
- debug_log(ASL_LEVEL_NOTICE, " rename %s ---> %s\n", src, dst);
- if (dryrun == 1) return;
-
- status = rename(src, dst);
- if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] rename %s ---> %s\n", status, errno, strerror(errno), src, dst);
-}
-
-void
-filesystem_unlink(const char *path)
-{
- int status = 0;
-
- debug_log(ASL_LEVEL_NOTICE, " remove %s\n", path);
- if (dryrun == 1) return;
-
- status = unlink(path);
- if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] unlink %s\n", status, errno, strerror(errno), path);
-}
-
-void
-filesystem_truncate(const char *path)
-{
- int status = 0;
-
- debug_log(ASL_LEVEL_NOTICE, " truncate %s\n", path);
- if (dryrun == 1) return;
-
- status = truncate(path, 0);
- if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] unlink %s\n", status, errno, strerror(errno), path);
-}
-
-void
-filesystem_rmdir(const char *path)
-{
- int status = 0;
-
- debug_log(ASL_LEVEL_NOTICE, " remove directory %s\n", path);
- if (dryrun == 1) return;
-
- status = rmdir(path);
- if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] rmdir %s\n", status, errno, strerror(errno), path);
-}
-
-int32_t
-filesystem_copy(asl_out_dst_data_t *asldst, const char *src, const char *dst, uint32_t flags)
-{
- char *dot;
-
- if ((src == NULL) || (dst == NULL)) return 0;
-
- dot = strrchr(src, '.');
- if ((dot != NULL) && (!strcmp(dot, ".gz"))) flags &= ~MODULE_FLAG_COMPRESS;
-
- if (((flags & MODULE_FLAG_COMPRESS) == 0) && (!strcmp(src, dst))) return 0;
-
- if (flags & MODULE_FLAG_TYPE_ASL) debug_log(ASL_LEVEL_NOTICE, " copy asl %s ---> %s\n", src, dst);
- else if (flags & MODULE_FLAG_COMPRESS) debug_log(ASL_LEVEL_NOTICE, " copy compress %s ---> %s.gz\n", src, dst);
- else debug_log(ASL_LEVEL_NOTICE, " copy %s ---> %s\n", src, dst);
-
- if (dryrun == 1) return 0;
-
- if (flags & MODULE_FLAG_TYPE_ASL)
- {
- uint32_t status = copy_asl_file(src, dst, asldst->mode);
- if (status != 0)
- {
- debug_log(ASL_LEVEL_ERR, " FAILED status %u [%s] asl copy %s ---> %s\n", status, asl_core_error(status), src, dst);
- return 0;
- }
- }
- else if (flags & MODULE_FLAG_COMPRESS)
- {
- char gzdst[MAXPATHLEN];
-
- snprintf(gzdst, sizeof(gzdst), "%s.gz", dst);
-
- int status = copy_compress_file(asldst, src, gzdst);
- if (status != 0)
- {
- debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] copy & compress %s ---> %s\n", status, errno, strerror(errno), src, dst);
- return 0;
- }
- }
- else
- {
- int status = copyfile(src, dst, NULL, COPYFILE_ALL | COPYFILE_RECURSIVE);
- if (status != 0)
- {
- debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] copy %s ---> %s\n", status, errno, strerror(errno), src, dst);
- return 0;
- }
- }
-
- return 1;
-}
-
-int
-remove_directory(const char *path)
-{
- DIR *dp;
- struct dirent *dent;
- char *str;
-
- dp = opendir(path);
- if (dp == NULL) return 0;
-
- while ((dent = readdir(dp)) != NULL)
- {
- if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue;
- asprintf(&str, "%s/%s", path, dent->d_name);
- if (str != NULL)
- {
- filesystem_unlink(str);
- free(str);
- str = NULL;
- }
- }
-
- closedir(dp);
- filesystem_rmdir(path);
-
- return 0;
-}
-
-/*
- * Determine the age (in whole days) of a YMD file from its name.
- * Also determines UID and GID from ".Unnn.Gnnn" part of file name.
- */
-uint32_t
-ymd_file_age(const char *name, time_t now, uid_t *u, gid_t *g)
-{
- struct tm ftime;
- time_t created;
- uint32_t days;
- const char *p;
-
- if (name == NULL) return 0;
-
- if (now == 0) now = time(NULL);
-
- memset(&ftime, 0, sizeof(struct tm));
- ftime.tm_hour = 24;
-
- /* name is YYYY.MM.DD.<...> */
-
- if ((name[0] < '0') || (name[0] > '9')) return 0;
- ftime.tm_year = 1000 * (name[0] - '0');
-
- if ((name[1] < '0') || (name[1] > '9')) return 0;
- ftime.tm_year += 100 * (name[1] - '0');
-
- if ((name[2] < '0') || (name[2] > '9')) return 0;
- ftime.tm_year += 10 * (name[2] - '0');
-
- if ((name[3] < '0') || (name[3] > '9')) return 0;
- ftime.tm_year += name[3] - '0';
- ftime.tm_year -= 1900;
-
- if (name[4] != '.') return 0;
-
- if ((name[5] < '0') || (name[5] > '9')) return 0;
- ftime.tm_mon = 10 * (name[5] - '0');
-
- if ((name[6] < '0') || (name[6] > '9')) return 0;
- ftime.tm_mon += name[6] - '0';
- ftime.tm_mon -= 1;
-
- if (name[7] != '.') return 0;
-
- if ((name[8] < '0') || (name[8] > '9')) return 0;
- ftime.tm_mday = 10 * (name[8] - '0');
-
- if ((name[9] < '0') || (name[9] > '9')) return 0;
- ftime.tm_mday += name[9] - '0';
-
- if (name[10] != '.') return 0;
-
- created = mktime(&ftime);
- if (created > now) return 0;
-
- days = (now - created) / 86400;
-
- if (u != NULL)
- {
- *u = -1;
- p = strchr(name+10, 'U');
- if (p != NULL) *u = atoi(p+1);
- }
-
- if (g != NULL)
- {
- *g = -1;
- p = strchr(name+10, 'G');
- if (p != NULL) *g = atoi(p+1);
- }
-
- return days;
-}
-
-void
-aux_url_callback(const char *url)
-{
- if (url == NULL) return;
- if (!strncmp(url, AUX_URL_MINE, AUX_URL_MINE_LEN)) filesystem_unlink(url + AUX_URL_PATH_OFFSET);
-}
-
-uint32_t
-ymd_file_filter(const char *name, const char *path, uint32_t keep_mask, mode_t ymd_mode, uid_t ymd_uid, gid_t ymd_gid)
-{
- asl_file_t *f = NULL;
- uint8_t km = keep_mask;
- uint32_t status, len, dstcount = 0;
- char src[MAXPATHLEN];
- char dst[MAXPATHLEN];
-
- if (snprintf(src, MAXPATHLEN, "%s/%s", path, name) >= MAXPATHLEN) return ASL_STATUS_FAILED;
- if (snprintf(dst, MAXPATHLEN, "%s/%s", path, name) >= MAXPATHLEN) return ASL_STATUS_FAILED;
- len = strlen(src) - 3;
- snprintf(dst + len, 4, "tmp");
-
- //TODO: check if src file is already filtered
- debug_log(ASL_LEVEL_NOTICE, " filter %s %s ---> %s\n", src, keep_str(km), dst);
-
- status = ASL_STATUS_OK;
-
- if (dryrun == 0)
- {
- status = asl_file_open_read(name, &f);
- if (status != ASL_STATUS_OK) return status;
-
- status = asl_file_filter_level(f, dst, keep_mask, ymd_mode, ymd_uid, ymd_gid, &dstcount, aux_url_callback);
- asl_file_close(f);
- }
-
- filesystem_unlink(src);
- if ((status != ASL_STATUS_OK) || (dstcount == 0)) filesystem_unlink(dst);
- else filesystem_rename(dst, src);
-
- return status;
-}
-
-/*
- * Used to set config parameters.
- * Line format "= name value"
- */
-static void
-_aslmanager_set_param(asl_out_dst_data_t *dst, char *s)
-{
- char **l;
- uint32_t count;
-
- if (s == NULL) return;
- if (s[0] == '\0') return;
-
- /* skip '=' and whitespace */
- if (*s == '=') s++;
- while ((*s == ' ') || (*s == '\t')) s++;
-
- l = explode(s, " \t");
- if (l == NULL) return;
-
- for (count = 0; l[count] != NULL; count++);
-
- /* name is required */
- if (count == 0)
- {
- free_string_list(l);
- return;
- }
-
- /* value is required */
- if (count == 1)
- {
- free_string_list(l);
- return;
- }
-
- if (!strcasecmp(l[0], "aslmanager_debug"))
- {
- /* = debug level */
- set_debug(DEBUG_ASL, l[1]);
- }
- else if (!strcasecmp(l[0], "store_ttl"))
- {
- /* = store_ttl days */
- dst->ttl[LEVEL_ALL] = (time_t)atoll(l[1]);
- }
- else if (!strcasecmp(l[0], "module_ttl"))
- {
- /* = module_ttl days */
- module_ttl = (time_t)atoll(l[1]);
- }
- else if (!strcasecmp(l[0], "max_store_size"))
- {
- /* = max_file_size bytes */
- dst->all_max = atoi(l[1]);
- }
- else if (!strcasecmp(l[0], "archive"))
- {
- free(dst->rotate_dir);
- dst->rotate_dir = NULL;
-
- /* = archive {0|1} path */
- if (!strcmp(l[1], "1"))
- {
- if (l[2] == NULL) dst->rotate_dir = strdup(PATH_ASL_ARCHIVE);
- else dst->rotate_dir = strdup(l[2]);
- }
- }
- else if (!strcasecmp(l[0], "store_path"))
- {
- /* = archive path */
- free(dst->path);
- dst->path = strdup(l[1]);
- }
- else if (!strcasecmp(l[0], "archive_mode"))
- {
- dst->mode = strtol(l[1], NULL, 0);
- if ((dst->mode == 0) && (errno == EINVAL)) dst->mode = 0400;
- }
-
- free_string_list(l);
-}
-
-size_t
-directory_size(const char *path)
-{
- DIR *dp;
- struct dirent *dent;
- struct stat sb;
- size_t size;
- char *str;
-
- dp = opendir(path);
- if (dp == NULL) return 0;
-
- size = 0;
- while ((dent = readdir(dp)) != NULL)
- {
- if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue;
-
- memset(&sb, 0, sizeof(struct stat));
- str = NULL;
- asprintf(&str, "%s/%s", path, dent->d_name);
-
- if ((str != NULL) && (stat(str, &sb) == 0) && S_ISREG(sb.st_mode))
- {
- size += sb.st_size;
- free(str);
- }
- }
-
- closedir(dp);
- return size;
-}
-
-static int
-process_asl_data_store(asl_out_dst_data_t *dst)
-{
- int32_t today_ymd_stringlen, expire_ymd_stringlen;
- time_t now, ttl, ymd_expire;
- struct tm ctm;
- char today_ymd_string[32], expire_ymd_string[32], *str;
- DIR *dp;
- struct dirent *dent;
- name_list_t *ymd_list, *bb_list, *aux_list, *bb_aux_list, *e;
- size_t file_size, store_size;
- struct stat sb;
-
- ymd_list = NULL;
- bb_list = NULL;
- aux_list = NULL;
- bb_aux_list = NULL;
- store_size = 0;
-
- if (dst == NULL) return 0;
- if (dst->path == NULL) return 0;
-
- debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
- debug_log(ASL_LEVEL_NOTICE, "Processing data store %s\n", dst->path);
-
- if (dst->rotate_dir != NULL)
- {
- /* check archive */
- memset(&sb, 0, sizeof(struct stat));
- if (stat(dst->rotate_dir, &sb) == 0)
- {
- /* must be a directory */
- if (!S_ISDIR(sb.st_mode))
- {
- debug_log(ASL_LEVEL_ERR, "aslmanager error: archive %s is not a directory", dst->rotate_dir);
- return -1;
- }
- }
- else
- {
- if (errno == ENOENT)
- {
- /* archive doesn't exist - create it */
- if (mkdir(dst->rotate_dir, 0755) != 0)
- {
- debug_log(ASL_LEVEL_ERR, "aslmanager error: can't create archive %s: %s\n", dst->rotate_dir, strerror(errno));
- return -1;
- }
- }
- else
- {
- /* stat failed for some other reason */
- debug_log(ASL_LEVEL_ERR, "aslmanager error: can't stat archive %s: %s\n", dst->rotate_dir, strerror(errno));
- return -1;
- }
- }
- }
-
- chdir(dst->path);
-
- /* determine current time */
- now = time(NULL);
-
- /* ttl 0 means files never expire */
- ymd_expire = 0;
- ttl = dst->ttl[LEVEL_ALL] * SECONDS_PER_DAY;
-
- if ((ttl > 0) && (ttl <= now)) ymd_expire = now - ttl;
-
- /* construct today's date as YYYY.MM.DD */
- memset(&ctm, 0, sizeof(struct tm));
- if (localtime_r((const time_t *)&now, &ctm) == NULL) return -1;
-
- snprintf(today_ymd_string, sizeof(today_ymd_string), "%d.%02d.%02d.", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
- today_ymd_stringlen = strlen(today_ymd_string);
-
- /* construct regular file expiry date as YYYY.MM.DD */
- memset(&ctm, 0, sizeof(struct tm));
- if (localtime_r((const time_t *)&ymd_expire, &ctm) == NULL) return -1;
-
- snprintf(expire_ymd_string, sizeof(expire_ymd_string), "%d.%02d.%02d.", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
- expire_ymd_stringlen = strlen(expire_ymd_string);
-
- debug_log(ASL_LEVEL_NOTICE, "Expiry Date %s\n", expire_ymd_string);
-
- dp = opendir(dst->path);
- if (dp == NULL) return -1;
-
- /* gather a list of YMD files, AUX dirs, BB.AUX dirs, and BB files */
- while ((dent = readdir(dp)) != NULL)
- {
- memset(&sb, 0, sizeof(struct stat));
- file_size = 0;
- if (stat(dent->d_name, &sb) == 0) file_size = sb.st_size;
-
- if ((dent->d_name[0] >= '0') && (dent->d_name[0] <= '9'))
- {
- ymd_list = add_to_name_list(ymd_list, dent->d_name, file_size);
- store_size += file_size;
- }
- else if (!strncmp(dent->d_name, "AUX.", 4) && (dent->d_name[4] >= '0') && (dent->d_name[4] <= '9') && S_ISDIR(sb.st_mode))
- {
- file_size = directory_size(dent->d_name);
- aux_list = add_to_name_list(aux_list, dent->d_name, file_size);
- store_size += file_size;
- }
- else if (!strncmp(dent->d_name, "BB.AUX.", 7) && (dent->d_name[7] >= '0') && (dent->d_name[7] <= '9') && S_ISDIR(sb.st_mode))
- {
- file_size = directory_size(dent->d_name);
- bb_aux_list = add_to_name_list(bb_aux_list, dent->d_name, file_size);
- store_size += file_size;
- }
- else if (!strncmp(dent->d_name, "BB.", 3) && (dent->d_name[3] >= '0') && (dent->d_name[3] <= '9'))
- {
- bb_list = add_to_name_list(bb_list, dent->d_name, file_size);
- store_size += file_size;
- }
- else if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, "..")))
- {}
- else if ((!strcmp(dent->d_name, "StoreData")) || (!strcmp(dent->d_name, "SweepStore")))
- {}
- else
- {
- debug_log(ASL_LEVEL_ERR, "aslmanager: unexpected file %s in ASL data store\n", dent->d_name);
- }
- }
-
- closedir(dp);
-
- debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size);
- debug_log(ASL_LEVEL_NOTICE, "Data Store YMD Files\n");
- for (e = ymd_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, " %s %lu\n", e->name, e->size);
- debug_log(ASL_LEVEL_NOTICE, "Data Store AUX Directories\n");
- for (e = aux_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, " %s %lu\n", e->name, e->size);
- debug_log(ASL_LEVEL_NOTICE, "Data Store BB.AUX Directories\n");
- for (e = bb_aux_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, " %s %lu\n", e->name, e->size);
- debug_log(ASL_LEVEL_NOTICE, "Data Store BB Files\n");
- for (e = bb_list; e != NULL; e = e->next) debug_log(ASL_LEVEL_NOTICE, " %s %lu\n", e->name, e->size);
-
- /* Delete/achive expired YMD files */
- debug_log(ASL_LEVEL_NOTICE, "Start YMD File Scan\n");
-
- e = ymd_list;
- while (e != NULL)
- {
- if (strncmp(e->name, expire_ymd_string, expire_ymd_stringlen) <= 0)
- {
- /* file has expired, archive it if required, then unlink it */
- if (dst->rotate_dir != NULL)
- {
- str = NULL;
- asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
- if (str == NULL) return -1;
-
- filesystem_copy(dst, e->name, str, 0);
- free(str);
- }
-
- filesystem_unlink(e->name);
- store_size -= e->size;
- e->size = 0;
- }
- else
- {
- /* check if there are any per-level TTLs and filter the file if required */
- uint32_t i, bit, keep_mask;
- uid_t ymd_uid = -1;
- gid_t ymd_gid = -1;
- mode_t ymd_mode = 0600;
- uint32_t age = ymd_file_age(e->name, now, &ymd_uid, &ymd_gid);
-
- if (age > 0)
- {
- keep_mask = 0x000000ff;
- bit = 1;
- for (i = 0; i <= 7; i++)
- {
- if ((dst->ttl[i] > 0) && (age >= dst->ttl[i])) keep_mask &= ~bit;
- bit *= 2;
- }
-
- memset(&sb, 0, sizeof(struct stat));
- if (stat(e->name, &sb) == 0) ymd_mode = sb.st_mode & 0777;
-
- if (keep_mask != 0x000000ff) ymd_file_filter(e->name, dst->path, keep_mask, ymd_mode, ymd_uid, ymd_gid);
- }
- }
-
- e = e->next;
- }
-
- debug_log(ASL_LEVEL_NOTICE, "Finished YMD File Scan\n");
-
- /* Delete/achive expired YMD AUX directories */
- debug_log(ASL_LEVEL_NOTICE, "Start AUX Directory Scan\n");
-
- e = aux_list;
- while (e != NULL)
- {
- /* stop when a file name/date is after the expire date */
- if (strncmp(e->name + 4, expire_ymd_string, expire_ymd_stringlen) > 0) break;
-
- if (dst->rotate_dir != NULL)
- {
- str = NULL;
- asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
- if (str == NULL) return -1;
-
- filesystem_copy(dst, e->name, str, 0);
- free(str);
- }
-
- remove_directory(e->name);
- store_size -= e->size;
- e->size = 0;
-
- e = e->next;
- }
-
- debug_log(ASL_LEVEL_NOTICE, "Finished AUX Directory Scan\n");
-
- /* Delete/achive expired BB.AUX directories */
- debug_log(ASL_LEVEL_NOTICE, "Start BB.AUX Directory Scan\n");
-
- e = bb_aux_list;
- while (e != NULL)
- {
- /* stop when a file name/date is after the expire date */
- if (strncmp(e->name + 7, today_ymd_string, today_ymd_stringlen) > 0) break;
-
- if (dst->rotate_dir != NULL)
- {
- str = NULL;
- asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
- if (str == NULL) return -1;
-
- filesystem_copy(dst, e->name, str, 0);
- free(str);
- }
-
- remove_directory(e->name);
- store_size -= e->size;
- e->size = 0;
-
- e = e->next;
- }
-
- debug_log(ASL_LEVEL_NOTICE, "Finished BB.AUX Directory Scan\n");
-
- /* Delete/achive expired BB files */
- debug_log(ASL_LEVEL_NOTICE, "Start BB Scan\n");
-
- e = bb_list;
- while (e != NULL)
- {
- /* stop when a file name/date is after the expire date */
- if (strncmp(e->name + 3, today_ymd_string, today_ymd_stringlen) > 0) break;
-
- if (dst->rotate_dir != NULL)
- {
- str = NULL;
- asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
- if (str == NULL) return -1;
-
- /* syslog -x [str] -f [e->name] */
- filesystem_copy(dst, e->name, str, 0);
- free(str);
- }
-
- filesystem_unlink(e->name);
- store_size -= e->size;
- e->size = 0;
-
- e = e->next;
- }
-
- debug_log(ASL_LEVEL_NOTICE, "Finished BB Scan\n");
-
- if (dst->all_max > 0)
- {
- /* if data store is over max_size, delete/archive more YMD files */
- if (store_size > dst->all_max) debug_log(ASL_LEVEL_NOTICE, "Additional YMD Scan\n");
-
- e = ymd_list;
- while ((e != NULL) && (store_size > dst->all_max))
- {
- if (e->size != 0)
- {
- if (strncmp(e->name, today_ymd_string, today_ymd_stringlen) == 0)
- {
- /* do not touch active file YYYY.MM.DD.asl */
- if (strcmp(e->name + today_ymd_stringlen, "asl") == 0)
- {
- e = e->next;
- continue;
- }
- }
-
- if (dst->rotate_dir != NULL)
- {
- str = NULL;
- asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
- if (str == NULL) return -1;
-
- /* syslog -x [str] -f [e->name] */
- filesystem_copy(dst, e->name, str, 0);
- free(str);
- }
-
- filesystem_unlink(e->name);
- store_size -= e->size;
- e->size = 0;
- }
-
- e = e->next;
- }
-
- /* if data store is over dst->all_max, delete/archive more BB files */
- if (store_size > dst->all_max) debug_log(ASL_LEVEL_NOTICE, "Additional BB Scan\n");
-
- e = bb_list;
- while ((e != NULL) && (store_size > dst->all_max))
- {
- if (e->size != 0)
- {
- if (dst->rotate_dir != NULL)
- {
- str = NULL;
- asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
- if (str == NULL) return -1;
-
- /* syslog -x [str] -f [e->name] */
- filesystem_copy(dst, e->name, str, 0);
- free(str);
- }
-
- filesystem_unlink(e->name);
- store_size -= e->size;
- e->size = 0;
- }
-
- e = e->next;
- }
- }
-
- free_name_list(ymd_list);
- free_name_list(bb_list);
- free_name_list(aux_list);
- free_name_list(bb_aux_list);
-
- debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size);
-
- return 0;
-}
-
-/* move sequenced source files to dst dir, renaming as we go */
-static int
-module_copy_rename(asl_out_dst_data_t *dst)
-{
- asl_out_file_list_t *src_list, *dst_list, *f, *dst_last;
- char *base, *dst_dir;
- char fpathsrc[MAXPATHLEN], fpathdst[MAXPATHLEN];
- uint32_t src_count, dst_count;
- int32_t x, moved;
-
- if (dst == NULL) return -1;
- if (dst->path == NULL) return -1;
-
- base = strrchr(dst->path, '/');
- if (base == NULL) return -1;
-
- src_list = asl_list_src_files(dst);
- if (src_list == 0)
- {
- debug_log(ASL_LEVEL_INFO, " no src files\n");
- return 0;
- }
-
- debug_log(ASL_LEVEL_INFO, " src files\n");
-
- src_count = 0;
- for (f = src_list; f != NULL; f = f->next)
- {
- debug_log(ASL_LEVEL_INFO, " %s\n", f->name);
- src_count++;
- }
-
- dst_list = asl_list_dst_files(dst);
-
- *base = '\0';
- base++;
-
- dst_dir = dst->rotate_dir;
- if (dst_dir == NULL) dst_dir = dst->path;
-
- dst_count = 0;
- dst_last = dst_list;
-
- if (dst_list == NULL) debug_log(ASL_LEVEL_INFO, " no dst files\n");
- else debug_log(ASL_LEVEL_INFO, " dst files\n");
-
- for (f = dst_list; f != NULL; f = f->next)
- {
- debug_log(ASL_LEVEL_INFO, " %s\n", f->name);
- dst_last = f;
- dst_count++;
- }
-
- if (dst->flags & MODULE_FLAG_STYLE_SEQ)
- {
- for (f = dst_last; f != NULL; f = f->prev)
- {
- int is_gz = 0;
- char *dot = strrchr(f->name, '.');
- if ((dot != NULL) && (!strcmp(dot, ".gz"))) is_gz = 1;
-
- snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst_dir, f->name);
- snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d%s", dst_dir, base, f->seq+src_count, (is_gz == 1) ? ".gz" : "");
- filesystem_rename(fpathsrc, fpathdst);
- }
-
- for (f = src_list, x = 0; f != NULL; f = f->next, x++)
- {
- snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->path, f->name);
- snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d", dst_dir, base, x);
- moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags);
- if (moved != 0)
- {
- if (dst->flags & MODULE_FLAG_TRUNCATE) filesystem_truncate(fpathsrc);
- else filesystem_unlink(fpathsrc);
- }
- }
- }
- else
- {
- for (f = src_list; f != NULL; f = f->next)
- {
- /* final / active base stamped file looks like a checkpointed file - ignore it */
- if ((dst->flags & MODULE_FLAG_BASESTAMP) && (f->next == NULL)) break;
-
- snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->path, f->name);
-
- /* MODULE_FLAG_EXTERNAL files are not decorated with a timestamp */
- if (dst->flags & MODULE_FLAG_EXTERNAL)
- {
- char tstamp[32];
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
- asl_make_timestamp(f->ftime, dst->flags, tstamp, sizeof(tstamp));
- snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s", dst_dir, base, tstamp);
- }
- else
- {
- snprintf(fpathdst, sizeof(fpathdst), "%s/%s", dst_dir, f->name);
- }
+#include <asl.h>
+#include <asl_msg.h>
+#include <asl_msg_list.h>
+#include <asl_store.h>
+#include <errno.h>
+#include <vproc_priv.h>
- moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags);
- if (moved != 0)
- {
- if (dst->flags & MODULE_FLAG_TRUNCATE) filesystem_truncate(fpathsrc);
- else filesystem_unlink(fpathsrc);
- }
- }
- }
+#include "asl_common.h"
+#include "daemon.h"
+#include "cache_delete.h"
- asl_out_file_list_free(src_list);
- asl_out_file_list_free(dst_list);
+/* global */
+bool dryrun;
+uint32_t debug;
+FILE *debugfp;
+dispatch_queue_t work_queue;
- if (base != NULL) *--base = '/';
+static dispatch_queue_t server_queue;
+static time_t module_ttl;
+static xpc_connection_t listener;
+static bool main_task_enqueued;
+static bool initial_main_task = true;
+static dispatch_source_t sig_term_src;
- return 0;
-}
+/* wait 5 minutes to run main task after being invoked by XPC */
+#define MAIN_TASK_INITIAL_DELAY 300
-/* delete expired files */
-static int
-module_expire(asl_out_dst_data_t *dst)
+/*
+ * Used to set config parameters.
+ * Line format "= name value"
+ */
+static void
+_aslmanager_set_param(asl_out_dst_data_t *dst, char *s)
{
- asl_out_file_list_t *dst_list, *f;
- char *base, *dst_dir, fpath[MAXPATHLEN];
- time_t now, ttl, cutoff;
-
- if (dst == NULL) return -1;
- if (dst->path == NULL) return -1;
- if (dst->ttl[LEVEL_ALL] == 0) return 0;
-
- ttl = 0;
- if (module_ttl > 0) ttl = module_ttl;
- else ttl = dst->ttl[LEVEL_ALL];
-
- ttl *= SECONDS_PER_DAY;
-
- now = time(NULL);
- if (ttl > now) return 0;
-
- cutoff = now - ttl;
+ char **l;
+ uint32_t count;
- base = strrchr(dst->path, '/');
- if (base == NULL) return -1;
+ if (s == NULL) return;
+ if (s[0] == '\0') return;
- dst_list = asl_list_dst_files(dst);
+ /* skip '=' and whitespace */
+ if (*s == '=') s++;
+ while ((*s == ' ') || (*s == '\t')) s++;
- *base = '\0';
+ l = explode(s, " \t");
+ if (l == NULL) return;
- dst_dir = dst->rotate_dir;
- if (dst_dir == NULL) dst_dir = dst->path;
+ for (count = 0; l[count] != NULL; count++);
- if (dst_list == NULL)
- {
- debug_log(ASL_LEVEL_INFO, " no dst files\n");
- }
- else
+ /* name is required */
+ if (count == 0)
{
- debug_log(ASL_LEVEL_INFO, " dst files\n");
- for (f = dst_list; f != NULL; f = f->next) debug_log(ASL_LEVEL_INFO, " %s\n", f->name);
+ free_string_list(l);
+ return;
}
- for (f = dst_list; f != NULL; f = f->next)
+ /* value is required */
+ if (count == 1)
{
- if (f->ftime <= cutoff)
- {
- snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name);
- filesystem_unlink(fpath);
- }
+ free_string_list(l);
+ return;
}
- asl_out_file_list_free(dst_list);
-
- if (base != NULL) *base = '/';
-
- return 0;
-}
-
-/* check all_max size and delete files (oldest first) to stay within size limit */
-static int
-module_check_size(asl_out_dst_data_t *dst)
-{
- asl_out_file_list_t *dst_list, *f, *dst_end;
- char *base, *dst_dir, fpath[MAXPATHLEN];
- size_t total;
-
- if (dst == NULL) return -1;
- if (dst->path == NULL) return -1;
-
- if (dst->all_max == 0) return 0;
-
- dst_list = asl_list_dst_files(dst);
- if (dst_list == NULL)
+ if (!strcasecmp(l[0], "aslmanager_debug"))
{
- debug_log(ASL_LEVEL_INFO, " no dst files\n");
- return 0;
+ /* = debug level */
+ set_debug(DEBUG_ASL, l[1]);
}
-
- base = NULL;
- dst_dir = dst->rotate_dir;
- if (dst_dir == NULL)
+ else if (!strcasecmp(l[0], "store_ttl"))
{
- dst_dir = dst->path;
- base = strrchr(dst->path, '/');
- if (base == NULL)
- {
- asl_out_file_list_free(dst_list);
- return -1;
- }
-
- *base = '\0';
+ /* = store_ttl days */
+ dst->ttl[LEVEL_ALL] = asl_core_str_to_time(l[1], SECONDS_PER_DAY);
}
-
- debug_log(ASL_LEVEL_INFO, " dst files\n");
- dst_end = dst_list;
- for (f = dst_list; f != NULL; f = f->next)
+ else if (!strcasecmp(l[0], "module_ttl"))
{
- dst_end = f;
- debug_log(ASL_LEVEL_INFO, " %s size %lu\n", f->name, f->size);
+ /* = module_ttl days */
+ module_ttl = asl_core_str_to_time(l[1], SECONDS_PER_DAY);
}
-
- total = 0;
- for (f = dst_list; f != NULL; f = f->next) total += f->size;
-
- for (f = dst_end; (total > dst->all_max) && (f != NULL); f = f->prev)
+ else if (!strcasecmp(l[0], "max_store_size"))
{
- snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name);
- filesystem_unlink(fpath);
- total -= f->size;
+ /* = max_file_size bytes */
+ dst->all_max = asl_core_str_to_size(l[1]);
}
-
- asl_out_file_list_free(dst_list);
-
- if (base != NULL) *base = '/';
-
- return 0;
-}
-
-
-static int
-process_module(asl_out_module_t *mod)
-{
- asl_out_rule_t *r;
-
- if (mod == NULL) return -1;
-
- debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
- debug_log(ASL_LEVEL_NOTICE, "Processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name);
-
- for (r = mod->ruleset; r != NULL; r = r->next)
+ else if (!strcasecmp(l[0], "archive"))
{
- if (r->action == ACTION_OUT_DEST)
- {
- if (r->dst == NULL)
- {
- debug_log(ASL_LEVEL_NOTICE, "NULL dst data for output rule - skipped\n");
- }
- else if (r->dst->flags & MODULE_FLAG_ROTATE)
- {
- debug_log(ASL_LEVEL_NOTICE, "Checking file %s\n", r->dst->path);
- debug_log(ASL_LEVEL_NOTICE, "- Rename, move to destination directory, and compress as required\n");
-
- module_copy_rename(r->dst);
-
- if (r->dst->ttl[LEVEL_ALL] > 0)
- {
- debug_log(ASL_LEVEL_NOTICE, "- Check for expired files - TTL = %d days\n", r->dst->ttl[LEVEL_ALL]);
- module_expire(r->dst);
- }
+ free(dst->rotate_dir);
+ dst->rotate_dir = NULL;
- if (r->dst->all_max > 0)
- {
- debug_log(ASL_LEVEL_NOTICE, "- Check total storage used - MAX = %lu\n", r->dst->all_max);
- module_check_size(r->dst);
- }
- }
- else if ((r->dst->flags & MODULE_FLAG_TYPE_ASL_DIR) && (r->dst->ttl[LEVEL_ALL] > 0))
- {
- process_asl_data_store(r->dst);
- }
+ /* = archive {0|1} path */
+ if (!strcmp(l[1], "1"))
+ {
+ if (l[2] == NULL) dst->rotate_dir = strdup(PATH_ASL_ARCHIVE);
+ else dst->rotate_dir = strdup(l[2]);
}
}
-
- debug_log(ASL_LEVEL_NOTICE, "Finished processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name);
- return 0;
-}
-
-asl_msg_list_t *
-control_query(asl_msg_t *a)
-{
- asl_msg_list_t *out;
- char *qstr, *str, *res;
- uint32_t len, reslen, status;
- uint64_t cmax, qmin;
- kern_return_t kstatus;
- caddr_t vmstr;
- security_token_t sec;
-
- if (asl_server_port == MACH_PORT_NULL)
- {
- bootstrap_look_up2(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
- if (asl_server_port == MACH_PORT_NULL) return NULL;
- }
-
- qstr = asl_msg_to_string((asl_msg_t *)a, &len);
-
- str = NULL;
- if (qstr == NULL)
+ else if (!strcasecmp(l[0], "store_path"))
{
- asprintf(&str, "1\nQ [= ASLOption control]\n");
+ /* = archive path */
+ free(dst->path);
+ dst->path = strdup(l[1]);
}
- else
+ else if (!strcasecmp(l[0], "archive_mode"))
{
- asprintf(&str, "1\n%s [= ASLOption control]\n", qstr);
- free(qstr);
+ dst->mode = strtol(l[1], NULL, 0);
+ if ((dst->mode == 0) && (errno == EINVAL)) dst->mode = 0400;
}
- if (str == NULL) return NULL;
-
- /* length includes trailing nul */
- len = strlen(str) + 1;
- out = NULL;
- qmin = 0;
- cmax = 0;
- sec.val[0] = -1;
- sec.val[1] = -1;
-
- res = NULL;
- reslen = 0;
- status = ASL_STATUS_OK;
-
- kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
- if (kstatus != KERN_SUCCESS) return NULL;
-
- memmove(vmstr, str, len);
- free(str);
-
- status = 0;
- kstatus = _asl_server_query(asl_server_port, vmstr, len, qmin, 1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status, &sec);
- if (kstatus != KERN_SUCCESS) return NULL;
-
- if (res == NULL) return NULL;
-
- out = asl_msg_list_from_string(res);
- vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
-
- return out;
-}
-
-int
-checkpoint(const char *name)
-{
- /* send checkpoint message to syslogd */
- debug_log(ASL_LEVEL_NOTICE, "Checkpoint module %s\n", (name == NULL) ? "*" : name);
- if (dryrun != 0) return 0;
-
- asl_msg_t *qmsg = asl_msg_new(ASL_TYPE_QUERY);
- char *tmp = NULL;
- asl_msg_list_t *res;
-
- asprintf(&tmp, "%s checkpoint", (name == NULL) ? "*" : name);
- asl_msg_set_key_val_op(qmsg, "action", tmp, ASL_QUERY_OP_EQUAL);
- free(tmp);
-
- res = control_query(qmsg);
-
- asl_msg_list_release(res);
- return 0;
+ free_string_list(l);
}
int
int i, work;
asl_out_module_t *mod, *m;
asl_out_rule_t *r;
- asl_out_dst_data_t store, *asl_store_dst = NULL;
+ asl_out_dst_data_t store, opts, *asl_store_dst = NULL;
const char *mname = NULL;
+ char *path = NULL;
+ bool quiet = false;
+ bool cache_delete = false;
+ bool cache_delete_query = false;
+#if !TARGET_OS_SIMULATOR
if (geteuid() != 0)
{
if (argc == 0) debug = DEBUG_ASL;
debug_log(ASL_LEVEL_ERR, "aslmanager must be run by root\n");
exit(1);
}
+#endif
module_ttl = DEFAULT_TTL;
store.ttl[LEVEL_ALL] = DEFAULT_TTL;
store.all_max = DEFAULT_MAX_SIZE;
+ memset(&opts, 0, sizeof(opts));
+ opts.ttl[LEVEL_ALL] = DEFAULT_TTL;
+ opts.all_max = DEFAULT_MAX_SIZE;
+
for (i = 1; i < argc; i++)
{
- if (!strcmp(argv[i], "-s"))
+ if (!strcmp(argv[i], "-q"))
+ {
+ quiet = true;
+ }
+ else if (!strcmp(argv[i], "-dd"))
+ {
+ quiet = true;
+ }
+ else if (!strcmp(argv[i], "-s"))
{
if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
{
}
}
+ if (!quiet)
+ {
+ int status = asl_make_database_dir(NULL, NULL);
+ if (status == 0) status = asl_make_database_dir(ASL_INTERNAL_LOGS_DIR, &path);
+ if (status == 0)
+ {
+ char tstamp[32], *str = NULL;
+
+ asl_make_timestamp(time(NULL), MODULE_NAME_STYLE_STAMP_LCL_B, tstamp, sizeof(tstamp));
+ asprintf(&str, "%s/aslmanager.%s", path, tstamp);
+
+ if (str != NULL)
+ {
+ if (status == 0) debugfp = fopen(str, "w");
+ if (debugfp != NULL) debug |= DEBUG_FILE;
+ free(str);
+ }
+ }
+ }
+
/* get parameters from asl.conf */
mod = asl_out_module_init();
if (mod != NULL)
{
- for (r = mod->ruleset; r != NULL; r = r->next)
+ for (r = mod->ruleset; (r != NULL) && (asl_store_dst == NULL); r = r->next)
{
- if ((asl_store_dst == NULL) && (r->action == ACTION_OUT_DEST) && (!strcmp(r->dst->path, PATH_ASL_STORE)))
+ if ((r->dst != NULL) && (r->action == ACTION_OUT_DEST) && (!strcmp(r->dst->path, PATH_ASL_STORE)))
asl_store_dst = r->dst;
}
{
if (!strcmp(argv[i], "-a"))
{
+ if (asl_store_dst == NULL) asl_store_dst = &store;
+
if (((i + 1) < argc) && (argv[i + 1][0] != '-')) asl_store_dst->rotate_dir = strdup(argv[++i]);
else asl_store_dst->rotate_dir = strdup(PATH_ASL_ARCHIVE);
asl_store_dst->mode = 0400;
}
else if (!strcmp(argv[i], "-store_ttl"))
{
- if (((i + 1) < argc) && (argv[i + 1][0] != '-')) asl_store_dst->ttl[LEVEL_ALL] = atoi(argv[++i]);
+ if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
+ {
+ if (asl_store_dst == NULL) asl_store_dst = &store;
+ asl_store_dst->ttl[LEVEL_ALL] = asl_core_str_to_time(argv[++i], SECONDS_PER_DAY);
+ }
}
else if (!strcmp(argv[i], "-module_ttl"))
{
- if (((i + 1) < argc) && (argv[i + 1][0] != '-')) module_ttl = atoi(argv[++i]);
+ if (((i + 1) < argc) && (argv[i + 1][0] != '-')) module_ttl = asl_core_str_to_time(argv[++i], SECONDS_PER_DAY);
}
else if (!strcmp(argv[i], "-ttl"))
{
- if (((i + 1) < argc) && (argv[i + 1][0] != '-')) module_ttl = asl_store_dst->ttl[LEVEL_ALL] = atoi(argv[++i]);
+ if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
+ {
+ opts.ttl[LEVEL_ALL] = asl_core_str_to_time(argv[++i], SECONDS_PER_DAY);
+
+ if (asl_store_dst == NULL) asl_store_dst = &store;
+ asl_store_dst->ttl[LEVEL_ALL] = opts.ttl[LEVEL_ALL];
+
+ module_ttl = opts.ttl[LEVEL_ALL];
+ }
}
else if (!strcmp(argv[i], "-size"))
{
- if (((i + 1) < argc) && (argv[i + 1][0] != '-')) asl_store_dst->all_max = asl_str_to_size(argv[++i]);
+ if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
+ {
+ opts.all_max = asl_core_str_to_size(argv[++i]);
+
+ if (asl_store_dst == NULL) asl_store_dst = &store;
+ asl_store_dst->all_max = opts.all_max;
+ }
}
else if (!strcmp(argv[i], "-checkpoint"))
{
work |= DO_CHECKPT;
}
+ else if (!strcmp(argv[i], "-cache_delete"))
+ {
+ cache_delete = true;
+ if (((i + 1) < argc) && (argv[i + 1][0] == 'q')) cache_delete_query = true;
+ }
else if (!strcmp(argv[i], "-module"))
{
work &= ~DO_ASLDB;
}
else if (!strcmp(argv[i], "-dd"))
{
- dryrun = 1;
+ dryrun = true;
if (((i + i) < argc) && (argv[i+1][0] != '-')) set_debug(DEBUG_STDERR, argv[++i]);
- else set_debug(DEBUG_STDERR, NULL);
+ else set_debug(DEBUG_STDERR, "l7");
}
}
if (asl_store_dst->path == NULL) asl_store_dst->path = strdup(PATH_ASL_STORE);
- debug_log(ASL_LEVEL_ERR, "aslmanager starting%s\n", (dryrun == 1) ? " dryrun" : "");
+ debug_log(ASL_LEVEL_ERR, "aslmanager starting%s\n", dryrun ? " dryrun" : "");
+
+ if (cache_delete)
+ {
+ size_t curr_size = 0;
+
+ if (cache_delete_task(true, &curr_size) != 0)
+ {
+ debug_log(ASL_LEVEL_NOTICE, "cache_delete_process failed - can't determine current size\n");
+ }
+ else
+ {
+ debug_log(ASL_LEVEL_NOTICE, "cache delete current size = %lu\n", curr_size);
+
+ if (!cache_delete_query)
+ {
+ size_t new_size = curr_size - opts.all_max;
+
+ if (cache_delete_task(false, &new_size) != 0)
+ {
+ debug_log(ASL_LEVEL_NOTICE, "cache_delete_process failed - delete failed\n");
+ }
+ else
+ {
+ debug_log(ASL_LEVEL_NOTICE, "cache delete new size = %lu\n", new_size);
+ }
+ }
+ }
+
+ asl_out_module_free(mod);
+
+ debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
+ debug_log(ASL_LEVEL_ERR, "aslmanager finished%s\n", dryrun ? " dryrun" : "");
+ debug_close();
+
+ return 0;
+ }
- if (work & DO_ASLDB) process_asl_data_store(asl_store_dst);
+ if (work & DO_ASLDB) process_asl_data_store(asl_store_dst, &opts);
if (work & DO_MODULE)
{
{
for (m = mod; m != NULL; m = m->next)
{
- if ((mname == NULL) || ((m->name != NULL) && (!strcmp(m->name, mname))))
+ if (mname == NULL)
{
- process_module(m);
+ process_module(m, NULL);
+ }
+ else if ((m->name != NULL) && (!strcmp(m->name, mname)))
+ {
+ process_module(m, &opts);
}
}
}
asl_out_module_free(mod);
debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
- debug_log(ASL_LEVEL_ERR, "aslmanager finished%s\n", (dryrun == 1) ? " dryrun" : "");
- if (asl_aux_fd >= 0) asl_close_auxiliary_file(asl_aux_fd);
+ debug_log(ASL_LEVEL_ERR, "aslmanager finished%s\n", dryrun ? " dryrun" : "");
+ debug_close();
return 0;
}
+/* dispatched on server_queue, dispatches to work_queue */
+void
+main_task(void)
+{
+ /* if main task is already running or queued, do nothing */
+ if (main_task_enqueued) return;
+
+ main_task_enqueued = true;
+ xpc_transaction_begin();
+
+ if (initial_main_task)
+ {
+ initial_main_task = false;
+ dispatch_time_t delay = dispatch_walltime(NULL, MAIN_TASK_INITIAL_DELAY * NSEC_PER_SEC);
+
+ dispatch_after(delay, work_queue, ^{
+ cli_main(0, NULL);
+ main_task_enqueued = false;
+ xpc_transaction_end();
+ });
+ }
+ else
+ {
+ dispatch_async(work_queue, ^{
+ cli_main(0, NULL);
+ main_task_enqueued = false;
+ xpc_transaction_end();
+ });
+ }
+}
+
static void
accept_connection(xpc_connection_t peer)
{
* Some day, we may use the dictionary to pass parameters
* to aslmanager, but for now, we ignore the input.
*/
- if (uid == 0) cli_main(0, NULL);
+
+ if (uid == geteuid())
+ {
+ main_task();
+ }
}
else if (xpc_get_type(request) == XPC_TYPE_ERROR)
{
/* disconnect */
}
-
- dispatch_async(serverq, ^__attribute__((noreturn)) { xpc_server_exit(0); });
});
xpc_connection_resume(peer);
if (is_managed == 0) return cli_main(argc, argv);
+ /* Set I/O policy */
+ setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE);
+
/* XPC server */
- serverq = dispatch_queue_create("aslmanager", NULL);
- xpc_track_activity();
+ server_queue = dispatch_queue_create("aslmanager", NULL);
+
+ work_queue = dispatch_queue_create("work queue", NULL);
+
+ /* Exit on SIGTERM */
+ signal(SIGTERM, SIG_IGN);
+ sig_term_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, (uintptr_t)SIGTERM, 0, dispatch_get_main_queue());
+ dispatch_source_set_event_handler(sig_term_src, ^{
+ debug_log(ASL_LEVEL_NOTICE, "SIGTERM exit\n");
+ exit(0);
+ });
+
+ dispatch_resume(sig_term_src);
/* Handle incoming messages. */
- listener = xpc_connection_create_mach_service("com.apple.aslmanager", serverq, XPC_CONNECTION_MACH_SERVICE_LISTENER);
+ listener = xpc_connection_create_mach_service("com.apple.aslmanager", server_queue, XPC_CONNECTION_MACH_SERVICE_LISTENER);
xpc_connection_set_event_handler(listener, ^(xpc_object_t peer) {
if (xpc_get_type(peer) == XPC_TYPE_CONNECTION) accept_connection(peer);
});
xpc_connection_resume(listener);
+ cache_delete_register();
+
dispatch_main();
}
--- /dev/null
+/*
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <CacheDelete/CacheDelete.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <asl.h>
+#include "daemon.h"
+
+/* CacheDelete ID (stored in cache delete plist). Must match suggested CacheDelete id naming conventions. */
+#define CACHE_DELETE_ID "com.apple.activity_tracing.cache-delete"
+
+#define CFSTR_FROM_DICT(dict, key) ({ \
+ void *strRef = NULL; \
+ if (dict != NULL) { \
+ strRef = (void *)CFDictionaryGetValue(dict, key); \
+ if ((strRef == NULL) || (CFStringGetTypeID() != CFGetTypeID(strRef))) strRef = NULL; \
+ } \
+ (CFStringRef)strRef; \
+})
+
+#define INT64_FROM_DICT(dict, key) ({ \
+ int64_t value = 0; \
+ if (dict != NULL) { \
+ void *numRef = (void *)CFDictionaryGetValue(dict, key); \
+ if (numRef && (CFNumberGetTypeID() == CFGetTypeID(numRef))) {\
+ if (!CFNumberGetValue(numRef, kCFNumberSInt64Type, &value)) value = 0; \
+ } \
+ } \
+ value; \
+})
+
+static int64_t
+_purgeable(void)
+{
+ size_t psize = 0;
+ int status = cache_delete_task(true, &psize);
+ if (status == 0) return (uint64_t)psize;
+ return 0;
+}
+
+static int64_t
+_purge(int64_t purge_amount_bytes, CacheDeleteUrgency urgency)
+{
+ size_t curr_size, new_size;
+ curr_size = 0;
+
+ int status = cache_delete_task(true, &curr_size);
+ if (status != 0) return 0;
+
+ new_size = curr_size - purge_amount_bytes;
+
+ status = cache_delete_task(false, &new_size);
+ if (status == 0) return new_size;
+
+ return 0;
+}
+
+static bool
+_volume_contains_cached_data(CFStringRef volume)
+{
+ return true;
+}
+
+
+static CFDictionaryRef
+_handle_cache_delete_with_urgency(CFDictionaryRef info, CacheDeleteUrgency urgency, bool purge)
+{
+ xpc_transaction_begin();
+
+ uint64_t amount_requested = INT64_FROM_DICT(info, CFSTR(CACHE_DELETE_AMOUNT_KEY));
+ CFStringRef volume_requested = CFSTR_FROM_DICT(info, CFSTR(CACHE_DELETE_VOLUME_KEY));
+
+ CFMutableDictionaryRef result = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (result == NULL)
+ {
+ goto bail;
+ }
+ else if (volume_requested == NULL)
+ {
+ goto bail;
+ }
+
+ /* TODO: CFStringGetCStringPtr can return NULL */
+// debug_log(ASL_LEVEL_DEBUG, "CacheDelete request (purge=%d, urgency=%d, volume=%s, amount=%llu).", (int)urgency, CFStringGetCStringPtr(volume_requested, kCFStringEncodingUTF8), amount_requested);
+
+ int64_t amount_purged = 0;
+
+ if (_volume_contains_cached_data(volume_requested))
+ {
+ if (purge)
+ {
+ amount_purged = _purge(amount_requested, urgency);
+// debug_log(ASL_LEVEL_WARNING, "Purged %lld bytes.", amount_purged);
+ }
+ else
+ {
+ amount_purged = _purgeable();
+// debug_log(ASL_LEVEL_WARNING, "%lld bytes of purgeable space.", amount_purged);
+ }
+ }
+
+ CFNumberRef amount_purged_obj = CFNumberCreate(NULL, kCFNumberSInt64Type, &amount_purged);
+ if (amount_purged_obj != NULL)
+ {
+ CFDictionaryAddValue(result, CFSTR(CACHE_DELETE_AMOUNT_KEY), amount_purged_obj);
+ CFRelease(amount_purged_obj);
+ }
+
+bail:
+
+ xpc_transaction_end();
+ return result;
+}
+
+bool
+cache_delete_register(void)
+{
+ return CacheDeleteRegisterInfoCallbacks(CFSTR(CACHE_DELETE_ID), ^CFDictionaryRef(CacheDeleteUrgency urgency, CFDictionaryRef info) {
+ /* Purgeable Space Request */
+ return _handle_cache_delete_with_urgency(info, urgency, false);
+ }, ^CFDictionaryRef(CacheDeleteUrgency urgency, CFDictionaryRef info) {
+ /* Purge Request */
+ return _handle_cache_delete_with_urgency(info, urgency, true);
+ }, NULL, NULL) == 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+bool cache_delete_register(void);
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CACHE_DELETE_ID</key>
+ <string>com.apple.activity_tracing.cache-delete</string>
+ <key>CACHE_DELETE_SERVICES</key>
+ <array>
+ <string>PURGE</string>
+ </array>
+</dict>
+</plist>
<dict>
<key>com.apple.aslmanager</key>
<true/>
+ <key>com.apple.activity_tracing.cache-delete</key>
+ <true/>
</dict>
<key>EnableTransactions</key>
- <false/>
+ <true/>
+ <key>EnablePressuredExit</key>
+ <true/>
<key>POSIXSpawnType</key>
<string>Interactive</string>
</dict>
--- /dev/null
+/*
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <asl.h>
+#include <asl_private.h>
+#include <asl_core.h>
+#include <asl_file.h>
+#include <asl_store.h>
+#include <copyfile.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <zlib.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <servers/bootstrap.h>
+#include <bootstrap_priv.h>
+#include <mach/mach.h>
+#include <fcntl.h>
+#include <sys/attr.h>
+#include <dispatch/dispatch.h>
+#include <xpc/xpc.h>
+#include <xpc/private.h>
+#include <os/assumes.h>
+#include <vproc_priv.h>
+#include <libkern/OSAtomic.h>
+#include "daemon.h"
+
+/* global */
+extern bool dryrun;
+extern uint32_t debug;
+extern FILE *debugfp;
+extern dispatch_queue_t work_queue;
+
+static mach_port_t asl_server_port;
+static aslclient aslc;
+static int asl_aux_fd = -1;
+
+extern kern_return_t _asl_server_query
+(
+ mach_port_t server,
+ caddr_t request,
+ mach_msg_type_number_t requestCnt,
+ uint64_t startid,
+ int count,
+ int flags,
+ caddr_t *reply,
+ mach_msg_type_number_t *replyCnt,
+ uint64_t *lastid,
+ int *status,
+ security_token_t *token
+ );
+
+const char *
+keep_str(uint8_t mask)
+{
+ static char str[9];
+ uint32_t x = 0;
+
+ memset(str, 0, sizeof(str));
+ if (mask & 0x01) str[x++] = '0';
+ if (mask & 0x02) str[x++] = '1';
+ if (mask & 0x04) str[x++] = '2';
+ if (mask & 0x08) str[x++] = '3';
+ if (mask & 0x10) str[x++] = '4';
+ if (mask & 0x20) str[x++] = '5';
+ if (mask & 0x40) str[x++] = '6';
+ if (mask & 0x80) str[x++] = '7';
+ if (x == 0) str[x++] = '-';
+ return str;
+}
+
+void
+set_debug(int flag, const char *str)
+{
+ int level, x;
+
+ if (str == NULL) x = ASL_LEVEL_ERR;
+ else if (((str[0] == 'L') || (str[0] == 'l')) && ((str[1] >= '0') && (str[1] <= '7')) && (str[2] == '\0')) x = atoi(str+1);
+ else if ((str[0] >= '0') && (str[0] <= '7') && (str[1] == '\0')) x = ASL_LEVEL_CRIT + atoi(str);
+ else x = ASL_LEVEL_ERR;
+
+ if (x <= 0) x = 0;
+ else if (x > 7) x = 7;
+
+ level = debug & DEBUG_LEVEL_MASK;
+ if (x > level) level = x;
+
+ debug = debug & DEBUG_FLAG_MASK;
+ debug |= flag;
+ debug |= level;
+}
+
+void
+debug_log(int level, char *str, ...)
+{
+ va_list v;
+ char ts[32];
+
+ time_t now = time(NULL);
+ memset(ts, 0, sizeof(ts));
+ strftime(ts, sizeof(ts), "%b %e %T", localtime(&now));
+
+ if ((debug & DEBUG_STDERR) && (level <= (debug & DEBUG_LEVEL_MASK)))
+ {
+ fprintf(stderr, "%s: ", ts);
+ va_start(v, str);
+ vfprintf(stderr, str, v);
+ va_end(v);
+ }
+
+ if ((debug & DEBUG_FILE) && (debugfp != NULL))
+ {
+ fprintf(debugfp, "%s: ", ts);
+ va_start(v, str);
+ vfprintf(debugfp, str, v);
+ va_end(v);
+ }
+
+ if (debug & DEBUG_ASL)
+ {
+ char *line = NULL;
+
+ if (aslc == NULL)
+ {
+ aslc = asl_open("aslmanager", "syslog", 0);
+ asl_msg_t *msg = asl_msg_new(ASL_TYPE_MSG);
+
+ asl_msg_set_key_val(msg, ASL_KEY_MSG, "Status Report");
+ asl_msg_set_key_val(msg, ASL_KEY_LEVEL, ASL_STRING_NOTICE);
+ asl_create_auxiliary_file((asl_object_t)msg, "Status Report", "public.text", &asl_aux_fd);
+ asl_msg_release(msg);
+ }
+
+ va_start(v, str);
+ vasprintf(&line, str, v);
+ va_end(v);
+
+ if (line != NULL)
+ {
+ write(asl_aux_fd, ts, strlen(ts));
+ write(asl_aux_fd, line, strlen(line));
+ }
+
+ free(line);
+ }
+}
+
+void
+debug_close()
+{
+ if (asl_aux_fd >= 0) asl_close_auxiliary_file(asl_aux_fd);
+ if (debugfp != NULL) fclose(debugfp);
+}
+
+name_list_t *
+add_to_name_list(name_list_t *l, const char *name, size_t size, uint32_t flags)
+{
+ name_list_t *e, *x;
+
+ if (name == NULL) return l;
+
+ e = (name_list_t *)calloc(1, sizeof(name_list_t));
+ if (e == NULL) return NULL;
+
+ e->name = strdup(name);
+ if (e->name == NULL)
+ {
+ free(e);
+ return NULL;
+ }
+
+ e->size = size;
+ e->flags = flags;
+
+ /* list is sorted by name (i.e. primarily by timestamp) */
+ if (l == NULL) return e;
+
+ if (strcmp(e->name, l->name) <= 0)
+ {
+ e->next = l;
+ return e;
+ }
+
+ for (x = l; (x->next != NULL) && (strcmp(e->name, x->next->name) > 0) ; x = x->next);
+
+ e->next = x->next;
+ x->next = e;
+ return l;
+}
+
+void
+free_name_list(name_list_t *l)
+{
+ name_list_t *e;
+
+ while (l != NULL)
+ {
+ e = l;
+ l = l->next;
+ free(e->name);
+ free(e);
+ }
+
+ free(l);
+}
+
+int
+copy_compress_file(asl_out_dst_data_t *asldst, const char *src, const char *dst)
+{
+ int in, out;
+ size_t n;
+ gzFile gz;
+ char buf[IOBUFSIZE];
+
+ in = open(src, O_RDONLY, 0);
+ if (in < 0) return -1;
+
+ out = open(dst, O_WRONLY | O_CREAT, asldst->mode & 0666);
+ if (out >= 0) out = asl_out_dst_set_access(out, asldst);
+ if (out < 0)
+ {
+ close(in);
+ return -1;
+ }
+
+ gz = gzdopen(out, "w");
+ if (gz == NULL)
+ {
+ close(in);
+ close(out);
+ return -1;
+ }
+
+ do {
+ n = read(in, buf, sizeof(buf));
+ if (n > 0) gzwrite(gz, buf, n);
+ } while (n == IOBUFSIZE);
+
+ gzclose(gz);
+ close(in);
+ close(out);
+
+ return 0;
+}
+
+void
+filesystem_rename(const char *src, const char *dst)
+{
+ int status = 0;
+
+ debug_log(ASL_LEVEL_NOTICE, " rename %s ---> %s\n", src, dst);
+ if (dryrun) return;
+
+ status = rename(src, dst);
+ if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] rename %s ---> %s\n", status, errno, strerror(errno), src, dst);
+}
+
+void
+filesystem_unlink(const char *path)
+{
+ int status = 0;
+
+ debug_log(ASL_LEVEL_NOTICE, " remove %s\n", path);
+ if (dryrun) return;
+
+ status = unlink(path);
+ if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] unlink %s\n", status, errno, strerror(errno), path);
+}
+
+void
+filesystem_truncate(const char *path)
+{
+ int status = 0;
+
+ debug_log(ASL_LEVEL_NOTICE, " truncate %s\n", path);
+ if (dryrun) return;
+
+ status = truncate(path, 0);
+ if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] unlink %s\n", status, errno, strerror(errno), path);
+}
+
+void
+filesystem_rmdir(const char *path)
+{
+ int status = 0;
+
+ debug_log(ASL_LEVEL_NOTICE, " remove directory %s\n", path);
+ if (dryrun) return;
+
+ status = rmdir(path);
+ if (status != 0) debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] rmdir %s\n", status, errno, strerror(errno), path);
+}
+
+/*
+ * Copy ASL files by reading and writing each record.
+ */
+static uint32_t
+copy_asl_file(const char *src, const char *dst, mode_t mode)
+{
+ asl_file_t *fin, *fout;
+ uint32_t status;
+
+ if (src == NULL) return ASL_STATUS_INVALID_ARG;
+ if (dst == NULL) return ASL_STATUS_INVALID_ARG;
+
+ fin = NULL;
+ status = asl_file_open_read(src, &fin);
+ if (status != ASL_STATUS_OK) return status;
+
+ fout = NULL;
+ status = asl_file_open_write(dst, mode, -1, -1, &fout);
+ if (status != ASL_STATUS_OK)
+ {
+ asl_file_close(fin);
+ return status;
+ }
+
+ if (fout == NULL)
+ {
+ asl_file_close(fin);
+ return ASL_STATUS_FAILED;
+ }
+
+ fout->flags = ASL_FILE_FLAG_PRESERVE_MSG_ID;
+
+ status = asl_file_read_set_position(fin, ASL_FILE_POSITION_FIRST);
+ if (status != ASL_STATUS_OK)
+ {
+ asl_file_close(fin);
+ asl_file_close(fout);
+ return ASL_STATUS_READ_FAILED;
+ }
+
+ while (status == ASL_STATUS_OK)
+ {
+ uint64_t mid = 0;
+ asl_msg_t *msg = NULL;
+
+ status = asl_file_fetch_next(fin, &msg);
+ if (msg == NULL)
+ {
+ status = ASL_STATUS_OK;
+ break;
+ }
+
+ if (status != ASL_STATUS_OK) break;
+
+ status = asl_file_save(fout, msg, &mid);
+ asl_msg_release(msg);
+ }
+
+ asl_file_close(fin);
+ asl_file_close(fout);
+
+ return status;
+}
+
+int32_t
+filesystem_copy(asl_out_dst_data_t *asldst, const char *src, const char *dst, uint32_t flags)
+{
+ char *dot;
+
+ if ((src == NULL) || (dst == NULL)) return 0;
+
+ dot = strrchr(src, '.');
+ if ((dot != NULL) && (!strcmp(dot, ".gz"))) flags &= ~MODULE_FLAG_COMPRESS;
+
+ if (((flags & MODULE_FLAG_COMPRESS) == 0) && (!strcmp(src, dst))) return 0;
+
+ if (flags & MODULE_FLAG_TYPE_ASL) debug_log(ASL_LEVEL_NOTICE, " copy asl %s ---> %s\n", src, dst);
+ else if (flags & MODULE_FLAG_COMPRESS) debug_log(ASL_LEVEL_NOTICE, " copy compress %s ---> %s.gz\n", src, dst);
+ else debug_log(ASL_LEVEL_NOTICE, " copy %s ---> %s\n", src, dst);
+
+ if (dryrun) return 0;
+
+ if (flags & MODULE_FLAG_TYPE_ASL)
+ {
+ uint32_t status = copy_asl_file(src, dst, asldst->mode);
+ if (status != 0)
+ {
+ debug_log(ASL_LEVEL_ERR, " FAILED status %u [%s] asl copy %s ---> %s\n", status, asl_core_error(status), src, dst);
+ return 0;
+ }
+ }
+ else if (flags & MODULE_FLAG_COMPRESS)
+ {
+ char gzdst[MAXPATHLEN];
+
+ snprintf(gzdst, sizeof(gzdst), "%s.gz", dst);
+
+ int status = copy_compress_file(asldst, src, gzdst);
+ if (status != 0)
+ {
+ debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] copy & compress %s ---> %s\n", status, errno, strerror(errno), src, dst);
+ return 0;
+ }
+ }
+ else
+ {
+ int status = copyfile(src, dst, NULL, COPYFILE_ALL | COPYFILE_RECURSIVE);
+ if (status != 0)
+ {
+ debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] copy %s ---> %s\n", status, errno, strerror(errno), src, dst);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int32_t
+filesystem_reset_ctime(const char *path)
+{
+ struct attrlist attr_list;
+ struct timespec now;
+
+ debug_log(ASL_LEVEL_NOTICE, " reset ctime %s\n", path);
+
+ memset(&attr_list, 0, sizeof(attr_list));
+ attr_list.bitmapcount = ATTR_BIT_MAP_COUNT;
+ attr_list.commonattr = ATTR_CMN_CRTIME;
+
+ memset(&now, 0, sizeof(now));
+ now.tv_sec = time(NULL);
+
+ return setattrlist(path, &attr_list, &now, sizeof(now), 0);
+}
+
+int
+remove_directory(const char *path)
+{
+ DIR *dp;
+ struct dirent *dent;
+ char *str;
+
+ dp = opendir(path);
+ if (dp == NULL) return 0;
+
+ while ((dent = readdir(dp)) != NULL)
+ {
+ if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue;
+ asprintf(&str, "%s/%s", path, dent->d_name);
+ if (str != NULL)
+ {
+ filesystem_unlink(str);
+ free(str);
+ str = NULL;
+ }
+ }
+
+ closedir(dp);
+ filesystem_rmdir(path);
+
+ return 0;
+}
+
+size_t
+directory_size(const char *path)
+{
+ DIR *dp;
+ struct dirent *dent;
+ struct stat sb;
+ size_t size;
+ char *str;
+
+ dp = opendir(path);
+ if (dp == NULL) return 0;
+
+ size = 0;
+ while ((dent = readdir(dp)) != NULL)
+ {
+ if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) continue;
+
+ memset(&sb, 0, sizeof(struct stat));
+ str = NULL;
+ asprintf(&str, "%s/%s", path, dent->d_name);
+
+ if ((str != NULL) && (stat(str, &sb) == 0) && S_ISREG(sb.st_mode))
+ {
+ size += sb.st_size;
+ free(str);
+ }
+ }
+
+ closedir(dp);
+ return size;
+}
+
+time_t
+parse_ymd_name(const char *name)
+{
+ struct tm ftime;
+ time_t created;
+ int32_t tzh, tzm, sign = -1;
+ const char *x;
+ bool legacy = false;
+
+ if (name == NULL) return -1;
+
+ x = name;
+
+ if ((*x == 'T') || (*x == 't'))
+ {
+ x++;
+ created = atol(x);
+ if ((created == 0) && (*x != '0')) return -1;
+
+ x = strchr(x, '.');
+ if (x == NULL) return -1;
+
+ return created;
+ }
+
+ memset(&ftime, 0, sizeof(ftime));
+
+ if ((*x < '0') || (*x > '9')) return 1;
+ ftime.tm_year = 1000 * (*x++ - '0');
+
+ if ((*x < '0') || (*x > '9')) return 1;
+ ftime.tm_year += 100 * (*x++ - '0');
+
+ if ((*x < '0') || (*x > '9')) return 1;
+ ftime.tm_year += 10 * (*x++ - '0');
+
+ if ((*x < '0') || (*x > '9')) return 1;
+ ftime.tm_year += *x++ - '0';
+ ftime.tm_year -= 1900;
+
+ if (*x == '-') x++;
+ else if (*x == '.')
+ {
+ x++;
+ legacy = true;
+ }
+
+ if ((*x < '0') || (*x > '9')) return 1;
+ ftime.tm_mon = 10 * (*x++ - '0');
+
+ if ((*x < '0') || (*x > '9')) return 1;
+ ftime.tm_mon += *x++ - '0';
+ ftime.tm_mon -= 1;
+
+ if ((*x == '-') || (*x == '.')) x++;
+
+ if ((*x < '0') || (*x > '9')) return 1;
+ ftime.tm_mday = 10 * (*x++ - '0');
+
+ if ((*x < '0') || (*x > '9')) return 1;
+ ftime.tm_mday += *x++ - '0';
+
+ if (legacy)
+ {
+ if ((*x != '.') && (*x != '\0')) return -1;
+
+ /* assume the file was created at midnight */
+ ftime.tm_hour = 24;
+ ftime.tm_min = 0;
+ ftime.tm_sec = 0;
+ ftime.tm_isdst = -1;
+
+ created = mktime(&ftime);
+ return created;
+ }
+
+ if ((*x != 'T') && (*x != 't')) return 1;
+ x++;
+
+ if ((*x < '0') || (*x > '9')) return 1;
+ ftime.tm_hour = 10 * (*x++ - '0');
+
+ if ((*x < '0') || (*x > '9')) return 1;
+ ftime.tm_hour += *x++ - '0';
+
+ if (*x == ':') x++;
+
+ if ((*x < '0') || (*x > '9')) return 1;
+ ftime.tm_min = 10 * (*x++ - '0');
+
+ if ((*x < '0') || (*x > '9')) return 1;
+ ftime.tm_min += *x++ - '0';
+
+ if (*x == ':') x++;
+
+ if ((*x < '0') || (*x > '9')) return 1;
+ ftime.tm_sec = 10 * (*x++ - '0');
+
+ if ((*x < '0') || (*x > '9')) return 1;
+ ftime.tm_sec += *x++ - '0';
+
+ if ((*x == 'Z') || (*x == 'z'))
+ {
+ created = timegm(&ftime);
+ return created;
+ }
+
+ if ((*x != '+') && (*x != '-')) return 1;
+
+ if (*x == '-') sign = 1;
+ x++;
+
+ if ((*x < '0') || (*x > '9')) return 1;
+ tzh = 10 * (*x++ - '0');
+
+ if ((*x < '0') || (*x > '9')) tzh /= 10;
+ else tzh += *x++ - '0';
+
+ if (tzh > 23) return 1;
+
+ tzm = 0;
+ if ((*x == ':') || ((*x >= '0') && (*x <= '9')))
+ {
+ if (*x != ':') tzm = 10 * (*x - '0');
+ x++;
+
+ if ((*x < '0') || (*x > '9'))return -1;
+ tzm += *x++ - '0';
+
+ if (tzm > 59) return -1;
+ }
+
+ ftime.tm_sec += (sign * (tzh * SECONDS_PER_HOUR) + (tzm * SECONDS_PER_MINUTE));
+
+ if ((*x != '.') && (*x != '\0')) return -1;
+
+ created = timegm(&ftime);
+ return created;
+}
+
+
+/*
+ * Determine the age (in seconds) of a YMD file from its name.
+ * Also determines UID and GID from ".Unnn.Gnnn" part of file name.
+ */
+uint32_t
+ymd_file_age(const char *name, time_t now, uid_t *u, gid_t *g)
+{
+ struct tm ftime;
+ time_t created;
+ uint32_t seconds;
+ const char *p;
+
+ if (name == NULL) return 0;
+
+ if (now == 0) now = time(NULL);
+
+ memset(&ftime, 0, sizeof(struct tm));
+
+ created = parse_ymd_name(name);
+ if (created < 0) return 0;
+ if (created > now) return 0;
+ seconds = now - created;
+
+ if (u != NULL)
+ {
+ *u = -1;
+ p = strchr(name, 'U');
+ if (p != NULL) *u = atoi(p+1);
+ }
+
+ if (g != NULL)
+ {
+ *g = -1;
+ p = strchr(name, 'G');
+ if (p != NULL) *g = atoi(p+1);
+ }
+
+ return seconds;
+}
+
+
+static void
+aux_url_callback(const char *url)
+{
+ if (url == NULL) return;
+ if (!strncmp(url, AUX_URL_MINE, AUX_URL_MINE_LEN)) filesystem_unlink(url + AUX_URL_PATH_OFFSET);
+}
+
+uint32_t
+ymd_file_filter(const char *name, const char *path, uint32_t keep_mask, mode_t ymd_mode, uid_t ymd_uid, gid_t ymd_gid)
+{
+ asl_file_t *f = NULL;
+ uint8_t km = keep_mask;
+ uint32_t status, len, dstcount = 0;
+ char src[MAXPATHLEN];
+ char dst[MAXPATHLEN];
+
+ if (snprintf(src, MAXPATHLEN, "%s/%s", path, name) >= MAXPATHLEN) return ASL_STATUS_FAILED;
+ if (snprintf(dst, MAXPATHLEN, "%s/%s", path, name) >= MAXPATHLEN) return ASL_STATUS_FAILED;
+ len = strlen(src) - 3;
+ snprintf(dst + len, 4, "tmp");
+
+ //TODO: check if src file is already filtered
+ debug_log(ASL_LEVEL_NOTICE, " filter %s %s ---> %s\n", src, keep_str(km), dst);
+
+ status = ASL_STATUS_OK;
+
+ if (!dryrun)
+ {
+ status = asl_file_open_read(name, &f);
+ if (status != ASL_STATUS_OK) return status;
+
+ status = asl_file_filter_level(f, dst, keep_mask, ymd_mode, ymd_uid, ymd_gid, &dstcount, aux_url_callback);
+ asl_file_close(f);
+ }
+
+ filesystem_unlink(src);
+ if ((status != ASL_STATUS_OK) || (dstcount == 0)) filesystem_unlink(dst);
+ else filesystem_rename(dst, src);
+
+ return status;
+}
+
+int
+process_asl_data_store(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts)
+{
+ time_t now, midnight, since_midnight;
+ char *str;
+ DIR *dp;
+ struct dirent *dent;
+ name_list_t *ymd_list, *bb_list, *aux_list, *bb_aux_list, *e;
+ size_t file_size, store_size;
+ struct stat sb;
+ char tstr[128];
+ struct tm t_tmp;
+ uint32_t ttl = 0;
+
+ ymd_list = NULL;
+ bb_list = NULL;
+ aux_list = NULL;
+ bb_aux_list = NULL;
+ store_size = 0;
+
+ if (dst == NULL) return 0;
+ if (dst->path == NULL) return 0;
+
+ ttl = dst->ttl[LEVEL_ALL];
+ if ((opts != NULL) && (opts->ttl[LEVEL_ALL] > 0)) ttl = opts->ttl[LEVEL_ALL];
+
+ size_t all_max = dst->all_max;
+ if ((opts != NULL) && (opts->all_max > 0)) all_max = opts->all_max;
+
+ debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
+ debug_log(ASL_LEVEL_NOTICE, "Processing data store %s\n", dst->path);
+
+ if (dst->rotate_dir != NULL)
+ {
+ /* check archive */
+ memset(&sb, 0, sizeof(struct stat));
+ if (stat(dst->rotate_dir, &sb) == 0)
+ {
+ /* must be a directory */
+ if (!S_ISDIR(sb.st_mode))
+ {
+ debug_log(ASL_LEVEL_ERR, "aslmanager error: archive %s is not a directory", dst->rotate_dir);
+ return -1;
+ }
+ }
+ else
+ {
+ if (errno == ENOENT)
+ {
+ /* archive doesn't exist - create it */
+ if (mkdir(dst->rotate_dir, 0755) != 0)
+ {
+ debug_log(ASL_LEVEL_ERR, "aslmanager error: can't create archive %s: %s\n", dst->rotate_dir, strerror(errno));
+ return -1;
+ }
+ }
+ else
+ {
+ /* stat failed for some other reason */
+ debug_log(ASL_LEVEL_ERR, "aslmanager error: can't stat archive %s: %s\n", dst->rotate_dir, strerror(errno));
+ return -1;
+ }
+ }
+ }
+
+ chdir(dst->path);
+
+ /* determine current time */
+ now = time(NULL);
+
+ localtime_r(&now, &t_tmp);
+
+ t_tmp.tm_sec = 0;
+ t_tmp.tm_min = 0;
+ t_tmp.tm_hour = 0;
+
+ midnight = mktime(&t_tmp);
+ since_midnight = now - midnight;
+
+ dp = opendir(dst->path);
+ if (dp == NULL) return -1;
+
+ /* gather a list of YMD files, AUX dirs, BB.AUX dirs, and BB files */
+ while ((dent = readdir(dp)) != NULL)
+ {
+ uint32_t file_flags = 0;
+ char *dot = NULL;
+
+ memset(&sb, 0, sizeof(struct stat));
+ file_size = 0;
+ if (stat(dent->d_name, &sb) == 0) file_size = sb.st_size;
+
+ dot = strrchr(dent->d_name, '.');
+ if ((dot != NULL) && !strcmp(dot, ".gz")) file_flags |= NAME_LIST_FLAG_COMPRESSED;
+
+ if ((dent->d_name[0] >= '0') && (dent->d_name[0] <= '9'))
+ {
+ ymd_list = add_to_name_list(ymd_list, dent->d_name, file_size, file_flags);
+ store_size += file_size;
+ }
+ else if (((dent->d_name[0] == 'T') || (dent->d_name[0] == 't')) && (dent->d_name[1] >= '0') && (dent->d_name[1] <= '9'))
+ {
+ ymd_list = add_to_name_list(ymd_list, dent->d_name, file_size, file_flags);
+ store_size += file_size;
+ }
+ else if (!strncmp(dent->d_name, "AUX.", 4) && (dent->d_name[4] >= '0') && (dent->d_name[4] <= '9') && S_ISDIR(sb.st_mode))
+ {
+ file_size = directory_size(dent->d_name);
+ aux_list = add_to_name_list(aux_list, dent->d_name, file_size, file_flags);
+ store_size += file_size;
+ }
+ else if (!strncmp(dent->d_name, "BB.AUX.", 7) && (dent->d_name[7] >= '0') && (dent->d_name[7] <= '9') && S_ISDIR(sb.st_mode))
+ {
+ file_size = directory_size(dent->d_name);
+ bb_aux_list = add_to_name_list(bb_aux_list, dent->d_name, file_size, file_flags);
+ store_size += file_size;
+ }
+ else if (!strncmp(dent->d_name, "BB.", 3) && (dent->d_name[3] >= '0') && (dent->d_name[3] <= '9'))
+ {
+ bb_list = add_to_name_list(bb_list, dent->d_name, file_size, file_flags);
+ store_size += file_size;
+ }
+ else if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, "..")))
+ {}
+ else if ((!strcmp(dent->d_name, "StoreData")) || (!strcmp(dent->d_name, "SweepStore")))
+ {}
+ else if (!strcmp(dent->d_name, ASL_INTERNAL_LOGS_DIR))
+ {}
+ else
+ {
+ debug_log(ASL_LEVEL_ERR, "aslmanager: unexpected file %s in ASL data store\n", dent->d_name);
+ }
+ }
+
+ closedir(dp);
+
+ debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size);
+ asl_core_time_to_str(ttl, tstr, sizeof(tstr));
+ debug_log(ASL_LEVEL_NOTICE, "Data Store YMD Files (TTL = %s)\n", tstr);
+ for (e = ymd_list; e != NULL; e = e->next)
+ {
+ uint32_t age = ymd_file_age(e->name, now, NULL, NULL);
+ asl_core_time_to_str(age, tstr, sizeof(tstr));
+ debug_log(ASL_LEVEL_NOTICE, " %s %lu (age %s%s)\n", e->name, e->size, tstr, (age > ttl) ? " - expired" : "");
+ }
+
+ debug_log(ASL_LEVEL_NOTICE, "Data Store AUX Directories\n");
+ for (e = aux_list; e != NULL; e = e->next)
+ {
+ uint32_t age = ymd_file_age(e->name + 4, now, NULL, NULL) / SECONDS_PER_DAY;
+ asl_core_time_to_str(age, tstr, sizeof(tstr));
+ debug_log(ASL_LEVEL_NOTICE, " %s %lu (age %s)\n", e->name, e->size, tstr, (age > ttl) ? " - expired" : "");
+ }
+
+ debug_log(ASL_LEVEL_NOTICE, "Data Store BB.AUX Directories\n");
+ for (e = bb_aux_list; e != NULL; e = e->next)
+ {
+ uint32_t age = ymd_file_age(e->name + 7, now, NULL, NULL);
+ asl_core_time_to_str(age, tstr, sizeof(tstr));
+ debug_log(ASL_LEVEL_NOTICE, " %s %lu (age %s)\n", e->name, e->size, tstr, ((age / SECONDS_PER_DAY) > 0) ? " - expired" : "");
+ }
+
+ debug_log(ASL_LEVEL_NOTICE, "Data Store BB Files\n");
+ for (e = bb_list; e != NULL; e = e->next)
+ {
+ uint32_t age = ymd_file_age(e->name + 3, now, NULL, NULL) / SECONDS_PER_DAY;
+ asl_core_time_to_str(age, tstr, sizeof(tstr));
+ debug_log(ASL_LEVEL_NOTICE, " %s %lu (age %s)\n", e->name, e->size, tstr, ((age / SECONDS_PER_DAY) > 0) ? " - expired" : "");
+ }
+
+ /* Delete/achive expired YMD files */
+ debug_log(ASL_LEVEL_NOTICE, "Start YMD File Scan\n");
+
+ e = ymd_list;
+ while (e != NULL)
+ {
+ uid_t ymd_uid = -1;
+ gid_t ymd_gid = -1;
+ uint32_t age = ymd_file_age(e->name, now, &ymd_uid, &ymd_gid);
+
+ if (age > ttl)
+ {
+ /* file has expired, archive it if required, then unlink it */
+ if (dst->rotate_dir != NULL)
+ {
+ str = NULL;
+ asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
+ if (str == NULL) return -1;
+
+ filesystem_copy(dst, e->name, str, 0);
+ free(str);
+ }
+
+ filesystem_unlink(e->name);
+ store_size -= e->size;
+ e->size = 0;
+ }
+ else if ((e->flags & NAME_LIST_FLAG_COMPRESSED) == 0)
+ {
+ uint32_t i, bit, keep_mask;
+ mode_t ymd_mode = 0600;
+
+ /* check if there are any per-level TTLs and filter the file if required */
+ if (age > 0)
+ {
+ keep_mask = 0x000000ff;
+ bit = 1;
+ for (i = 0; i <= 7; i++)
+ {
+ if ((dst->ttl[i] > 0) && (age >= dst->ttl[i])) keep_mask &= ~bit;
+ bit *= 2;
+ }
+
+ memset(&sb, 0, sizeof(struct stat));
+ if (stat(e->name, &sb) == 0) ymd_mode = sb.st_mode & 0777;
+
+ if (keep_mask != 0x000000ff) ymd_file_filter(e->name, dst->path, keep_mask, ymd_mode, ymd_uid, ymd_gid);
+ }
+
+ if ((age > since_midnight) && (dst->flags & MODULE_FLAG_COMPRESS))
+ {
+ char gzdst[MAXPATHLEN];
+
+ snprintf(gzdst, sizeof(gzdst), "%s.gz", e->name);
+ debug_log(ASL_LEVEL_NOTICE, " compress %s ---> %s\n", e->name, gzdst);
+
+ if (!dryrun)
+ {
+ int status = copy_compress_file(dst, e->name, gzdst);
+ if (status == 0)
+ {
+ filesystem_unlink(e->name);
+ }
+ else
+ {
+ debug_log(ASL_LEVEL_ERR, " FAILED status %d errno %d [%s] compress %s ---> %s\n", status, errno, strerror(errno), e->name, gzdst);
+ return 0;
+ }
+ }
+ }
+ }
+
+ e = e->next;
+ }
+
+ debug_log(ASL_LEVEL_NOTICE, "Finished YMD File Scan\n");
+
+ /* Delete/achive expired YMD AUX directories */
+ debug_log(ASL_LEVEL_NOTICE, "Start AUX Directory Scan\n");
+
+ e = aux_list;
+ while (e != NULL)
+ {
+ uint32_t age = ymd_file_age(e->name + 4, now, NULL, NULL);
+
+ if (age > ttl)
+ {
+ if (dst->rotate_dir != NULL)
+ {
+ str = NULL;
+ asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
+ if (str == NULL) return -1;
+
+ filesystem_copy(dst, e->name, str, 0);
+ free(str);
+ }
+
+ remove_directory(e->name);
+ store_size -= e->size;
+ e->size = 0;
+ }
+
+ e = e->next;
+ }
+
+ debug_log(ASL_LEVEL_NOTICE, "Finished AUX Directory Scan\n");
+
+ /* Delete/achive expired BB.AUX directories */
+ debug_log(ASL_LEVEL_NOTICE, "Start BB.AUX Directory Scan\n");
+
+ e = bb_aux_list;
+ while (e != NULL)
+ {
+ uint32_t age = ymd_file_age(e->name + 7, now, NULL, NULL);
+
+ if (age > 0)
+ {
+ if (dst->rotate_dir != NULL)
+ {
+ str = NULL;
+ asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
+ if (str == NULL) return -1;
+
+ filesystem_copy(dst, e->name, str, 0);
+ free(str);
+ }
+
+ remove_directory(e->name);
+ store_size -= e->size;
+ e->size = 0;
+ }
+
+ e = e->next;
+ }
+
+ debug_log(ASL_LEVEL_NOTICE, "Finished BB.AUX Directory Scan\n");
+
+ /* Delete/achive expired BB files */
+ debug_log(ASL_LEVEL_NOTICE, "Start BB Scan\n");
+
+ e = bb_list;
+ while (e != NULL)
+ {
+ uint32_t age = ymd_file_age(e->name + 3, now, NULL, NULL);
+
+ if (age > 0)
+ {
+ if (dst->rotate_dir != NULL)
+ {
+ str = NULL;
+ asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
+ if (str == NULL) return -1;
+
+ /* syslog -x [str] -f [e->name] */
+ filesystem_copy(dst, e->name, str, 0);
+ free(str);
+ }
+
+ filesystem_unlink(e->name);
+ store_size -= e->size;
+ e->size = 0;
+ }
+
+ e = e->next;
+ }
+
+ debug_log(ASL_LEVEL_NOTICE, "Finished BB Scan\n");
+
+ if (all_max > 0)
+ {
+ /* if data store is over max_size, delete/archive more YMD files */
+ if (store_size > all_max) debug_log(ASL_LEVEL_NOTICE, "Additional YMD Scan\n");
+
+ e = ymd_list;
+ while ((e != NULL) && (store_size > all_max))
+ {
+ if (e->size != 0)
+ {
+ uint32_t age = ymd_file_age(e->name, now, NULL, NULL);
+ if (age == 0)
+ {
+ /* do not touch active file YYYY.MM.DD.asl */
+ e = e->next;
+ continue;
+ }
+
+ if (dst->rotate_dir != NULL)
+ {
+ str = NULL;
+ asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
+ if (str == NULL) return -1;
+
+ /* syslog -x [str] -f [e->name] */
+ filesystem_copy(dst, e->name, str, 0);
+ free(str);
+ }
+
+ filesystem_unlink(e->name);
+ store_size -= e->size;
+ e->size = 0;
+ }
+
+ e = e->next;
+ }
+
+ /* if data store is over all_max, delete/archive more BB files */
+ if (store_size > all_max) debug_log(ASL_LEVEL_NOTICE, "Additional BB Scan\n");
+
+ e = bb_list;
+ while ((e != NULL) && (store_size > all_max))
+ {
+ if (e->size != 0)
+ {
+ if (dst->rotate_dir != NULL)
+ {
+ str = NULL;
+ asprintf(&str, "%s/%s", dst->rotate_dir, e->name);
+ if (str == NULL) return -1;
+
+ /* syslog -x [str] -f [e->name] */
+ filesystem_copy(dst, e->name, str, 0);
+ free(str);
+ }
+
+ filesystem_unlink(e->name);
+ store_size -= e->size;
+ e->size = 0;
+ }
+
+ e = e->next;
+ }
+ }
+
+ free_name_list(ymd_list);
+ free_name_list(bb_list);
+ free_name_list(aux_list);
+ free_name_list(bb_aux_list);
+
+ debug_log(ASL_LEVEL_NOTICE, "Data Store Size = %lu\n", store_size);
+
+ return 0;
+}
+
+static asl_out_file_list_t *
+_remove_youngest_activity_tracing_file(asl_out_file_list_t *l)
+{
+ asl_out_file_list_t *f;
+
+ /* ignore youngest activity tracing file - it is the active file */
+ if (l->next == NULL)
+ {
+ debug_log(ASL_LEVEL_INFO, " ignore youngest (only) activity tracing file %s\n", l->name);
+ asl_out_file_list_free(l);
+ return NULL;
+ }
+
+ for (f = l; f->next->next != NULL; f = f->next);
+ debug_log(ASL_LEVEL_INFO, " ignore youngest activity tracing file %s\n", f->next->name);
+ asl_out_file_list_free(f->next);
+ f->next = NULL;
+ return l;
+}
+
+/* move sequenced source files to dst dir, renaming as we go */
+int
+module_copy_rename(asl_out_dst_data_t *dst)
+{
+ asl_out_file_list_t *src_list, *dst_list, *f;
+ char *dst_dir;
+ char fpathsrc[MAXPATHLEN], fpathdst[MAXPATHLEN];
+ uint32_t src_count, dst_count;
+ int32_t x, moved;
+
+ if (dst == NULL) return -1;
+ if (dst->path == NULL) return -1;
+
+ src_list = asl_list_src_files(dst);
+
+ /*
+ * Note: the unmarked file (e.g. system.log) is included in src_list.
+ * If it is from a MODULE_FLAG_EXTERNAL dst and it is less than 24 hours old,
+ * we ignore it. If it is not external, we also ignore it since syslogd will
+ * checkpoint it to create system.log.Tnnnnnnnnnn.
+ */
+ if ((src_list != NULL) && (src_list->stamp == STAMP_STYLE_NULL))
+ {
+ bool ignore_it = false;
+
+ if (dst->flags & MODULE_FLAG_EXTERNAL)
+ {
+ if ((time(NULL) - src_list->ftime) < SECONDS_PER_DAY)
+ {
+ debug_log(ASL_LEVEL_INFO, " ignore src file %s since it is external and less than a day old\n", src_list->name);
+ ignore_it = true;
+ }
+ }
+ else
+ {
+ debug_log(ASL_LEVEL_INFO, " ignore src file %s since it is internal and syslogd will checkpoint it when it needs to be renamed\n", src_list->name);
+ ignore_it = true;
+ }
+
+ if (ignore_it)
+ {
+ asl_out_file_list_t *first = src_list;
+ src_list = src_list->next;
+ first->next = NULL;
+ asl_out_file_list_free(first);
+ }
+ }
+
+ if (src_list == NULL)
+ {
+ debug_log(ASL_LEVEL_INFO, " no src files\n");
+ return 0;
+ }
+
+ debug_log(ASL_LEVEL_INFO, " src files\n");
+
+ src_count = 0;
+ for (f = src_list; f != NULL; f = f->next)
+ {
+ debug_log(ASL_LEVEL_INFO, " %s\n", f->name);
+ src_count++;
+ }
+
+ dst_list = asl_list_dst_files(dst);
+
+ if ((dst_list != NULL) && (dst->flags & MODULE_FLAG_ACTIVITY))
+ {
+ dst_list = _remove_youngest_activity_tracing_file(dst_list);
+ }
+
+ dst_dir = dst->rotate_dir;
+ if (dst_dir == NULL) dst_dir = dst->dir;
+
+ dst_count = 0;
+
+ if (dst_list == NULL) debug_log(ASL_LEVEL_INFO, " no dst files\n");
+ else debug_log(ASL_LEVEL_INFO, " dst files\n");
+
+ for (f = dst_list; f != NULL; f = f->next)
+ {
+ debug_log(ASL_LEVEL_INFO, " %s\n", f->name);
+ dst_count++;
+ }
+
+ if (dst->style_flags & MODULE_NAME_STYLE_STAMP_SEQ)
+ {
+ for (f = dst_list; f != NULL; f = f->next)
+ {
+ int is_gz = 0;
+ char *dot = strrchr(f->name, '.');
+ if ((dot != NULL) && (!strcmp(dot, ".gz"))) is_gz = 1;
+
+ snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst_dir, f->name);
+
+ if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BS)
+ {
+ snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d%s", dst_dir, dst->base, f->seq+src_count, (is_gz == 1) ? ".gz" : "");
+ }
+ else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BES)
+ {
+ snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s.%d%s", dst_dir, dst->base, dst->ext, f->seq+src_count, (is_gz == 1) ? ".gz" : "");
+ }
+ else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BSE)
+ {
+ snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d.%s%s", dst_dir, dst->base, f->seq+src_count, dst->ext, (is_gz == 1) ? ".gz" : "");
+ }
+
+ filesystem_rename(fpathsrc, fpathdst);
+ }
+
+ for (f = src_list, x = 0; f != NULL; f = f->next, x++)
+ {
+ snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->dir, f->name);
+
+ if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BS)
+ {
+ snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d", dst_dir, dst->base, x);
+ }
+ else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BES)
+ {
+ snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s.%d", dst_dir, dst->base, dst->ext, x);
+ }
+ else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BSE)
+ {
+ snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%d.%s", dst_dir, dst->base, x, dst->ext);
+ }
+
+ moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags);
+ if (moved != 0)
+ {
+ if (dst->flags & MODULE_FLAG_TRUNCATE)
+ {
+ filesystem_truncate(fpathsrc);
+ filesystem_reset_ctime(fpathsrc);
+ }
+ else
+ {
+ filesystem_unlink(fpathsrc);
+ }
+ }
+ }
+ }
+ else
+ {
+ for (f = src_list; f != NULL; f = f->next)
+ {
+ /* final / active base stamped file looks like a checkpointed file - ignore it */
+ if ((dst->flags & MODULE_FLAG_BASESTAMP) && (f->next == NULL)) break;
+
+ snprintf(fpathsrc, sizeof(fpathsrc), "%s/%s", dst->dir, f->name);
+
+ /* MODULE_FLAG_EXTERNAL files are not decorated with a timestamp */
+ if (dst->flags & MODULE_FLAG_EXTERNAL)
+ {
+ char tstamp[32];
+
+ asl_make_timestamp(f->ftime, dst->style_flags, tstamp, sizeof(tstamp));
+
+ if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BS)
+ {
+ snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s", dst_dir, dst->base, tstamp);
+ }
+ else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BES)
+ {
+ snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s.%s", dst_dir, dst->base, dst->ext, tstamp);
+ }
+ else if (dst->style_flags & MODULE_NAME_STYLE_FORMAT_BSE)
+ {
+ snprintf(fpathdst, sizeof(fpathdst), "%s/%s.%s.%s", dst_dir, dst->base, tstamp, dst->ext);
+ }
+
+ }
+ else
+ {
+ snprintf(fpathdst, sizeof(fpathdst), "%s/%s", dst_dir, f->name);
+ }
+
+ moved = filesystem_copy(dst, fpathsrc, fpathdst, dst->flags);
+ if (moved != 0)
+ {
+ if (dst->flags & MODULE_FLAG_TRUNCATE) filesystem_truncate(fpathsrc);
+ else filesystem_unlink(fpathsrc);
+ }
+ }
+ }
+
+ asl_out_file_list_free(src_list);
+ asl_out_file_list_free(dst_list);
+
+ return 0;
+}
+
+/* delete expired files */
+int
+module_expire(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts)
+{
+ asl_out_file_list_t *dst_list, *f;
+ char *base, *dst_dir, fpath[MAXPATHLEN];
+ time_t now, ttl, age;
+
+ if (dst == NULL) return -1;
+ if (dst->path == NULL) return -1;
+ if (dst->ttl[LEVEL_ALL] == 0) return 0;
+
+ ttl = dst->ttl[LEVEL_ALL];
+ if ((opts != NULL) && (opts->ttl[LEVEL_ALL] > 0)) ttl = opts->ttl[LEVEL_ALL];
+
+ now = time(NULL);
+ if (ttl > now) return 0;
+
+ base = strrchr(dst->path, '/');
+ if (base == NULL) return -1;
+
+ dst_list = asl_list_dst_files(dst);
+
+ if ((dst_list != NULL) && (dst->flags & MODULE_FLAG_ACTIVITY))
+ {
+ dst_list = _remove_youngest_activity_tracing_file(dst_list);
+ }
+
+ *base = '\0';
+
+ dst_dir = dst->rotate_dir;
+ if (dst_dir == NULL) dst_dir = dst->dir;
+
+ if (dst_list == NULL)
+ {
+ debug_log(ASL_LEVEL_INFO, " no dst files\n");
+ }
+ else
+ {
+ debug_log(ASL_LEVEL_INFO, " dst files\n");
+ for (f = dst_list; f != NULL; f = f->next)
+ {
+ char tstr[150];
+ age = now - f->ftime;
+
+ asl_core_time_to_str(age, tstr, sizeof(tstr));
+ debug_log(ASL_LEVEL_INFO, " %s (age %s%s)\n", f->name, tstr, (age > ttl) ? " - expired" : "");
+ }
+ }
+
+ for (f = dst_list; f != NULL; f = f->next)
+ {
+ age = now - f->ftime;
+ if (age > ttl)
+ {
+ snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name);
+ filesystem_unlink(fpath);
+ }
+ }
+
+ asl_out_file_list_free(dst_list);
+
+ if (base != NULL) *base = '/';
+
+ return 0;
+}
+
+/*
+ * Check all_max size and delete files (oldest first) to stay within size limit.
+ * If query is true, then just report total size.
+ */
+int
+module_check_size(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts, bool query, size_t *msize)
+{
+ asl_out_file_list_t *dst_list, *f, *dst_end;
+ char *dst_dir, fpath[MAXPATHLEN];
+ size_t total;
+
+ size_t all_max = dst->all_max;
+ if ((opts != NULL) && (opts->all_max > 0)) all_max = opts->all_max;
+
+ if (dst == NULL) return -1;
+ if (dst->path == NULL) return -1;
+
+ if (all_max == 0) return 0;
+
+ dst_list = asl_list_dst_files(dst);
+
+ if ((dst_list != NULL) && (dst->flags & MODULE_FLAG_ACTIVITY))
+ {
+ dst_list = _remove_youngest_activity_tracing_file(dst_list);
+ }
+
+ if (dst_list == NULL)
+ {
+ debug_log(ASL_LEVEL_INFO, " no dst files\n");
+ return 0;
+ }
+
+ dst_dir = dst->rotate_dir;
+ if (dst_dir == NULL) dst_dir = dst->dir;
+
+ debug_log(ASL_LEVEL_INFO, " dst files\n");
+ dst_end = dst_list;
+ for (f = dst_list; f != NULL; f = f->next)
+ {
+ dst_end = f;
+ debug_log(ASL_LEVEL_INFO, " %s size %lu\n", f->name, f->size);
+ }
+
+ total = 0;
+ for (f = dst_list; f != NULL; f = f->next) total += f->size;
+
+ if (!query)
+ {
+ for (f = dst_list; (total > all_max) && (f != NULL); f = f->next)
+ {
+ snprintf(fpath, sizeof(fpath), "%s/%s", dst_dir, f->name);
+ filesystem_unlink(fpath);
+ total -= f->size;
+ }
+ }
+
+ if (msize != NULL) *msize = total;
+
+ asl_out_file_list_free(dst_list);
+
+ return 0;
+}
+
+int
+process_dst(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts)
+{
+ uint32_t ttl = dst->ttl[LEVEL_ALL];
+ if ((opts != NULL) && (opts->ttl[LEVEL_ALL] > 0)) ttl = opts->ttl[LEVEL_ALL];
+
+ size_t all_max = dst->all_max;
+ if ((opts != NULL) && (opts->all_max > 0)) all_max = opts->all_max;
+
+ if (dst == NULL)
+ {
+ debug_log(ASL_LEVEL_NOTICE, "NULL dst data for output rule - skipped\n");
+ }
+ else if (dst->flags & MODULE_FLAG_ROTATE)
+ {
+ debug_log(ASL_LEVEL_NOTICE, "Checking file %s\n", dst->path);
+ debug_log(ASL_LEVEL_NOTICE, "- Rename, move to destination directory, and compress as required\n");
+
+ module_copy_rename(dst);
+
+ if (ttl > 0)
+ {
+ char tstr[150];
+
+ asl_core_time_to_str(ttl, tstr, sizeof(tstr));
+ debug_log(ASL_LEVEL_NOTICE, "- Check for expired files - TTL = %s\n", tstr);
+ module_expire(dst, opts);
+ }
+
+ if (all_max > 0)
+ {
+ debug_log(ASL_LEVEL_NOTICE, "- Check total storage used - MAX = %lu\n", all_max);
+ module_check_size(dst, opts, false, NULL);
+ }
+ }
+ else if ((dst->flags & MODULE_FLAG_TYPE_ASL_DIR) && (ttl > 0))
+ {
+ process_asl_data_store(dst, opts);
+ }
+
+ return 0;
+}
+
+int
+process_module(asl_out_module_t *mod, asl_out_dst_data_t *opts)
+{
+ asl_out_rule_t *r;
+ uint32_t flags = 0;
+
+ if (mod == NULL) return -1;
+
+ if (opts != NULL) flags = opts->flags;
+
+ debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
+ debug_log(ASL_LEVEL_NOTICE, "Processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name);
+
+ for (r = mod->ruleset; r != NULL; r = r->next)
+ {
+ if (r->action == ACTION_OUT_DEST)
+ {
+ if ((flags == 0) || ((flags & r->dst->flags) != 0)) process_dst(r->dst, opts);
+ }
+ }
+
+ debug_log(ASL_LEVEL_NOTICE, "Finished processing module %s\n", (mod->name == NULL) ? "asl.conf" : mod->name);
+ return 0;
+}
+
+int
+cache_delete_task(bool query, size_t *size)
+{
+ dispatch_sync(work_queue, ^{
+ asl_out_module_t *mod, *m;
+ asl_out_dst_data_t opts;
+ size_t total_size = 0;
+
+ memset(&opts, 0, sizeof(opts));
+ if ((!query) && (size != NULL)) opts.all_max = *size;
+
+ debug_log(ASL_LEVEL_NOTICE, "cache_delete_process%s size %lu\n", query ? " query" : "", opts.all_max);
+
+ mod = asl_out_module_init();
+
+ for (m = mod; m != NULL; m = m->next)
+ {
+ bool logged = false;
+ asl_out_rule_t *r;
+
+ for (r = m->ruleset; r != NULL; r = r->next)
+ {
+ if (r->action == ACTION_OUT_DEST)
+ {
+ if (r->dst->flags & MODULE_FLAG_ACTIVITY)
+ {
+ if (!logged)
+ {
+ debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
+ debug_log(ASL_LEVEL_NOTICE, "Processing activity module %s\n", (m->name == NULL) ? "asl.conf" : m->name);
+ logged = true;
+ }
+
+ size_t dsize = 0;
+ module_check_size(r->dst, &opts, false, &dsize);
+ total_size += dsize;
+ }
+ }
+ }
+
+ if (logged) debug_log(ASL_LEVEL_NOTICE, "Finished processing activity module %s\n", (m->name == NULL) ? "asl.conf" : m->name);
+ }
+
+ asl_out_module_free(mod);
+
+ if (size != NULL) *size = total_size;
+ });
+
+ return 0;
+}
+
+asl_msg_list_t *
+control_query(asl_msg_t *a)
+{
+ asl_msg_list_t *out;
+ char *qstr, *str, *res;
+ uint32_t len, reslen, status;
+ uint64_t cmax, qmin;
+ kern_return_t kstatus;
+ caddr_t vmstr;
+ security_token_t sec;
+
+ if (asl_server_port == MACH_PORT_NULL)
+ {
+ kstatus = bootstrap_look_up2(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
+ if (asl_server_port == MACH_PORT_NULL) return NULL;
+ }
+
+ qstr = asl_msg_to_string((asl_msg_t *)a, &len);
+
+ str = NULL;
+ if (qstr == NULL)
+ {
+ asprintf(&str, "1\nQ [= ASLOption control]\n");
+ }
+ else
+ {
+ asprintf(&str, "1\n%s [= ASLOption control]\n", qstr);
+ free(qstr);
+ }
+
+ if (str == NULL) return NULL;
+
+ /* length includes trailing nul */
+ len = strlen(str) + 1;
+ out = NULL;
+ qmin = 0;
+ cmax = 0;
+ sec.val[0] = -1;
+ sec.val[1] = -1;
+
+ res = NULL;
+ reslen = 0;
+ status = ASL_STATUS_OK;
+
+ kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
+ if (kstatus != KERN_SUCCESS) return NULL;
+
+ memmove(vmstr, str, len);
+ free(str);
+
+ status = 0;
+ kstatus = _asl_server_query(asl_server_port, vmstr, len, qmin, 1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status, &sec);
+ if (kstatus != KERN_SUCCESS) return NULL;
+
+ if (res == NULL) return NULL;
+
+ out = asl_msg_list_from_string(res);
+ vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
+
+ return out;
+}
+
+int
+checkpoint(const char *name)
+{
+ /* send checkpoint message to syslogd */
+ debug_log(ASL_LEVEL_NOTICE, "Checkpoint module %s\n", (name == NULL) ? "*" : name);
+ if (dryrun) return 0;
+
+ asl_msg_t *qmsg = asl_msg_new(ASL_TYPE_QUERY);
+ char *tmp = NULL;
+ asl_msg_list_t *res;
+
+ asprintf(&tmp, "%s checkpoint", (name == NULL) ? "*" : name);
+ asl_msg_set_key_val_op(qmsg, "action", tmp, ASL_QUERY_OP_EQUAL);
+ free(tmp);
+
+ res = control_query(qmsg);
+
+ asl_msg_list_release(res);
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <asl_msg_list.h>
+#include "asl_common.h"
+
+#define DEFAULT_MAX_SIZE 150000000
+#define IOBUFSIZE 4096
+
+#define DO_ASLDB 0x00000001
+#define DO_MODULE 0x00000002
+#define DO_CHECKPT 0x00000004
+
+#define DEBUG_FLAG_MASK 0xfffffff0
+#define DEBUG_LEVEL_MASK 0x0000000f
+#define DEBUG_FILE 0x00000010
+#define DEBUG_STDERR 0x00000020
+#define DEBUG_ASL 0x00000040
+
+#define AUX_URL_MINE "file:///var/log/asl/"
+#define AUX_URL_MINE_LEN 20
+
+#define SECONDS_PER_HOUR 3600
+#define SECONDS_PER_MINUTE 60
+
+/* length of "file://" */
+#define AUX_URL_PATH_OFFSET 7
+
+#define NAME_LIST_FLAG_COMPRESSED 0x00000001
+
+#define DAEMON_STATE_IDLE 0x00000000
+#define DAEMON_STATE_MAIN 0x00000001
+#define DAEMON_STATE_CACHE 0x00000002
+
+typedef struct name_list_s
+{
+ char *name;
+ size_t size;
+ uint32_t flags;
+ struct name_list_s *next;
+} name_list_t;
+
+const char *keep_str(uint8_t mask);
+void set_debug(int flag, const char *str);
+void debug_log(int level, char *str, ...);
+void debug_close();
+
+name_list_t *add_to_name_list(name_list_t *l, const char *name, size_t size, uint32_t flags);
+void free_name_list(name_list_t *l);
+
+int copy_compress_file(asl_out_dst_data_t *asldst, const char *src, const char *dst);
+
+void filesystem_rename(const char *src, const char *dst);
+void filesystem_unlink(const char *path);
+void filesystem_truncate(const char *path);
+void filesystem_rmdir(const char *path);
+int32_t filesystem_copy(asl_out_dst_data_t *asldst, const char *src, const char *dst, uint32_t flags);
+int32_t filesystem_reset_ctime(const char *path);
+
+int remove_directory(const char *path);
+size_t directory_size(const char *path);
+
+time_t parse_ymd_name(const char *name);
+uint32_t ymd_file_age(const char *name, time_t now, uid_t *u, gid_t *g);
+uint32_t ymd_file_filter(const char *name, const char *path, uint32_t keep_mask, mode_t ymd_mode, uid_t ymd_uid, gid_t ymd_gid);
+
+int process_asl_data_store(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts);
+int module_copy_rename(asl_out_dst_data_t *dst);
+int module_expire(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts);
+int module_check_size(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts, bool check, size_t *msize);
+int process_module(asl_out_module_t *mod, asl_out_dst_data_t *opts);
+int process_dst(asl_out_dst_data_t *dst, asl_out_dst_data_t *opts);
+
+asl_msg_list_t * control_query(asl_msg_t *a);
+int checkpoint(const char *name);
+
+int cache_delete_task(bool query, size_t *size);
+void main_task(void);
+
/*
- * Copyright (c) 2004-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <Availability.h>
/* Version number encodes the date YYYYMMDD */
-#define ASL_API_VERSION 20131108
+#define ASL_API_VERSION 20150225
typedef struct __asl_object_s *asl_object_t;
typedef asl_object_t aslclient;
* similarly must still be freed by the caller by calling asl_free() if the
* caller loses reference to it. Any changes made to it after calling
* asl_log_descriptor() are not applicable to the message used. descriptor
- * is treated differentlty based on the value of fd_type.
+ * is treated differently based on the value of fd_type.
*
* If fd_type is ASL_LOG_DESCRIPTOR_READ, the descriptor must be open for read
* access. ASL uses GCD to read from the descriptor as data becomes available.
asl_msg_list_t *asl_client_search(asl_client_t *client, asl_msg_t *query) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
asl_msg_list_t *asl_client_match(asl_client_t *client, asl_msg_list_t *querylist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t direction) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
+uint32_t asl_client_set_control(asl_client_t *client, uint32_t filter) __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0);
+uint32_t asl_client_get_control(asl_client_t *client) __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0);
+
__END_DECLS
#endif /* __ASL_CLIENT_H__ */
#include <time.h>
#include <mach/mach.h>
#include <Availability.h>
+#include <TargetConditionals.h>
+
+#define streq(A, B) (strcmp(A, B) == 0)
+#define strneq(A, B) (strcmp(A, B) != 0)
+
+#define streq_len(A, B, C) (strncmp(A, B, C) == 0)
+#define strneq_len(A, B, C) (strncmp(A, B, C) != 0)
+
+#define strcaseeq(A, B) (strcasecmp(A, B) == 0)
+#define strcaseneq(A, B) (strcasecmp(A, B) != 0)
+
+#define strcaseeq_len(A, B, C) (strncasecmp(A, B, C) == 0)
+#define strcaseneq_len(A, B, C) (strcasecmp(A, B, C) != 0)
typedef uint32_t ASL_STATUS;
#define ASL_PLACE_DATABASE 0
#define ASL_PLACE_ARCHIVE 1
+#if TARGET_OS_SIMULATOR
+#define ASL_PLACE_DATABASE_DEFAULT asl_filesystem_path(ASL_PLACE_DATABASE)
+#define ASL_PLACE_ARCHIVE_DEFAULT asl_filesystem_path(ASL_PLACE_ARCHIVE)
+#else
#define ASL_PLACE_DATABASE_DEFAULT "/var/log/asl"
#define ASL_PLACE_ARCHIVE_DEFAULT "/var/log/asl.archive"
+#endif
mach_port_t asl_core_get_service_port(int reset) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
int32_t asl_core_decode_buffer(const char *in, char **buf, uint32_t *len) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
time_t asl_core_parse_time(const char *in, uint32_t *tlen) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
+size_t asl_core_str_to_size(char *s) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); //TODO: 10_11 & 7_1 or 8_0
+time_t asl_core_str_to_time(char *s, uint32_t def_n) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); //TODO: 10_11 & 7_1 or 8_0
+void asl_core_time_to_str(time_t s, char *str, size_t len) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0); //TODO: 10_11 & 7_1 or 8_0
const char *asl_filesystem_path(uint32_t place) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
#define ASL_FILE_FILTER_FLAG_KEEP_MATCHES 0x00000001
/* NB CACHE_SIZE must be > 1 */
-#define CACHE_SIZE 256
+#define CACHE_SIZE 128
+
+/* This makes the maximum size of a file_string_t 128 bytes */
+#define CACHE_MAX_STRING_LEN 108
/* Size of the fixed-length part of a MSG record */
#define MSG_RECORD_FIXED_LENGTH 122
uint64_t where;
uint32_t hash;
struct file_string_s *next;
- char str[];
+ char str[CACHE_MAX_STRING_LEN];
} file_string_t;
typedef struct asl_file_s
uint32_t string_cache_count;
uint32_t msg_count;
file_string_t *string_list;
+ file_string_t *string_spare;
uint64_t first;
uint64_t last;
+ uint64_t last_mid;
uint64_t prev;
uint64_t cursor;
uint64_t cursor_xid;
#define __ASL_MSG_H__
#include <stdint.h>
+#include <xpc/xpc.h>
+#include <asl.h>
#include <asl_string.h>
#include <asl_core.h>
#include <asl_object.h>
#define IndexNull ((uint32_t)-1)
-#define ASL_MSG_PAGE_DATA_SIZE 830
-#define ASL_MSG_PAGE_SLOTS 25
+#define ASL_MSG_PAGE_DATA_SIZE 220
+
+#define ASL_MSG_KVO_COUNT 30
+// ASL_MSG_KVO_QUERY_SLOTS = ASL_MSG_KVO_COUNT / 3;
+#define ASL_MSG_KVO_QUERY_SLOTS 10
+// ASL_MSG_KVO_MSG_SLOTS = ASL_MSG_KVO_COUNT / 2;
+#define ASL_MSG_KVO_MSG_SLOTS 15
#define ASL_MSG_OFFSET_MASK 0x3fff
#define ASL_MSG_KV_MASK 0xc000
uint32_t data_size;
uint64_t mem_size;
struct asl_msg_s *next;
- uint16_t key[ASL_MSG_PAGE_SLOTS];
- uint16_t val[ASL_MSG_PAGE_SLOTS];
- uint16_t op[ASL_MSG_PAGE_SLOTS];
+#ifndef __LP64__
+ uint32_t pad;
+#endif
+ uint16_t kvo[ASL_MSG_KVO_COUNT];
char data[ASL_MSG_PAGE_DATA_SIZE];
} asl_msg_t;
int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
+void _asl_log_args_to_xpc(asl_object_t client, asl_object_t msg, xpc_object_t dict); //TODO: ADD AVAILABLITY INFO
+
__END_DECLS
#endif /* __ASL_MSG_H__ */
/*
- * Copyright (c) 2007-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2015 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
+#include <mach/vm_statistics.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <Availability.h>
#include <os/object.h>
#include <os/object_private.h>
-#define streq(A, B) (strcmp(A, B) == 0)
-#define strcaseeq(A, B) (strcasecmp(A, B) == 0)
-
#define ASL_QUERY_OP_NULL 0x00000
#define ASLMANAGER_SERVICE_NAME "com.apple.aslmanager"
/* File and Store Open Option */
#define ASL_OPT_OPEN_READ 0x80000000
+#define ASL_OPT_SHIM_NO_ASL 0x10000000
+#define ASL_OPT_SHIM_NO_TRACE 0x20000000
+
#define ASL_STORE_LOCATION_FILE 0
#define ASL_STORE_LOCATION_MEMORY 1
#define ASL_OPT_SYSLOG_LEGACY 0x00010000
#define ASL_KEY_FREE_NOTE "ASLFreeNotify"
+#define ASL_KEY_MESSAGETRACER "com.apple.message.domain"
+
+/* remote control bits */
+#define EVAL_LEVEL_MASK 0x000000ff
+#define EVAL_ACTION_MASK 0xffff0000
+#define EVAL_ACTIVE 0x00010000
+#define EVAL_SEND_ASL 0x00020000
+#define EVAL_SEND_TRACE 0x00040000
+#define EVAL_TEXT_FILE 0x00080000
+#define EVAL_ASL_FILE 0x00100000
+#define EVAL_TUNNEL 0x00200000
+#define EVAL_QUOTA 0x00400000
/*
* Private types
#define NOQUOTA_FILE_PATH "/etc/asl/.noquota"
+// TODO: this could move to vm_statistics.h
+#ifndef VM_MEMORY_ASL
+#define VM_MEMORY_ASL (VM_MEMORY_APPLICATION_SPECIFIC_1 + 7)
+#endif
+
+/*
+ * Memory limits: work queue size for syslogd and max message size in libasl
+ */
+#if TARGET_OS_EMBEDDED
+#define SYSLOGD_WORK_QUEUE_MEMORY 3072000
+#define LIBASL_MAX_MSG_SIZE 2048000
+#else
+#define SYSLOGD_WORK_QUEUE_MEMORY 10240000
+#define LIBASL_MAX_MSG_SIZE 8192000
+#endif
+
__BEGIN_DECLS
int asl_store_location() __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
const char *asl_syslog_faciliy_num_to_name(int n) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
int asl_trigger_aslmanager(void) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_7_0);
int asl_get_filter(asl_object_t client, int *local, int *master, int *remote, int *active) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
+uint32_t asl_set_local_control(asl_object_t client, uint32_t filter) __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0);
+uint32_t asl_get_local_control(asl_object_t client) __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0);
/* EXCLUSIVLY FOR USE BY DEV TOOLS */
/* DO NOT USE THIS INTERFACE OTHERWISE */
.Fc
is similar to
.Fn asl_log ,
-except the value for ASL_KEY_MESSAGE is taken from
+except the value for ASL_KEY_MSG is taken from
.Ar msg
rather than being constructed using a
.Fn printf
/*
- * Copyright (c) 2004-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <dispatch/dispatch.h>
#include <libkern/OSAtomic.h>
#include <os/activity.h>
+#include <os/trace.h>
+#include <os/log_private.h>
#include <asl_ipc.h>
#include <asl_client.h>
#include <asl_core.h>
#define FETCH_BATCH 256
-#define LEVEL_MASK 0x0000000f
-#define EVAL_MASK 0x000000f0
-#define EVAL_IGNORE 0x00000000
-#define EVAL_ASLFILE 0x00000010
-#define EVAL_SEND 0x00000020
-#define EVAL_TUNNEL 0x00000040
-#define EVAL_FILE 0x00000080
-#define EVAL_QUOTA 0x00000100
+#define EVAL_DEFAULT_ACTION (EVAL_SEND_ASL | EVAL_SEND_TRACE)
+#define EVAL_ASL (EVAL_SEND_ASL | EVAL_TEXT_FILE | EVAL_ASL_FILE)
/*
* Clients get a max of 36000 messages per hour.
#define NOQUOTA_ENV "ASL_QUOTA_DISABLED"
#define QUOTA_DISABLED_MSG "*** MESSAGE QUOTA DISABLED FOR THIS PROCESS ***"
#define QUOTA_MSG "*** LOG MESSAGE QUOTA EXCEEDED - SOME MESSAGES FROM THIS PROCESS HAVE BEEN DISCARDED ***"
-#define QUOTA_LEVEL 2
-#define QUOTA_LEVEL_STR "2"
+#define QUOTA_LEVEL ASL_LEVEL_CRIT
+#define QUOTA_LEVEL_STR ASL_STRING_CRIT
+
+/*
+ * Limit the size of messages sent to syslogd.
+ */
+#define SIZE_LIMIT_MSG "*** ASL MESSAGE SIZE (%u bytes) EXCEEDED MAXIMIMUM SIZE (%u bytes) ***"
+
+static const uint8_t shim_asl_to_trace_type[8] = {
+ OS_TRACE_TYPE_FAULT, OS_TRACE_TYPE_FAULT, OS_TRACE_TYPE_FAULT, // Emergency, Alert, Critical
+ OS_TRACE_TYPE_ERROR, // Error
+ OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_RELEASE, // Warning, Notice, Info
+ OS_TRACE_TYPE_DEBUG // Debug
+};
+
/* forward */
static ASL_STATUS _asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstring);
/*
* Evaluate client / message / level to determine what to do with a message.
- * Checks filters, tunneling, and log files. Returns EVAL_IGNORE if the message
- * can be ignored. Otherwise it returns the bits below, ORed with the level.
+ * Checks filters, tunneling, and log files.
+ * Returns the bits below, ORed with the message level.
*
- * EVAL_ASLFILE - will write to an asl file (see asl_open_from_file)
- * EVAL_SEND - will send to syslogd
- * EVAL_TUNNEL - will send to syslogd with tunneling enabled
- * EVAL_FILE - will write to file
+ * EVAL_SEND_ASL - send this message to syslogd
+ * EVAL_SEND_TRACE - log this message with Activity Tracing
+ * EVAL_ASL_FILE - write to a standalone ASL file (see asl_open_from_file)
+ * EVAL_TEXT_FILE - write this message to a text file / stderr
+ * EVAL_TUNNEL - tunneling enabled when sending to syslogd
*/
uint32_t
_asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel)
int check;
uint64_t v64;
const char *val;
+ uint32_t eval;
level = ASL_LEVEL_DEBUG;
if (slevel >= 0) level = slevel;
-
+
val = NULL;
if ((asl_msg_lookup(msg, ASL_KEY_LEVEL, &val, NULL) == 0) && (val != NULL)) level = atoi(val);
-
+
if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
else if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
if ((client != NULL) && (asl_get_type(client) != ASL_TYPE_CLIENT))
{
/* sending to something other than a client */
- return (level | EVAL_SEND);
+ return EVAL_ACTIVE | EVAL_SEND_ASL | level;
}
asl = (asl_client_t *)client;
+ if ((asl != NULL) && (asl->aslfile != NULL)) return (EVAL_ASL_FILE | level);
+
+ if (asl == NULL) asl = _asl_open_default();
if (asl == NULL)
{
- asl = _asl_open_default();
- if (asl == NULL) return EVAL_IGNORE;
+ eval = EVAL_ACTIVE | EVAL_DEFAULT_ACTION | level;
+ eval &= ~EVAL_SEND_ASL;
+ return eval;
}
- if (asl->aslfile != NULL) return (level | EVAL_ASLFILE);
-
- lmask = ASL_FILTER_MASK(level);
+ eval = (asl_client_get_control(asl) & EVAL_ACTION_MASK) | level;
filter = asl->filter & 0xff;
tunnel = (asl->filter & ASL_FILTER_MASK_TUNNEL) >> 8;
+ if (tunnel != 0) eval |= EVAL_TUNNEL;
+
+ /* don't send MessageTracer messages to Activity Tracing */
+ val = NULL;
+ if ((asl_msg_lookup(msg, ASL_KEY_MESSAGETRACER, &val, NULL) == 0) && (val != NULL)) eval &= ~EVAL_SEND_TRACE;
- if (!(asl->options & ASL_OPT_NO_REMOTE))
+ if ((asl->options & ASL_OPT_NO_REMOTE) == 0)
{
pthread_mutex_lock(&_asl_global.lock);
}
}
- pthread_mutex_unlock(&_asl_global.lock);
- /* master filter overrides local filter */
- if (_asl_global.master_filter != 0)
+ if (_asl_global.master_filter & EVAL_ACTIVE)
{
- filter = _asl_global.master_filter;
- tunnel = 1;
- }
+ /* clear bits and set according to master */
+ eval &= ~(EVAL_SEND_ASL | EVAL_SEND_TRACE);
+ eval |= (_asl_global.master_filter & (EVAL_SEND_ASL | EVAL_SEND_TRACE));
+ eval |= EVAL_TUNNEL;
- /* process-specific filter overrides local and master */
- if (_asl_global.proc_filter != 0)
- {
- filter = _asl_global.proc_filter;
- tunnel = 1;
+ if ((_asl_global.master_filter & EVAL_LEVEL_MASK) != 0) filter = _asl_global.proc_filter & EVAL_LEVEL_MASK;
}
- }
- if ((filter != 0) && ((filter & lmask) != 0))
- {
- level |= EVAL_SEND;
- if (tunnel != 0) level |= EVAL_TUNNEL;
- if (asl->out_count > 0) level |= EVAL_FILE;
+ if (_asl_global.proc_filter & EVAL_ACTIVE)
+ {
+ /* clear bits and set according to proc */
+ eval &= ~(EVAL_SEND_ASL | EVAL_SEND_TRACE | EVAL_TEXT_FILE);
+ eval |= (_asl_global.proc_filter & (EVAL_SEND_ASL | EVAL_SEND_TRACE | EVAL_TEXT_FILE));
+ eval |= EVAL_TUNNEL;
- return level;
- }
+ if ((_asl_global.proc_filter & EVAL_LEVEL_MASK) != 0) filter = _asl_global.proc_filter & EVAL_LEVEL_MASK;
+ }
- if ((asl->options & ASL_OPT_SYSLOG_LEGACY) && (filter != 0) && ((filter & lmask) == 0))
- {
- return EVAL_IGNORE;
+ pthread_mutex_unlock(&_asl_global.lock);
}
- if (asl->out_count > 0) return (level | EVAL_FILE);
+ lmask = ASL_FILTER_MASK(level);
+ if ((filter != 0) && ((filter & lmask) == 0)) eval &= ~EVAL_SEND_ASL;
+ if (asl->out_count > 0) eval |= EVAL_TEXT_FILE;
- return EVAL_IGNORE;
+ return eval;
}
/*
* ap: va_list for the format
* returns 0 for success, non-zero for failure
*/
-static ASL_STATUS
+__private_extern__ ASL_STATUS
_asl_lib_vlog(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *format, va_list ap)
{
int saved_errno = errno;
if (expand != 0)
{
fmt = malloc(len + 1);
- if (fmt == NULL)
- {
- if (estr != NULL) free(estr);
- return ASL_STATUS_NO_MEMORY;
- }
+ if (fmt == NULL) return ASL_STATUS_NO_MEMORY;
len = 0;
int
asl_vlog(asl_object_t client, asl_object_t msg, int level, const char *format, va_list ap)
{
+ ASL_STATUS status = ASL_STATUS_OK;
uint32_t eval = _asl_evaluate_send(client, msg, level);
- if (eval == EVAL_IGNORE) return 0;
- ASL_STATUS status = _asl_lib_vlog(client, eval, msg, format, ap);
+ if (eval & EVAL_SEND_TRACE)
+ {
+ va_list ap_copy;
+ if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
+ if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
+ uint8_t trace_type = shim_asl_to_trace_type[level];
+
+ va_copy(ap_copy, ap);
+ os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, format, ap_copy, ^(xpc_object_t xdict) {_asl_log_args_to_xpc(client, msg, xdict);} );
+ va_end(ap_copy);
+ }
+
+ if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL))
+ {
+ asl_msg_t *smsg = asl_msg_new(ASL_TYPE_MSG);
+ if (eval & EVAL_SEND_TRACE) asl_msg_set_key_val(smsg, "ASLSHIM", "1");
+ smsg = asl_msg_merge(smsg, (asl_msg_t *)msg);
+
+ status = _asl_lib_vlog(client, eval, (asl_object_t)smsg, format, ap);
+
+ asl_msg_release(smsg);
+ }
+
return (status == ASL_STATUS_OK) ? 0 : -1;
}
/*
* _asl_lib_log
- * SPI used by ASL_PREFILTER_LOG. Converts format arguments to a va_list and
+ * SPI used by legacy (non-shim) ASL_PREFILTER_LOG. Converts format arguments to a va_list and
* forwards the call to _asl_lib_vlog.
* msg: an asl message
* eval: log level and send flags for the message
int
_asl_lib_log(asl_object_t client, uint32_t eval, asl_object_t msg, const char *format, ...)
{
- int status;
- if (eval == EVAL_IGNORE) return 0;
+ int status = 0;
- va_list ap;
- va_start(ap, format);
- status = _asl_lib_vlog(client, eval, msg, format, ap);
- va_end(ap);
+ if (eval & EVAL_ASL)
+ {
+ va_list ap;
+
+ va_start(ap, format);
+ status = _asl_lib_vlog(client, eval, msg, format, ap);
+ va_end(ap);
+ }
return status;
}
int
asl_log(asl_object_t client, asl_object_t msg, int level, const char *format, ...)
{
- ASL_STATUS status;
+ ASL_STATUS status = ASL_STATUS_OK;
uint32_t eval = _asl_evaluate_send(client, msg, level);
- if (eval == EVAL_IGNORE) return 0;
- va_list ap;
- va_start(ap, format);
- status = _asl_lib_vlog(client, eval, msg, format, ap);
- va_end(ap);
+ if (eval & EVAL_SEND_TRACE)
+ {
+ va_list ap;
+ if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
+ if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
+ uint8_t trace_type = shim_asl_to_trace_type[level];
+
+ va_start(ap, format);
+ os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, format, ap, ^(xpc_object_t xdict) {_asl_log_args_to_xpc(client, msg, xdict);} );
+ va_end(ap);
+ }
+
+ if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL))
+ {
+ va_list ap;
+ asl_msg_t *smsg = asl_msg_new(ASL_TYPE_MSG);
+ if (eval & EVAL_SEND_TRACE) asl_msg_set_key_val(smsg, "ASLSHIM", "1");
+ smsg = asl_msg_merge(smsg, (asl_msg_t *)msg);
+
+ va_start(ap, format);
+ status = _asl_lib_vlog(client, eval, (asl_object_t)smsg, format, ap);
+ va_end(ap);
+
+ asl_msg_release(smsg);
+ }
return (status == ASL_STATUS_OK) ? 0 : -1;
}
int
asl_log_message(int level, const char *format, ...)
{
- int status;
+ ASL_STATUS status = ASL_STATUS_OK;
uint32_t eval = _asl_evaluate_send(NULL, NULL, level);
- if (eval == EVAL_IGNORE) return 0;
- va_list ap;
- va_start(ap, format);
- status = _asl_lib_vlog(NULL, eval, NULL, format, ap);
- va_end(ap);
+ if (eval & EVAL_SEND_TRACE)
+ {
+ va_list ap;
+ if (level < ASL_LEVEL_EMERG) level = ASL_LEVEL_EMERG;
+ if (level > ASL_LEVEL_DEBUG) level = ASL_LEVEL_DEBUG;
+ uint8_t trace_type = shim_asl_to_trace_type[level];
+
+ va_start(ap, format);
+ os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, format, ap, NULL);
+ va_end(ap);
+ }
+
+ if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL))
+ {
+ va_list ap;
+ asl_msg_t *smsg = asl_msg_new(ASL_TYPE_MSG);
+ if (eval & EVAL_SEND_TRACE) asl_msg_set_key_val(smsg, "ASLSHIM", "1");
+
+ va_start(ap, format);
+ status = _asl_lib_vlog(NULL, eval, (asl_object_t)smsg, format, ap);
+ va_end(ap);
+
+ asl_msg_release(smsg);
+ }
return (status == ASL_STATUS_OK) ? 0 : -1;
}
asl = (asl_client_t *)client;
if (asl == NULL) asl = asl_default;
- if (asl != NULL) l = asl->filter & 0xff;
+ if (asl != NULL) l = asl->filter & EVAL_LEVEL_MASK;
if ((asl_default != NULL) && (!(asl_default->options & ASL_OPT_NO_REMOTE)))
{
return 0;
}
+/* SPI for SHIM control */
+uint32_t
+asl_set_local_control(asl_object_t client, uint32_t filter)
+{
+ asl_client_t *asl = (asl_client_t *)client;
+ if (asl == NULL)
+ {
+ asl = _asl_open_default();
+ if (asl == NULL) return UINT32_MAX;
+ }
+ else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX;
+
+ return asl_client_set_control(asl, filter);
+}
+
+uint32_t
+asl_get_local_control(asl_object_t client)
+{
+ asl_client_t *asl = (asl_client_t *)client;
+ if (asl == NULL)
+ {
+ asl = _asl_open_default();
+ if (asl == NULL) return UINT32_MAX;
+ }
+ else if (asl_get_type(client) != ASL_TYPE_CLIENT) return UINT32_MAX;
+
+ return asl_client_get_control(asl);
+}
+
/*
- * Sets Host, PID, UID, GID, and OSActivityID values in a new message.
+ * Sets PID and OSActivityID values in a new message.
* Also sets Level, Time, TimeNanoSec, Sender, Facility and Message if provided.
*/
asl_msg_t *
asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const char *sstr, const char *fstr, const char *mstr)
{
char aux_val[64];
- char aux_host[_POSIX_HOST_NAME_MAX];
asl_msg_t *aux;
int status;
unsigned int osacount = 1;
/* Time and TimeNanoSec */
if (tv != NULL)
{
- snprintf(aux_val, sizeof(aux_val), "%lu", tv->tv_sec);
+ snprintf(aux_val, sizeof(aux_val), "%llu", (unsigned long long) tv->tv_sec);
asl_msg_set_key_val(aux, ASL_KEY_TIME, aux_val);
snprintf(aux_val, sizeof(aux_val), "%d", tv->tv_usec * 1000);
/* Message */
if (mstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_MSG, mstr);
- /* Host */
- memset(&aux_host, 0, _POSIX_HOST_NAME_MAX);
- if (gethostname(aux_host, _POSIX_HOST_NAME_MAX) == 0) asl_msg_set_key_val(aux, ASL_KEY_HOST, aux_host);
-
/* PID */
snprintf(aux_val, sizeof(aux_val), "%u", getpid());
asl_msg_set_key_val(aux, ASL_KEY_PID, aux_val);
- /* UID */
- snprintf(aux_val, sizeof(aux_val), "%d", getuid());
- asl_msg_set_key_val(aux, ASL_KEY_UID, aux_val);
-
- /* GID */
- snprintf(aux_val, sizeof(aux_val), "%d", getgid());
- asl_msg_set_key_val(aux, ASL_KEY_GID, aux_val);
-
/* OSActivityID */
if (os_activity_get_active(&osaid, &osacount) == 1)
{
}
/* Sender */
- if (sstr == NULL)
+ if ((sstr == NULL) && (asl != NULL))
{
/* See if the client has a value for ASL_KEY_SENDER */
status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_SENDER, &sstr, NULL);
if (sstr != NULL) asl_msg_set_key_val(aux, ASL_KEY_SENDER, sstr);
/* Facility */
- if (fstr == NULL)
+ if ((fstr == NULL) && (asl != NULL))
{
status = asl_msg_lookup((asl_msg_t *)asl->kvdict, ASL_KEY_FACILITY, &fstr, NULL);
if (status != 0) fstr = NULL;
}
#endif
+static void
+_asl_set_option(asl_msg_t *msg, const char *opt)
+{
+ const char *val = NULL;
+ uint32_t status;
+
+ if (msg == NULL) return;
+ if (opt == NULL) return;
+
+ status = asl_msg_lookup(msg, ASL_KEY_OPTION, &val, NULL);
+ if ((status != 0) || (val == NULL))
+ {
+ asl_msg_set_key_val(msg, ASL_KEY_OPTION, opt);
+ }
+ else
+ {
+ char *option = NULL;
+ asprintf(&option, "%s %s", opt, val);
+ asl_msg_set_key_val(msg, ASL_KEY_OPTION, option);
+ free(option);
+ }
+}
+
static ASL_STATUS
_asl_send_message(asl_object_t obj, uint32_t eval, asl_msg_t *msg, const char *mstr)
{
asl_client_t *asl = NULL;
static dispatch_once_t noquota_once;
- if (eval == EVAL_IGNORE) return ASL_STATUS_OK;
+ if ((eval & EVAL_ASL) == 0) return ASL_STATUS_OK;
if (obj == NULL)
{
{
objtype = asl_get_type(obj);
if (objtype == ASL_TYPE_CLIENT) asl = (asl_client_t *)obj;
- else asl = _asl_open_default();
}
- level = eval & LEVEL_MASK;
+ level = eval & EVAL_LEVEL_MASK;
if (level > 7) level = 7;
- eval &= EVAL_MASK;
lmask = ASL_FILTER_MASK(level);
if ((objtype == ASL_TYPE_CLIENT) && (asl->aslfile != NULL)) use_global_lock = 1;
if (sendmsg == NULL) return ASL_STATUS_FAILED;
/* Set "ASLOption store" if tunneling */
- if (eval & EVAL_TUNNEL)
- {
- const char *val = NULL;
- status = asl_msg_lookup(msg, ASL_KEY_OPTION, &val, NULL);
- if ((status != 0) || (val == NULL))
- {
- asl_msg_set_key_val(sendmsg, ASL_KEY_OPTION, ASL_OPT_STORE);
- }
- else
- {
- char *option = NULL;
- asprintf(&option, "%s %s", ASL_OPT_STORE, val);
- asl_msg_set_key_val(sendmsg, ASL_KEY_OPTION, option);
- free(option);
- }
- }
+ if (eval & EVAL_TUNNEL) _asl_set_option(sendmsg, ASL_OPT_STORE);
outstatus = -1;
* - Environment variable ASL_QUOTA_DISABLED == 1
* - /etc/asl/.noquota existed at the time that the process started
*
- * Note that we just check /etc/asl/.noquota once, since it would be
+ * We just check /etc/asl/.noquota once, since it would be
* expensive to stat() for every log message.
+ *
+ * We only check the Environment variable once, since getenv() is
+ * not thread safe. If someone is changing the environment,
+ * this can crash.
*/
-
+
dispatch_once(&noquota_once, ^{
struct stat sb;
memset(&sb, 0, sizeof(struct stat));
- if (stat(NOQUOTA_FILE_PATH, &sb) == 0) _asl_global.quota = UINT32_MAX;
- });
-
- if (_asl_global.quota != UINT32_MAX)
- {
- const char *qtest = getenv(NOQUOTA_ENV);
- if ((qtest != NULL) && (!strcmp(qtest, "1")))
+
+ int save_errno = errno;
+
+ if (stat(NOQUOTA_FILE_PATH, &sb) == 0)
{
_asl_global.quota = UINT32_MAX;
-
- qd_msg = asl_base_msg(asl, QUOTA_LEVEL, &tval, sstr, fstr, QUOTA_DISABLED_MSG);
- asl_msg_set_key_val(qd_msg, ASL_KEY_OPTION, ASL_OPT_STORE);
}
- }
-
+ else
+ {
+ const char *qtest = getenv(NOQUOTA_ENV);
+ if ((qtest != NULL) && (!strcmp(qtest, "1"))) _asl_global.quota = UINT32_MAX;
+ }
+
+ /* reset errno since we want stat() to fail silently */
+ errno = save_errno;
+ });
+
if (((eval & EVAL_TUNNEL) == 0) && (_asl_global.quota != UINT32_MAX))
{
time_t last_send = _asl_global.last_send;
}
else
{
- eval &= ~EVAL_SEND;
+ eval &= ~EVAL_SEND_ASL;
}
}
else
}
}
- if ((_asl_global.server_port != MACH_PORT_NULL) && (eval & EVAL_SEND))
+ if ((_asl_global.server_port != MACH_PORT_NULL) && (eval & EVAL_SEND_ASL))
{
asl_string_t *send_str;
const char *str;
if ((str != NULL) && (vmsize != 0)) vm_deallocate(mach_task_self(), (vm_address_t)str, vmsize);
asl_msg_release(qd_msg);
}
-
+
send_str = asl_msg_to_string_raw(ASL_STRING_MIG, sendmsg, "raw");
len = asl_string_length(send_str);
+
+ if (len > LIBASL_MAX_MSG_SIZE)
+ {
+ char tmp[256];
+
+ snprintf(tmp, sizeof(tmp), SIZE_LIMIT_MSG, len, LIBASL_MAX_MSG_SIZE);
+ asl_msg_t *limitmsg = asl_base_msg(asl, ASL_LEVEL_CRIT, &tval, sstr, fstr, tmp);
+
+ asl_string_release(send_str);
+ len = 0;
+
+ if (limitmsg != NULL)
+ {
+ /* Set "ASLOption store" if tunneling */
+ if (eval & EVAL_TUNNEL) _asl_set_option(limitmsg, ASL_OPT_STORE);
+
+ send_str = asl_msg_to_string_raw(ASL_STRING_MIG, limitmsg, "raw");
+ len = asl_string_length(send_str);
+ asl_msg_release(limitmsg);
+ }
+ }
+
vmsize = asl_string_allocated_size(send_str);
str = asl_string_release_return_bytes(send_str);
res = NULL;
reslen = 0;
- kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
+ kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
if (kstatus != KERN_SUCCESS) return NULL;
memmove(vmstr, ctlstr, len);
if (opts & ASL_OPT_CREATE_STORE)
{
if (asl_store_open_write(path, &sout) != ASL_STATUS_OK) return NULL;
- return (asl_object_t)fout;
+ return (asl_object_t)sout;
}
else
{
/*
- * Copyright (c) 2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
client->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE);
+ client->filter |= EVAL_ACTIVE;
+ if (!(opts & ASL_OPT_SHIM_NO_ASL)) client->filter |= EVAL_SEND_ASL;
+ if (!(opts & ASL_OPT_SHIM_NO_TRACE)) client->filter |= EVAL_SEND_TRACE;
+
if (client->options & ASL_OPT_STDERR)
{
/* only add stderr if it is valid */
if (client == NULL) return NULL;
client->filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG);
+ client->filter |= (EVAL_ACTIVE | EVAL_SEND_ASL);
status = asl_file_open_write_fd(descriptor, &(client->aslfile));
if (status != ASL_STATUS_OK)
if (str == NULL) return NULL;
- kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
+ kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
if (kstatus != KERN_SUCCESS) return NULL;
memmove(vmstr, str, len);
if (str == NULL) return NULL;
- kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
+ kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
if (kstatus != KERN_SUCCESS) return NULL;
memmove(vmstr, str, len);
#pragma mark -
#pragma mark output control
-/* returns last filter value, or -1 on error */
+/*
+ * Returns last filter value, or -1 on error.
+ * Note that this allows ASL_FILTER_MASK_TUNNEL (0x100) to be set.
+ * That is SPI that's used by some clients.
+ */
int
asl_client_set_filter(asl_client_t *client, int filter)
{
- int last;
-
if (client == NULL) return -1;
- last = client->filter;
+
+ uint32_t allbits = client->filter;
+ int last = allbits & (~EVAL_ACTION_MASK);
+ client->filter = (allbits & EVAL_ACTION_MASK) | (filter & (~EVAL_ACTION_MASK));
+ return last;
+}
+
+/* SPI */
+uint32_t
+asl_client_set_control(asl_client_t *client, uint32_t filter)
+{
+ if (client == NULL) return UINT32_MAX;
+
+ uint32_t last = client->filter;
client->filter = filter;
return last;
}
+uint32_t
+asl_client_get_control(asl_client_t *client)
+{
+ if (client == NULL) return UINT32_MAX;
+ return client->filter;
+}
+
ASL_STATUS
asl_client_add_output_file(asl_client_t *client, int descriptor, const char *mfmt, const char *tfmt, int filter, int text_encoding)
{
client->out_list[client->out_count].fd = descriptor;
client->out_list[client->out_count].encoding = text_encoding;
client->out_list[client->out_count].filter = filter;
+ client->out_list[client->out_count].mfmt = NULL;
if (mfmt != NULL) client->out_list[client->out_count].mfmt = strdup(mfmt);
+ client->out_list[client->out_count].tfmt = NULL;
if (tfmt != NULL) client->out_list[client->out_count].tfmt = strdup(tfmt);
client->out_count++;
ASL_STRING_DEBUG
};
-static char *asl_filesystem_path_database = NULL;
-static char *asl_filesystem_path_archive = NULL;
-
/*
* Message ID generation
*/
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;
asl_filesystem_path(uint32_t place)
{
static dispatch_once_t once;
+ static char *asl_filesystem_path_database = NULL;
+ static char *asl_filesystem_path_archive = NULL;
dispatch_once(&once, ^{
char *asl_var_log = NULL;
const char *const_asl_var_log = "/var/log";
-#if TARGET_IPHONE_SIMULATOR
+#if TARGET_OS_SIMULATOR
asl_var_log = getenv("SIMULATOR_LOG_ROOT");
#endif
{
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:
{
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);
}
asl_core_str_match_char(const char *target, const char c, uint32_t mincount, uint32_t flags, uint32_t *length)
{
uint32_t n;
-
+
if (length == NULL) length = &n;
*length = 0;
-
+
if (target == NULL) return (mincount == 0);
-
+
if ((*target == c) && (flags & MFLAG_INCLUDE)) *length = 1;
if ((*target != c) && (flags & MFLAG_EXCLUDE)) *length = 1;
-
+
return (*length >= mincount);
}
asl_core_str_to_uint32(const char *target, uint32_t length)
{
uint32_t i, d, out = 0;
-
+
for (i = 0; i < length; i++)
{
d = target[i] - '0';
out = (out * 10) + d;
}
-
+
+ return out;
+}
+
+size_t
+asl_core_str_to_size(char *s)
+{
+ size_t len, n, max;
+ char x;
+
+ if (s == NULL) return 0;
+
+ len = strlen(s);
+ if (len == 0) return 0;
+
+ n = 1;
+ x = s[len - 1];
+ if (x > 90) x -= 32;
+ if (x == 'K') n = 1ll << 10;
+ else if (x == 'M') n = 1ll << 20;
+ else if (x == 'G') n = 1ll << 30;
+
+ max = atoll(s) * n;
+ return max;
+}
+
+time_t
+asl_core_str_to_time(char *s, uint32_t def_n)
+{
+ size_t len;
+ time_t n, out;
+ char x;
+
+ if (s == NULL) return 0;
+
+ len = strlen(s);
+ if (len == 0) return 0;
+
+ n = def_n;
+
+ x = s[len - 1];
+ if (x > 90) x -= 32;
+
+ if (x == 'S') n = 1;
+ else if (x == 'M') n = SECONDS_PER_MINUTE;
+ else if (x == 'H') n = SECONDS_PER_HOUR;
+ else if (x == 'D') n = SECONDS_PER_DAY;
+
+ out = atoll(s) * n;
return out;
}
+void
+asl_core_time_to_str(time_t s, char *str, size_t len)
+{
+ char days[32], hms[32];
+ uint32_t d, h, m;
+
+ d = s / SECONDS_PER_DAY;
+ s %= SECONDS_PER_DAY;
+
+ h = s / SECONDS_PER_HOUR;
+ s %= SECONDS_PER_HOUR;
+
+ m = s / SECONDS_PER_MINUTE;
+ s %= SECONDS_PER_MINUTE;
+
+ memset(days, 0, sizeof(days));
+ if (d > 0) snprintf(days, sizeof(days), "%u day%s", d, (d == 1) ? "" : "s");
+
+ memset(hms, 0, sizeof(hms));
+ snprintf(hms, sizeof(hms), "%02u:%02u:%02lld", h, m, (long long) s);
+
+ if ((h + m + s) == 0)
+ {
+ if (d == 0) snprintf(str, len, "0");
+ else snprintf(str, len, "%s", days);
+ return;
+ }
+
+ if (d == 0) snprintf(str, len, "%s", hms);
+ else snprintf(str, len, "%s %s", days, hms);
+}
+
static bool
asl_core_str_match_absolute_or_relative_time(const char *target, time_t *tval, uint32_t *tlen)
{
bool test;
const char *p;
time_t start = 0;
-
+
if (target == NULL) return false;
-
+
/* [+-] */
p = target;
test = asl_core_str_match(p, "+-", 0, 1, MFLAG_INCLUDE, &len);
if (!test) return false;
-
+
if (len == 1)
{
/* relative time */
start = time(NULL);
if (*p == '-') sign = -1;
}
-
+
/* [0-9]+ */
p += len;
test = asl_core_str_match(p, DIGITS, 1, 0, MFLAG_INCLUDE, &len);
if (!test) return false;
val = asl_core_str_to_uint32(p, len);
-
+
/* [shmdw] */
p += len;
test = asl_core_str_match(p, "SsMmHhDdWw", 0, 1, MFLAG_INCLUDE, &len);
if (!test) return false;
-
+
if ((*p == 'M') || (*p == 'm')) val *= SECONDS_PER_MINUTE;
else if ((*p == 'H') || (*p == 'h')) val *= SECONDS_PER_HOUR;
else if ((*p == 'D') || (*p == 'd')) val *= SECONDS_PER_DAY;
else if ((*p == 'W') || (*p == 'w')) val *= SECONDS_PER_WEEK;
-
+
/* matched string must be followed by space, tab, newline (not counted in length) */
p += len;
if (*p != '\0')
test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len);
if (!test) return false;
}
-
+
if (tlen != NULL) *tlen = p - target;
if (tval != NULL) *tval = start + (sign * val);
-
+
return true;
}
if (!strncasecmp(s, "nov", 3)) return 10;
if (!strncasecmp(s, "dec", 3)) return 11;
return -1;
-
+
}
/*
const char *p;
struct tm t;
time_t now;
-
+
if (target == NULL) return false;
memset(&t, 0, sizeof(t));
-
+
/* determine current date */
now = time(NULL);
localtime_r(&now, &t);
y = t.tm_year;
memset(&t, 0, sizeof(t));
t.tm_year = y;
-
+
/* Mth */
p = target;
t.tm_mon = _month_num(p);
len = 3;
if (t.tm_mon == -1) return false;
-
+
/* whitespace */
p += len;
test = asl_core_str_match(p, WHITESPACE, 1, 0, MFLAG_INCLUDE, &len);
if (!test) return false;
-
+
/* [D]D */
p += len;
test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len);
if (!test) return false;
t.tm_mday = asl_core_str_to_uint32(p, len);
if (t.tm_mday > 31) return false;
-
+
/* whitespace */
p += len;
test = asl_core_str_match(p, WHITESPACE, 1, 0, MFLAG_INCLUDE, &len);
if (!test) return false;
-
+
/* [h]h */
p += len;
test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len);
if (!test) return false;
t.tm_hour = asl_core_str_to_uint32(p, len);
if (t.tm_hour > 23) return false;
-
+
/* : */
p += len;
if (*p != ':') return false;
len = 1;
-
+
/* mm */
p += len;
test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
if (!test) return false;
t.tm_min = asl_core_str_to_uint32(p, len);
if (t.tm_min > 59) return false;
-
+
/* : */
p += len;
if (*p != ':') return false;
len = 1;
-
+
/* ss */
p += len;
test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
if (!test) return false;
t.tm_sec = asl_core_str_to_uint32(p, len);
if (t.tm_sec > 59) return false;
-
+
/* matched string must be followed by space, tab, newline (not counted in length) */
p += len;
if (*p != '\0')
test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len);
if (!test) return false;
}
-
+
t.tm_isdst = -1;
-
+
if (tlen != NULL) *tlen = p - target;
if (tval != NULL) *tval = mktime(&t);
-
+
return true;
}
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 (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')
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;
}
const char *p;
struct tm t;
int32_t tzh, tzs, sign = -1;
-
+
if (target == NULL) return false;
memset(&t, 0, sizeof(t));
-
+
/* YYYY */
p = target;
test = asl_core_str_match(p, DIGITS, 4, 4, MFLAG_INCLUDE, &len);
if (!test) return false;
t.tm_year = asl_core_str_to_uint32(p, len) - 1900;
-
+
/* [-] */
p += len;
test = asl_core_str_match_char(p, '-', 0, MFLAG_INCLUDE, &len);
if (!test) return false;
-
+
/* MM */
p += len;
test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
if (t.tm_mon < 1) return false;
if (t.tm_mon > 12) return false;
t.tm_mon -= 1;
-
+
/* [-] */
p += len;
test = asl_core_str_match_char(p, '-', 0, MFLAG_INCLUDE, &len);
if (!test) return false;
-
+
/* DD */
p += len;
test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
if (!test) return false;
t.tm_mday = asl_core_str_to_uint32(p, len);
if (t.tm_mday > 31) return false;
-
+
/* T or t */
p += len;
test = asl_core_str_match(p, "Tt", 1, 1, MFLAG_INCLUDE, &len);
if (!test) return false;
-
+
/* hh */
p += len;
test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
if (!test) return false;
t.tm_hour = asl_core_str_to_uint32(p, len);
if (t.tm_hour > 23) return false;
-
+
/* [:] */
p += len;
test = asl_core_str_match_char(p, ':', 0, MFLAG_INCLUDE, &len);
if (!test) return false;
-
+
/* mm */
p += len;
test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
if (!test) return false;
t.tm_min = asl_core_str_to_uint32(p, len);
if (t.tm_min > 59) return false;
-
+
/* [:] */
p += len;
test = asl_core_str_match_char(p, ':', 0, MFLAG_INCLUDE, &len);
if (!test) return false;
-
+
/* ss */
p += len;
test = asl_core_str_match(p, DIGITS, 2, 2, MFLAG_INCLUDE, &len);
if (!test) return false;
t.tm_sec = asl_core_str_to_uint32(p, len);
if (t.tm_sec > 59) return false;
-
+
p += len;
-
+
/* default to local time if we hit the end of the string */
if ((*p == '\0') || (*p == ' ') || (*p == '\t') || (*p == '\n'))
{
t.tm_isdst = -1;
-
+
if (tlen != NULL) *tlen = p - target;
if (tval != NULL) *tval = mktime(&t);
-
+
return true;
}
-
+
/* Z, z, +, or - */
test = asl_core_str_match(p, "Zz+-", 1, 1, MFLAG_INCLUDE, &len);
if (!test) return false;
-
+
if ((*p == 'Z') || (*p == 'z'))
{
/* matched string must be followed by space, tab, newline (not counted in length) */
test = asl_core_str_match(p, " \t\n", 1, 1, MFLAG_INCLUDE, &len);
if (!test) return false;
}
-
+
if (tlen != NULL) *tlen = p - target;
if (tval != NULL) *tval = timegm(&t);
-
+
return true;
}
-
+
if (*p == '-') sign = 1;
-
+
/* [h]h */
p += len;
test = asl_core_str_match(p, DIGITS, 1, 2, MFLAG_INCLUDE, &len);
if (!test) return false;
tzh = asl_core_str_to_uint32(p, len);
if (tzh > 23) return false;
-
+
/* [:] */
p += len;
test = asl_core_str_match_char(p, ':', 0, MFLAG_INCLUDE, &len);
if (!test) return false;
-
+
/* mm */
p += len;
test = asl_core_str_match(p, DIGITS, 0, 2, MFLAG_INCLUDE, &len);
if (!test) return false;
tzs = asl_core_str_to_uint32(p, len);
if (tzs > 59) return false;
-
+
t.tm_sec += (sign * (tzh * SECONDS_PER_HOUR) + (tzs * SECONDS_PER_MINUTE));
-
+
/* matched string must be followed by space, tab, newline (not counted in length) */
p += len;
if (*p != '\0')
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;
}
{
time_t tval = 0;
uint32_t inlen;
-
+
if (tlen != NULL) *tlen = 0;
if (in == NULL) return -1;
-
+
/*
* Heuristics to determine the string format.
* Warning: this code must be checked and may need to be adjusted if new formats are added.
*/
inlen = strlen(in);
if (inlen == 0) return -1;
-
+
/* leading plus or minus means it must be a relative time */
if ((in[0] == '+') || (in[0] == '-'))
{
if (asl_core_str_match_absolute_or_relative_time(in, &tval, tlen)) return tval;
return -1;
}
-
+
/* leading alphabetic char means it must be ctime() format */
if (((in[0] >= 'a') && (in[0] <= 'z')) || ((in[0] >= 'A') && (in[0] <= 'Z')))
{
if (asl_core_str_match_c_time(in, &tval, tlen)) return tval;
return -1;
}
-
+
/* only absolute, dotted, or iso8601 formats at this point */
-
+
/* one to for chars means it must be absolute */
if (inlen < 5)
{
if (asl_core_str_match_absolute_or_relative_time(in, &tval, tlen)) return tval;
return -1;
}
-
+
/* check for dot */
if (in[4] == '.')
{
if (asl_core_str_match_dotted_time(in, &tval, tlen)) return tval;
return -1;
}
-
+
/* only absolute or iso8601 at this point */
-
+
/* check for absolute first, since that's quicker */
if (asl_core_str_match_absolute_or_relative_time(in, &tval, tlen)) return tval;
-
+
if (asl_core_str_match_iso_8601_time(in, &tval, tlen)) return tval;
-
+
return -1;
}
return ASL_STATUS_OK;
}
+static file_string_t *
+file_string_create(asl_file_t *s)
+{
+ if ((s != NULL) && (s->string_spare != NULL))
+ {
+ file_string_t *out = s->string_spare;
+ s->string_spare = NULL;
+ return out;
+ }
+
+ return (file_string_t *)calloc(1, sizeof(file_string_t));
+}
+
+static void
+file_string_dispose(asl_file_t *s, file_string_t *x)
+{
+ if ((s != NULL) && (s->string_spare == NULL))
+ {
+ s->string_spare = x;
+ memset(s->string_spare, 0, sizeof(file_string_t));
+ }
+ else
+ {
+ free(x);
+ }
+}
+
+
asl_file_t *
asl_file_retain(asl_file_t *s)
{
s->string_list = x;
}
+ free(s->string_spare);
+
if (s->store != NULL) fclose(s->store);
if (s->scratch != NULL) free(s->scratch);
if ((out->last + last_len) > out->file_size) out->last = 0;
}
+ if (out->last != 0)
+ {
+ /* skip type (uint16_t), len (uint32_t), and next (uint64_t) */
+ off = out->last + sizeof(uint16_t) + sizeof (uint32_t) + sizeof(uint64_t);
+ status = asl_file_read_uint64(out, off, &(out->last_mid));
+ if (status != ASL_STATUS_OK)
+ {
+ asl_file_close(out);
+ return status;
+ }
+ }
+
aslstatus = asl_file_read_set_position(out, ASL_FILE_POSITION_LAST);
if (aslstatus != ASL_STATUS_OK)
{
return ASL_STATUS_OK;
}
- /* check the cache */
- hash = asl_core_string_hash(str, len);
+ /* cached strings include trailing nul */
+ len++;
- sp = NULL;
- for (sx = s->string_list; sx != NULL; sx = sx->next)
+ if (len <= CACHE_MAX_STRING_LEN)
{
- if ((hash == sx->hash) && (!strcmp(str, sx->str)))
+ /* check the cache */
+ hash = asl_core_string_hash(str, len);
+
+ sp = NULL;
+ for (sx = s->string_list; sx != NULL; sx = sx->next)
{
- /* Move this string to the head of the list */
- if (sp != NULL)
+ if ((hash == sx->hash) && (!strcmp(str, sx->str)))
{
- sl = s->string_list;
- sp->next = sx->next;
- sx->next = sl;
- s->string_list = sx;
+ /* Move this string to the head of the list */
+ if (sp != NULL)
+ {
+ sl = s->string_list;
+ sp->next = sx->next;
+ sx->next = sl;
+ s->string_list = sx;
+ }
+
+ *out = sx->where;
+ return ASL_STATUS_OK;
}
- *out = sx->where;
- return ASL_STATUS_OK;
+ sp = sx;
}
-
- sp = sx;
}
off = ftello(s->store);
if (i != 1) return ASL_STATUS_WRITE_FAILED;
/* Length (includes trailing nul) */
- x32 = htonl(len + 1);
+ x32 = htonl(len);
i = fwrite(&x32, sizeof(uint32_t), 1, s->store);
if (i != 1) return ASL_STATUS_WRITE_FAILED;
/* String data (nul terminated) */
- i = fwrite(str, len + 1, 1, s->store);
+ i = fwrite(str, len, 1, s->store);
if (i != 1) return ASL_STATUS_WRITE_FAILED;
/* flush data */
fflush(s->store);
- /* create file_string_t and insert into the cache */
- sx = (file_string_t *)calloc(1, offsetof(file_string_t, str) + len + 1);
- if (sx == NULL) return ASL_STATUS_NO_MEMORY;
+ /*
+ * Create file_string_t and insert into the cache, but only if the
+ * string is small. This prevents a huge string from eating memory.
+ * It's unlikely that large strings will be very re-usable.
+ */
+ if (len <= CACHE_MAX_STRING_LEN)
+ {
+ sx = file_string_create(s);
+ if (sx == NULL) return ASL_STATUS_NO_MEMORY;
- sx->where = off;
- sx->hash = hash;
- sx->next = s->string_list;
- memcpy(sx->str, str, len);
+ sx->where = off;
+ sx->hash = hash;
+ sx->next = s->string_list;
- s->string_list = sx;
+ /* includes trailing nul */
+ memcpy(sx->str, str, len);
- if (((s->flags & ASL_FILE_FLAG_UNLIMITED_CACHE) == 0) && (s->string_cache_count == CACHE_SIZE))
- {
- /* drop last (lru) string from cache */
- sp = s->string_list;
- sx = sp->next;
+ s->string_list = sx;
- /* NB CACHE_SIZE must be > 1 */
- while (sx->next != NULL)
+ if (((s->flags & ASL_FILE_FLAG_UNLIMITED_CACHE) == 0) && (s->string_cache_count == CACHE_SIZE))
{
- sp = sx;
- sx = sx->next;
- }
+ /* drop last (lru) string from cache */
+ sp = s->string_list;
+ sx = sp->next;
- sp->next = NULL;
- free(sx);
- }
- else
- {
- s->string_cache_count++;
+ /* NB CACHE_SIZE must be > 1 */
+ while (sx->next != NULL)
+ {
+ sp = sx;
+ sx = sx->next;
+ }
+
+ sp->next = NULL;
+ file_string_dispose(s, sx);
+ }
+ else
+ {
+ s->string_cache_count++;
+ }
}
*out = off;
* Encode an asl_msg_t *as a record structure.
* Creates and caches strings.
*/
+#define KVSTACK_SIZE 128
+
ASL_STATUS
asl_file_save(asl_file_t *s, asl_msg_t *in, uint64_t *mid)
{
uint32_t i, len, x, status;
file_record_t r;
uint64_t k, v;
+ uint64_t kvstack[KVSTACK_SIZE];
+ uint64_t *kvmalloc = NULL;
uint64_t *kvlist;
off_t off;
asl_msg_t *msg;
memset(&r, 0, sizeof(file_record_t));
+ r.mid = UINT64_MAX;
+ if ((mid != NULL ) && (*mid != 0)) r.mid = *mid;
+
r.flags = 0;
r.level = ASL_LEVEL_DEBUG;
r.pid = -1;
r.time = 0;
r.nano = 0;
r.prev = s->prev;
- kvlist = NULL;
+ kvlist = kvstack;
key = NULL;
val = NULL;
status = asl_file_string_encode(s, val, &(r.host));
if (status != ASL_STATUS_OK)
{
- if (kvlist != NULL) free(kvlist);
+ free(kvmalloc);
return status;
}
}
status = asl_file_string_encode(s, val, &(r.sender));
if (status != ASL_STATUS_OK)
{
- if (kvlist != NULL) free(kvlist);
+ free(kvmalloc);
return status;
}
}
status = asl_file_string_encode(s, val, &(r.message));
if (status != ASL_STATUS_OK)
{
- if (kvlist != NULL) free(kvlist);
+ free(kvmalloc);
return status;
}
}
status = asl_file_string_encode(s, val, &(r.facility));
if (status != ASL_STATUS_OK)
{
- if (kvlist != NULL) free(kvlist);
+ free(kvmalloc);
return status;
}
}
status = asl_file_string_encode(s, val, &(r.refproc));
if (status != ASL_STATUS_OK)
{
- if (kvlist != NULL) free(kvlist);
+ free(kvmalloc);
return status;
}
}
status = asl_file_string_encode(s, val, &(r.session));
if (status != ASL_STATUS_OK)
{
- if (kvlist != NULL) free(kvlist);
+ free(kvmalloc);
return status;
}
}
}
else if (!strcmp(key, ASL_KEY_MSG_ID))
{
- if (s->flags & ASL_FILE_FLAG_PRESERVE_MSG_ID) *mid = atoll(val);
+ if (s->flags & ASL_FILE_FLAG_PRESERVE_MSG_ID)
+ {
+ r.mid = atoll(val);
+ if (mid != NULL) *mid = r.mid;
+ }
}
else if (!strcmp(key, ASL_KEY_OPTION))
{
status = asl_file_string_encode(s, key, &k);
if (status != ASL_STATUS_OK)
{
- if (kvlist != NULL) free(kvlist);
+ free(kvmalloc);
return status;
}
status = asl_file_string_encode(s, val, &v);
if (status != ASL_STATUS_OK)
{
- if (kvlist != NULL) free(kvlist);
+ free(kvmalloc);
return status;
}
}
- if (r.kvcount == 0)
+ if (r.kvcount >= KVSTACK_SIZE)
{
- kvlist = (uint64_t *)calloc(2, sizeof(uint64_t));
- }
- else
- {
- kvlist = (uint64_t *)reallocf(kvlist, (r.kvcount + 2) * sizeof(uint64_t));
- }
+ /* out of space for the kvlist on the stack - fall back to malloc */
+ kvmalloc = reallocf(kvmalloc, (r.kvcount + 2) * sizeof(uint64_t));
+ if (kvmalloc == NULL) return ASL_STATUS_NO_MEMORY;
- if (kvlist == NULL)
- {
- return ASL_STATUS_NO_MEMORY;
+ kvlist = kvmalloc;
+
+ if (r.kvcount == KVSTACK_SIZE)
+ {
+ /* copy kvstack to kvmalloc */
+ for (i = 0; i < KVSTACK_SIZE; i++) kvmalloc[i] = kvstack[i];
+ }
}
kvlist[r.kvcount++] = k;
if (buf == NULL) return ASL_STATUS_NO_MEMORY;
- if (*mid != 0)
+ if (r.mid == UINT64_MAX)
{
- r.mid = *mid;
- }
- else
- {
- r.mid = asl_core_new_msg_id(0);
- *mid = r.mid;
+ s->last_mid = s->last_mid + 1;
+ r.mid = s->last_mid;
}
p = buf;
_asl_put_64(r.prev, p);
p += sizeof(uint64_t);
- free(kvlist);
- kvlist = NULL;
+ free(kvmalloc);
/* write record at end of file */
status = fseeko(s->store, 0, SEEK_END);
}
static ASL_STATUS
-asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outlen)
+asl_file_fetch_object(asl_file_t *s, uint16_t fetch_type, uint64_t where, char **out, uint32_t *outlen)
{
char ils[9];
char *p;
*out = NULL;
*outlen = 0;
-
+
inls = 0;
x64 = asl_core_htonq(where);
memcpy(&inls, &x64, 1);
if (inls & 0x80)
{
+ if (fetch_type != ASL_FILE_TYPE_STR) return ASL_STATUS_INVALID_STORE;
+
/* inline string */
inls &= 0x0f;
if (inls > 7) return ASL_STATUS_INVALID_STORE;
return ASL_STATUS_OK;
}
+ if (fetch_type == ASL_FILE_TYPE_STR)
+ {
+ /* check the string cache */
+ file_string_t *sx, *sp;
+
+ sp = NULL;
+ for (sx = s->string_list; sx != NULL; sx = sx->next)
+ {
+ if (sx->where == where)
+ {
+ *out = strdup(sx->str);
+ if (*out == NULL) return ASL_STATUS_NO_MEMORY;
+
+ /* N.B. hash field is used to hold length when reading */
+ *outlen = sx->hash;
+
+ /* Move this string to the head of the list */
+ if (sp != NULL)
+ {
+ file_string_t *sl = s->string_list;
+ sp->next = sx->next;
+ sx->next = sl;
+ s->string_list = sx;
+ }
+
+ return ASL_STATUS_OK;
+ }
+
+ sp = sx;
+ }
+ }
+
off = where;
if ((off + sizeof(uint16_t) + sizeof(uint32_t)) > s->file_size) return ASL_STATUS_READ_FAILED;
/* Type */
status = fread(&type, sizeof(uint16_t), 1, s->store);
if (status != 1) return ASL_STATUS_READ_FAILED;
+ type = ntohs(type);
off += sizeof(uint16_t);
+ if (type != fetch_type) return ASL_STATUS_INVALID_STORE;
+
/* Length */
len = 0;
status = fread(&len, sizeof(uint32_t), 1, s->store);
}
*outlen = len;
+
+ if ((fetch_type == ASL_FILE_TYPE_STR) && (len <= CACHE_MAX_STRING_LEN))
+ {
+ file_string_t *sx = file_string_create(s);
+ if (sx != NULL)
+ {
+ sx->where = where;
+
+ /* N.B. hash field is used to hold length when reading */
+ sx->hash = len;
+ sx->next = s->string_list;
+ memcpy(sx->str, *out, len);
+
+ s->string_list = sx;
+
+ if (((s->flags & ASL_FILE_FLAG_UNLIMITED_CACHE) == 0) && (s->string_cache_count == CACHE_SIZE))
+ {
+ /* drop last (lru) string from cache */
+ file_string_t *sp = s->string_list;
+ sx = sp->next;
+
+ /* NB CACHE_SIZE must be > 1 */
+ while (sx->next != NULL)
+ {
+ sp = sx;
+ sx = sx->next;
+ }
+
+ sp->next = NULL;
+ file_string_dispose(s, sx);
+ }
+ else
+ {
+ s->string_cache_count++;
+ }
+ }
+ }
+
return ASL_STATUS_OK;
}
val = NULL;
len = 0;
status = ASL_STATUS_OK;
- if (out != 0) status = asl_file_fetch_object(s, out, &val, &len);
+ if (out != 0) status = asl_file_fetch_object(s, ASL_FILE_TYPE_STR, out, &val, &len);
if (err != NULL) *err = status;
if ((status == ASL_STATUS_OK) && (val != NULL))
buf = NULL;
buflen = 0;
- status = asl_file_fetch_object(s, where, &buf, &buflen);
+ status = asl_file_fetch_object(s, ASL_FILE_TYPE_MSG, where, &buf, &buflen);
if ((status != ASL_STATUS_OK) || (buf == NULL))
{
s->cursor = 0;
kv = _asl_get_64(p);
p += sizeof(uint64_t);
- status = asl_file_fetch_object(s, kv, &k, &len);
+ status = asl_file_fetch_object(s, ASL_FILE_TYPE_STR, kv, &k, &len);
if (status != ASL_STATUS_OK)
{
asl_msg_release(out);
if (kv != 0)
{
- status = asl_file_fetch_object(s, kv, &v, &len);
+ status = asl_file_fetch_object(s, ASL_FILE_TYPE_STR, kv, &v, &len);
if (status != ASL_STATUS_OK)
{
free(k);
* 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,
* 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 <asl_object.h>
#include <asl_private.h>
#include <asl_core.h>
+#include <asl_client.h>
#include <sys/types.h>
#include <libkern/OSAtomic.h>
#include <asl_msg.h>
#define forever for(;;)
-#define streq(A, B) (strcmp(A, B) == 0)
-#define streq_len(A, B, C) (strncmp(A, B, C) == 0)
-#define strneq(A, B) (strcmp(A, B) != 0)
-#define strcaseeq(A, B) (strcasecmp(A, B) == 0)
-#define strcaseneq(A, B) (strcasecmp(A, B) != 0)
-
#ifndef ASL_QUERY_OP_FALSE
#define ASL_QUERY_OP_FALSE 0
#endif
#pragma mark -
#pragma mark asl_msg
-static asl_msg_t *
-_asl_msg_make_page(void)
+static uint32_t
+_slot_count(asl_msg_t *m)
{
- int i;
- asl_msg_t *out = (asl_msg_t *)calloc(1, sizeof(asl_msg_t));
+ if (m == NULL) return 0;
+ if (m->asl_type == ASL_TYPE_MSG) return ASL_MSG_KVO_MSG_SLOTS;
+ if (m->asl_type == ASL_TYPE_QUERY) return ASL_MSG_KVO_QUERY_SLOTS;
+ return 0;
+}
- if (out == NULL) return NULL;
- for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++)
+static uint16_t
+_get_slot_key(asl_msg_t *m, uint32_t slot)
+{
+ if (m == NULL) return 0;
+
+ if (m->asl_type == ASL_TYPE_MSG)
+ {
+ if (slot < ASL_MSG_KVO_MSG_SLOTS) return m->kvo[slot];
+ return 0;
+ }
+
+ if (m->asl_type == ASL_TYPE_QUERY)
+ {
+ if (slot < ASL_MSG_KVO_QUERY_SLOTS) return m->kvo[slot];
+ return 0;
+ }
+
+ return 0;
+}
+
+
+static void
+_set_slot_key(asl_msg_t *m, uint32_t slot, uint16_t x)
+{
+ if (m == NULL) return;
+
+ if (m->asl_type == ASL_TYPE_MSG)
+ {
+ if (slot < ASL_MSG_KVO_MSG_SLOTS) m->kvo[slot] = x;
+ return;
+ }
+
+ if (m->asl_type == ASL_TYPE_QUERY)
+ {
+ if (slot < ASL_MSG_KVO_QUERY_SLOTS) m->kvo[slot] = x;
+ return;
+ }
+}
+
+
+static uint16_t
+_get_slot_val(asl_msg_t *m, uint32_t slot)
+{
+ if (m == NULL) return 0;
+ if (m->asl_type == ASL_TYPE_MSG)
+ {
+ if (slot < ASL_MSG_KVO_MSG_SLOTS) return m->kvo[slot + ASL_MSG_KVO_MSG_SLOTS];
+ return 0;
+ }
+
+ if (m->asl_type == ASL_TYPE_QUERY)
{
- out->key[i] = ASL_MSG_SLOT_FREE;
- out->val[i] = ASL_MSG_SLOT_FREE;
+ if (slot < ASL_MSG_KVO_QUERY_SLOTS) return m->kvo[slot + ASL_MSG_KVO_QUERY_SLOTS];
+ return 0;
}
+ return 0;
+}
+
+static void
+_set_slot_val(asl_msg_t *m, uint32_t slot, uint16_t x)
+{
+ if (m == NULL) return;
+
+ if (m->asl_type == ASL_TYPE_MSG)
+ {
+ if (slot < ASL_MSG_KVO_MSG_SLOTS) m->kvo[slot + ASL_MSG_KVO_MSG_SLOTS] = x;
+ return;
+ }
+
+ if (m->asl_type == ASL_TYPE_QUERY)
+ {
+ if (slot < ASL_MSG_KVO_QUERY_SLOTS) m->kvo[slot + ASL_MSG_KVO_QUERY_SLOTS] = x;
+ return;
+ }
+}
+
+static uint16_t
+_get_slot_op(asl_msg_t *m, uint32_t slot)
+{
+ if (m == NULL) return 0;
+
+ if (m->asl_type == ASL_TYPE_QUERY)
+ {
+ if (slot < ASL_MSG_KVO_QUERY_SLOTS) return m->kvo[slot + (ASL_MSG_KVO_QUERY_SLOTS * 2)];
+ return 0;
+ }
+
+ return 0;
+}
+
+static void
+_set_slot_op(asl_msg_t *m, uint32_t slot, uint16_t x)
+{
+ if (m == NULL) return;
+
+ if (m->asl_type == ASL_TYPE_QUERY)
+ {
+ if (slot < ASL_MSG_KVO_QUERY_SLOTS) m->kvo[slot + (ASL_MSG_KVO_QUERY_SLOTS * 2)] = x;
+ }
+}
+
+static asl_msg_t *
+_asl_msg_make_page(uint32_t type)
+{
+ uint32_t i, n = 0;
+ asl_msg_t *out = (asl_msg_t *)calloc(1, sizeof(asl_msg_t));
+ if (out == NULL) return NULL;
+
+ if (type == ASL_TYPE_MSG) n = ASL_MSG_KVO_MSG_SLOTS * 2;
+ else if (type == ASL_TYPE_QUERY) n = ASL_MSG_KVO_QUERY_SLOTS * 2;
+
+ for (i = 0; i < n; i++) out->kvo[i] = ASL_MSG_SLOT_FREE;
+
out->mem_size = sizeof(asl_msg_t);
+ out->asl_type = type;
return out;
}
_asl_msg_slot_key(asl_msg_t *page, uint32_t slot)
{
const char *out;
- uint16_t x;
+ uint16_t x, k;
if (page == NULL) return NULL;
- if (slot >= ASL_MSG_PAGE_SLOTS) return NULL;
- if (page->key[slot] == ASL_MSG_SLOT_FREE) return NULL;
- switch (page->key[slot] & ASL_MSG_KV_MASK)
+ if ((page->asl_type == ASL_TYPE_MSG) && (slot >= ASL_MSG_KVO_MSG_SLOTS)) return NULL;
+ else if ((page->asl_type == ASL_TYPE_QUERY) && (slot >= ASL_MSG_KVO_QUERY_SLOTS)) return NULL;
+
+ k = _get_slot_key(page, slot);
+
+ if (k == ASL_MSG_SLOT_FREE) return NULL;
+
+ switch (k & ASL_MSG_KV_MASK)
{
case ASL_MSG_KV_INLINE:
{
- return page->data + page->key[slot];
+ return page->data + k;
}
case ASL_MSG_KV_DICT:
{
- if ((page->key[slot] > ASL_STD_KEY_BASE) && (page->key[slot] <= ASL_STD_KEY_LAST))
+ if ((k > ASL_STD_KEY_BASE) && (k <= ASL_STD_KEY_LAST))
{
- x = page->key[slot] - ASL_STD_KEY_BASE - 1;
+ x = k - ASL_STD_KEY_BASE - 1;
return ASLStandardKey[x];
}
- else if ((page->key[slot] > ASL_MT_KEY_BASE) && (page->key[slot] <= ASL_MT_KEY_LAST))
+ else if ((k > ASL_MT_KEY_BASE) && (k <= ASL_MT_KEY_LAST))
{
- x = page->key[slot] - ASL_MT_KEY_BASE - 1;
+ x = k - ASL_MT_KEY_BASE - 1;
return MTStandardKey[x];
}
}
case ASL_MSG_KV_EXTERN:
{
- x = page->key[slot] & ASL_MSG_OFFSET_MASK;
+ x = k & ASL_MSG_OFFSET_MASK;
memcpy(&out, page->data + x, sizeof(char *));
return out;
}
_asl_msg_slot_val(asl_msg_t *page, uint32_t slot)
{
const char *out;
- uint16_t x, type;
+ uint16_t x, v, type;
if (page == NULL) return NULL;
- if (slot >= ASL_MSG_PAGE_SLOTS) return NULL;
- if (page->val[slot] == ASL_MSG_SLOT_FREE) return NULL;
+ if ((page->asl_type == ASL_TYPE_MSG) && (slot >= ASL_MSG_KVO_MSG_SLOTS)) return NULL;
+ else if ((page->asl_type == ASL_TYPE_QUERY) && (slot >= ASL_MSG_KVO_QUERY_SLOTS)) return NULL;
- type = page->val[slot] & ASL_MSG_KV_MASK;
+ v = _get_slot_val(page, slot);
+
+ if (v == ASL_MSG_SLOT_FREE) return NULL;
+
+ type = v & ASL_MSG_KV_MASK;
if (type == ASL_MSG_KV_INLINE)
{
- return page->data + page->val[slot];
+ return page->data + v;
}
else if (type == ASL_MSG_KV_EXTERN)
{
- x = page->val[slot] & ASL_MSG_OFFSET_MASK;
+ x = v & ASL_MSG_OFFSET_MASK;
memcpy(&out, page->data + x, sizeof(char *));
return out;
}
{
asl_msg_t *out;
- out = _asl_msg_make_page();
+ out = _asl_msg_make_page(type);
if (out == NULL) return NULL;
out->asl_type = type;
static void
_asl_msg_free_page(asl_msg_t *page)
{
- uint32_t i;
+ uint32_t i, mslots;
char *p;
if (page == NULL) return;
- for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++)
+ mslots = _slot_count(page);
+
+ for (i = 0; i < mslots; i++)
{
- if (page->key[i] == ASL_STD_KEY_FREE_NOTE)
+ uint16_t k = _get_slot_key(page, i);
+ uint16_t v = _get_slot_val(page, i);
+
+ if (k == ASL_STD_KEY_FREE_NOTE)
{
const char *x = _asl_msg_slot_val(page, i);
if (x != NULL) notify_post(x);
}
- if ((page->key[i] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ if ((k & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
- memcpy(&p, page->data + (page->key[i] & ASL_MSG_OFFSET_MASK), sizeof(char *));
+ memcpy(&p, page->data + (k & ASL_MSG_OFFSET_MASK), sizeof(char *));
free(p);
}
- if ((page->val[i] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ if ((v & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
- memcpy(&p, page->data + (page->val[i] & ASL_MSG_OFFSET_MASK), sizeof(char *));
+ memcpy(&p, page->data + (v & ASL_MSG_OFFSET_MASK), sizeof(char *));
free(p);
}
}
void
_asl_msg_dump(FILE *f, const char *comment, asl_msg_t *msg)
{
- int i, page1 = 1;
+ uint32_t i, mslots, page1 = 1;
if (f == NULL) return;
if (msg == NULL)
return;
}
+ mslots = _slot_count(msg);
+
while (msg != NULL)
{
if (page1 == 1)
fprintf(f, " mem_size: %llu\n", msg->mem_size);
fprintf(f, " next: %p\n", msg->next);
- for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++)
+ for (i = 0; i < mslots; i++)
{
fprintf(f, " slot[%d]: ", i);
- _asl_msg_dump_kv(f, msg, msg->key[i]);
+ _asl_msg_dump_kv(f, msg, _get_slot_key(msg, i));
fprintf(f, " ");
- _asl_msg_dump_kv(f, msg, msg->val[i]);
- fprintf(f, " 0x%04x\n", msg->op[i]);
+ _asl_msg_dump_kv(f, msg, _get_slot_val(msg, i));
+ if (msg->asl_type == ASL_TYPE_QUERY) fprintf(f, " 0x%04x\n", _get_slot_op(msg, i));
}
msg = msg->next;
static uint32_t
_asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opage)
{
- uint32_t i, len, slot;
+ uint32_t i, len, slot, mslots;
uint16_t kx;
asl_msg_t *page;
const char *kp;
i = 0;
slot = 0;
+ mslots = _slot_count(msg);
+
if (oslot != NULL) *oslot = slot;
page = msg;
forever
{
- if (page->key[slot] != ASL_MSG_SLOT_FREE)
+ if (_get_slot_key(page, slot) != ASL_MSG_SLOT_FREE)
{
if (kx != 0)
{
- if (page->key[slot] == kx) return i;
+ if (_get_slot_key(page, slot) == kx) return i;
}
- else if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_DICT)
+ else if ((_get_slot_key(page, slot) & ASL_MSG_KV_MASK) == ASL_MSG_KV_DICT)
{
- /* page->key[slot] is a dictionary key, but key is not (kx == 0) so skip this slot */
+ /* _get_slot_key(page, slot) is a dictionary key, but key is not (kx == 0) so skip this slot */
}
- else if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ else if ((_get_slot_key(page, slot) & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
- memcpy(&kp, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
+ memcpy(&kp, page->data + (_get_slot_key(page, slot) & ASL_MSG_OFFSET_MASK), sizeof(char *));
if (streq(key, kp)) return i;
}
else
{
- kp = page->data + page->key[slot];
+ kp = page->data + _get_slot_key(page, slot);
if (streq(key, kp)) return i;
}
}
slot++;
if (oslot != NULL) *oslot = slot;
- if (slot >= ASL_MSG_PAGE_SLOTS)
+ if (slot >= mslots)
{
if (page->next == NULL) return IndexNull;
static int
_asl_msg_resolve_index(asl_msg_t *msg, uint32_t n, asl_msg_t **page, uint32_t *slot)
{
- uint32_t i, sx;
+ uint32_t i, sx, mslots;
asl_msg_t *px;
if (msg == NULL) return -1;
*slot = IndexNull;
*page = NULL;
+ mslots = _slot_count(msg);
+
sx = 0;
/* find page */
*page = px;
/* find slot */
- for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++)
+ for (i = 0; i < mslots; i++)
{
- if (px->key[i] != ASL_MSG_SLOT_FREE)
+ if (px->kvo[i] != ASL_MSG_SLOT_FREE)
{
if (sx == n)
{
}
/*
- * asl_msg_fetch: iterate over entries
+ * asl_msg_fetch: iterate over entries
* initial value of n should be 0. Subseqent calls should use the last
* returned value. Returns IndexNull when there are no more entries
* Sets the pointers for the next key, value, and op in the msg.
uint32_t
asl_msg_fetch(asl_msg_t *msg, uint32_t x, const char **keyout, const char **valout, uint16_t *opout)
{
- uint32_t p, xpn, xsn;
+ uint32_t p, xpn, xsn, mslots;
asl_msg_t *page = NULL;
if (msg == NULL) return IndexNull;
+ mslots = _slot_count(msg);
+
xsn = x >> 24;
xpn = x & 0x00ffffff;
if (keyout != NULL) *keyout = _asl_msg_slot_key(page, xsn);
if (valout != NULL) *valout = _asl_msg_slot_val(page, xsn);
- if (opout != NULL) *opout = (uint32_t)(page->op[xsn]);
+ if (opout != NULL) *opout = _get_slot_op(page, xsn);
/* advance to the next slot */
forever
{
xsn++;
- if (xsn >= ASL_MSG_PAGE_SLOTS)
+ if (xsn >= mslots)
{
if (page->next == NULL) return 0xff000000;
xsn = 0;
xpn++;
}
- if (page->key[xsn] != ASL_MSG_SLOT_FREE) return ((xsn << 24) | xpn);
+ if (page->kvo[xsn] != ASL_MSG_SLOT_FREE) return ((xsn << 24) | xpn);
}
return IndexNull;
if (i == IndexNull) return -1;
if (valout != NULL) *valout = _asl_msg_slot_val(page, slot);
- if (opout != NULL) *opout = (uint32_t)(page->op[slot]);
+ if (opout != NULL) *opout = _get_slot_op(page, slot);
return 0;
}
const char *
asl_msg_key(asl_msg_t *msg, uint32_t n)
{
- uint32_t slot, i;
+ uint32_t slot, i, mslots;
asl_msg_t *page;
if (msg == NULL) return NULL;
+ mslots = _slot_count(msg);
+
i = 0;
for (page = msg; page != NULL; page = page->next)
{
- for (slot = 0; slot < ASL_MSG_PAGE_SLOTS; slot++)
+ for (slot = 0; slot < mslots; slot++)
{
- if (page->key[slot] != ASL_MSG_SLOT_FREE)
+ if (_get_slot_key(page, slot) != ASL_MSG_SLOT_FREE)
{
if (i == n) return _asl_msg_slot_key(page, slot);
i++;
static int
_asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
{
- uint32_t slot, keylen, vallen, total;
+ uint32_t slot, keylen, vallen, total, mslots;
uint64_t klen, vlen;
- uint16_t kx;
+ uint16_t kx, k, v, o;
asl_msg_t *page, *last;
char *extkey, *extval;
if (msg == NULL) return -1;
if (key == NULL) return -1;
+ mslots = _slot_count(msg);
+
+ o = op;
extkey = NULL;
extval = NULL;
if (total <= (ASL_MSG_PAGE_DATA_SIZE - page->data_size))
{
/* check for a free slot */
- for (slot = 0; (slot < ASL_MSG_PAGE_SLOTS) && (page->key[slot] != ASL_MSG_SLOT_FREE); slot++);
- if (slot < ASL_MSG_PAGE_SLOTS) break;
+ for (slot = 0; (slot < mslots) && (_get_slot_key(page, slot) != ASL_MSG_SLOT_FREE); slot++);
+ if (slot < mslots) break;
}
}
if (page == NULL)
{
/* allocate a new page and attach it */
- page = _asl_msg_make_page();
+ page = _asl_msg_make_page(msg->asl_type);
if (page == NULL)
{
if (extkey != NULL) free(extkey);
/* copy key or external key pointer into page data */
if (kx != 0)
{
- page->key[slot] = kx;
+ k = kx;
}
else if (extkey == NULL)
{
- page->key[slot] = page->data_size;
+ k = page->data_size;
memcpy(page->data + page->data_size, key, keylen);
}
else
{
- page->key[slot] = page->data_size | ASL_MSG_KV_EXTERN;
+ k = page->data_size | ASL_MSG_KV_EXTERN;
memcpy(page->data + page->data_size, &extkey, keylen);
page->mem_size += klen;
}
+ _set_slot_key(page, slot, k);
page->data_size += keylen;
/* copy val or external val pointer into page data */
- page->val[slot] = ASL_MSG_SLOT_FREE;
+
+ v = ASL_MSG_SLOT_FREE;
if (val != NULL)
{
if (extval == NULL)
{
- page->val[slot] = page->data_size;
+ v = page->data_size;
memcpy(page->data + page->data_size, val, vallen);
}
else
{
- page->val[slot] = page->data_size | ASL_MSG_KV_EXTERN;
+ v = page->data_size | ASL_MSG_KV_EXTERN;
memcpy(page->data + page->data_size, &extval, vallen);
page->mem_size += vlen;
}
+ _set_slot_val(page, slot, v);
page->data_size += vallen;
}
/* set op */
- page->op[slot] = (uint16_t)op;
+ _set_slot_op(page, slot, o);
/* update page count */
page->count++;
static int
_asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
{
- uint32_t i, slot, newexternal;
+ uint32_t i, slot, mslots, newexternal;
asl_msg_t *page;
uint32_t intvallen, extvallen, newvallen;
char *intval, *extval, *newval;
+ uint16_t k, v, o;
if (msg == NULL) return -1;
if (key == NULL) return -1;
+ mslots = _slot_count(msg);
+
slot = IndexNull;
page = NULL;
+ o = op;
+
if ((msg->asl_type == ASL_TYPE_QUERY) || (IndexNull == _asl_msg_index(msg, key, &slot, &page)))
{
/* add key */
extval = NULL;
extvallen = 0;
- if (page->val[slot] != ASL_MSG_SLOT_FREE)
+ v = _get_slot_val(page, slot);
+
+ if (v != ASL_MSG_SLOT_FREE)
{
- if ((page->val[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ if ((v & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
- i = page->val[slot] & ASL_MSG_OFFSET_MASK;
+ i = v & ASL_MSG_OFFSET_MASK;
memcpy(&extval, page->data + i, sizeof(char *));
extvallen = sizeof(char *);
}
else
{
- intval = page->data + page->val[slot];
+ intval = page->data + v;
intvallen = strlen(intval) + 1;
}
}
free(extval);
}
- page->val[slot] = ASL_MSG_SLOT_FREE;
- if (op != IndexNull) page->op[slot] = (uint16_t)op;
+ _set_slot_val(page, slot, ASL_MSG_SLOT_FREE);
+ if (op != IndexNull) _set_slot_op(page, slot, o);
return 0;
}
/* trivial case - internal val doesn't change */
if ((intval != NULL) && (streq(val, intval)))
{
- if (op != IndexNull) page->op[slot] = (uint16_t)op;
+ if (op != IndexNull) _set_slot_op(page, slot, o);
return 0;
}
/* trivial case - external val doesn't change */
if ((extval != NULL) && (streq(val, extval)))
{
- if (op != IndexNull) page->op[slot] = (uint16_t)op;
+ if (op != IndexNull) _set_slot_op(page, slot, o);
return 0;
}
/*
* special case: we generally don't compress out holes in the data
* space, but if this is the last string in the currently used data space
- * we can just back up the data_size and reset page->val[slot]
+ * we can just back up the data_size and reset page->val[slot] (a.k.a. page->kvo[slot + mslots])
*/
- i = page->val[slot] & ASL_MSG_OFFSET_MASK;
+ i = v & ASL_MSG_OFFSET_MASK;
if ((intval != NULL) && ((i + intvallen) == page->data_size))
{
- page->val[slot] = ASL_MSG_SLOT_FREE;
+ _set_slot_val(page, slot, ASL_MSG_SLOT_FREE);
page->data_size -= intvallen;
intval = NULL;
intvallen = 0;
}
else if ((extval != NULL) && ((i + extvallen) == page->data_size))
{
- page->val[slot] = ASL_MSG_SLOT_FREE;
+ _set_slot_val(page, slot, ASL_MSG_SLOT_FREE);
page->data_size -= extvallen;
page->mem_size -= (strlen(extval) + 1);
free(extval);
extval = NULL;
/* we can re-use the space of the old value */
- i = page->val[slot] & ASL_MSG_OFFSET_MASK;
+ i = v & ASL_MSG_OFFSET_MASK;
if (newexternal == 1)
{
if (newval == NULL) return -1;
page->mem_size += (strlen(newval) + 1);
- page->val[slot] = i | ASL_MSG_KV_EXTERN;
+ _set_slot_val(page, slot, i | ASL_MSG_KV_EXTERN);
memcpy(page->data + i, &newval, sizeof(char *));
}
else
{
/* new internal value */
- page->val[slot] = i;
+ _set_slot_val(page, slot, i);
memcpy(page->data + i, val, newvallen);
}
- if (op != IndexNull) page->op[slot] = (uint16_t)op;
+ if (op != IndexNull) _set_slot_op(page, slot, o);
return 0;
}
if (newval == NULL) return -1;
page->mem_size += (strlen(newval) + 1);
- page->val[slot] = i | ASL_MSG_KV_EXTERN;
+ _set_slot_val(page, slot, i | ASL_MSG_KV_EXTERN);
memcpy(page->data + i, &newval, sizeof(char *));
}
else
{
/* new internal value */
- page->val[slot] = i;
+ _set_slot_val(page, slot, i);
memcpy(page->data + i, val, newvallen);
}
- if (op != IndexNull) page->op[slot] = (uint16_t)op;
+ if (op != IndexNull) _set_slot_op(page, slot, o);
return 0;
}
/* no room on this page - free up existing entry and treat this as a new entry */
- if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ if ((k & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
- memcpy(&extval, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
+ memcpy(&extval, page->data + (k & ASL_MSG_OFFSET_MASK), sizeof(char *));
page->mem_size -= (strlen(extval) + 1);
free(extval);
}
- page->key[slot] = ASL_MSG_SLOT_FREE;
- page->val[slot] = ASL_MSG_SLOT_FREE;
- page->op[slot] = 0;
+ _set_slot_key(page, slot, ASL_MSG_SLOT_FREE);
+ _set_slot_val(page, slot, ASL_MSG_SLOT_FREE);
+ _set_slot_op(page, slot, 0);
return _asl_msg_new_key_val_op(msg, key, val, op);
}
uint32_t i, len;
int status;
+ if (msg == NULL) return -1;
+ if (key == NULL) return -1;
+
/* Special case handling */
special = NULL;
_asl_msg_unset_page_slot(asl_msg_t *page, uint32_t slot)
{
char *ext;
+ uint16_t k, v;
if (page == NULL) return;
- if (slot >= ASL_MSG_PAGE_SLOTS) return;
- if (page->key[slot] == ASL_MSG_SLOT_FREE) return;
- if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ if (slot >= _slot_count(page)) return;
+
+ k = _get_slot_key(page, slot);
+ v = _get_slot_val(page, slot);
+
+ if (k == ASL_MSG_SLOT_FREE) return;
+
+ if ((k & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
- memcpy(&ext, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
+ memcpy(&ext, page->data + (k & ASL_MSG_OFFSET_MASK), sizeof(char *));
page->mem_size -= (strlen(ext) + 1);
free(ext);
}
- if ((page->val[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ if ((v & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
- memcpy(&ext, page->data + (page->val[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
+ memcpy(&ext, page->data + (v & ASL_MSG_OFFSET_MASK), sizeof(char *));
page->mem_size -= (strlen(ext) + 1);
free(ext);
}
- page->key[slot] = ASL_MSG_SLOT_FREE;
- page->val[slot] = ASL_MSG_SLOT_FREE;
- page->op[slot] = 0;
+ _set_slot_key(page, slot, ASL_MSG_SLOT_FREE);
+ _set_slot_val(page, slot, ASL_MSG_SLOT_FREE);
+ _set_slot_op(page, slot, 0);
page->count--;
}
off %= 3600;
zm = off / 60;
- if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02ld", neg ? '-' : '+', zh);
- else snprintf(zstr, sizeof(zstr), "%c%02ld:%02ld", neg ? '-' : '+', zh, zm);
+ if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02lld", neg ? '-' : '+', (long long) zh);
+ else snprintf(zstr, sizeof(zstr), "%c%02lld:%02lld", neg ? '-' : '+', (long long) zh, (long long) zm);
asprintf(&out, "%d-%02d-%02d%c%02d:%02d:%02d%s%s", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, sep, stm.tm_hour, stm.tm_min, stm.tm_sec, nanobuf, zstr);
return out;
off %= 3600;
zm = off / 60;
- if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02ld", neg ? '-' : '+', zh);
- else snprintf(zstr, sizeof(zstr), "%c%02ld:%02ld", neg ? '-' : '+', zh, zm);
+ if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02lld", neg ? '-' : '+', (long long) zh);
+ else snprintf(zstr, sizeof(zstr), "%c%02lld:%02lld", neg ? '-' : '+', (long long) zh, (long long) zm);
asprintf(&out, "%d%02d%02dT%02d%02d%02d%s%s", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec, nanobuf, zstr);
return out;
if ((!strcasecmp(fmt, "sec")) || (!strcasecmp(fmt, "raw")))
{
- asprintf(&out, "%lu%s", tick, nanobuf);
+ asprintf(&out, "%llu%s", (unsigned long long) tick, nanobuf);
return out;
}
off = (zh * 3600) + (zm * 60);
if (neg) off *= -1;
- if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02ld", neg ? '-' : '+', zh);
- else snprintf(zstr, sizeof(zstr), "%c%02ld:%02ld", neg ? '-' : '+', zh, zm);
+ if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02lld", neg ? '-' : '+', (long long) zh);
+ else snprintf(zstr, sizeof(zstr), "%c%02lld:%02lld", neg ? '-' : '+', (long long) zh, (long long) zm);
}
return out;
}
+#pragma mark -
+#pragma mark xpc conversion
+
+static void
+_asl_msg_to_xpc(asl_msg_t *msg, xpc_object_t dict)
+{
+ uint32_t x, len;
+ const char *key, *val, *nano;
+ uint16_t kx;
+
+ if (msg == NULL) return;
+ if (dict == NULL) return;
+
+ nano = NULL;
+ asl_msg_lookup(msg, ASL_KEY_TIME_NSEC, &nano, NULL);
+
+ for (x = asl_msg_fetch(msg, 0, &key, &val, NULL); x != IndexNull; x = asl_msg_fetch(msg, x, &key, &val, NULL))
+ {
+ if (key == NULL) continue;
+
+ len = strlen(key);
+ kx = _asl_msg_std_key(key, len);
+
+ if (val == NULL)
+ {
+ xpc_object_t obj = xpc_null_create();
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
+ }
+ else if (kx == 0)
+ {
+ if (streq(key, ASL_KEY_SENDER_MACH_UUID))
+ {
+ uuid_t v;
+ if (uuid_parse(val, v) == 0)
+ {
+ xpc_object_t obj = xpc_uuid_create(v);
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
+ }
+ }
+ else
+ {
+ xpc_object_t obj = xpc_string_create(val);
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
+ }
+ }
+ else if (kx == ASL_STD_KEY_TIME)
+ {
+ uint64_t t = NSEC_PER_SEC * asl_core_parse_time(val, NULL);
+ if (nano != NULL) t += atoll(nano);
+ xpc_object_t obj = xpc_date_create(t);
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
+ }
+ else if (kx == ASL_STD_KEY_NANO)
+ {
+ /* handled with ASL_STD_KEY_TIME */
+ }
+ else if ((kx == ASL_STD_KEY_PID) || (kx == ASL_STD_KEY_REF_PID))
+ {
+ int64_t v = atoll(val);
+ xpc_object_t obj = xpc_int64_create(v);
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
+ }
+ else if ((kx == ASL_STD_KEY_UID) || (kx == ASL_STD_KEY_GID))
+ {
+ int64_t v = atoll(val);
+ xpc_object_t obj = xpc_int64_create(v);
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
+ }
+ else if (kx == ASL_STD_KEY_LEVEL)
+ {
+ int64_t v = atoll(val);
+ xpc_object_t obj = xpc_int64_create(v);
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
+ }
+ else if ((kx == ASL_STD_KEY_READ_UID) || (kx == ASL_STD_KEY_READ_GID))
+ {
+ int64_t v = atoll(val);
+ xpc_object_t obj = xpc_int64_create(v);
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
+ }
+ else if (kx == ASL_STD_KEY_MSG_ID)
+ {
+ /* ignore */
+ }
+ else
+ {
+ xpc_object_t obj = xpc_string_create(val);
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
+ }
+ }
+}
+
+void
+_asl_log_args_to_xpc(asl_object_t client, asl_object_t msg, xpc_object_t dict)
+{
+ _asl_msg_to_xpc(asl_client_kvdict((asl_client_t *)client), dict);
+ _asl_msg_to_xpc((asl_msg_t *)msg, dict);
+}
+
#pragma mark -
#pragma mark asl_object support
if (key != NULL) *key = _asl_msg_slot_key(page, slot);
if (val != NULL) *val = _asl_msg_slot_val(page, slot);
- if (op != NULL) *op = page->op[slot];
+ if (op != NULL) *op = _get_slot_op(page, slot);
+
return 0;
}
void
asl_object_append(asl_object_private_t *obj, asl_object_private_t *newobj)
{
- int type = ASL_TYPE_CLIENT;
+ uint32_t type = ASL_TYPE_CLIENT;
if (obj != NULL) type = obj->asl_type;
if (type >= ASL_TYPE_COUNT) return;
asl_store_t *out;
struct stat sb;
uint32_t i, flags;
- char *path;
+ char path[MAXPATHLEN];
FILE *sd;
uint64_t last_id;
time_t start;
if (basedir == NULL) basedir = PATH_ASL_STORE;
memset(&sb, 0, sizeof(struct stat));
- if (stat(basedir, &sb) != 0) return ASL_STATUS_INVALID_STORE;
- if (!S_ISDIR(sb.st_mode)) return ASL_STATUS_INVALID_STORE;
-
- path = NULL;
- asprintf(&path, "%s/%s", basedir, FILE_ASL_STORE_DATA);
- if (path == NULL) return ASL_STATUS_NO_MEMORY;
+ if (stat(basedir, &sb) != 0)
+ {
+ if (errno != ENOENT) return ASL_STATUS_INVALID_STORE;
+ if (mkdir(basedir, 0755) != 0) return ASL_STATUS_WRITE_FAILED;
+ }
+ else
+ {
+ if (!S_ISDIR(sb.st_mode)) return ASL_STATUS_INVALID_STORE;
+ }
+
+ snprintf(path, sizeof(path), "%s/%s", basedir, FILE_ASL_STORE_DATA);
sd = NULL;
memset(&sb, 0, sizeof(struct stat));
if (stat(path, &sb) != 0)
{
- if (errno != ENOENT)
- {
- free(path);
- return ASL_STATUS_FAILED;
- }
+ if (errno != ENOENT) return ASL_STATUS_FAILED;
sd = fopen(path, "w+");
- free(path);
if (sd == NULL) return ASL_STATUS_FAILED;
else
{
sd = fopen(path, "r+");
- free(path);
if (sd == NULL) return ASL_STATUS_FAILED;
if (fread(&last_id, sizeof(uint64_t), 1, sd) != 1)
static char *
asl_store_make_ug_path(const char *dir, const char *base, const char *ext, uid_t ruid, gid_t rgid, uid_t *u, gid_t *g, mode_t *m)
{
- char *path = NULL;
+ char *path = NULL;
*u = 0;
*g = 0;
{
struct tm ctm;
time_t msg_time, now, bb;
- char *path, *tmp_path, *tstring, *scratch;
+ char *path;
+ char tstring[128], tmp_path[MAXPATHLEN];
const char *val;
uid_t ruid;
gid_t rgid;
if (localtime_r((const time_t *)&msg_time, &ctm) == NULL) return ASL_STATUS_FAILED;
- tstring = NULL;
if (bb == 1)
{
/*
bb = mktime(&ctm);
if (localtime_r((const time_t *)&bb, &ctm) == NULL) return ASL_STATUS_FAILED;
- asprintf(&tstring, "BB.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
+ snprintf(tstring, sizeof(tstring), "BB.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
}
else
{
- asprintf(&tstring, "%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
+ snprintf(tstring, sizeof(tstring), "%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
}
- if (tstring == NULL) return ASL_STATUS_NO_MEMORY;
-
status = asl_store_file_open_write(s, tstring, ruid, rgid, bb, &f, now, check_cache);
- free(tstring);
- tstring = NULL;
-
if (status != ASL_STATUS_OK) return status;
status = asl_file_save(f, msg, &xid);
if (path != NULL)
{
- tmp_path = NULL;
-
len = strlen(path);
if ((len >= 4) && (!strcmp(path + len - 4, ".asl")))
{
/* rename xxxxxxx.asl to xxxxxxx.timestamp.asl */
- scratch = strdup(path);
- if (scratch != NULL)
- {
- scratch[len - 4] = '\0';
- asprintf(&tmp_path, "%s.%llu.asl", scratch, ftime);
- free(scratch);
-
- }
+ char scratch[MAXPATHLEN];
+ snprintf(scratch, sizeof(scratch), "%s", path);
+ scratch[len - 4] = '\0';
+ snprintf(tmp_path, sizeof(tmp_path), "%s.%llu.asl", scratch, ftime);
}
else
{
/* append timestamp */
- asprintf(&tmp_path, "%s.%llu", path, ftime);
+ snprintf(tmp_path, sizeof(tmp_path), "%s.%llu", path, ftime);
}
- if (tmp_path == NULL)
- {
- status = ASL_STATUS_NO_MEMORY;
- }
- else
- {
- if (rename(path, tmp_path) != 0) status = ASL_STATUS_FAILED;
- free(tmp_path);
- }
+ if (rename(path, tmp_path) != 0) status = ASL_STATUS_FAILED;
free(path);
}
static ASL_STATUS
asl_store_mkdir(asl_store_t *s, const char *dir, mode_t m)
{
- char *tstring = NULL;
+ char tstring[MAXPATHLEN];
int status;
struct stat sb;
- asprintf(&tstring, "%s/%s", s->base_dir, dir);
- if (tstring == NULL) return ASL_STATUS_NO_MEMORY;
+ snprintf(tstring, sizeof(tstring), "%s/%s", s->base_dir, dir);
memset(&sb, 0, sizeof(struct stat));
status = stat(tstring, &sb);
if (status == 0)
{
/* must be a directory */
- if (!S_ISDIR(sb.st_mode))
- {
- free(tstring);
- return ASL_STATUS_INVALID_STORE;
- }
+ if (!S_ISDIR(sb.st_mode)) return ASL_STATUS_INVALID_STORE;
}
else
{
if (errno == ENOENT)
{
/* doesn't exist - create it */
- if (mkdir(tstring, m) != 0)
- {
- free(tstring);
- return ASL_STATUS_WRITE_FAILED;
- }
+ if (mkdir(tstring, m) != 0) return ASL_STATUS_WRITE_FAILED;
}
else
{
/* stat failed for some other reason */
- free(tstring);
return ASL_STATUS_FAILED;
}
}
- free(tstring);
return ASL_STATUS_OK;
}
{
struct tm ctm;
time_t msg_time, bb;
- char *path, *dir, *tstring;
+ char *path;
+ char tstring[128], dir[128];
const char *val;
uid_t ruid, u;
gid_t rgid, g;
if (localtime_r((const time_t *)&msg_time, &ctm) == NULL) return ASL_STATUS_FAILED;
- dir = NULL;
if (bb == 1)
{
/*
bb = mktime(&ctm);
if (localtime_r((const time_t *)&bb, &ctm) == NULL) return ASL_STATUS_FAILED;
- asprintf(&dir, "BB.AUX.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
+ snprintf(dir, sizeof(dir), "BB.AUX.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
}
else
{
- asprintf(&dir, "AUX.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
+ snprintf(dir, sizeof(dir), "AUX.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
}
- if (dir == NULL) return ASL_STATUS_NO_MEMORY;
-
status = asl_store_mkdir(s, dir, 0755);
- if (status != ASL_STATUS_OK)
- {
- free(dir);
- return status;
- }
+ if (status != ASL_STATUS_OK) return status;
fid = s->next_id;
s->next_id++;
- tstring = NULL;
- asprintf(&tstring, "%s/%llu", dir, fid);
- free(dir);
- if (tstring == NULL) return ASL_STATUS_NO_MEMORY;
+ snprintf(tstring, sizeof(tstring), "%s/%llu", dir, fid);
u = 0;
g = 0;
m = 0644;
path = asl_store_make_ug_path(s->base_dir, tstring, NULL, ruid, rgid, &u, &g, &m);
- free(tstring);
if (path == NULL) return ASL_STATUS_NO_MEMORY;
fd = asl_file_create(path, u, g, m);
struct dirent *dent;
uint32_t status;
asl_file_t *f;
- char *path;
+ char path[MAXPATHLEN];
asl_file_list_t *files;
asl_msg_list_t *res;
{
if (dent->d_name[0] == '.') continue;
- path = NULL;
- asprintf(&path, "%s/%s", s->base_dir, dent->d_name);
+ snprintf(path, sizeof(path), "%s/%s", s->base_dir, dent->d_name);
/* NB asl_file_open_read will fail if path is NULL, if the file is not an ASL store file, or if it isn't readable */
status = asl_file_open_read(path, &f);
- if (path != NULL) free(path);
if ((status != ASL_STATUS_OK) || (f == NULL)) continue;
files = asl_file_list_add(files, f);
struct dirent *dent;
uint32_t status;
asl_file_t *f;
- char *path;
+ char path[MAXPATHLEN];
asl_file_list_t *files;
if (s == NULL) return ASL_STATUS_INVALID_STORE;
{
if (dent->d_name[0] == '.') continue;
- path = NULL;
- asprintf(&path, "%s/%s", s->base_dir, dent->d_name);
+ snprintf(path, sizeof(path), "%s/%s", s->base_dir, dent->d_name);
/*
* NB asl_file_open_read will fail if path is NULL,
* We expect that.
*/
status = asl_file_open_read(path, &f);
- if (path != NULL) free(path);
if ((status != ASL_STATUS_OK) || (f == NULL)) continue;
files = asl_file_list_add(files, f);
asl_msg_list_t *out = NULL;
asl_msg_list_t *ql = NULL;
uint64_t last;
- uint32_t status = ASL_STATUS_FAILED;
if (query == NULL)
{
asl_msg_list_release(ql);
}
- if (status != ASL_STATUS_OK) return NULL;
return (asl_object_private_t *)out;
}
/*
- * Copyright (c) 2007-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2015 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#define ASL_STRING_QUANTUM 256
static const char *cvis_7_13 = "abtnvfr";
+/* Forward */
+asl_string_t *asl_string_append_no_encoding_len(asl_string_t *str, const char *app, size_t copylen);
+
asl_string_t *
asl_string_new(uint32_t encoding)
{
str->bufsize = 0;
str->cursor = 0;
- if (encoding & ASL_STRING_LEN) asl_string_append_no_encoding(str, " 0 ");
+ if (encoding & ASL_STRING_LEN) asl_string_append_no_encoding_len(str, " 0 ", 11);
return str;
}
char *out;
if (str == NULL) return NULL;
+ if (str->encoding & ASL_STRING_LEN)
+ {
+ char tmp[11];
+ snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10);
+ memcpy(str->buf, tmp, 10);
+ }
+
if (OSAtomicDecrement32Barrier(&(str->refcount)) != 0)
{
/* string is still retained - copy buf */
if (str->bufsize == 0) return NULL;
vm_address_t new = 0;
- kern_return_t kstatus = vm_allocate(mach_task_self(), &new, str->bufsize, TRUE);
+ kern_return_t kstatus = vm_allocate(mach_task_self(), &new, str->bufsize, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
if (kstatus != KERN_SUCCESS) return NULL;
memcpy((void *)new, str->buf, str->bufsize);
asl_string_bytes(asl_string_t *str)
{
if (str == NULL) return NULL;
+
+ if (str->encoding & ASL_STRING_LEN)
+ {
+ char tmp[11];
+ snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10);
+ memcpy(str->buf, tmp, 10);
+ }
+
return str->buf;
}
kern_return_t kstatus;
vm_address_t new = 0;
- kstatus = vm_allocate(mach_task_self(), &new, newlen, TRUE);
+ kstatus = vm_allocate(mach_task_self(), &new, newlen, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
if (kstatus != KERN_SUCCESS)
{
new = 0;
len = 1;
if (str->bufsize == 0) len++;
-
if (_asl_string_grow(str, len) < 0) return str;
str->buf[str->cursor] = c;
str->cursor++;
str->buf[str->cursor] = '\0';
- if (str->encoding & ASL_STRING_LEN)
- {
- char tmp[11];
- snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10);
- memcpy(str->buf, tmp, 10);
- }
-
return str;
}
asl_string_t *
-asl_string_append_no_encoding(asl_string_t *str, const char *app)
+asl_string_append_no_encoding_len(asl_string_t *str, const char *app, size_t copylen)
{
size_t len, applen;
if (str == NULL) return NULL;
if (app == NULL) return str;
- applen = strlen(app);
+ applen = copylen;
+ if (applen == 0) applen = strlen(app);
+
len = applen;
if (str->bufsize == 0) len++;
str->cursor += applen;
str->buf[str->cursor] = '\0';
- if (str->encoding & ASL_STRING_LEN)
- {
- char tmp[11];
- snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10);
- memcpy(str->buf, tmp, 10);
- }
-
return str;
}
+asl_string_t *
+asl_string_append_no_encoding(asl_string_t *str, const char *app)
+{
+ return asl_string_append_no_encoding_len(str, app, 0);
+}
+
static asl_string_t *
asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
{
- uint8_t x;
- const char *p;
+ uint8_t x, y, z;
+ const uint8_t *s, *p;
+ size_t copylen;
if (str == NULL) return NULL;
if (app == NULL) return str;
{
case ASL_ENCODE_NONE:
{
- return asl_string_append_no_encoding(str, app);
+ return asl_string_append_no_encoding_len(str, app, 0);
}
case ASL_ENCODE_SAFE:
{
/* minor encoding to reduce the likelyhood of spoof attacks */
const char *p;
+ s = NULL;
+ copylen = 0;
+
for (p = app; *p != '\0'; p++)
{
- if ((*p == 10) || (*p == 13))
+ x = p[0];
+ y = 0;
+ z = 0;
+
+ if (x != 0) y = p[1];
+ if (y != 0) z = p[2];
+
+ if ((x == 10) || (x == 13))
{
- asl_string_append_no_encoding(str, "\n\t");
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
+ asl_string_append_no_encoding_len(str, "\n\t", 2);
}
- else if (*p == 8)
+ else if (x == 8)
{
- asl_string_append_no_encoding(str, "^H");
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
+ asl_string_append_no_encoding_len(str, "^H", 2);
+ }
+ else if ((x == 0xc2) && (y == 0x85))
+ {
+ p++;
+
+ /* next line - format like newline */
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
+ asl_string_append_no_encoding_len(str, "\n\t", 2);
+ }
+ else if ((x == 0xe2) && (y == 0x80) && ((z == 0xa8) || (z == 0xa9)))
+ {
+ p += 3;
+
+ /* line separator or paragraph separator - format like newline */
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
+ asl_string_append_no_encoding_len(str, "\n\t", 2);
}
else
{
- asl_string_append_char_no_encoding(str, *p);
+ if (s == NULL) s = p;
+ copylen++;
}
}
+ if (copylen > 0) asl_string_append_no_encoding_len(str, s, copylen);
+
return str;
}
case ASL_ENCODE_ASL:
{
+ s = NULL;
+ copylen = 0;
+
for (p = app; *p != '\0'; p++)
{
int meta = 0;
/* except meta-space, which is \240 */
if (x == 160)
{
- asl_string_append_no_encoding(str, "\\240");
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
+ asl_string_append_no_encoding_len(str, "\\240", 4);
continue;
}
- asl_string_append_no_encoding(str, "\\M");
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
+ asl_string_append_no_encoding_len(str, "\\M", 2);
x &= 0x7f;
meta = 1;
}
{
if (encode_space == 0)
{
- asl_string_append_char_no_encoding(str, ' ');
+ if (s == NULL) s = p;
+ copylen++;
continue;
}
- asl_string_append_no_encoding(str, "\\s");
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
+ asl_string_append_no_encoding_len(str, "\\s", 2);
continue;
}
/* \ is escaped */
if ((meta == 0) && (x == 92))
{
- asl_string_append_no_encoding(str, "\\\\");
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
+ asl_string_append_no_encoding_len(str, "\\\\", 2);
continue;
}
/* [ and ] are escaped in ASL encoding */
if ((str->encoding & ASL_ENCODE_ASL) && (meta == 0) && ((*p == 91) || (*p == 93)))
{
- if (*p == '[') asl_string_append_no_encoding(str, "\\[");
- else asl_string_append_no_encoding(str, "\\]");
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
+ if (*p == '[') asl_string_append_no_encoding_len(str, "\\[", 2);
+ else asl_string_append_no_encoding_len(str, "\\]", 2);
continue;
}
{
if (meta == 0)
{
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
asl_string_append_char_no_encoding(str, '\\');
}
- asl_string_append_no_encoding(str, "^?");
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
+ asl_string_append_no_encoding_len(str, "^?", 2);
continue;
}
{
if (meta == 1)
{
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
asl_string_append_char_no_encoding(str, '-');
+ asl_string_append_char_no_encoding(str, x);
+ continue;
}
- asl_string_append_char_no_encoding(str, x);
+ if (s == NULL) s = p;
+ copylen++;
+
continue;
}
/* non-meta BEL, BS, HT, NL, VT, NP, CR (7-13) are \a, \b, \t, \n, \v, \f, and \r */
if ((meta == 0) && (x >= 7) && (x <= 13))
{
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
asl_string_append_char_no_encoding(str, '\\');
asl_string_append_char_no_encoding(str, cvis_7_13[x - 7]);
continue;
{
if (meta == 0)
{
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
asl_string_append_char_no_encoding(str, '\\');
}
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
asl_string_append_char_no_encoding(str, '^');
asl_string_append_char_no_encoding(str, 64 + x);
continue;
}
- asl_string_append_char_no_encoding(str, x);
+ if (s == NULL) s = p;
+ copylen++;
+ }
+
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
}
return str;
}
case ASL_ENCODE_XML:
{
+ s = NULL;
+ copylen = 0;
+
for (p = app; *p != '\0'; p++)
{
x = *p;
if (x == '&')
{
- asl_string_append_no_encoding(str, "&");
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
+ asl_string_append_no_encoding_len(str, "&", 5);
}
else if (x == '<')
{
- asl_string_append_no_encoding(str, "<");
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
+ asl_string_append_no_encoding_len(str, "<", 4);
}
else if (x == '>')
{
- asl_string_append_no_encoding(str, ">");
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
+ asl_string_append_no_encoding_len(str, ">", 4);
}
else if (x == '"')
{
- asl_string_append_no_encoding(str, """);
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
+ asl_string_append_no_encoding_len(str, """, 6);
}
else if (x == '\'')
{
- asl_string_append_no_encoding(str, "'");
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
+ asl_string_append_no_encoding_len(str, "'", 6);
}
else if (iscntrl(x))
{
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
char tmp[8];
snprintf(tmp, sizeof(tmp), "&#x%02hhx;", x);
- asl_string_append_no_encoding(str, tmp);
+ asl_string_append_no_encoding_len(str, tmp, 6);
}
else
{
- asl_string_append_char_no_encoding(str, x);
+ if (s == NULL) s = p;
+ copylen++;
}
}
+
+ if (copylen > 0)
+ {
+ asl_string_append_no_encoding_len(str, s, copylen);
+ s = NULL;
+ copylen = 0;
+ }
+
+ return str;
}
default:
{
}
opstr[i] = '\0';
- return asl_string_append_no_encoding(str, opstr);
+ return asl_string_append_no_encoding_len(str, opstr, 0);
}
asl_string_t *
asl_string_append_xml_tag(asl_string_t *str, const char *tag, const char *s)
{
- asl_string_append_no_encoding(str, "\t\t<");
- asl_string_append_no_encoding(str, tag);
- asl_string_append_no_encoding(str, ">");
+ asl_string_append_no_encoding_len(str, "\t\t<", 3);
+ asl_string_append_no_encoding_len(str, tag, 0);
+ asl_string_append_char_no_encoding(str, '>');
asl_string_append_internal(str, s, 0);
- asl_string_append_no_encoding(str, "</");
- asl_string_append_no_encoding(str, tag);
- asl_string_append_no_encoding(str, ">\n");
+ asl_string_append_no_encoding_len(str, "</", 2);
+ asl_string_append_no_encoding_len(str, tag, 0);
+ asl_string_append_no_encoding_len(str, ">\n", 2);
return str;
}
#include <os/assumes.h>
#include <xpc/xpc.h>
#include <syslog.h>
+#include <asl_core.h>
#include <asl_private.h>
static uint8_t *b64charset = (uint8_t *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/*
- * Copyright (c) 1999-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 1999-2015 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <asl.h>
#include <asl_msg.h>
#include <asl_private.h>
+#include <os/trace.h>
+#include <os/log_private.h>
#ifdef __STDC__
#include <stdarg.h>
#ifdef BUILDING_VARIANT
__private_extern__ pthread_mutex_t _sl_lock;
-__private_extern__ aslclient _sl_asl;
+__private_extern__ asl_object_t _sl_asl;
__private_extern__ char *_sl_ident;
__private_extern__ int _sl_fac;
__private_extern__ int _sl_opts;
__private_extern__ int _sl_mask;
#else /* !BUILDING_VARIANT */
__private_extern__ pthread_mutex_t _sl_lock = PTHREAD_MUTEX_INITIALIZER;
-__private_extern__ aslclient _sl_asl = NULL;
+__private_extern__ asl_object_t _sl_asl = NULL;
__private_extern__ char *_sl_ident = NULL;
__private_extern__ int _sl_fac = 0;
__private_extern__ int _sl_opts = 0;
__private_extern__ int _sl_mask = 0;
#endif /* BUILDING_VARIANT */
+#define EVAL_ASL (EVAL_SEND_ASL | EVAL_TEXT_FILE | EVAL_ASL_FILE)
+
+static const uint8_t shim_syslog_to_trace_type[8] = {
+ OS_TRACE_TYPE_FAULT, OS_TRACE_TYPE_FAULT, OS_TRACE_TYPE_FAULT, // LOG_EMERG, LOG_ALERT, LOG_CRIT
+ OS_TRACE_TYPE_ERROR, // LOG_ERROR
+ OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_RELEASE, // LOG_WARN, LOG_NOTICE, LOG_INFO
+ OS_TRACE_TYPE_DEBUG // LOG_DEBUG
+};
+
+extern uint32_t _asl_evaluate_send(asl_object_t client, asl_object_t m, int slevel);
+extern uint32_t _asl_lib_vlog(asl_object_t obj, uint32_t eval, asl_object_t msg, const char *format, va_list ap);
+
+
+/* SHIM SPI */
+asl_object_t
+_syslog_asl_client()
+{
+ pthread_mutex_lock(&_sl_lock);
+ if (_sl_asl == NULL)
+ {
+ _sl_asl = asl_open(NULL, NULL, ASL_OPT_SYSLOG_LEGACY);
+ _sl_mask = ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG);
+ asl_set_filter(_sl_asl, _sl_mask);
+ }
+ pthread_mutex_unlock(&_sl_lock);
+
+ return _sl_asl;
+}
+
/*
* syslog, vsyslog --
* print message on log file; output is intended for syslogd(8).
*/
+
+void
+vsyslog(int pri, const char *fmt, va_list ap)
+{
+ int level = pri & LOG_PRIMASK;
+ uint32_t eval;
+
+ _syslog_asl_client();
+
+ eval = _asl_evaluate_send(_sl_asl, NULL, level);
+
+ if (eval & EVAL_SEND_TRACE)
+ {
+ va_list ap_copy;
+ uint8_t trace_type = shim_syslog_to_trace_type[level];
+
+ va_copy(ap_copy, ap);
+ os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, fmt, ap_copy, NULL);
+ va_end(ap_copy);
+ }
+
+ if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL))
+ {
+ asl_object_t msg = asl_new(ASL_TYPE_MSG);
+ const char *facility;
+ int fac = pri & LOG_FACMASK;
+
+ if (fac != 0)
+ {
+ facility = asl_syslog_faciliy_num_to_name(fac);
+ if (facility != NULL) asl_set(msg, ASL_KEY_FACILITY, facility);
+ }
+
+ if (eval & EVAL_SEND_TRACE) asl_set(msg, "ASLSHIM", "2");
+
+ _asl_lib_vlog(_sl_asl, eval, msg, fmt, ap);
+
+ asl_release(msg);
+ }
+}
+
void
#ifdef __STDC__
syslog(int pri, const char *fmt, ...)
#else
syslog(pri, fmt, va_alist)
- int pri;
- char *fmt;
- va_dcl
+int pri;
+char *fmt;
+va_dcl
#endif
{
- va_list ap;
-
+ int level = pri & LOG_PRIMASK;
+ uint32_t eval;
+
+ _syslog_asl_client();
+
+ eval = _asl_evaluate_send(_sl_asl, NULL, level);
+
+ if (eval & EVAL_SEND_TRACE)
+ {
+ va_list ap;
+ uint8_t trace_type = shim_syslog_to_trace_type[level];
+
#ifdef __STDC__
- va_start(ap, fmt);
+ va_start(ap, fmt);
#else
- va_start(ap);
+ va_start(ap);
#endif
- vsyslog(pri, fmt, ap);
- va_end(ap);
-}
-
-void
-vsyslog(int pri, const char *fmt, va_list ap)
-{
- int fac;
- asl_msg_t *facmsg;
- const char *facility;
-
- facmsg = NULL;
- fac = pri & LOG_FACMASK;
- if (fac != 0)
+ os_log_shim_with_va_list(__builtin_return_address(0), OS_LOG_DEFAULT, trace_type, fmt, ap, NULL);
+ va_end(ap);
+ }
+
+ if (os_log_shim_legacy_logging_enabled() && (eval & EVAL_ASL))
{
- facility = asl_syslog_faciliy_num_to_name(fac);
- if (facility != NULL)
+ va_list ap;
+ asl_object_t msg = asl_new(ASL_TYPE_MSG);
+ const char *facility;
+ int fac = pri & LOG_FACMASK;
+
+ if (fac != 0)
{
- facmsg = asl_msg_new(ASL_TYPE_MSG);
- asl_msg_set_key_val(facmsg, ASL_KEY_FACILITY, facility);
+ facility = asl_syslog_faciliy_num_to_name(fac);
+ if (facility != NULL) asl_set(msg, ASL_KEY_FACILITY, facility);
}
+
+ if (eval & EVAL_SEND_TRACE) asl_set(msg, "ASLSHIM", "2");
+
+#ifdef __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ _asl_lib_vlog(_sl_asl, eval, msg, fmt, ap);
+ va_end(ap);
+
+ asl_release(msg);
}
-
- pthread_mutex_lock(&_sl_lock);
-
- /* open syslog ASL client if required */
- if (_sl_asl == NULL)
- {
- _sl_asl = asl_open(NULL, NULL, ASL_OPT_SYSLOG_LEGACY);
- _sl_mask = ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG);
- asl_set_filter(_sl_asl, _sl_mask);
- }
-
- asl_vlog(_sl_asl, (aslmsg)facmsg, LOG_PRI(pri), fmt, ap);
-
- pthread_mutex_unlock(&_sl_lock);
-
- if (facmsg != NULL) asl_msg_release(facmsg);
}
#ifndef BUILDING_VARIANT
pthread_mutex_lock(&_sl_lock);
- if (_sl_asl != NULL) asl_close(_sl_asl);
+ if (_sl_asl != NULL) asl_release(_sl_asl);
_sl_asl = NULL;
free(_sl_ident);
isa = PBXAggregateTarget;
buildConfigurationList = 3FFD4402174862D0007DAC1B /* Build configuration list for PBXAggregateTarget "executables_Sim" */;
buildPhases = (
- 3F5F5B9C17487ADB00C12281 /* Configuration */,
);
dependencies = (
3FFD440717486325007DAC1B /* PBXTargetDependency */,
/* Begin PBXBuildFile section */
2D30656E150E6EFF00F31A54 /* asl_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D30656C150E6EFF00F31A54 /* asl_common.c */; };
+ 2D30D2811AE6C84200673818 /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D30D27F1AE6C84200673818 /* daemon.c */; };
2D31F3C517E77F3300F2A60C /* asl_client.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D31F3C117E77F3300F2A60C /* asl_client.h */; settings = {ATTRIBUTES = (Private, ); }; };
2D31F3C617E77F3300F2A60C /* asl_msg_list.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D31F3C217E77F3300F2A60C /* asl_msg_list.h */; settings = {ATTRIBUTES = (Private, ); }; };
2D31F3C717E77F3300F2A60C /* asl_object.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D31F3C317E77F3300F2A60C /* asl_object.h */; settings = {ATTRIBUTES = (Private, ); }; };
2D31F3D017E77F8800F2A60C /* asl_string.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D31F3CC17E77F8800F2A60C /* asl_string.c */; };
2D60F61115657D0F00F2E3F9 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D60F61015657D0F00F2E3F9 /* libz.dylib */; };
2D9DEB64150E6FE80059BA61 /* asl_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D30656D150E6EFF00F31A54 /* asl_common.h */; };
+ 2DAF75551AE8613000054190 /* com.apple.activity_tracing.CacheDelete.plist in Copy CacheDelete plist */ = {isa = PBXBuildFile; fileRef = 2DAF75541AE8610200054190 /* com.apple.activity_tracing.CacheDelete.plist */; };
2DCF701A150E97C0002D5E8F /* libaslcommon.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 505ACB9D108FD16400197086 /* libaslcommon.a */; };
+ 2DEE8C411AE575A2007B5CBE /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DEE8C401AE575A2007B5CBE /* CoreFoundation.framework */; };
+ 2DEE8C431AE575AB007B5CBE /* CacheDelete.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DEE8C421AE575AB007B5CBE /* CacheDelete.framework */; };
+ 2DEE8C461AE5798B007B5CBE /* cache_delete.c in Sources */ = {isa = PBXBuildFile; fileRef = 2DEE8C441AE5798B007B5CBE /* cache_delete.c */; };
3F6F43F21613A8E300CA9ADB /* asl.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F6F43CF1613A8E300CA9ADB /* asl.h */; settings = {ATTRIBUTES = (Public, ); }; };
3F6F43F31613A8E300CA9ADB /* asl_core.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F6F43D01613A8E300CA9ADB /* asl_core.h */; settings = {ATTRIBUTES = (Private, ); }; };
3F6F43F41613A8E300CA9ADB /* asl_file.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F6F43D11613A8E300CA9ADB /* asl_file.h */; settings = {ATTRIBUTES = (Private, ); }; };
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
+ 2D30D27D1AE6BBA000673818 /* Copy CacheDelete plist */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /System/Library/CacheDelete;
+ dstSubfolderSpec = 0;
+ files = (
+ 2DAF75551AE8613000054190 /* com.apple.activity_tracing.CacheDelete.plist in Copy CacheDelete plist */,
+ );
+ name = "Copy CacheDelete plist";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
3F6F44131613AA9300CA9ADB /* Install man3 */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
- dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man3";
+ dstPath = /usr/share/man/man3;
dstSubfolderSpec = 0;
files = (
3F6F44141613AAA600CA9ADB /* asl.3 in Install man3 */,
503A82631099037D00B0D08A /* Copy Manpage.8 */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
- dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man8";
+ dstPath = /usr/share/man/man8;
dstSubfolderSpec = 0;
files = (
503A82741099045F00B0D08A /* aslmanager.8 in Copy Manpage.8 */,
503A8285109904FD00B0D08A /* Copy Manpage.1 */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
- dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man1";
+ dstPath = /usr/share/man/man1;
dstSubfolderSpec = 0;
files = (
503A82761099049900B0D08A /* syslog.1 in Copy Manpage.1 */,
503A8286109904FD00B0D08A /* Copy Manpage.8 */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
- dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man8";
+ dstPath = /usr/share/man/man8;
dstSubfolderSpec = 0;
files = (
503A8278109904C000B0D08A /* syslogd.8 in Copy Manpage.8 */,
503A8287109904FD00B0D08A /* Copy Manpages.5 */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
- dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man5";
+ dstPath = /usr/share/man/man5;
dstSubfolderSpec = 0;
files = (
503A827A109904E400B0D08A /* asl.conf.5 in Copy Manpages.5 */,
/* Begin PBXFileReference section */
2D30656C150E6EFF00F31A54 /* asl_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_common.c; sourceTree = "<group>"; };
2D30656D150E6EFF00F31A54 /* asl_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_common.h; sourceTree = "<group>"; };
+ 2D30D27F1AE6C84200673818 /* daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = daemon.c; path = aslmanager.tproj/daemon.c; sourceTree = "<group>"; };
+ 2D30D2801AE6C84200673818 /* daemon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = daemon.h; path = aslmanager.tproj/daemon.h; sourceTree = "<group>"; };
2D31F3C117E77F3300F2A60C /* asl_client.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_client.h; sourceTree = "<group>"; };
2D31F3C217E77F3300F2A60C /* asl_msg_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_msg_list.h; sourceTree = "<group>"; };
2D31F3C317E77F3300F2A60C /* asl_object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asl_object.h; sourceTree = "<group>"; };
2D31F3CB17E77F8800F2A60C /* asl_object.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_object.c; sourceTree = "<group>"; };
2D31F3CC17E77F8800F2A60C /* asl_string.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_string.c; sourceTree = "<group>"; };
2D60F61015657D0F00F2E3F9 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
+ 2D9C4F131B3A29E700219FB3 /* com.apple.system.log */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = com.apple.system.log; path = syslogd.tproj/com.apple.system.log; sourceTree = "<group>"; };
+ 2DAF75541AE8610200054190 /* com.apple.activity_tracing.CacheDelete.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.activity_tracing.CacheDelete.plist; path = aslmanager.tproj/com.apple.activity_tracing.CacheDelete.plist; sourceTree = "<group>"; };
2DB4DA0A125FC69A001CDC45 /* after_install.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = after_install.sh; path = syslogd.tproj/after_install.sh; sourceTree = "<group>"; };
2DB8178915589D0C004D0BDE /* entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; name = entitlements.plist; path = util.tproj/entitlements.plist; sourceTree = "<group>"; };
+ 2DEE8C401AE575A2007B5CBE /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = ../../../../../../../../System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<group>"; };
+ 2DEE8C421AE575AB007B5CBE /* CacheDelete.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CacheDelete.framework; path = ../../../../../../../../System/Library/PrivateFrameworks/CacheDelete.framework; sourceTree = "<group>"; };
+ 2DEE8C441AE5798B007B5CBE /* cache_delete.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cache_delete.c; path = aslmanager.tproj/cache_delete.c; sourceTree = "<group>"; };
+ 2DEE8C451AE5798B007B5CBE /* cache_delete.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cache_delete.h; path = aslmanager.tproj/cache_delete.h; sourceTree = "<group>"; };
3F6B6311185AF66C00F692C5 /* aslmanager.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = aslmanager.xcconfig; sourceTree = "<group>"; };
3F6B6312185AF66C00F692C5 /* base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = base.xcconfig; sourceTree = "<group>"; };
3F6B6313185AF66C00F692C5 /* syslogd.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = syslogd.xcconfig; sourceTree = "<group>"; };
3F6F43E81613A8E300CA9ADB /* asl_store.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_store.c; sourceTree = "<group>"; };
3F6F43E91613A8E300CA9ADB /* asl_util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asl_util.c; sourceTree = "<group>"; };
3F900DB619383950003CA7E6 /* sim-compat-symlink.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "sim-compat-symlink.sh"; sourceTree = "<group>"; };
- 3FCCB5361749B53D00F8FEBC /* asl_sim.conf */ = {isa = PBXFileReference; lastKnownFileType = text; name = asl_sim.conf; path = syslogd.tproj/asl_sim.conf; sourceTree = "<group>"; };
+ 3FCCB5361749B53D00F8FEBC /* asl.conf.ios_sim */ = {isa = PBXFileReference; lastKnownFileType = text; name = asl.conf.ios_sim; path = syslogd.tproj/asl.conf.ios_sim; sourceTree = "<group>"; };
+ 3FE6E8391A529FEF0075D75F /* asl.conf.ios */ = {isa = PBXFileReference; lastKnownFileType = text; name = asl.conf.ios; path = syslogd.tproj/asl.conf.ios; sourceTree = "<group>"; };
+ 3FE6E83A1A529FEF0075D75F /* asl.conf.osx */ = {isa = PBXFileReference; lastKnownFileType = text; name = asl.conf.osx; path = syslogd.tproj/asl.conf.osx; sourceTree = "<group>"; };
+ 3FE6E83B1A529FEF0075D75F /* syslog.conf */ = {isa = PBXFileReference; lastKnownFileType = text; name = syslog.conf; path = syslogd.tproj/syslog.conf; sourceTree = "<group>"; };
3FE798E316161F2A00D547B0 /* syslog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = syslog.c; sourceTree = "<group>"; };
3FE798E516161F3A00D547B0 /* syslog.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = syslog.3; sourceTree = "<group>"; };
3FFD43F817485C5B007DAC1B /* libasl.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = libasl.xcconfig; sourceTree = "<group>"; };
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 2DEE8C431AE575AB007B5CBE /* CacheDelete.framework in Frameworks */,
+ 2DEE8C411AE575A2007B5CBE /* CoreFoundation.framework in Frameworks */,
2D60F61115657D0F00F2E3F9 /* libz.dylib in Frameworks */,
2DCF701A150E97C0002D5E8F /* libaslcommon.a in Frameworks */,
);
08FB7794FE84155DC02AAC07 /* syslog */ = {
isa = PBXGroup;
children = (
+ 2DEE8C421AE575AB007B5CBE /* CacheDelete.framework */,
+ 2DEE8C401AE575A2007B5CBE /* CoreFoundation.framework */,
505ACBA1108FD18400197086 /* aslcommon */,
503917691091404D0001165E /* aslmanager */,
503917C41091412B0001165E /* util */,
503917691091404D0001165E /* aslmanager */ = {
isa = PBXGroup;
children = (
+ 2DAF75541AE8610200054190 /* com.apple.activity_tracing.CacheDelete.plist */,
+ 2DEE8C441AE5798B007B5CBE /* cache_delete.c */,
+ 2DEE8C451AE5798B007B5CBE /* cache_delete.h */,
5039176B1091408B0001165E /* aslmanager.8 */,
5039176C1091408B0001165E /* aslmanager.c */,
+ 2D30D27F1AE6C84200673818 /* daemon.c */,
+ 2D30D2801AE6C84200673818 /* daemon.h */,
5039176D1091408B0001165E /* com.apple.aslmanager.plist */,
);
name = aslmanager;
503917711091409F0001165E /* syslogd */ = {
isa = PBXGroup;
children = (
- 3FCCB5361749B53D00F8FEBC /* asl_sim.conf */,
+ 3FE6E8391A529FEF0075D75F /* asl.conf.ios */,
+ 2D9C4F131B3A29E700219FB3 /* com.apple.system.log */,
+ 3FE6E83A1A529FEF0075D75F /* asl.conf.osx */,
+ 3FCCB5361749B53D00F8FEBC /* asl.conf.ios_sim */,
+ 3FE6E83B1A529FEF0075D75F /* syslog.conf */,
503917A61091410E0001165E /* asl_action.c */,
2DB4DA0A125FC69A001CDC45 /* after_install.sh */,
503917A81091410E0001165E /* asl.conf.5 */,
50391764109140450001165E /* Frameworks */,
503A82631099037D00B0D08A /* Copy Manpage.8 */,
FCAC6D7410AB34C9008DEAC9 /* ShellScript */,
+ 2D30D27D1AE6BBA000673818 /* Copy CacheDelete plist */,
);
buildRules = (
);
/* End PBXProject section */
/* Begin PBXShellScriptBuildPhase section */
- 3F5F5B9C17487ADB00C12281 /* Configuration */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 8;
- files = (
- );
- inputPaths = (
- );
- name = Configuration;
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 1;
- shellPath = /bin/sh;
- shellScript = "mkdir -p ${DSTROOT}${INSTALL_PATH_PREFIX}/etc\ncp ${SRCROOT}/syslogd.tproj/asl_sim.conf ${DSTROOT}${INSTALL_PATH_PREFIX}/etc/asl.conf\n";
- };
3F900DB41938393C003CA7E6 /* Sim compat symlink */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 8;
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
- shellScript = "set -e\n\nDESTDIR=\"$DSTROOT$INSTALL_PATH_PREFIX\"/System/Library/LaunchDaemons\ninstall -d -m 0755 -o root -g wheel -d \"$DESTDIR\"\ninstall -m 0644 -o root -g wheel \"$SRCROOT\"/aslmanager.tproj/com.apple.aslmanager.plist \"$DESTDIR\"\nplutil -convert binary1 \"$DESTDIR\"/com.apple.aslmanager.plist";
+ shellScript = "set -e\n\nDESTDIR=\"$DSTROOT\"/System/Library/LaunchDaemons\ninstall -d -m 0755 -o root -g wheel -d \"$DESTDIR\"\ninstall -m 0644 -o root -g wheel \"$SRCROOT\"/aslmanager.tproj/com.apple.aslmanager.plist \"$DESTDIR\"\nplutil -convert binary1 \"$DESTDIR\"/com.apple.aslmanager.plist";
showEnvVarsInLog = 0;
};
FCF3762A10D2F47C00C0EC8D /* ShellScript */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 2D30D2811AE6C84200673818 /* daemon.c in Sources */,
5039176F1091408B0001165E /* aslmanager.c in Sources */,
+ 2DEE8C461AE5798B007B5CBE /* cache_delete.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
COPY_PHASE_STRIP = YES;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
GCC_DYNAMIC_NO_PIC = NO;
OTHER_CFLAGS = (
"-Wall",
"-DINET6",
);
+ OTHER_LDFLAGS = "";
PRODUCT_NAME = aslmanager;
ZERO_LINK = NO;
};
-#! /bin/bash
-set -e
+#! /bin/bash -e -x
-if [ "${RC_ProjectName%_Sim}" != "${RC_ProjectName}" ] ; then
+if [[ "${PLATFORM_NAME}" =~ "simulator" ]] ; then
PLIST="${SRCROOT}"/syslogd.tproj/com.apple.syslogd_sim.plist
+ ASL_CONF="${SRCROOT}"/syslogd.tproj/asl.conf.ios_sim
+elif [[ "${PLATFORM_NAME}" == "macosx" ]] ; then
+ PLIST="${SRCROOT}"/syslogd.tproj/com.apple.syslogd.plist
+ ASL_CONF="${SRCROOT}"/syslogd.tproj/asl.conf.osx
+ SYSLOG_CONF="${SRCROOT}"/syslogd.tproj/syslog.conf
else
PLIST="${SRCROOT}"/syslogd.tproj/com.apple.syslogd.plist
+ ASL_CONF="${SRCROOT}"/syslogd.tproj/asl.conf.ios
+ SYSLOG_CONF="${SRCROOT}"/syslogd.tproj/syslog.conf
+ SYSTEM_LOG_CONF="${SRCROOT}"/syslogd.tproj/com.apple.system.log
fi
-DESTDIR="${DSTROOT}${INSTALL_PATH_PREFIX}"/System/Library/LaunchDaemons
+DESTDIR="${DSTROOT}"/private/etc
+install -d -m 0755 -o root -g wheel "${DESTDIR}"
+install -m 0644 -o root -g wheel "${ASL_CONF}" "${DESTDIR}"/asl.conf
+if [[ -n "${SYSLOG_CONF}" ]] ; then
+ install -m 0644 -o root -g wheel "${SYSLOG_CONF}" "${DESTDIR}"
+fi
+DESTDIR="${DSTROOT}"/System/Library/LaunchDaemons
install -d -m 0755 -o root -g wheel "${DESTDIR}"
install -m 0644 -o root -g wheel "${PLIST}" "${DESTDIR}"/com.apple.syslogd.plist
plutil -convert binary1 "${DESTDIR}"/com.apple.syslogd.plist
-if [ "${RC_ProjectName%_Sim}" != "${RC_ProjectName}" ] ; then
+if [[ "${PLATFORM_NAME}" =~ "simulator" ]] ; then
exit 0
fi
install -d -m 0755 -o root -g wheel "$DSTROOT"/private/var/log/asl
-PRODUCT=$(xcodebuild -sdk "${SDKROOT}" -version PlatformPath | head -1 | sed 's,^.*/\([^/]*\)\.platform$,\1,')
-
-if [ ${SDKROOT}x = x ]; then
- PRODUCT=MacOSX
-fi
-
-if [ ${PRODUCT}x = x ]; then
- PRODUCT=MacOSX
-fi
-
-if [ ${PRODUCT} = iPhone ]; then
+if [[ "${PLATFORM_NAME}" != "macosx" ]]; then
install -d -m 0755 -o root -g wheel "$DSTROOT"/usr/share/sandbox
install -m 0644 -o root -g wheel "$SRCROOT"/syslogd.tproj/syslogd.sb "$DSTROOT"/usr/share/sandbox
fi
+
+if ! [[ "${PLATFORM_NAME}" =~ "simulator" || "${PLATFORM_NAME}" == "macosx" ]]; then
+ DESTDIR="${DSTROOT}"/usr/local/etc/asl
+ install -d -m 0755 -o root -g wheel "${DESTDIR}"
+ install -m 0644 -o root -g wheel "${SYSTEM_LOG_CONF}" "${DESTDIR}"/com.apple.system.log
+fi
.It rotate=NAME_STYLE
Enables log file rotation and specifies the file naming scheme for rotated files.
This option does not apply to ASL directories.
-Four styles are supported:
-.Pp
-.Bl -tag -width "local-basic" -compact -indent
-.It sec
-Rotated file names are of the form
-.Dq example.log.T1340607600 .
-The file names include the creation time of the file in seconds since the epoch.
-.Pp
-.It utc
-Rotated file names are in ISO 8601 extended format, for example
-.Dq example.log.2012-06-24T07:00:00Z .
-The file names includes its creation time as a UTC date and time.
-.Pp
-.It utc-basic
-Rotated file names are in ISO 8601 basic format, for example
-.Dq example.log.20120624T070000Z .
-The file names includes its creation time as a UTC date and time.
-.Pp
-.It local
-Rotated file names are in ISO 8601 extended format, for example
-.Dq example.log.2012-06-24T07:00:00-7 .
-The file names includes its creation time as date and time in the local time zone.
-The local timezone offset is included as a trailing part of the name.
-.Pp
-.It local-basic
-Rotated file names are in ISO 8601 basic format, for example
-.Dq example.log.20120624T070000-07 .
-The file names includes its creation time as date and time in the local time zone.
-The local timezone offset is included as a trailing part of the name.
-.Pp
-.It seq
-Rotated file names are of the form
-.Dq example.log.N
-where N is an integer sequence number.
-Files are re-numbered on each rotation so that the
-.Dq 0
-file is the most recent.
-.El
+NAME_STYLE may either be a simple time-stamp style:
+.Dq sec ,
+.Dq utc ,
+.Dq utc-basic ,
+.Dq local ,
+.Dq local-basic ,
+or
+.Dq seq ;
+or the value may contain the file's base name, a file name extension, and one of the time-stame styles.
+For example
+.Dq example.seq.log
+or
+.Dq example.log.utc-basic.
+A detailed description of name styles may be found in the FILE ROTATION section below.
.Pp
If the option
.Dq rotate
appears without a value, the naming style defaults to
.Dq "sec" .
.Pp
-Note that using the local timezone for timestamped files may cause odd behavior on highly-mobile systems.
-.Nm aslmanager
-will delete files after a specified time-to-live (see below).
-The age of the file is determined by the file name.
-If files are created in different timezones but saved with a non-absolute timestamp,
-the age calculation may result in some files being considered older or newer than they are in reality.
-.Pp
-Also note that sequenced files (using the
-.Dq seq
-style) will initially be checkpointed using a file name containing a timestamp in seconds.
-.Nm aslmanager
-will re-sequence the files when it scans for checkpoint files.
-.Pp
.It ttl=DAYS
Specifies the number of days that older versions of rotated files should be allowed to remain in the filesystem.
Rotated files older than this limit are deleted.
When compressed, the extension
.Dq .gz
is appended to the file name.
+When the output is an ASL directory, data files are compressed after midnight local time.
+This means that messages written in the current day will be readable using
+.Nm syslog Fl d
+or using the
+.Xr asl 3
+API.
+Messages in compressed data files will not be available until the files are un-compressed.
.Pp
.It file_max=SIZE
Limits the size of an active log file.
.Nm aslmanager
will delete rotated files, oldest first, to reduce the total below the limit.
SIZE may be specified in the same format as the file_max option.
+.Pp
+.It basestamp
+Causes
+.Nm syslogd
+to add a timestamp to the file name when it is created.
+For example,
+.Pp
+.Dl
+> example.log rotate=utc-basic basestamp
+.Pp
+will result in syslogd writing to, e.g.
+.Dq example.log.20120625T070000Z
+rather than to
+.Dq example.log .
+Note that this option does nothing with sequenced (``seq'') files.
+.Pp
+.It symlink
+This option may only be used together with the basestamp option.
+It causes
+.Nm syslogd
+to create a symlink with the unstamped file name to the currently active log file.
+For example,
+.Pp
+.Dl
+> example.log rotate=sec basestamp symlink
+.Pp
+will result in syslogd writing to, e.g.
+.Dq example.log.T1340607600 ,
+and creating a sybolic link from
+.Dq example.log
+to the active file.
+.Pp
.El
.Ss FILE ROTATION
.Nm syslogd
and
.Nm aslmanager
-work together to automatically provide all the features of file rotation.
-However, it is useful to understand how the process works.
+work together to provide the features of file rotation.
This section describes the file rotation options that may be used in /etc/asl.conf
or an ASL Output Module configuration file,
together with a description of how the system works to support those features.
.Pp
+File rotation or file rolling is enabled by the
+.Dq rotate
+output configuration option.
+It is typically specificed with a value which specifies the naming sytle for rotated files.
+Name styles may simply be a timestamp format, which is appended to the filename.
+.Pp
+.Bl -tag -width "local-basic" -compact -indent
+.It sec
+Rotated file names are of the form
+.Dq example.log.T1340607600 .
+The file names include the creation time of the file in seconds since the epoch.
+.Pp
+.It utc
+Rotated file names are in ISO 8601 extended format, for example
+.Dq example.log.2012-06-24T07:00:00Z .
+The file names includes its creation time as a UTC date and time.
+.Pp
+.It utc-basic
+Rotated file names are in ISO 8601 basic format, for example
+.Dq example.log.20120624T070000Z .
+The file names includes its creation time as a UTC date and time.
+.Pp
+.It local
+Rotated file names are in ISO 8601 extended format, for example
+.Dq example.log.2012-06-24T07:00:00-7 .
+The file names includes its creation time as date and time in the local time zone.
+The local timezone offset is included as a trailing part of the name.
+The value
+.Dq lcl
+is an alias for
+.Dq local .
+.Pp
+.It local-basic
+Rotated file names are in ISO 8601 basic format, for example
+.Dq example.log.20120624T070000-07 .
+The file names includes its creation time as date and time in the local time zone.
+The local timezone offset is included as a trailing part of the name.
+The value
+.Dq lcl-basic
+is an alias for
+.Dq local-basic .
+.Pp
+.It seq
+Rotated file names are of the form
+.Dq example.log.N
+where N is an integer sequence number.
+Files are re-numbered on each rotation so that the
+.Dq 0
+file is the most recent.
+.El
+.Pp
+Note that using the local timezone for timestamped files may cause odd behavior on highly mobile systems.
+.Nm aslmanager
+will delete files after a specified time-to-live (see below).
+The age of the file is determined by the file name.
+If files are created in different timezones but saved with a non-absolute timestamp,
+the age calculation may result in some files being considered older or newer than they are in reality.
+.Pp
+Also note that sequenced files (using the
+.Dq seq
+style) will initially be checkpointed using a file name containing a timestamp in seconds.
+.Nm aslmanager
+will re-sequence the files when it scans for checkpoint files.
+.Pp
+.Pp
+Alternatively, the name style may be have two or three components.
+The first component is the
+.Dq base
+name of the file, with no filename extension.
+The base name may be followed by a timestamp format and optionally by a filename extension,
+or the base name may be followed by an extension (the extension is optional) and a timestamp format.
+These components must be separated by a dot character.
+.Pp
+For example, this output configuration line specifies that the output file
+.Dq example.log
+should be rotated to create the files
+.Dq example.0.log ,
+.Dq example.1.log ,
+and so on.
+.Pp
+.Dl > example.log rotate=example.seq.log
+.Pp
If a file is marked for rotation,
.Nm syslogd
will close the file at the start of a new day or when the file exceeds its
size limit.
At that point,
.Nm syslogd
-renames the file and starts a new file to continue logging.
-The old file is renamed with the file's creation time included in its name.
+renames the file with the file's creation time included in its name
+(unless the basestamp option is present, in which case the file's creation time
+is already included in the filename) and starts a new file to continue logging.
This operation is called checkpointing the file.
.Pp
For example,
--- /dev/null
+##
+# configuration file for syslogd and aslmanager
+##
+
+# aslmanager logs
+> /var/log/asl/Logs/aslmanager external style=lcl-b ttl=2
+
+# authpriv messages are root/admin readable
+? [= Facility authpriv] access 0 80
+
+# remoteauth critical, alert, and emergency messages are root/admin readable
+? [= Facility remoteauth] [<= Level critical] access 0 80
+
+# broadcast emergency messages
+? [= Level emergency] broadcast
+
+# save kernel [PID 0] and launchd [PID 1] messages
+? [<= PID 1] store
+
+# ignore "internal" facility
+? [= Facility internal] ignore
+
+# save everything from emergency to notice
+? [<= Level notice] store
+
+# Specify owner, group, and access bits for mobile-owned log directories
+> /var/mobile/Library uid=501 gid=501 mode=0700
+> /var/mobile/Library/Logs uid=501 gid=501 mode=0755
+> /var/mobile/Library/Logs/CrashReporter uid=501 gid=501 mode=0755
+> /var/mobile/Library/Logs/CrashReporter/DiagnosticLogs uid=501 gid=501 mode=0755
--- /dev/null
+##
+# configuration file for syslogd and aslmanager in the iOS Simulator
+##
+
+# 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(SIMULATOR_LOG_ROOT)/performance
+? [A= Facility com.apple.performance] store_dir $ENV(SIMULATOR_LOG_ROOT)/performance
+
+# redirect com.apple.eventmonitor* messages to $ENV(SIMULATOR_LOG_ROOT)/eventmonitor
+? [A= Facility com.apple.eventmonitor] store_dir $ENV(SIMULATOR_LOG_ROOT)/eventmonitor
+
+# ignore "internal" facility
+? [= Facility internal] ignore
+
+# save everything from emergency to notice
+? [<= Level notice] store
+
+# install messages get saved only in install.log
+? [= 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(SIMULATOR_LOG_ROOT)/system.log
+
+# Facility auth to level info gets saved in system.log
+? [= Facility auth] [<= Level info] file $ENV(SIMULATOR_LOG_ROOT)/system.log
+
+# Facility authpriv gets saved in system.log
+? [= Facility authpriv] file $ENV(SIMULATOR_LOG_ROOT)/system.log
--- /dev/null
+##
+# configuration file for syslogd and aslmanager
+##
+
+# aslmanager logs
+> /var/log/asl/Logs/aslmanager external style=lcl-b ttl=2
+
+# authpriv messages are root/admin readable
+? [= Facility authpriv] access 0 80
+
+# remoteauth critical, alert, and emergency messages are root/admin readable
+? [= Facility remoteauth] [<= Level critical] access 0 80
+
+# broadcast emergency messages
+? [= Level emergency] broadcast
+
+# save kernel [PID 0] and launchd [PID 1] messages
+? [<= PID 1] store
+
+# ignore "internal" facility
+? [= Facility internal] ignore
+
+# save everything from emergency to notice
+? [<= Level notice] store
+
+# Rules for /var/log/system.log
+> system.log mode=0640 format=bsd rotate=seq compress file_max=5M all_max=50M
+? [= Sender kernel] file system.log
+? [<= Level notice] file system.log
+? [= Facility auth] [<= Level info] file system.log
+? [= Facility authpriv] [<= Level info] file system.log
+
+# Facility com.apple.alf.logging gets saved in appfirewall.log
+? [= Facility com.apple.alf.logging] file appfirewall.log file_max=5M all_max=50M
if (as_data->pending != 0)
{
char *str = NULL;
- asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message ASL Store %s was closed with %d pending messages]", global.pid, r->dst->fname, as_data->pending);
+ asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message ASL Store %s was closed with %d pending messages]", global.pid, r->dst->current_name, as_data->pending);
internal_log_message(str);
free(str);
}
as_data->p_month = 0;
as_data->p_day = 0;
- free(r->dst->fname);
- r->dst->fname = NULL;
+ free(r->dst->current_name);
+ r->dst->current_name = NULL;
as_data->aslfile = NULL;
}
static int
_act_checkpoint(asl_out_rule_t *r, uint32_t force)
{
- char tmpfname[MAXPATHLEN], *fn;
+ char tmpcurrent_name[MAXPATHLEN], *fn;
if (r == NULL) return 0;
if (r->dst == NULL) return 0;
- fn = r->dst->fname;
+ fn = r->dst->current_name;
if (fn == NULL)
{
if (r->dst->path == NULL) return 0;
- asl_make_dst_filename(r->dst, tmpfname, sizeof(tmpfname));
- fn = tmpfname;
+ asl_dst_make_current_name(r->dst, 0, tmpcurrent_name, sizeof(tmpcurrent_name));
+ fn = tmpcurrent_name;
}
if ((force == CHECKPOINT_TEST) && (r->dst->file_max == 0)) return 0;
- if ((r->dst->size == 0) || (r->dst->stamp == 0))
+ if ((r->dst->size == 0) || (r->dst->timestamp == 0))
{
struct stat sb;
return -1;
}
- if (r->dst->stamp == 0) r->dst->stamp = sb.st_birthtimespec.tv_sec;
- if (r->dst->stamp == 0) r->dst->stamp = sb.st_mtimespec.tv_sec;
+ if (r->dst->timestamp == 0) r->dst->timestamp = sb.st_birthtimespec.tv_sec;
+ if (r->dst->timestamp == 0) r->dst->timestamp = sb.st_mtimespec.tv_sec;
r->dst->size = sb.st_size;
}
{
char srcpath[MAXPATHLEN];
char dstpath[MAXPATHLEN];
- char tstamp[32];
-
- if (r->dst->stamp == 0) r->dst->stamp = time(NULL);
- asl_make_timestamp(r->dst->stamp, r->dst->flags, tstamp, sizeof(tstamp));
snprintf(srcpath, sizeof(srcpath), "%s", fn);
- snprintf(dstpath, sizeof(dstpath), "%s.%s", fn, tstamp);
+
+ r->dst->timestamp = time(NULL);
+ asl_dst_make_current_name(r->dst, MODULE_FLAG_BASESTAMP, dstpath, sizeof(dstpath));
_act_dst_close(r, DST_CLOSE_CHECKPOINT);
- rename(srcpath, dstpath);
+ if (strneq(srcpath, dstpath))
+ {
+ rename(srcpath, dstpath);
+ asldebug("CHECKPOINT RENAME %s %s\n", srcpath, dstpath);
+ }
}
- r->dst->stamp = 0;
+ r->dst->timestamp = 0;
r->dst->size = 0;
return 1;
}
/* checks file_max and closes if required */
status = _act_checkpoint(r, CHECKPOINT_TEST);
- if (status == 1) trigger_aslmanager();
+ if (status == 1) asl_trigger_aslmanager();
if (as_data->aslfile != NULL)
{
tick = (const time_t *)&now;
}
- asl_make_timestamp(now, r->dst->flags, tstamp, sizeof(tstamp));
- asprintf(&(r->dst->fname), "%s/%s.asl", r->dst->path, tstamp);
+ asl_make_timestamp(now, r->dst->style_flags, tstamp, sizeof(tstamp));
+ asprintf(&(r->dst->current_name), "%s/%s.asl", r->dst->path, tstamp);
}
else
{
- asprintf(&(r->dst->fname), "%s/%d.%02d.%02d.asl", r->dst->path, ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
+ asprintf(&(r->dst->current_name), "%s/%d.%02d.%02d.asl", r->dst->path, ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
}
- if (r->dst->fname == NULL)
+ if (r->dst->current_name == NULL)
{
asldebug("_asl_dir_today_open: asprintf error %s\n", strerror(errno));
return -1;
#endif
mask = umask(0);
- status = asl_file_open_write(r->dst->fname, (r->dst->mode & 00666), uid, gid, &(as_data->aslfile));
+ status = asl_file_open_write(r->dst->current_name, (r->dst->mode & 00666), uid, gid, &(as_data->aslfile));
umask(mask);
if (status != ASL_STATUS_OK)
{
- asldebug("_asl_dir_today_open: asl_file_open_write %s error %s\n", r->dst->fname, asl_core_error(status));
- free(r->dst->fname);
- r->dst->fname = NULL;
+ asldebug("_asl_dir_today_open: asl_file_open_write %s error %s\n", r->dst->current_name, asl_core_error(status));
+ free(r->dst->current_name);
+ r->dst->current_name = NULL;
return -1;
}
if (fseek(as_data->aslfile->store, 0, SEEK_END) != 0)
{
- asldebug("_asl_dir_today_open: fseek %s error %s\n", r->dst->fname, strerror(errno));
- free(r->dst->fname);
- r->dst->fname = NULL;
+ asldebug("_asl_dir_today_open: fseek %s error %s\n", r->dst->current_name, strerror(errno));
+ free(r->dst->current_name);
+ r->dst->current_name = NULL;
return -1;
}
dispatch_resume(as_data->aslfile_monitor);
}
- asldebug("_asl_dir_today_open ASL file %s fd %d\n", r->dst->fname, fd);
+ asldebug("_asl_dir_today_open ASL file %s fd %d\n", r->dst->current_name, fd);
return 0;
}
if (af_data->pending != 0)
{
char *str = NULL;
- asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message ASL File %s was closed with %d pending messages]", global.pid, r->dst->fname, af_data->pending);
+ asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message ASL File %s was closed with %d pending messages]", global.pid, r->dst->current_name, af_data->pending);
internal_log_message(str);
free(str);
}
fd = _act_file_create_open(r->dst);
if (fd < 0)
{
- asldebug("_asl_file_open: _act_file_create_open %s failed %d %s\n", r->dst->fname, errno, strerror(errno));
+ asldebug("_asl_file_open: _act_file_create_open %s failed %d %s\n", r->dst->current_name, errno, strerror(errno));
return -1;
}
close(fd);
- if (r->dst->fname == NULL) return -1;
+ if (r->dst->current_name == NULL) return -1;
- status = asl_file_open_write(r->dst->fname, 0, -1, -1, &(af_data->aslfile));
+ status = asl_file_open_write(r->dst->current_name, 0, -1, -1, &(af_data->aslfile));
if (status != ASL_STATUS_OK)
{
- asldebug("_asl_file_open: asl_file_open_write %s failed %d %s\n", r->dst->fname, errno, strerror(errno));
+ asldebug("_asl_file_open: asl_file_open_write %s failed %d %s\n", r->dst->current_name, errno, strerror(errno));
return -1;
}
dispatch_resume(af_data->monitor);
}
- asldebug("_asl_file_open ASL file %s fd %d\n", r->dst->fname, fd);
+ asldebug("_asl_file_open ASL file %s fd %d\n", r->dst->current_name, fd);
return 0;
}
if (f_data->pending != 0)
{
char *str = NULL;
- asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message File %s was closed with %d pending messages]", global.pid, r->dst->fname, f_data->pending);
+ asprintf(&str, "[Sender syslogd] [Level 4] [PID %u] [Facility syslog] [Message File %s was closed with %d pending messages]", global.pid, r->dst->current_name, f_data->pending);
internal_log_message(str);
free(str);
}
}
else if (r->action == ACTION_ASL_FILE)
{
- asldebug("_act_dst_close: %s ASL FILE %s\n", why_str[why], (r->dst->fname == NULL) ? r->dst->path : r->dst->fname);
+ asldebug("_act_dst_close: %s ASL FILE %s\n", why_str[why], (r->dst->current_name == NULL) ? r->dst->path : r->dst->current_name);
_asl_file_close(r);
}
else if (r->action == ACTION_FILE)
{
- asldebug("_act_dst_close: %s FILE %s\n", why_str[why], (r->dst->fname == NULL) ? r->dst->path : r->dst->fname);
+ asldebug("_act_dst_close: %s FILE %s\n", why_str[why], (r->dst->current_name == NULL) ? r->dst->path : r->dst->current_name);
_text_file_close(r);
}
}
{
r->dst->size = af_data->aslfile->file_size;
- if (_act_checkpoint(r, CHECKPOINT_TEST) == 1) trigger_aslmanager();
+ if (_act_checkpoint(r, CHECKPOINT_TEST) == 1) asl_trigger_aslmanager();
}
}
if ((status < 0) || (status < len))
{
- asldebug("%s: error writing repeat message (%s): %s\n", MY_ID, r->dst->fname, strerror(errno));
+ asldebug("%s: error writing repeat message (%s): %s\n", MY_ID, r->dst->current_name, strerror(errno));
return -1;
}
if (_act_file_checkpoint(m, NULL, force) > 0) did_checkpoint = 1;
}
- trigger_aslmanager();
+ asl_trigger_aslmanager();
return did_checkpoint;
}
char *str;
time_t now;
+ if (r == NULL) return;
+ if (r->dst == NULL) return;
if (r->dst->private == NULL) return;
f_data = (asl_action_file_data_t *)r->dst->private;
size_t bytes = write(f_data->fd, str, len - 1);
if (bytes > 0) r->dst->size += bytes;
- if (_act_checkpoint(r, CHECKPOINT_TEST) == 1) trigger_aslmanager();
+ if (_act_checkpoint(r, CHECKPOINT_TEST) == 1) asl_trigger_aslmanager();
}
}
}
void
-asl_out_message(asl_msg_t *msg)
+asl_out_message(asl_msg_t *msg, int64_t msize)
{
OSAtomicIncrement32(&global.asl_queue_count);
asl_msg_retain(msg);
p = asl_msg_get_val_for_key(msg, ASL_KEY_FINAL_NOTIFICATION);
if (p != NULL) asl_msg_set_key_val(msg, ASL_KEY_FREE_NOTE, p);
+ /* chain to the next output module (done this way to make queue size accounting easier */
+#if !TARGET_IPHONE_SIMULATOR
+ if (global.bsd_out_enabled) bsd_out_message(msg, msize);
+ else OSAtomicAdd64(-1ll * msize, &global.memory_size);
+#else
+ OSAtomicAdd64(-1ll * msize, &global.memory_size);
+#endif
+
asl_msg_release(msg);
OSAtomicDecrement32(&global.asl_queue_count);
+++ /dev/null
-##
-# configuration file for syslogd and aslmanager in the iOS Simulator
-##
-
-# 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(SIMULATOR_LOG_ROOT)/performance
-? [A= Facility com.apple.performance] store_dir $ENV(SIMULATOR_LOG_ROOT)/performance
-
-# redirect com.apple.eventmonitor* messages to $ENV(SIMULATOR_LOG_ROOT)/eventmonitor
-? [A= Facility com.apple.eventmonitor] store_dir $ENV(SIMULATOR_LOG_ROOT)/eventmonitor
-
-# broadcast emergency messages
-? [= Level emergency] broadcast
-
-# ignore "internal" facility
-? [= Facility internal] ignore
-
-# save everything from emergency to notice
-? [<= Level notice] store
-
-# install messages get saved only in install.log
-? [= 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(SIMULATOR_LOG_ROOT)/system.log
-
-# Facility auth to level info gets saved in system.log
-? [= Facility auth] [<= Level info] file $ENV(SIMULATOR_LOG_ROOT)/system.log
-
-# Facility authpriv gets saved in system.log
-? [= Facility authpriv] file $ENV(SIMULATOR_LOG_ROOT)/system.log
}
void
-bsd_out_message(asl_msg_t *msg)
+bsd_out_message(asl_msg_t *msg, int64_t msize)
{
if (msg == NULL) return;
dispatch_async(bsd_out_queue, ^{
_bsd_match_and_send(msg);
asl_msg_release((asl_msg_t *)msg);
+
+ /* end of the output module chain (after asl) - decrement global memory stats */
+ OSAtomicAdd64(-1ll * msize, &global.memory_size);
+
OSAtomicDecrement32(&global.bsd_queue_count);
});
}
--- /dev/null
+# Rules for /var/log/system.log
+# This file is installed in /usr/local/etc/asl on iOS for Apple Internal
+#
+> /var/log/system.log mode=0640 format=bsd rotate=system.seq.log compress file_max=5M all_max=50M
+? [= Sender kernel] file system.log
+? [<= Level notice] file system.log
+? [= Facility auth] [<= Level info] file system.log
+? [= Facility authpriv] [<= Level info] file system.log
#include <libkern/OSAtomic.h>
#include <libproc.h>
#include <uuid/uuid.h>
+#include <asl_private.h>
#include "daemon.h"
#define LIST_SIZE_DELTA 256
+#define STATS_TABLE_SIZE 256
#define forever for(;;)
static int name_change_token = -1;
static OSSpinLock count_lock = 0;
-static int aslmanager_triggered = 0;
-
#if !TARGET_OS_EMBEDDED
static vproc_transaction_t vproc_trans = {0};
-#define DEFAULT_WORK_QUEUE_SIZE_MAX 10240000
-#else
-#define DEFAULT_WORK_QUEUE_SIZE_MAX 4096000
#endif
+#define DEFAULT_MEMORY_MAX SYSLOGD_WORK_QUEUE_MEMORY
+
#define QUOTA_KERN_EXCEEDED_MESSAGE "*** kernel exceeded %d log message per second limit - remaining messages this second discarded ***"
#define DEFAULT_DB_FILE_MAX 25600000
-#define DEFAULT_DB_MEMORY_MAX 512
-#define DEFAULT_DB_MEMORY_STR_MAX 4096000
+#define DEFAULT_DB_MEMORY_MAX 256
+#define DEFAULT_DB_MEMORY_STR_MAX 1024000
#define DEFAULT_MPS_LIMIT 500
#define DEFAULT_REMOTE_DELAY 5000
#define DEFAULT_BSD_MAX_DUP_SEC 30
#define DEFAULT_MARK_SEC 0
#define DEFAULT_UTMP_TTL_SEC 31622400
+#define DEFAULT_STATS_INTERVAL 600
+
+#define ASL_STATS_LEVEL 5
static time_t quota_time = 0;
static int32_t kern_quota;
"com.apple.system.log.kernel.debug"
};
-static int kern_notify_token[8] = {-1, -1, -1, -1, -1, -1, -1, -1 };
+static int kern_notify_token[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
+
+static stats_table_t *
+stats_table_new()
+{
+ stats_table_t *t = (stats_table_t *)malloc(sizeof(stats_table_t));
+ if (t == NULL) return NULL;
+
+ t->bucket_count = STATS_TABLE_SIZE;
+ t->bucket = (sender_stats_t **)calloc(t->bucket_count, sizeof(sender_stats_t *));
+ if (t->bucket == NULL)
+ {
+ free(t);
+ return NULL;
+ }
+
+ t->mcount = 0;
+ t->shim_count = 0;
+
+ return t;
+}
+
+static asl_msg_t *
+stats_table_final(stats_table_t *t)
+{
+ uint32_t i;
+ asl_msg_t *msg;
+ char val[64];
+
+ if (t == NULL) return NULL;
+
+ msg = asl_msg_new(ASL_TYPE_MSG);
+ if (msg == NULL) return NULL;
+
+ asl_msg_set_key_val(msg, ASL_KEY_MSG, "ASL Sender Statistics");
+ asl_msg_set_key_val(msg, ASL_KEY_SENDER, "syslogd");
+ asl_msg_set_key_val(msg, ASL_KEY_FACILITY, "com.apple.asl.statistics");
+ snprintf(val, sizeof(val), "%d", global.pid);
+ asl_msg_set_key_val(msg, ASL_KEY_PID, val);
+ snprintf(val, sizeof(val), "%d", ASL_STATS_LEVEL);
+ asl_msg_set_key_val(msg, ASL_KEY_LEVEL, val);
+ snprintf(val, sizeof(val), "%u", t->mcount);
+ asl_msg_set_key_val(msg, "MsgCount", val);
+ snprintf(val, sizeof(val), "%u", t->shim_count);
+ asl_msg_set_key_val(msg, "ShimCount", val);
+
+ for (i = 0; i < t->bucket_count; i++)
+ {
+ sender_stats_t *s;
+ s = t->bucket[i];
+ while (s != NULL)
+ {
+ char val[64], *key = NULL;
+ sender_stats_t *n = s->next;
+
+ snprintf(val, sizeof(val), "%llu %llu", s->count, s->size);
+ asprintf(&key, "*%s", s->sender);
+ if (key != NULL) asl_msg_set_key_val(msg, key, val);
+ free(key);
+ free(s->sender);
+ free(s);
+ s = n;
+ }
+ }
+
+ free(t->bucket);
+ free(t);
+
+ return msg;
+}
+
+static void
+stats_table_update(stats_table_t *t, const char *sender, uint64_t msg_size)
+{
+ uint32_t i;
+ sender_stats_t *s;
+ uint8_t *p;
+
+ if (t == NULL) return;
+ if (sender == NULL) return;
+
+ /* hash */
+ i = 0;
+ for (p = (uint8_t *)sender; *p != '\0'; p++) i = (i << 1) ^ (i ^ *p);
+ i %= STATS_TABLE_SIZE;
+
+ for (s = t->bucket[i]; s != NULL; s = s->next)
+ {
+ if ((s->sender != NULL) && (strcmp(sender, s->sender) == 0))
+ {
+ s->count++;
+ s->size += msg_size;
+ return;
+ }
+ }
+
+ s = (sender_stats_t *)malloc(sizeof(sender_stats_t));
+ s->sender = strdup(sender);
+ if (s->sender == NULL)
+ {
+ free(s);
+ return;
+ }
+
+ s->count = 1;
+ s->size = msg_size;
+ s->next = t->bucket[i];
+ t->bucket[i] = s;
+}
static uint32_t
kern_quota_check(time_t now, asl_msg_t *msg, uint32_t level)
return VERIFY_STATUS_OK;
}
+static void
+stats_msg(const char *sender, time_t now, asl_msg_t *msg)
+{
+ asl_msg_t *x;
+ uint64_t msize = 0;
+
+ /* flush stats after N seconds */
+ if ((global.stats_interval != 0) && ((now - global.stats_last) >= global.stats_interval) && (global.stats != NULL))
+ {
+ asl_msg_t *msg = stats_table_final(global.stats);
+ process_message(msg, SOURCE_INTERNAL);
+ global.stats = NULL;
+ global.stats_last = now;
+ }
+
+ if (global.stats == NULL) global.stats = stats_table_new();
+
+ for (x = msg; x != NULL; x = x->next) msize += x->mem_size;
+
+ const char *shim_vers = asl_msg_get_val_for_key(msg, "ASLSHIM");
+ global.stats->mcount++;
+ if (shim_vers != NULL) global.stats->shim_count++;
+
+ /* update count and total size - total and for this sender */
+ stats_table_update(global.stats, "*", msize);
+ stats_table_update(global.stats, sender, msize);
+}
+
static const char *
whatsmyhostname()
{
static dispatch_once_t once;
int check, status;
+ if (global.hostname != NULL) return global.hostname;
+
dispatch_once(&once, ^{
snprintf(myname, sizeof(myname), "%s", "localhost");
notify_register_check(kNotifySCHostNameChange, &name_change_token);
static uint32_t
aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t *uid_out)
{
- const char *val, *fac, *ruval, *rgval;
+ const char *val, *fac, *ruval, *rgval, *sval = NULL;
char buf[64];
time_t tick, now;
uid_t uid;
if (val == NULL) asl_msg_set_key_val(msg, ASL_KEY_PID, "0");
else pid = (pid_t)atoi(val);
- /* if PID is 1 (launchd), use the refpid if provided */
+ /* if PID is 1 (launchd), use the RefPID and RefProc provided */
if (pid == 1)
{
val = asl_msg_get_val_for_key(msg, ASL_KEY_REF_PID);
if (val != NULL) pid = (pid_t)atoi(val);
+
+ sval = asl_msg_get_val_for_key(msg, ASL_KEY_REF_PROC);
}
/* Level */
snprintf(buf, sizeof(buf), "%d", level);
asl_msg_set_key_val(msg, ASL_KEY_LEVEL, buf);
+
/* check kernel quota if enabled and no processes are watching */
if ((pid == 0) && (global.mps_limit > 0) && (global.watchers_active == 0))
{
if ((tick == 0) || (tick > now)) tick = now;
/* Canonical form: seconds since the epoch */
- snprintf(buf, sizeof(buf) - 1, "%lu", tick);
+ snprintf(buf, sizeof(buf) - 1, "%llu", (unsigned long long) tick);
asl_msg_set_key_val(msg, ASL_KEY_TIME, buf);
/* Host */
}
/* Sender */
- val = asl_msg_get_val_for_key(msg, ASL_KEY_SENDER);
- if (val == NULL)
+ if (sval == NULL) sval = asl_msg_get_val_for_key(msg, ASL_KEY_SENDER);
+ if (sval == NULL)
{
switch (source)
{
case SOURCE_KERN:
{
- asl_msg_set_key_val(msg, ASL_KEY_SENDER, "kernel");
+ sval = "kernel";
+ asl_msg_set_key_val(msg, ASL_KEY_SENDER, sval);
break;
}
case SOURCE_INTERNAL:
{
- asl_msg_set_key_val(msg, ASL_KEY_SENDER, "syslogd");
+ sval = "syslogd";
+ asl_msg_set_key_val(msg, ASL_KEY_SENDER, sval);
break;
}
default:
}
}
}
- else if ((source != SOURCE_KERN) && (uid != 0) && (!strcmp(val, "kernel")))
+ else if ((source != SOURCE_KERN) && (uid != 0) && (!strcmp(sval, "kernel")))
{
/* allow UID 0 to send messages with "Sender kernel", but nobody else */
asl_msg_set_key_val(msg, ASL_KEY_SENDER, "Unknown");
+ sval = NULL;
}
/* Facility */
/* Set DB Expire Time for com.apple.system.utmpx and lastlog */
if ((!strcmp(fac, "com.apple.system.utmpx")) || (!strcmp(fac, "com.apple.system.lastlog")))
{
- snprintf(buf, sizeof(buf), "%lu", tick + global.utmp_ttl);
+ snprintf(buf, sizeof(buf), "%llu", (unsigned long long) tick + global.utmp_ttl);
asl_msg_set_key_val(msg, ASL_KEY_EXPIRE_TIME, buf);
}
/* Set DB Expire Time for Filesystem errors */
if (!strcmp(fac, FSLOG_VAL_FACILITY))
{
- snprintf(buf, sizeof(buf), "%lu", tick + FS_TTL_SEC);
+ snprintf(buf, sizeof(buf), "%llu", (unsigned long long) tick + FS_TTL_SEC);
asl_msg_set_key_val(msg, ASL_KEY_EXPIRE_TIME, buf);
}
disaster_message(msg);
}
+ /*
+ * gather sender stats
+ */
+ if (source != SOURCE_INTERNAL) stats_msg(sval, now, msg);
+
return VERIFY_STATUS_OK;
}
global.bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC;
global.mark_time = DEFAULT_MARK_SEC;
global.utmp_ttl = DEFAULT_UTMP_TTL_SEC;
- global.max_work_queue_size = DEFAULT_WORK_QUEUE_SIZE_MAX;
+ global.memory_max = DEFAULT_MEMORY_MAX;
+ global.stats_interval = DEFAULT_STATS_INTERVAL;
global.asl_out_module = asl_out_module_init();
OSSpinLockUnlock(&global.lock);
return -1;
}
- if (!strcasecmp(l[0], "mark_time"))
+ if (!strcasecmp(l[0], "hostname"))
+ {
+ /* = hostname name */
+ OSSpinLockLock(&global.lock);
+ if (eval)
+ {
+ global.hostname = strdup(l[1]);
+ }
+ else
+ {
+ free(global.hostname);
+ global.hostname = NULL;
+ }
+ OSSpinLockUnlock(&global.lock);
+ }
+ else if (!strcasecmp(l[0], "mark_time"))
{
/* = mark_time seconds */
OSSpinLockLock(&global.lock);
else global.mps_limit = DEFAULT_MPS_LIMIT;
OSSpinLockUnlock(&global.lock);
}
- else if (!strcasecmp(l[0], "max_work_queue_size"))
+ else if (!strcasecmp(l[0], "memory_max"))
{
- /* = max_work_queue_size number */
+ /* = memory_max number */
OSSpinLockLock(&global.lock);
- if (eval) global.max_work_queue_size = (int64_t)atoll(l[1]);
- else global.max_work_queue_size = DEFAULT_WORK_QUEUE_SIZE_MAX;
+ if (eval) global.memory_max = (int64_t)atoll(l[1]);
+ else global.memory_max = DEFAULT_MEMORY_MAX;
+ OSSpinLockUnlock(&global.lock);
+ }
+ else if (!strcasecmp(l[0], "stats_interval"))
+ {
+ /* = stats_interval number */
+ OSSpinLockLock(&global.lock);
+ if (eval) global.stats_interval = (time_t)atoll(l[1]);
+ else global.stats_interval = DEFAULT_STATS_INTERVAL;
OSSpinLockUnlock(&global.lock);
}
else if (!strcasecmp(l[0], "max_file_size"))
process_message(asl_msg_t *msg, uint32_t source)
{
int64_t msize = 0;
- static bool wq_draining = false;
bool is_control = false;
asl_msg_t *x;
is_control = asl_check_option(msg, ASL_OPT_CONTROL) != 0;
- if ((!is_control) && wq_draining)
- {
- if (global.work_queue_size >= (global.max_work_queue_size / 2))
- {
- asldebug("Work queue draining: dropped message.\n");
- asl_msg_release(msg);
- return;
- }
- else
- {
- asldebug("Work queue re-enabled at 1/2 max. size %llu max %llu\n", global.work_queue_size, global.max_work_queue_size);
- wq_draining = false;
- }
- }
+ __block vproc_transaction_t vt = vproc_transaction_begin(NULL);
for (x = msg; x != NULL; x = x->next) msize += x->mem_size;
- if ((global.work_queue_size + msize) >= global.max_work_queue_size)
+ if ((global.memory_size + msize) >= global.memory_max)
{
- char *str = NULL;
-
- wq_draining = true;
+ char str[256];
asl_msg_release(msg);
- asldebug("Work queue disabled. msize %llu size %llu max %llu\n", msize, global.work_queue_size + msize, global.max_work_queue_size);
- asprintf(&str, "[Sender syslogd] [Level 2] [PID %u] [Message Internal work queue size limit exceeded - dropping messages] [UID 0] [UID 0] [Facility syslog]", global.pid);
+ asldebug("Work queue memory limit - dropped message. msize %lld size %lld max %lld\n", msize, global.memory_size + msize, global.memory_max);
+ snprintf(str, sizeof(str), "[Sender syslogd] [Level 2] [PID %u] [Message Received message size %lld overflows work queue limit %lld - dropping message] [UID 0] [UID 0] [Facility syslog]", global.pid, msize, global.memory_max);
msg = asl_msg_from_string(str);
- free(str);
+ for (x = msg; x != NULL; x = x->next) msize += x->mem_size;
}
- OSAtomicAdd64(msize, &global.work_queue_size);
+ OSAtomicAdd64(msize, &global.memory_size);
OSAtomicIncrement32(&global.work_queue_count);
+
dispatch_async(global.work_queue, ^{
int32_t kplevel;
uint32_t status;
if ((uid == 0) && is_control) control_message(msg);
- /* send message to output modules */
- asl_out_message(msg);
-#if !TARGET_IPHONE_SIMULATOR
- if (global.bsd_out_enabled) bsd_out_message(msg);
-#endif
+ /*
+ * Send message to output module chain (asl is first).
+ * The last module in the chain will decrement global.memory_size.
+ */
+ asl_out_message(msg, msize);
+ }
+ else
+ {
+ OSAtomicAdd64(-1ll * msize, &global.memory_size);
}
asl_msg_release(msg);
- OSAtomicAdd64(-1ll * msize, &global.work_queue_size);
OSAtomicDecrement32(&global.work_queue_count);
+ vproc_transaction_end(NULL, vt);
});
}
return 0;
}
-void
-trigger_aslmanager()
-{
- dispatch_async(dispatch_get_main_queue(), ^{
- if (aslmanager_triggered == 0)
- {
- aslmanager_triggered = 1;
-
- time_t now = time(0);
- if ((now - global.aslmanager_last_trigger) >= ASLMANAGER_DELAY)
- {
- global.aslmanager_last_trigger = now;
- asl_trigger_aslmanager();
- aslmanager_triggered = 0;
- }
- else
- {
- uint64_t delta = ASLMANAGER_DELAY - (now - global.aslmanager_last_trigger);
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delta * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
- global.aslmanager_last_trigger = time(0);
- asl_trigger_aslmanager();
- aslmanager_triggered = 0;
- });
- }
- }
- });
-}
-
int
asldebug(const char *str, ...)
{
if (dfp == NULL) return 0;
va_start(v, str);
+ fprintf(dfp, "W %d %llu", global.work_queue_count, global.memory_size);
+ if (global.memory_db != NULL) fprintf(dfp, " M %u %u %lu", global.memory_db->record_count, global.memory_db->string_count, global.memory_db->curr_string_mem);
+ fprintf(dfp, " ; ");
vfprintf(dfp, str, v);
va_end(v);
/* Time */
if (when != NULL)
{
- snprintf(str, sizeof(str), "%lu", when->tv_sec);
+ snprintf(str, sizeof(str), "%llu", (unsigned long long) when->tv_sec);
asl_msg_set_key_val(m, ASL_KEY_TIME, str);
snprintf(str, sizeof(str), "%lu", 1000 * (unsigned long int)when->tv_usec);
else
{
now = time(NULL);
- snprintf(str, sizeof(str), "%lu", now);
+ snprintf(str, sizeof(str), "%llu", (unsigned long long) now);
asl_msg_set_key_val(m, ASL_KEY_TIME, str);
}
#define SEC_PER_DAY 86400
-/* trigger aslmanager no more often than 300 seconds */
-#define ASLMANAGER_DELAY 300
+typedef struct sender_stats_s
+{
+ char *sender;
+ uint64_t count;
+ uint64_t size;
+ struct sender_stats_s *next;
+} sender_stats_t;
+
+typedef struct
+{
+ uint32_t mcount;
+ uint32_t shim_count;
+ uint32_t bucket_count;
+ sender_stats_t **bucket;
+} stats_table_t;
typedef struct
{
int reset;
pid_t pid;
int32_t work_queue_count;
- int64_t work_queue_size;
+ /* memory_size must be aligned for OSAtomicAdd64 */
+ __attribute__((aligned(8))) int64_t memory_size;
int32_t asl_queue_count;
int32_t bsd_queue_count;
pthread_mutex_t *db_lock;
int launchd_enabled;
module_t **module;
asl_out_module_t *asl_out_module;
- time_t aslmanager_last_trigger;
+ time_t stats_last;
+ stats_table_t *stats;
/* parameters below are configurable as command-line args or in /etc/asl.conf */
int debug;
char *debug_file;
+ char *hostname;
int dbtype;
uint32_t db_file_max;
uint32_t db_memory_max;
uint64_t bsd_max_dup_time;
uint64_t mark_time;
time_t utmp_ttl;
- int64_t max_work_queue_size;
+ time_t stats_interval;
+ int64_t memory_max;
};
extern struct global_s global;
asl_msg_t *asl_input_parse(const char *in, int len, char *rhost, uint32_t source);
void process_message(asl_msg_t *msg, uint32_t source);
-void asl_out_message(asl_msg_t *msg);
-void bsd_out_message(asl_msg_t *msg);
+void asl_out_message(asl_msg_t *msg, int64_t msize);
+void bsd_out_message(asl_msg_t *msg, int64_t msize);
int control_set_param(const char *s, bool eval);
int asl_action_control_set_param(const char *s);
-void trigger_aslmanager();
-
/* notify SPI */
uint32_t notify_register_plain(const char *name, int *out_token);
/*
- * Copyright (c) 2007-2012 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2015 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <sys/errno.h>
#include <mach/mach.h>
#include <mach/mach_error.h>
+#include <mach/vm_param.h>
#include <bsm/libbsm.h>
#include <errno.h>
#include <netinet/in.h>
#define ASL_ENTITLEMENT_UID_KEY "com.apple.asl.access_as_uid"
#define ASL_ENTITLEMENT_GID_KEY "com.apple.asl.access_as_gid"
+#define PAGE_ROUND_UP(x) ((((x)+PAGE_SIZE-1)/PAGE_SIZE)*PAGE_SIZE)
+
static dispatch_queue_t asl_server_queue;
static dispatch_queue_t watch_queue;
static dispatch_once_t watch_init_once;
else
{
if (global.db_file_max != 0) asl_store_max_file_size(global.file_db, global.db_file_max);
- trigger_aslmanager();
+ asl_trigger_aslmanager();
}
}
if (all || (0 == asl_msg_lookup(q, "utmp_ttl", NULL, NULL)))
{
- snprintf(val, sizeof(val), "%lu", global.utmp_ttl);
+ snprintf(val, sizeof(val), "%llu", (unsigned long long) global.utmp_ttl);
asl_msg_set_key_val(m, "utmp_ttl", val);
}
- if (all || (0 == asl_msg_lookup(q, "max_work_queue_size", NULL, NULL)))
+ if (all || (0 == asl_msg_lookup(q, "memory_size", NULL, NULL)))
{
- snprintf(val, sizeof(val), "%lld", global.max_work_queue_size);
- asl_msg_set_key_val(m, "max_work_queue_size", val);
+ snprintf(val, sizeof(val), "%lld", global.memory_size);
+ asl_msg_set_key_val(m, "memory_size", val);
+ }
+
+ if (all || (0 == asl_msg_lookup(q, "memory_max", NULL, NULL)))
+ {
+ snprintf(val, sizeof(val), "%lld", global.memory_max);
+ asl_msg_set_key_val(m, "memory_max", val);
+ }
+
+ if (all || (0 == asl_msg_lookup(q, "stats_interval", NULL, NULL)))
+ {
+ snprintf(val, sizeof(val), "%lld", (long long) global.stats_interval);
+ asl_msg_set_key_val(m, "stats_interval", val);
}
if (all || (0 == asl_msg_lookup(q, "work_queue_count", NULL, NULL)))
return ASL_STATUS_OK;
}
+static kern_return_t
+_server_message_processing(asl_request_msg *request)
+{
+ const uint32_t sbits = MACH_SEND_MSG | MACH_SEND_TIMEOUT;;
+ kern_return_t ks;
+ asl_reply_msg *reply = calloc(1, sizeof(asl_reply_msg) + MAX_TRAILER_SIZE);
+
+ voucher_mach_msg_state_t voucher = voucher_mach_msg_adopt(&(request->head));
+
+ /* MIG server routine */
+ asl_ipc_server(&(request->head), &(reply->head));
+
+ if (!(reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
+ {
+ if (reply->reply.Reply__asl_server_message.RetCode == MIG_NO_REPLY)
+ {
+ reply->head.msgh_remote_port = MACH_PORT_NULL;
+ }
+ else if ((reply->reply.Reply__asl_server_message.RetCode != KERN_SUCCESS) && (request->head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
+ {
+ /* destroy the request - but not the reply port */
+ request->head.msgh_remote_port = MACH_PORT_NULL;
+ mach_msg_destroy(&(request->head));
+ }
+ }
+
+ if (reply->head.msgh_remote_port != MACH_PORT_NULL)
+ {
+ ks = mach_msg(&(reply->head), sbits, reply->head.msgh_size, 0, MACH_PORT_NULL, 10, MACH_PORT_NULL);
+ if ((ks == MACH_SEND_INVALID_DEST) || (ks == MACH_SEND_TIMED_OUT))
+ {
+ /* clean up */
+ mach_msg_destroy(&(reply->head));
+ }
+ else if (ks == MACH_SEND_INVALID_HEADER)
+ {
+ /*
+ * This should never happen, but we can continue running.
+ */
+ char str[256];
+ asldebug("ERROR: mach_msg() send failed with MACH_SEND_INVALID_HEADER 0x%08x\n", ks);
+ snprintf(str, sizeof(str), "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message mach_msg() send failed with status 0x%08x (MACH_SEND_INVALID_HEADER)]", global.pid, ks);
+ internal_log_message(str);
+ mach_msg_destroy(&(reply->head));
+ }
+ else if (ks == MACH_SEND_NO_BUFFER)
+ {
+ /*
+ * This should never happen, but the kernel can run out of memory.
+ * We clean up and continue running.
+ */
+ char str[256];
+ asldebug("ERROR: mach_msg() send failed with MACH_SEND_NO_BUFFER 0x%08x\n", ks);
+ snprintf(str, sizeof(str), "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message mach_msg() send failed with status 0x%08x (MACH_SEND_NO_BUFFER)]", global.pid, ks);
+ internal_log_message(str);
+ mach_msg_destroy(&(reply->head));
+ }
+ else if (ks != KERN_SUCCESS)
+ {
+ /*
+ * Failed to send a reply message. This should never happen,
+ * but the best action is to crash.
+ */
+ char str[256];
+ asldebug("FATAL ERROR: mach_msg() send failed with status 0x%08x\n", ks);
+ snprintf(str, sizeof(str), "[Sender syslogd] [Level 1] [PID %u] [Facility syslog] [Message FATAL ERROR: mach_msg() send failed with status 0x%08x]", global.pid, ks);
+ internal_log_message(str);
+ sleep(1);
+ abort();
+ }
+ }
+ else if (reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
+ {
+ mach_msg_destroy(&reply->head);
+ }
+
+ voucher_mach_msg_revert(voucher);
+ free(request);
+ free(reply);
+}
+
/*
* Receives messages on the "com.apple.system.logger" mach port.
* Services database search requests.
* Runs in it's own thread.
+ *
+ * The logic in this routine got a bit more complex due to (1) increased logging load and (2) 16K page size.
+ * Out-of-line (OOL) memory sent to syslogd from libasl is allocated in pages, so the minimum size of a
+ * message is one page. Since this routine can get slammed with messages at a very high rate, and since
+ * the message queue in the kernel is only 5 messages, it is critical that this routine service the port
+ * as fast as possible. To that end, it needs to do as little processing as possible.
+ * In the version of this code found up to syslog-312, this routine received messages and dispatched them
+ * on the asl_server_queue for further processing. When pages were only 4K, this was not a problem. With
+ * 16K pages, it only takes about 650 messages to run syslogd's dirty memoory size up to the point of its
+ * jetsam limit. Code was added here to track the memory being used in this queue + the work queue that's
+ * used by process_message(), such that messages will get dropped if the queues reach a memory limit.
+ * The actual message data in the VM pages is typically only a few hundred bytes, so holding VM pages in
+ * the queue was a waste, and seriously limited the number of queued messages.
+ *
+ * The solution implemented here is a bit of a hack. It peeks at the received message header to determine
+ * which MIG routine is being called. If the call is for _asl_server_message, it calls asl_ipc_server()
+ * on the server thread. This routes the call through the MIG server code for error checking and so on,
+ * and invokes _asl_server_message() on this thread. _asl_server_message() has been modified to copy
+ * the message data into malloced memory, vm_deallocate the OOL memory, and then it dispatches the real
+ * work onto the asl_server_queue.
*/
void
database_server()
{
asl_request_msg *request;
- uint32_t rqs;
+ uint32_t rqs, asl_server_message_num = 0;
+ size_t i;
struct timeval now, send_time;
mach_dead_name_notification_t *deadname;
const uint32_t rbits = MACH_RCV_MSG | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) | MACH_RCV_VOUCHER;
-
send_time.tv_sec = 0;
send_time.tv_usec = 0;
+ struct mig_map_s {
+ const char *routine;
+ int num;
+ } migmap[] = { subsystem_to_name_map_asl_ipc };
+
+ for (i = 0; (i < (sizeof(migmap) / sizeof(struct mig_map_s))) && (asl_server_message_num == 0); i++)
+ {
+ if (!strcmp(migmap[i].routine, "_asl_server_message")) asl_server_message_num = migmap[i].num;
+ }
rqs = sizeof(asl_request_msg) + MAX_TRAILER_SIZE;
continue;
}
- dispatch_async(asl_server_queue, ^{
- const uint32_t sbits = MACH_SEND_MSG | MACH_SEND_TIMEOUT;;
- kern_return_t ks;
- asl_reply_msg *reply = calloc(1, sizeof(asl_reply_msg) + MAX_TRAILER_SIZE);
-
- voucher_mach_msg_state_t voucher = voucher_mach_msg_adopt(&(request->head));
-
- /* MIG server routine */
- asl_ipc_server(&(request->head), &(reply->head));
-
- if (!(reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
- {
- if (reply->reply.Reply__asl_server_message.RetCode == MIG_NO_REPLY)
- {
- reply->head.msgh_remote_port = MACH_PORT_NULL;
- }
- else if ((reply->reply.Reply__asl_server_message.RetCode != KERN_SUCCESS) && (request->head.msgh_bits & MACH_MSGH_BITS_COMPLEX))
- {
- /* destroy the request - but not the reply port */
- request->head.msgh_remote_port = MACH_PORT_NULL;
- mach_msg_destroy(&(request->head));
- }
- }
-
- if (reply->head.msgh_remote_port != MACH_PORT_NULL)
- {
- ks = mach_msg(&(reply->head), sbits, reply->head.msgh_size, 0, MACH_PORT_NULL, 10, MACH_PORT_NULL);
- if ((ks == MACH_SEND_INVALID_DEST) || (ks == MACH_SEND_TIMED_OUT))
- {
- /* clean up */
- mach_msg_destroy(&(reply->head));
- }
- else if (ks == MACH_SEND_INVALID_HEADER)
- {
- /*
- * This should never happen, but we can continue running.
- */
- char str[256];
- asldebug("ERROR: mach_msg() send failed with MACH_SEND_INVALID_HEADER 0x%08x\n", ks);
- snprintf(str, sizeof(str), "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message mach_msg() send failed with status 0x%08x (MACH_SEND_INVALID_HEADER)]", global.pid, ks);
- internal_log_message(str);
- mach_msg_destroy(&(reply->head));
- }
- else if (ks == MACH_SEND_NO_BUFFER)
- {
- /*
- * This should never happen, but the kernel can run out of memory.
- * We clean up and continue running.
- */
- char str[256];
- asldebug("ERROR: mach_msg() send failed with MACH_SEND_NO_BUFFER 0x%08x\n", ks);
- snprintf(str, sizeof(str), "[Sender syslogd] [Level 3] [PID %u] [Facility syslog] [Message mach_msg() send failed with status 0x%08x (MACH_SEND_NO_BUFFER)]", global.pid, ks);
- internal_log_message(str);
- mach_msg_destroy(&(reply->head));
- }
- else if (ks != KERN_SUCCESS)
- {
- /*
- * Failed to send a reply message. This should never happen,
- * but the best action is to crash.
- */
- char str[256];
- asldebug("FATAL ERROR: mach_msg() send failed with status 0x%08x\n", ks);
- snprintf(str, sizeof(str), "[Sender syslogd] [Level 1] [PID %u] [Facility syslog] [Message FATAL ERROR: mach_msg() send failed with status 0x%08x]", global.pid, ks);
- internal_log_message(str);
- sleep(1);
- abort();
- }
- }
- else if (reply->head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
- {
- mach_msg_destroy(&reply->head);
- }
-
- voucher_mach_msg_revert(voucher);
- free(request);
- free(reply);
- });
+ int64_t msize = 0;
+ if (request->head.msgh_id == asl_server_message_num)
+ {
+ _server_message_processing(request);
+ }
+ else
+ {
+ dispatch_async(asl_server_queue, ^{ _server_message_processing(request); });
+ }
}
}
if ((out == NULL) || (outlen == 0)) return KERN_SUCCESS;
- kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, outlen, TRUE);
+ kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, outlen, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
if (kstatus != KERN_SUCCESS)
{
free(out);
return KERN_SUCCESS;
}
+/*
+ * Does the actual processing for __asl_server_message.
+ * Dispatched on asl_server_queue. This lets us avoid
+ * calling asl_msg_from_string(), task_name_for_pid(),
+ * and register_session() on the database_server() thread.
+ */
+static void
+_asl_message_processing(char *mbuf, uint64_t msize, uid_t uid, gid_t gid, pid_t pid)
+{
+ asl_msg_t *msg;
+ char tmp[64];
+ kern_return_t kstatus;
+ mach_port_name_t client;
+
+ msg = asl_msg_from_string(mbuf);
+ free(mbuf);
+
+ /*
+ * process_message() will update global.memory_size with the
+ * size of msg, and it increements the work_queue_count.
+ */
+ OSAtomicAdd64(-1ll * msize, &global.memory_size);
+ OSAtomicDecrement32(&global.work_queue_count);
+
+ if (msg == NULL) return;
+
+ client = MACH_PORT_NULL;
+ kstatus = task_name_for_pid(mach_task_self(), pid, &client);
+ if (kstatus == KERN_SUCCESS) register_session(client, pid);
+
+ snprintf(tmp, sizeof(tmp), "%d", uid);
+ asl_msg_set_key_val(msg, ASL_KEY_UID, tmp);
+
+ snprintf(tmp, sizeof(tmp), "%d", gid);
+ asl_msg_set_key_val(msg, ASL_KEY_GID, tmp);
+
+ snprintf(tmp, sizeof(tmp), "%d", pid);
+ asl_msg_set_key_val(msg, ASL_KEY_PID, tmp);
+
+ process_message(msg, SOURCE_ASL_MESSAGE);
+}
+
+/*
+ * This MIG server routine is something of a special case in database_server() above.
+ * It is called on the server thread that's responsible for servicing syslogd's mach port.
+ * In this routine we copy the actual ASL message raw string out of the message into
+ * malloc memory, deallocate the message, and dispatch the real work onto the asl_server_queue.
+ */
kern_return_t
__asl_server_message
(
audit_token_t token
)
{
- asl_msg_t *msg;
- char tmp[64];
uid_t uid;
gid_t gid;
pid_t pid;
- kern_return_t kstatus;
- mach_port_name_t client;
+ char *mbuf;
- if (message == NULL)
+ if (message == NULL) return KERN_SUCCESS;
+
+ if (message[messageCnt - 1] != '\0')
{
+ vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
return KERN_SUCCESS;
}
- if (message[messageCnt - 1] != '\0')
+ asldebug("__asl_server_message: %s\n", message);
+
+ if ((global.memory_size + messageCnt) > global.memory_max)
{
+ char str[256];
+ asldebug("Server queue dropped message. message size %u queue size %lld max %lld\n", messageCnt, global.memory_size, global.memory_max);
+ snprintf(str, sizeof(str), "[Sender syslogd] [Level 2] [PID %u] [Message Received message size %u overflows work queue (size %lld limit %lld) - dropping message] [UID 0] [UID 0] [Facility syslog]", global.pid, messageCnt, global.memory_size, global.memory_max);
+ internal_log_message(str);
+
vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
return KERN_SUCCESS;
}
- asldebug("__asl_server_message: %s\n", (message == NULL) ? "NULL" : message);
-
- msg = asl_msg_from_string(message);
+ mbuf = malloc(messageCnt);
+ if (mbuf != NULL) memcpy(mbuf, message, messageCnt);
vm_deallocate(mach_task_self(), (vm_address_t)message, messageCnt);
- if (msg == NULL) return KERN_SUCCESS;
+ if (mbuf == NULL) return KERN_SUCCESS;
uid = (uid_t)-1;
gid = (gid_t)-1;
pid = (pid_t)-1;
audit_token_to_au32(token, NULL, &uid, &gid, NULL, NULL, &pid, NULL, NULL);
- client = MACH_PORT_NULL;
- kstatus = task_name_for_pid(mach_task_self(), pid, &client);
- if (kstatus == KERN_SUCCESS) register_session(client, pid);
+ OSAtomicIncrement32(&global.work_queue_count);
+ OSAtomicAdd64(messageCnt, &(global.memory_size));
- snprintf(tmp, sizeof(tmp), "%d", uid);
- asl_msg_set_key_val(msg, ASL_KEY_UID, tmp);
-
- snprintf(tmp, sizeof(tmp), "%d", gid);
- asl_msg_set_key_val(msg, ASL_KEY_GID, tmp);
-
- snprintf(tmp, sizeof(tmp), "%d", pid);
- asl_msg_set_key_val(msg, ASL_KEY_PID, tmp);
-
- process_message(msg, SOURCE_ASL_MESSAGE);
+ dispatch_async(asl_server_queue, ^{ _asl_message_processing(mbuf, messageCnt, uid, gid, pid); });
return KERN_SUCCESS;
}
*newurlCnt = strlen(url) + 1;
- kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, *newurlCnt, TRUE);
+ kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmbuffer, *newurlCnt, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
if (kstatus != KERN_SUCCESS)
{
free(url);
}
else
{
+ free(out);
+ out = NULL;
+
+ asl_msg_list_release(res);
+ res = NULL;
+
goto exit_session;
}
}
--- /dev/null
+# Note that flat file logs are now configured in /etc/asl.conf
+
+install.* @127.0.0.1:32376
main(int argc, const char *argv[])
{
int32_t i;
+ uint64_t master_val;
#if !TARGET_IPHONE_SIMULATOR
int network_change_token;
#endif
- int quota_file_token, asl_db_token;
+ int quota_file_token, asl_db_token, master_token;
char tstr[32], *notify_key;
time_t now;
int first_syslogd_start = 1;
*/
write_boot_log(first_syslogd_start);
+ /* default NOTIFY_SYSTEM_MASTER settings */
+ master_val = 0x0;
+ notify_register_plain(NOTIFY_SYSTEM_MASTER, &master_token);
+ notify_set_state(master_token, master_val);
+
asldebug("reading launch plist\n");
launch_config();
return 0;
}
-/* N.B. Does NOT close fds. They "belong" to launchd. */
int
udp_in_close(void)
{
if (ufd[i] != -1)
{
+ close(ufd[i]);
ufd[i] = -1;
}
}
.Fl x Ar file Ar expression
.D1 ""
.Nm
-.Fl c Ar process Op filter
+.Fl c Ar process Op mask
.D1 ""
.Nm
.Fl config Op options
The
.Fl c
option may be used to control filtering.
-In addition to the internal filter value that processes may set as described above,
+In addition to the internal filter mask value that processes may set as described above,
the system maintains a global
.Dq master
-filter.
+filter mask.
This filter is normally
.Dq off ,
meaning that it has no effect.
-If a value is set for the master filter, it overrides the local filter for all processes.
-Root user access is required to set the master filter value.
+If a value is set for the master filter mask, it overrides the local filter mask for all processes.
+Root user access is required to set the master filter mask value.
.Pp
The current setting of the master filter mask may be inspected using:
.Pp
The character
.Dq x
may be used for Error, as it is used for sending messages.
-The master filter may be unset with:
+The master filter mask may be deactivated with:
.Pp
.Dl syslog -c 0 off
.Pp
-Since it is common to use the filter as a
+Since it is common to use the filter mask as a
.Dq cutoff
mechanism, for example to cut off messages with Debug and Info priority,
a single character from the list above may be specified, preceded by a minus sign.
uses a filter mask starting at level 0 (Emergency)
.Dq up to
the given level.
-For example, to set the master filter level to cause all processes to log messages from Emergency up to Debug:
+For example, to set the master filter mask to cause all processes to log messages from Emergency up to Debug:
.Pp
.Dl syslog -c 0 -d
.Pp
-While the master filter level may be set to control the messages produced by all processes,
+While the master filter mask may be set to control the messages produced by all processes,
another filter mask may be specified for an individual process.
If a per-process filter mask is set, it overrides both the local filter mask and the master filter mask.
The current setting for a per-process filter mask may be inspected using
/*
- * Copyright (c) 2007-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2015 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
static uint32_t dbselect = DB_SELECT_ASL;
#endif
+typedef struct
+{
+ char *name;
+ uint32_t count;
+ uint32_t total_messages;
+ size_t total_size;
+ uint32_t *messages;
+ size_t *size;
+} sender_stat_t;
+
+#define ASL_IOS_STATS_DIR "/var/log/asl/Logs/ASLStatistics"
+static uint32_t stats_sender_count;
+static sender_stat_t **stats_sender;
+static uint32_t stats_total_all_messages;
+
/* notify SPI */
uint32_t notify_register_plain(const char *name, int *out_token);
-//extern asl_msg_t *asl_msg_from_string(const char *buf);
-//extern char *asl_list_to_string(asl_msg_list_t *list, uint32_t *outlen);
-//extern asl_msg_list_t *asl_list_from_string(const char *buf);
-//extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b);
asl_msg_t *_asl_server_control_query(void);
extern time_t asl_parse_time(const char *in);
+asl_msg_t * asl_base_msg(asl_client_t *asl, uint32_t level, const struct timeval *tv, const char *sstr, const char *fstr, const char *mstr);
/* END PRIVATE API */
static mach_port_t asl_server_port = MACH_PORT_NULL;
asl_msg_list_t *syslogd_query(asl_msg_list_t *q, uint64_t start, int count, int dir, uint64_t *last);
static void printmsg(FILE *f, asl_msg_t *msg, char *fmt, int pflags);
+#define HELP_UNAVAILABLE -1
+#define HELP_CONTROL HELP_UNAVAILABLE /* undocumented */
+#define HELP_ALL 0
+#define HELP_SEND 1
+#define HELP_REMOTE_CONTROL 2
+#define HELP_CONFIG 3
+#define HELP_MODULE 4
+#define HELP_SEARCH 5
+#define HELP_STATS 6
+
void
-usage()
+usage(uint32_t section)
{
+ if (section == HELP_UNAVAILABLE)
+ {
+ fprintf(stderr, "help is not available for this command\n");
+ return;
+ }
+
fprintf(stderr, "usage:\n");
- fprintf(stderr, "%s -s [-r host] [-l level] message...\n", myname);
- fprintf(stderr, " send a message\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "%s -s [-r host] -k key val [key val]...\n", myname);
- fprintf(stderr, " send a message with the given keys and values\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "%s -c process [filter]\n", myname);
- fprintf(stderr, " get (set if filter is specified) syslog filter for process (pid or name)\n");
- fprintf(stderr, " level may be any combination of the characters \"p a c e w n i d\"\n");
- fprintf(stderr, " p = Emergency (\"Panic\")\n");
- fprintf(stderr, " a = Alert\n");
- fprintf(stderr, " c = Critical\n");
- fprintf(stderr, " e = Error\n");
- fprintf(stderr, " w = Warning\n");
- fprintf(stderr, " n = Notice\n");
- fprintf(stderr, " i = Info\n");
- fprintf(stderr, " d = Debug\n");
- fprintf(stderr, " a minus sign preceding a single letter means \"up to\" that level\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "%s -config [params...]\n", myname);
- fprintf(stderr, " without params, fetch and print syslogd parameters and statistics\n");
- fprintf(stderr, " otherwise, set or reset syslogd configuration parameters\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "%s -module [name [action]]\n", myname);
- fprintf(stderr, " with no name, prints configuration for all ASL output modules\n");
- fprintf(stderr, " with name and no action, prints configuration for named ASL output module\n");
- fprintf(stderr, " supported actions - module name required, use '*' (with single quotes) for all modules:\n");
- fprintf(stderr, " enable [01] enables (or disables with 0) named module\n");
- fprintf(stderr, " does not apply to com.apple.asl when '*' is used\n");
- fprintf(stderr, " checkpoint [file] checkpoints all files or specified file for named module\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "%s [-f file...] [-d path...] [-x file] [-w [N]] [-F format] [-nocompress] [-u] [-sort key1 [key2]] [-nsort key1 [key2]] [-k key [[op] val]]... [-o -k key [[op] val]] ...]...\n", myname);
- fprintf(stderr, " -f read named file[s], rather than standard log message store.\n");
- fprintf(stderr, " -d read all file in named directory path, rather than standard log message store.\n");
- fprintf(stderr, " -x export to named ASL format file, rather than printing\n");
- fprintf(stderr, " -w watch data store (^C to quit)\n");
- fprintf(stderr, " prints the last N matching lines (default 10) before waiting\n");
- fprintf(stderr, " \"-w all\" prints all matching lines before waiting\n");
- fprintf(stderr, " \"-w boot\" prints all matching lines since last system boot before waiting\n");
- fprintf(stderr, " -F output format may be \"std\", \"raw\", \"bsd\", or \"xml\"\n");
- fprintf(stderr, " format may also be a string containing variables of the form\n");
- fprintf(stderr, " $Key or $(Key) - use the latter for non-whitespace delimited variables\n");
- fprintf(stderr, " -T timestamp format may be \"sec\" (seconds), \"utc\" (UTC), or \"local\" (local timezone)\n");
- fprintf(stderr, " -E text encoding may be \"vis\", \"safe\", or \"none\"\n");
- fprintf(stderr, " -nodc no duplicate message compression\n");
- fprintf(stderr, " -u print timestamps using UTC (equivalent to \"-T utc\")\n");
- fprintf(stderr, " -sort sort messages using value for specified key1 (secondary sort by key2 if provided)\n");
- fprintf(stderr, " -nsort numeric sort messages using value for specified key1 (secondary sort by key2 if provided)\n");
- fprintf(stderr, " -k key/value match\n");
- fprintf(stderr, " if no operator or value is given, checks for the existence of the key\n");
- fprintf(stderr, " if no operator is given, default is \"%s\"\n", OP_EQ);
- fprintf(stderr, " -B only process log messages since last system boot\n");
- fprintf(stderr, " -C alias for \"-k Facility com.apple.console\"\n");
- fprintf(stderr, " -o begins a new query\n");
- fprintf(stderr, " queries are \'OR\'ed together\n");
- fprintf(stderr, "operators are zero or more modifiers followed by a comparison\n");
- fprintf(stderr, " %s equal\n", OP_EQ);
- fprintf(stderr, " %s not equal\n", OP_NE);
- fprintf(stderr, " %s greater than\n", OP_GT);
- fprintf(stderr, " %s greater or equal\n", OP_GE);
- fprintf(stderr, " %s less than\n", OP_LT);
- fprintf(stderr, " %s less or equal\n", OP_LE);
- fprintf(stderr, "optional modifiers for operators\n");
- fprintf(stderr, " %c case-fold\n", MOD_CASE_FOLD);
- fprintf(stderr, " %c regular expression\n", MOD_REGEX);
- fprintf(stderr, " %c substring\n", MOD_SUBSTRING);
- fprintf(stderr, " %c prefix\n", MOD_PREFIX);
- fprintf(stderr, " %c suffix\n", MOD_SUFFIX);
- fprintf(stderr, " %c numeric comparison\n", MOD_NUMERIC);
+
+ if ((section == HELP_ALL) || (section == HELP_SEND))
+ {
+ fprintf(stderr, "%s -s [-r host] [-l level] message...\n", myname);
+ fprintf(stderr, " send a message\n");
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "%s -s [-r host] -k key val [key val]...\n", myname);
+ fprintf(stderr, " send a message with the given keys and values\n");
+ fprintf(stderr, "\n");
+ }
+
+ if ((section == HELP_ALL) || (section == HELP_REMOTE_CONTROL))
+ {
+ fprintf(stderr, "%s -c process [mask] [-s [on|off]] [-t [on|off]]\n", myname);
+ fprintf(stderr, " get (set if mask or actions are specified) syslog filter mask and actions for process (pid or name)\n");
+ fprintf(stderr, " mask may be any combination of the characters \"p a c e w n i d\"\n");
+ fprintf(stderr, " p = Emergency (\"Panic\")\n");
+ fprintf(stderr, " a = Alert\n");
+ fprintf(stderr, " c = Critical\n");
+ fprintf(stderr, " e = Error\n");
+ fprintf(stderr, " w = Warning\n");
+ fprintf(stderr, " n = Notice\n");
+ fprintf(stderr, " i = Info\n");
+ fprintf(stderr, " d = Debug\n");
+ fprintf(stderr, " a minus sign preceding a single letter means \"up to\" that level\n");
+ fprintf(stderr, " use \"0\" for process to get or set master syslog flags\n");
+ fprintf(stderr, " use \"-c process off\" to deactivate current settings\n");
+ fprintf(stderr, " -s controls sending ASL mesages (to syslogd)\n");
+ fprintf(stderr, " -t controls sending Activity Tracing mesages\n");
+ fprintf(stderr, "\n");
+ }
+
+ if ((section == HELP_ALL) || (section == HELP_CONFIG))
+ {
+ fprintf(stderr, "%s -config [params...]\n", myname);
+ fprintf(stderr, " without params, fetch and print syslogd parameters and statistics\n");
+ fprintf(stderr, " otherwise, set or reset syslogd configuration parameters\n");
+ fprintf(stderr, "\n");
+ }
+
+ if ((section == HELP_ALL) || (section == HELP_MODULE))
+ {
+ fprintf(stderr, "%s -module [name [action]]\n", myname);
+ fprintf(stderr, " with no name, prints configuration for all ASL output modules\n");
+ fprintf(stderr, " with name and no action, prints configuration for named ASL output module\n");
+ fprintf(stderr, " supported actions - module name required, use '*' (with single quotes) for all modules:\n");
+ fprintf(stderr, " enable [01] enables (or disables with 0) named module\n");
+ fprintf(stderr, " does not apply to com.apple.asl when '*' is used\n");
+ fprintf(stderr, " checkpoint [file] checkpoints all files or specified file for named module\n");
+ fprintf(stderr, "\n");
+ }
+
+ if ((section == HELP_ALL) || (section == HELP_SEARCH))
+ {
+ fprintf(stderr, "%s [-f file...] [-d path...] [-x file] [-w [N]] [-F format] [-nocompress] [-u] [-sort key1 [key2]] [-nsort key1 [key2]] [-k key [[op] val]]... [-o -k key [[op] val]] ...]...\n", myname);
+ fprintf(stderr, " -f read named file[s], rather than standard log message store.\n");
+ fprintf(stderr, " -d read all file in named directory path, rather than standard log message store.\n");
+ fprintf(stderr, " -x export to named ASL format file, rather than printing\n");
+ fprintf(stderr, " -w watch data store (^C to quit)\n");
+ fprintf(stderr, " prints the last N matching lines (default 10) before waiting\n");
+ fprintf(stderr, " \"-w all\" prints all matching lines before waiting\n");
+ fprintf(stderr, " \"-w boot\" prints all matching lines since last system boot before waiting\n");
+ fprintf(stderr, " -F output format may be \"std\", \"raw\", \"bsd\", or \"xml\"\n");
+ fprintf(stderr, " format may also be a string containing variables of the form\n");
+ fprintf(stderr, " $Key or $(Key) - use the latter for non-whitespace delimited variables\n");
+ fprintf(stderr, " -T timestamp format may be \"sec\" (seconds), \"utc\" (UTC), or \"local\" (local timezone)\n");
+ fprintf(stderr, " -E text encoding may be \"vis\", \"safe\", or \"none\"\n");
+ fprintf(stderr, " -nodc no duplicate message compression\n");
+ fprintf(stderr, " -u print timestamps using UTC (equivalent to \"-T utc\")\n");
+ fprintf(stderr, " -sort sort messages using value for specified key1 (secondary sort by key2 if provided)\n");
+ fprintf(stderr, " -nsort numeric sort messages using value for specified key1 (secondary sort by key2 if provided)\n");
+ fprintf(stderr, " -k key/value match\n");
+ fprintf(stderr, " if no operator or value is given, checks for the existence of the key\n");
+ fprintf(stderr, " if no operator is given, default is \"%s\"\n", OP_EQ);
+ fprintf(stderr, " -B only process log messages since last system boot\n");
+ fprintf(stderr, " -C alias for \"-k Facility com.apple.console\"\n");
+ fprintf(stderr, " -o begins a new query\n");
+ fprintf(stderr, " queries are \'OR\'ed together\n");
+ fprintf(stderr, "operators are zero or more modifiers followed by a comparison\n");
+ fprintf(stderr, " %s equal\n", OP_EQ);
+ fprintf(stderr, " %s not equal\n", OP_NE);
+ fprintf(stderr, " %s greater than\n", OP_GT);
+ fprintf(stderr, " %s greater or equal\n", OP_GE);
+ fprintf(stderr, " %s less than\n", OP_LT);
+ fprintf(stderr, " %s less or equal\n", OP_LE);
+ fprintf(stderr, "optional modifiers for operators\n");
+ fprintf(stderr, " %c case-fold\n", MOD_CASE_FOLD);
+ fprintf(stderr, " %c regular expression\n", MOD_REGEX);
+ fprintf(stderr, " %c substring\n", MOD_SUBSTRING);
+ fprintf(stderr, " %c prefix\n", MOD_PREFIX);
+ fprintf(stderr, " %c suffix\n", MOD_SUFFIX);
+ fprintf(stderr, " %c numeric comparison\n", MOD_NUMERIC);
+ }
+
+ if ((section == HELP_ALL) || (section == HELP_STATS))
+ {
+ fprintf(stderr, "%s -stats [-n n] [-d path] [-v]\n", myname);
+ fprintf(stderr, " compiles and prints syslogd usage statistics\n");
+ fprintf(stderr, " -n n prints stats for just the top n (e.g. top 10) senders\n");
+ fprintf(stderr, " -d path reads the ASL database at the given path for statistics\n");
+ fprintf(stderr, " -v verbose ([message_count total_data data_average] for 10 minute intervals)\n");
+ }
}
const char *
const char *val = NULL;
uint64_t last;
char *str;
+ int i;
+
+ for (i = 2; i < argc; i++)
+ {
+ if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help")))
+ {
+ usage(HELP_MODULE);
+ return 0;
+ }
+ }
asl_msg_t *ctl = _asl_server_control_query();
if (ctl == NULL)
fprintf(stderr, "can't allocate memory - exiting\n");
exit(-1);
}
-
+
asl_msg_list_append(q, qm);
asl_msg_release(qm);
-
+
asl_msg_set_key_val_op(qm, ASL_KEY_OPTION, "control", ASL_QUERY_OP_EQUAL);
asprintf(&str, "%s checkpoint%s%s", argv[0], (argc > 2) ? " " : "", (argc > 2) ? argv[2] : "");
asl_msg_set_key_val_op(qm, "action", str, ASL_QUERY_OP_EQUAL);
}
int
-rcontrol_set_string(const char *name, int filter)
+rcontrol_set_string(const char *name, uint32_t bits)
{
int t, status;
uint64_t x;
status = notify_register_plain(name, &t);
if (status != NOTIFY_STATUS_OK) return status;
- x = filter;
+ x = bits;
status = notify_set_state(t, x);
notify_post(NOTIFY_RC);
notify_cancel(t);
return str;
}
+void
+print_eval_bits(uint32_t eval)
+{
+ printf("0x%08x O%s ", eval, (eval & EVAL_ACTIVE) ? "N " : "FF");
+ if (eval & EVAL_SEND_ASL) printf("ASL ");
+ if (eval & EVAL_SEND_TRACE) printf("TRACE ");
+ if (eval & EVAL_TEXT_FILE) printf("TEXT ");
+ if (eval & EVAL_ASL_FILE) printf("FILE ");
+ if (eval & EVAL_TUNNEL) printf("TUNNEL ");
+ printf("/ 0x%02x %s\n", eval & EVAL_LEVEL_MASK, asl_filter_string(eval & EVAL_LEVEL_MASK));
+}
+
int
rcontrol_get(pid_t pid, uid_t uid)
{
status = rcontrol_get_string(rcontrol_name(pid, uid), &filter);
if (status == NOTIFY_STATUS_OK)
{
- printf("Master filter mask: %s\n", asl_filter_string(filter));
+ printf("Master settings: ");
+ print_eval_bits(filter);
return 0;
}
- printf("Unable to determine master filter mask\n");
+ printf("Unable to determine master settings\n");
return -1;
}
status = rcontrol_get_string(rcontrol_name(pid, uid), &filter);
if (status == NOTIFY_STATUS_OK)
{
- printf("Process %d syslog filter mask: %s\n", pid, asl_filter_string(filter));
+ printf("Process %d syslog settings: ", pid);
+ print_eval_bits(filter);
return 0;
}
- printf("Unable to determine syslog filter mask for pid %d\n", pid);
+ printf("Unable to determine syslog settings for pid %d\n", pid);
return -1;
}
int
-rcontrol_set(pid_t pid, uid_t uid, int filter)
+rcontrol_set(pid_t pid, uid_t uid, uint32_t bits)
{
int status;
const char *rcname;
if (pid < 0)
{
- status = rcontrol_set_string(rcname, filter);
+ status = rcontrol_set_string(rcname, bits);
if (status == NOTIFY_STATUS_OK)
{
return -1;
}
- status = rcontrol_set_string(rcname, filter);
+ status = rcontrol_set_string(rcname, bits);
if (status == NOTIFY_STATUS_OK)
{
status = notify_post(rcname);
int s;
struct sockaddr_in dst;
struct hostent *h;
- char myname[MAXHOSTNAMELEN + 1];
+ char host_name[MAXHOSTNAMELEN + 1];
if (msg == NULL) return 0;
tick = time(NULL);
timestr = NULL;
- asprintf(×tr, "%lu", tick);
+ asprintf(×tr, "%llu", (unsigned long long)tick);
if (timestr != NULL)
{
asl_msg_set_key_val(msg, ASL_KEY_TIME, timestr);
free(timestr);
}
- if (gethostname(myname, MAXHOSTNAMELEN) == 0) asl_msg_set_key_val(msg, ASL_KEY_HOST, myname);
+ if (gethostname(host_name, MAXHOSTNAMELEN) == 0) asl_msg_set_key_val(msg, ASL_KEY_HOST, host_name);
len = 0;
str = asl_msg_to_string((asl_msg_t *)msg, &len);
int s;
struct sockaddr_in dst;
struct hostent *h;
- char myname[MAXHOSTNAMELEN + 1];
+ char host_name[MAXHOSTNAMELEN + 1];
if (msg == NULL) return 0;
ltime = ctime(&tick);
ltime[19] = '\0';
- gethostname(myname, MAXHOSTNAMELEN);
+ gethostname(host_name, MAXHOSTNAMELEN);
- asprintf(&out, "<%d>%s %s syslog[%d]: %s", level, ltime+4, myname, getpid(), msg);
+ asprintf(&out, "<%d>%s %s syslog[%d]: %s", level, ltime+4, host_name, getpid(), msg);
len = strlen(out);
sendto(s, out, len, 0, (const struct sockaddr *)&dst, sizeof(struct sockaddr_in));
return 0;
}
+void
+stats_print_sender_stats(sender_stat_t *s, uint32_t interval, bool print_samples)
+{
+ uint32_t i;
+ uint32_t p10000 = (s->total_messages * 10000) / stats_total_all_messages;
+
+ if (strcmp(s->name, "*")) printf("%s: %u (%u.%02u%%) %lu\n", s->name, s->total_messages, p10000 / 100, p10000 % 100, s->total_size);
+ else printf("TOTAL: %u (100.00%%) %lu\n", s->total_messages, s->total_size);
+
+ if (print_samples)
+ {
+ int k = 0;
+ printf("[message_count data_size data_average]\n");
+
+ for (i = 0, k = 0; i < s->count; i++)
+ {
+ size_t avg = 0;
+
+ if (s->messages[i] > 0) avg = s->size[i] / s->messages[i];
+ printf("[%u %lu %lu]", s->messages[i], s->size[i], avg);
+ if (++k == 6)
+ {
+ printf("\n");
+ k = 0;
+ }
+ else
+ {
+ printf(" ");
+ }
+ }
+
+ for (; i < interval; i++)
+ {
+ printf("[0 0 0]");
+ if ((++k == 6) || ((i + 1) == interval))
+ {
+ printf("\n");
+ k = 0;
+ }
+ else
+ {
+ printf(" ");
+ }
+ }
+
+ printf("\n");
+ }
+}
+
+int
+stats_n_comp(const void *x, const void *y)
+{
+ int pn, qn;
+ sender_stat_t **p = (sender_stat_t **)x;
+ sender_stat_t **q = (sender_stat_t **)y;
+ pn = (*p)->total_messages;
+ qn = (*q)->total_messages;
+ return qn - pn;
+}
+
+void
+stats_sender_set_stat_numbers(const char *name, sender_stat_t *s, uint32_t interval, uint32_t nmsgs, size_t msize)
+{
+ s->messages = (uint32_t *)reallocf(s->messages, interval * sizeof(uint32_t));
+ s->size = (size_t *)reallocf(s->size, interval * sizeof(size_t));
+
+ for (; s->count < interval; s->count++)
+ {
+ s->messages[s->count] = 0;
+ s->size[s->count] = 0;
+ }
+
+ s->messages[interval - 1] = nmsgs;
+ s->size[interval - 1] = msize;
+
+ s->total_messages += nmsgs;
+ s->total_size += msize;
+
+ if (strcmp(name, "*")) stats_total_all_messages += nmsgs;
+}
+
+void
+stats_sender_set_stats(uint32_t interval, const char *name, uint32_t nmsgs, size_t msize)
+{
+ uint32_t i;
+ for (i = 0; i < stats_sender_count; i++)
+ {
+ if (strcmp(stats_sender[i]->name, name) == 0)
+ {
+ stats_sender_set_stat_numbers(name, stats_sender[i], interval, nmsgs, msize);
+ return;
+ }
+ }
+
+ stats_sender = (sender_stat_t **)realloc(stats_sender, (stats_sender_count + 1) * sizeof(sender_stat_t *));
+ stats_sender[stats_sender_count] = (sender_stat_t *)calloc(1, sizeof(sender_stat_t));
+ stats_sender[stats_sender_count]->name = strdup(name);
+
+ stats_sender_set_stat_numbers(name, stats_sender[stats_sender_count], interval, nmsgs, msize);
+ stats_sender_count++;
+}
+
+void
+stats_process_stat_msg(uint32_t interval, asl_object_t msg)
+{
+ uint32_t i, n;
+
+ n = asl_count(msg);
+
+ for (i = 0; i < n; i++)
+ {
+ const char *key = NULL;
+ const char *val = NULL;
+ uint32_t s_n = 0;
+ size_t s_size = 0;
+ if (asl_fetch_key_val_op(msg, i, &key, &val, NULL) != 0) break;
+ if (key[0] == '*')
+ {
+ if (2 == sscanf(val, "%u %lu", &s_n, &s_size))
+ {
+ stats_sender_set_stats(interval, key + 1, s_n, s_size);
+ }
+ }
+ }
+}
+
+
+int
+asl_stats(int argc, char *argv[])
+{
+ asl_object_t msg;
+ uint32_t i, interval, top = UINT32_MAX;
+ bool print_samples = false;
+ asl_object_t store = NULL;
+
+ for (i = 2; i < argc; i++)
+ {
+ if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help")))
+ {
+ usage(HELP_STATS);
+ return 0;
+ }
+ else if (!strcmp(argv[i], "-n"))
+ {
+ i++;
+ if (i >= argc)
+ {
+ fprintf(stderr, "error: expected an integer value following \"-n\"\n");
+ usage(HELP_STATS);
+ return -1;
+ }
+
+ top = 1 + atoi(argv[i]);
+ }
+ else if (!strcmp(argv[i], "-v"))
+ {
+ print_samples = true;
+ }
+ else if (!strcmp(argv[i], "-d"))
+ {
+ i++;
+ if (i >= argc)
+ {
+ fprintf(stderr, "error: expected a directory path following \"-d\"\n");
+ usage(HELP_STATS);
+ return -1;
+ }
+ store = asl_open_path(argv[i], 0);
+ if (store == NULL)
+ {
+ fprintf(stderr, "error: failed to open ASL directory %s\n", argv[i]);
+ return -1;
+ }
+ }
+ }
+
+#if TARGET_OS_EMBEDDED
+ if (store == NULL) store = asl_open_path(ASL_IOS_STATS_DIR, 0);
+ if (store == NULL)
+ {
+ fprintf(stderr, "error: failed to open ASL directory %s\n", ASL_IOS_STATS_DIR);
+ return -1;
+ }
+#endif
+
+ asl_object_t stats_query = asl_new(ASL_TYPE_QUERY);
+ if (stats_query == NULL)
+ {
+ fprintf(stderr, "error: failed to create stats_query\n");
+ return -1;
+ }
+
+ asl_set_query(stats_query, ASL_KEY_FACILITY, "com.apple.asl.statistics", ASL_QUERY_OP_EQUAL);
+
+ asl_object_t stats = asl_search(store, stats_query);
+ asl_release(stats_query);
+ asl_release(store);
+
+ if (stats == NULL)
+ {
+ printf("no statistics records in the ASL database\n");
+ return 0;
+ }
+
+ for (interval = 1, msg = asl_next(stats); msg != NULL; interval++, msg = asl_next(stats))
+ {
+ stats_process_stat_msg(interval, msg);
+ }
+
+ asl_release(stats);
+
+ qsort(stats_sender, stats_sender_count, sizeof(sender_stat_t *), stats_n_comp);
+
+ printf("sender: message_count (%% of total) data_size\n");
+
+ for (i = 0; (i < stats_sender_count) && (i < top); i++)
+ {
+ stats_print_sender_stats(stats_sender[i], interval - 1, print_samples);
+ }
+
+ /* NB sender stats are not freed since we exit after this */
+ return 0;
+}
+
static int
_isanumber(char *s)
{
int
syslog_remote_control(int argc, char *argv[])
{
- int pid, uid, status, mask;
+ int i, pid, uid, status, mask;
+ uint32_t bits;
- if ((argc < 3) || (argc > 4))
+ if (argc < 3)
{
- fprintf(stderr, "usage:\n");
- fprintf(stderr, "%s -c process [mask]\n", myname);
- fprintf(stderr, " get (set if mask is specified) syslog filter mask for process (pid or name)\n");
- fprintf(stderr, " process may be pid or process name\n");
- fprintf(stderr, " use \"-c 0\" to get master syslog filter mask\n");
- fprintf(stderr, " use \"-c 0 off\" to disable master syslog filter mask\n");
- fprintf(stderr, "\n");
+ usage(HELP_REMOTE_CONTROL);
return -1;
}
+ for (i = 2; i < argc; i++)
+ {
+ if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help")))
+ {
+ usage(HELP_REMOTE_CONTROL);
+ return 0;
+ }
+ }
+
pid = RC_MASTER;
uid = -2;
if (pid == 0) pid = RC_MASTER;
- if (argc == 4)
+ if (argc == 3)
{
- if ((pid == RC_MASTER) && (!strcasecmp(argv[3], "off"))) mask = 0;
+ rcontrol_get(pid, uid);
+ return 0;
+ }
+
+ bits = EVAL_ACTIVE | EVAL_SEND_ASL | EVAL_SEND_TRACE;
+
+ for (i = 3; i < argc; i++)
+ {
+ if ((!strcasecmp(argv[i], "off")) || (!strcmp(argv[i], "0")))
+ {
+ bits = 0;
+ }
+ else if (!strcmp(argv[i], "-s"))
+ {
+ if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
+ {
+ i++;
+ if (!strcasecmp(argv[i], "off") || !strcmp(argv[i], "0")) bits &= ~EVAL_SEND_ASL;
+ }
+ }
+ else if (!strcmp(argv[i], "-t"))
+ {
+ if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
+ {
+ i++;
+ if (!strcasecmp(argv[i], "off") || !strcmp(argv[i], "0")) bits &= ~EVAL_SEND_TRACE;
+ }
+ }
else
{
- mask = asl_string_to_filter(argv[3]);
+ mask = asl_string_to_filter(argv[i]);
if (mask < 0)
{
- printf("unknown syslog mask: %s\n", argv[3]);
+ printf("can't understand mask: %s\n", argv[i]);
return -1;
}
+ bits = (bits & EVAL_ACTION_MASK) | mask;
}
-
- rcontrol_set(pid, uid, mask);
- }
- else
- {
- rcontrol_get(pid, uid);
}
+ rcontrol_set(pid, uid, bits);
return 0;
}
int
syslog_send(int argc, char *argv[])
{
- int i, start, kv, len, rfmt, rlevel;
- asl_client_t *asl;
+ int status, i, start, kv, len, rfmt, rlevel;
+ asl_object_t asl = NULL;
asl_msg_t *m;
char tmp[64], *str, *rhost;
+ struct timeval tval = {0, 0};
+ char host_name[MAXHOSTNAMELEN + 1];
+
+ for (i = 2; i < argc; i++)
+ {
+ if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help")))
+ {
+ usage(HELP_SEND);
+ return 0;
+ }
+ }
+
+ status = gettimeofday(&tval, NULL);
+ if (status != 0)
+ {
+ time_t tick = time(NULL);
+ tval.tv_sec = tick;
+ tval.tv_usec = 0;
+ }
kv = 0;
rhost = NULL;
}
start = i+1;
}
+ else if (!strcmp(argv[i], "-x"))
+ {
+ i++;
+ if (i >= argc)
+ {
+ fprintf(stderr, "expected a path following -x\n");
+ return -1;
+ }
+
+ asl = asl_open_path(argv[i], ASL_OPT_OPEN_WRITE);
+ if (asl == NULL)
+ {
+ fprintf(stderr, "Could not open %s for write\n", argv[i]);
+ return -1;
+ }
+ }
}
- asl = asl_client_open(myname, "syslog", 0);
- asl_client_set_filter(asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
- m = asl_msg_new(ASL_TYPE_MSG);
- asl_msg_set_key_val(m, ASL_KEY_SENDER, myname);
+ if (asl == NULL) asl = asl_open(myname, "syslog", 0);
+ asl_set_filter(asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
+
+ m = asl_base_msg(NULL, rlevel, &tval, myname, "syslog", NULL);
+ if (m == NULL)
+ {
+ fprintf(stderr, "Could not create message\n");
+ return -1;
+ }
+
+ if (gethostname(host_name, MAXHOSTNAMELEN) == 0) asl_msg_set_key_val(m, ASL_KEY_HOST, host_name);
- sprintf(tmp, "%d", rlevel);
- asl_msg_set_key_val(m, ASL_KEY_LEVEL, tmp);
+ snprintf(tmp, sizeof(tmp), "%d", getuid());
+ asl_msg_set_key_val(m, ASL_KEY_UID, tmp);
+
+ snprintf(tmp, sizeof(tmp), "%d", getgid());
+ asl_msg_set_key_val(m, ASL_KEY_GID, tmp);
str = NULL;
if (rhost == NULL)
{
- asl_client_send(asl, m);
+ asl_send(asl, (asl_object_t)m);
}
else if (rfmt == SEND_FORMAT_ASL)
{
if (str != NULL) free(str);
- asl_client_release(asl);
+ asl_release(asl);
return 0;
}
asl_string_t *str;
const char *key, *val;
+ for (i = 2; i < argc; i++)
+ {
+ if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help")))
+ {
+ usage(HELP_CONFIG);
+ return 0;
+ }
+ }
+
if (argc == 2)
{
asl_msg_t *ctl = _asl_server_control_query();
asl_msg_t *m;
asl_string_t *str;
+ for (i = 2; i < argc; i++)
+ {
+ if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help")))
+ {
+ usage(HELP_CONTROL);
+ return 0;
+ }
+ }
+
uid = geteuid();
if (uid != 0)
{
len = 0;
str = asl_msg_list_to_string(q, &len);
- kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
+ kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_ASL));
if (kstatus != KERN_SUCCESS)
{
free(str);
}
int
-sort_compare(const void *ap, const void *bp)
+sort_compare(const void **ap, const void **bp)
{
int cmp;
asl_msg_t *a, *b;
if (sort_key == NULL) return 0;
- a = (asl_msg_t *)ap;
- b = (asl_msg_t *)bp;
+ a = (asl_msg_t *)*ap;
+ b = (asl_msg_t *)*bp;
cmp = sort_compare_key(a, b, sort_key);
if ((cmp == 0) && (sort_key_2 != NULL)) cmp = sort_compare_key(a, b, sort_key_2);
if (getuid() == 0) iamroot = 1;
+ if ((argc > 1) && ((!strcmp(argv[1], "-help")) || (!strcmp(argv[1], "--help"))))
+ {
+ usage(HELP_ALL);
+ exit(0);
+ }
+
for (i = 1; i < argc; i++)
{
- if ((!strcmp(argv[i], "-help")) || (!strcmp(argv[i], "--help")))
- {
- usage();
- exit(0);
- }
if ((!strcmp(argv[i], "-time")) || (!strcmp(argv[i], "--time")))
{
exit(0);
}
+ if ((!strcmp(argv[i], "-stats")) || (!strcmp(argv[i], "--stats")))
+ {
+ asl_stats(argc, argv);
+ exit(0);
+ }
+
if ((!strcmp(argv[i], "-config")) || (!strcmp(argv[i], "--config")))
{
syslog_config(argc, argv);
if ((i + 1) >= argc)
{
asl_msg_list_release(qlist);
- usage();
+ usage(HELP_SEARCH);
exit(1);
}
if ((i + 1) >= argc)
{
asl_msg_list_release(qlist);
- usage();
+ usage(HELP_SEARCH);
exit(1);
}
if ((i + 1) >= argc)
{
asl_msg_list_release(qlist);
- usage();
+ usage(HELP_SEARCH);
exit(1);
}
if ((i + 1) >= argc)
{
asl_msg_list_release(qlist);
- usage();
+ usage(HELP_SEARCH);
exit(1);
}
fprintf(stderr, "invalid sequence: -k");
for (j = i; j <= n; j++) fprintf(stderr, " %s", argv[j]);
fprintf(stderr, "\n");
- usage();
+ usage(HELP_SEARCH);
exit(1);
}
}
fprintf(stderr, "\ncan't allocate memory - exiting\n");
exit(1);
}
-
+
bq = asl_msg_new(ASL_TYPE_QUERY);
if (bq == NULL)
{
fprintf(stderr, "\ncan't allocate memory - exiting\n");
exit(1);
}
-
+
asl_msg_list_append(bt, bq);
asl_msg_release(bq);
-
+
asl_msg_set_key_val_op(bq, "ut_type", "2", ASL_QUERY_OP_EQUAL);
-
+
search_once(NULL, NULL, 0, (asl_msg_list_t *)bt, -1, &qmin, 1, 1, -1, 0);
asl_msg_list_release(bt);
-
+
if (qmin > 0) qmin--;
tail_count = 0;
}
#include "base.xcconfig"
-INSTALL_PATH_ACTUAL = /usr/sbin
+INSTALL_PATH = /usr/sbin
#include "<DEVELOPER_DIR>/Makefiles/CoreOS/Xcode/BSD.xcconfig"
-#include "<DEVELOPER_DIR>/AppleInternal/XcodeConfig/SimulatorSupport.xcconfig"
-
-// Set INSTALL_PATH[sdk=macosx*] when SimulatorSupport.xcconfig is unavailable
-INSTALL_PATH[sdk=macosx*] = $(INSTALL_PATH_ACTUAL)
PRODUCT_NAME = asl
-INSTALL_PATH_ACTUAL = /usr/lib/system
+INSTALL_PATH = /usr/lib/system
-PUBLIC_HEADERS_FOLDER_PATH = $(INSTALL_PATH_PREFIX)/usr/include
-PRIVATE_HEADERS_FOLDER_PATH = $(INSTALL_PATH_PREFIX)/usr/local/include
+PUBLIC_HEADERS_FOLDER_PATH = /usr/include
+PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include
LINK_WITH_STANDARD_LIBRARIES = NO
CR_LDFLAGS = -lCrashReporterClient
LIBCOMPILER_RT_LDFLAGS = -lcompiler_rt
LIBCLOSURE_LDFLAGS = -lsystem_blocks
-LIBCLOSURE_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_blocks
LIBC_LDFLAGS = -lsystem_c
-LIBC_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_c
LIBMALLOC_LDFLAGS = -lsystem_malloc
LIBNOTIFY_LDFLAGS = -lsystem_notify
LIBPLATFORM_LDFLAGS = -lsystem_platform
LIBSYSCALL_LDFLAGS = -lsystem_kernel
LIBSYSCALL_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_kernel
LIBM_LDFLAGS = -lsystem_m
-LIBM_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_m
LIBDYLD_LDFLAGS = -ldyld
LIBTRACE_LDFLAGS = -lsystem_trace
-LIBTRACE_LDFLAGS[sdk=iphonesimulator*] = -lsystem_sim_trace
-LIBUNWIND_LDFLAGS =
-LIBUNWIND_LDFLAGS[sdk=iphonesimulator*] = -lunwind_sim
+LIBUNWIND_LDFLAGS = -lunwind
OTHER_LDFLAGS = -all_load -L/usr/lib/system -umbrella System $(CR_LDFLAGS) $(LIBCOMPILER_RT_LDFLAGS) $(LIBDYLD_LDFLAGS) $(LIBSYSCALL_LDFLAGS) $(LIBPLATFORM_LDFLAGS) $(LIBPTHREAD_LDFLAGS) $(LIBMALLOC_LDFLAGS) $(LIBC_LDFLAGS) $(LIBUNWIND_LDFLAGS) $(LIBCLOSURE_LDFLAGS) -ldispatch $(LIBLAUNCH_LDFLAGS) -lxpc $(LIBTRACE_LDFLAGS) $(LIBNOTIFY_LDFLAGS) $(UPWARD_LINKS)
UPWARD_LINKS = -Wl,-upward-lsystem_info
-UPWARD_LINKS[sdk=iphonesimulator*] = -Wl,-upward-lsystem_sim_info
#include "base.xcconfig"
-INSTALL_PATH_ACTUAL = /usr/sbin
+INSTALL_PATH = /usr/sbin
#include "base.xcconfig"
-INSTALL_PATH_ACTUAL = /usr/bin
+INSTALL_PATH = /usr/bin