]> git.saurik.com Git - apple/syslog.git/blobdiff - aslmanager.tproj/aslmanager.c
syslog-322.tar.gz
[apple/syslog.git] / aslmanager.tproj / aslmanager.c
index a524421bf214a9221efd9f1f91e9dc69e8489fe8..ace82324328c03e027e6fee76c743d1e1886b44f 100644 (file)
@@ -1,15 +1,15 @@
 /*
- * 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,
  * 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 <copyfile.h>
 #include <asl.h>
-#include <asl_private.h>
-#include <asl_core.h>
-#include <asl_file.h>
+#include <asl_msg.h>
+#include <asl_msg_list.h>
 #include <asl_store.h>
+#include <errno.h>
+#include <vproc_priv.h>
 
-#define SECONDS_PER_DAY 86400
-#define DEFAULT_MAX_SIZE 150000000
-#define DEFAULT_TTL 7
-
-#define _PATH_ASL_CONF "/etc/asl.conf"
+#include "asl_common.h"
+#include "daemon.h"
+#include "cache_delete.h"
 
 /* global */
-static char *archive = NULL;
-static char *store_dir = PATH_ASL_STORE;
-static time_t ttl;
-static size_t max_size;
-static mode_t archive_mode = 0400;
-static int debug;
-
-typedef struct name_list_s
-{
-       char *name;
-       size_t size;
-       struct name_list_s *next;
-} name_list_t;
-
-name_list_t *
-add_to_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_list(name_list_t *l)
-{
-       name_list_t *e;
-
-       while (l != NULL)
-       {
-               e = l;
-               l = l->next;
-               free(e->name);
-               free(e);
-       }
-
-       free(l);
-}
-
-uint32_t
-do_copy(const char *infile, const char *outfile, mode_t mode)
-{
-       asl_search_result_t *res;
-       asl_file_t *f;
-       uint32_t status, i;
-       uint64_t mid;
-
-       if (infile == NULL) return ASL_STATUS_INVALID_ARG;
-       if (outfile == NULL) return ASL_STATUS_INVALID_ARG;
+bool dryrun;
+uint32_t debug;
+FILE *debugfp;
+dispatch_queue_t work_queue;
 
-       f = NULL;
-       status = asl_file_open_read(infile, &f);
-       if (status != ASL_STATUS_OK) return status;
+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;
 
-       res = NULL;
-       mid = 0;
-
-       status = asl_file_match(f, NULL, &res, &mid, 0, 0, 1);
-       asl_file_close(f);
-
-       if (status != ASL_STATUS_OK) return status;
-       if (res->count == 0)
-       {
-               aslresponse_free(res);
-               return ASL_STATUS_OK;
-       }
-
-       f = NULL;
-       status = asl_file_open_write(outfile, 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_UNLIMITED_CACHE | ASL_FILE_FLAG_PRESERVE_MSG_ID;
-
-       for (i = 0; i < res->count; i++)
-       {
-               mid = 0;
-               status = asl_file_save(f, (aslmsg)(res->msg[i]), &mid);
-               if (status != ASL_STATUS_OK) break;
-       }
-
-       asl_file_close(f);
-       return status;
-}
-
-int
-do_dir_archive(const char *indir, const char *outdir)
-{
-       return copyfile(indir, outdir, NULL, COPYFILE_ALL | COPYFILE_RECURSIVE);
-}
-
-int
-remove_directory(const char *path)
-{
-       DIR *dp;
-       struct dirent *dent;
-       char *str;
-       int status;
-
-       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)
-               {
-                       status = unlink(str);
-                       free(str);
-                       str = NULL;
-               }
-       }
-
-       closedir(dp);
-       status = rmdir(path);
-
-       return status;
-}
-
-
-static char **
-_insertString(char *s, char **l, uint32_t x)
-{
-       int i, len;
-
-       if (s == NULL) return l;
-       if (l == NULL) 
-       {
-               l = (char **)malloc(2 * sizeof(char *));
-               if (l == NULL) return NULL;
-
-               l[0] = strdup(s);
-               if (l[0] == NULL)
-               {
-                       free(l);
-                       return NULL;
-               }
-
-               l[1] = NULL;
-               return l;
-       }
-
-       for (i = 0; l[i] != NULL; i++);
-       len = i + 1; /* count the NULL on the end of the list too! */
-
-       l = (char **)reallocf(l, (len + 1) * sizeof(char *));
-       if (l == NULL) return NULL;
-
-       if ((x >= (len - 1)) || (x == IndexNull))
-       {
-               l[len - 1] = strdup(s);
-               if (l[len - 1] == NULL)
-               {
-                       free(l);
-                       return NULL;
-               }
-
-               l[len] = NULL;
-               return l;
-       }
-
-       for (i = len; i > x; i--) l[i] = l[i - 1];
-       l[x] = strdup(s);
-       if (l[x] == NULL) return NULL;
-
-       return l;
-}
-
-char **
-explode(const char *s, const char *delim)
-{
-       char **l = NULL;
-       const char *p;
-       char *t, quote;
-       int i, n;
-
-       if (s == NULL) return NULL;
-
-       quote = '\0';
-
-       p = s;
-       while (p[0] != '\0')
-       {
-               /* scan forward */
-               for (i = 0; p[i] != '\0'; i++)
-               {
-                       if (quote == '\0')
-                       {
-                               /* not inside a quoted string: check for delimiters and quotes */
-                               if (strchr(delim, p[i]) != NULL) break;
-                               else if (p[i] == '\'') quote = p[i];
-                               else if (p[i] == '"') quote = p[i];
-                       }
-                       else
-                       {
-                               /* inside a quoted string - look for matching quote */
-                               if (p[i] == quote) quote = '\0';
-                       }
-               }
-
-               n = i;
-               t = malloc(n + 1);
-               if (t == NULL) return NULL;
-
-               for (i = 0; i < n; i++) t[i] = p[i];
-               t[n] = '\0';
-               l = _insertString(t, l, IndexNull);
-               free(t);
-               t = NULL;
-               if (p[i] == '\0') return l;
-               if (p[i + 1] == '\0') l = _insertString("", l, IndexNull);
-               p = p + i + 1;
-       }
-
-       return l;
-}
-
-void
-freeList(char **l)
-{
-       int i;
-
-       if (l == NULL) return;
-       for (i = 0; l[i] != NULL; i++) free(l[i]);
-       free(l);
-}
+/* wait 5 minutes to run main task after being invoked by XPC */
+#define MAIN_TASK_INITIAL_DELAY 300
 
 /*
- * Used to sed config parameters.
+ * Used to set config parameters.
  * Line format "= name value"
  */
 static void
-_parse_set_param(char *s)
+_aslmanager_set_param(asl_out_dst_data_t *dst, char *s)
 {
        char **l;
        uint32_t count;
@@ -313,7 +62,7 @@ _parse_set_param(char *s)
        if (s[0] == '\0') return;
 
        /* skip '=' and whitespace */
-       s++;
+       if (*s == '=') s++;
        while ((*s == ' ') || (*s == '\t')) s++;
 
        l = explode(s, " \t");
@@ -324,505 +73,411 @@ _parse_set_param(char *s)
        /* name is required */
        if (count == 0)
        {
-               freeList(l);
+               free_string_list(l);
                return;
        }
 
        /* value is required */
        if (count == 1)
        {
-               freeList(l);
+               free_string_list(l);
                return;
        }
 
        if (!strcasecmp(l[0], "aslmanager_debug"))
        {
-               /* = debug {0|1} */
-               debug = atoi(l[1]);
+               /* = debug level */
+               set_debug(DEBUG_ASL, l[1]);
        }
        else if (!strcasecmp(l[0], "store_ttl"))
        {
                /* = store_ttl days */
-               ttl = SECONDS_PER_DAY * (time_t)atoll(l[1]);
+               dst->ttl[LEVEL_ALL] = asl_core_str_to_time(l[1], SECONDS_PER_DAY);
+       }
+       else if (!strcasecmp(l[0], "module_ttl"))
+       {
+               /* = module_ttl days */
+               module_ttl = asl_core_str_to_time(l[1], SECONDS_PER_DAY);
        }
        else if (!strcasecmp(l[0], "max_store_size"))
        {
                /* = max_file_size bytes */
-               max_size = atoi(l[1]);
+               dst->all_max = asl_core_str_to_size(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) archive = PATH_ASL_ARCHIVE;
-                       else archive = strdup(l[2]); /* never freed */
+                       if (l[2] == NULL) dst->rotate_dir = strdup(PATH_ASL_ARCHIVE);
+                       else dst->rotate_dir = strdup(l[2]);
                }
-               else archive = NULL;
        }
        else if (!strcasecmp(l[0], "store_path"))
        {
                /* = archive path */
-               store_dir = strdup(l[1]); /* never freed */
+               free(dst->path);
+               dst->path = strdup(l[1]);
        }
        else if (!strcasecmp(l[0], "archive_mode"))
        {
-               archive_mode = strtol(l[1], NULL, 0);
-               if ((archive_mode == 0) && (errno == EINVAL)) archive_mode = 0400;
+               dst->mode = strtol(l[1], NULL, 0);
+               if ((dst->mode == 0) && (errno == EINVAL)) dst->mode = 0400;
        }
 
-       freeList(l);
-}
-
-static void
-_parse_line(char *s)
-{
-       if (s == NULL) return;
-       while ((*s == ' ') || (*s == '\t')) s++;
-
-       /*
-        * First non-whitespace char is the rule type.
-        * aslmanager only checks "=" (set parameter) rules.
-        */
-       if (*s == '=') _parse_set_param(s);
+       free_string_list(l);
 }
 
-char *
-get_line_from_file(FILE *f)
+int
+cli_main(int argc, char *argv[])
 {
-       char *s, *out;
-       size_t len;
-
-       out = fgetln(f, &len);
-       if (out == NULL) return NULL;
-       if (len == 0) return NULL;
-
-       s = malloc(len + 1);
-       if (s == NULL) return NULL;
+       int i, work;
+       asl_out_module_t *mod, *m;
+       asl_out_rule_t *r;
+       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;
+               else debug = DEBUG_STDERR;
 
-       memcpy(s, out, len);
+               debug_log(ASL_LEVEL_ERR, "aslmanager must be run by root\n");
+               exit(1);
+       }
+#endif
 
-       s[len - 1] = '\0';
-       return s;
-}
+       module_ttl = DEFAULT_TTL;
 
-static int
-_parse_config_file(const char *name)
-{
-       FILE *cf;
-       char *line;
+       /* cobble up a dst_data with defaults and parameter settings */
+       memset(&store, 0, sizeof(store));
+       store.ttl[LEVEL_ALL] = DEFAULT_TTL;
+       store.all_max = DEFAULT_MAX_SIZE;
 
-       cf = fopen(name, "r");
-       if (cf == NULL) return 1;
+       memset(&opts, 0, sizeof(opts));
+       opts.ttl[LEVEL_ALL] = DEFAULT_TTL;
+       opts.all_max = DEFAULT_MAX_SIZE;
 
-       while (NULL != (line = get_line_from_file(cf)))
+       for (i = 1; i < argc; i++)
        {
-               _parse_line(line);
-               free(line);
+               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] != '-'))
+                       {
+                               store.path = strdup(argv[++i]);
+                               asl_store_dst = &store;
+                       }
+               }
        }
 
-       fclose(cf);
+       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;
 
-       return 0;
-}
+                       asl_make_timestamp(time(NULL), MODULE_NAME_STYLE_STAMP_LCL_B, tstamp, sizeof(tstamp));
+                       asprintf(&str, "%s/aslmanager.%s", path, tstamp);
 
-size_t
-directory_size(const char *path)
-{
-       DIR *dp;
-       struct dirent *dent;
-       struct stat sb;
-       size_t size;
-       char *str;
+                       if (str != NULL)
+                       {
+                               if (status == 0) debugfp = fopen(str, "w");
+                               if (debugfp != NULL) debug |= DEBUG_FILE;
+                               free(str);
+                       }
+               }
+       }
 
-       dp = opendir(path);
-       if (dp == NULL) return 0;
+       /* get parameters from asl.conf */
+       mod = asl_out_module_init();
 
-       size = 0;
-       while ((dent = readdir(dp)) != NULL)
+       if (mod != 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);
+               for (r = mod->ruleset; (r != NULL) && (asl_store_dst == NULL); r = r->next)
+               {
+                       if ((r->dst != NULL) && (r->action == ACTION_OUT_DEST) && (!strcmp(r->dst->path, PATH_ASL_STORE)))
+                               asl_store_dst = r->dst;
+               }
 
-               if ((str != NULL) && (stat(str, &sb) == 0) && S_ISREG(sb.st_mode))
+               for (r = mod->ruleset; r != NULL; r = r->next)
                {
-                       size += sb.st_size;
-                       free(str);
+                       if (r->action == ACTION_SET_PARAM)
+                       {
+                               if (r->query == NULL) _aslmanager_set_param(asl_store_dst, r->options);
+                       }
                }
        }
 
-       closedir(dp);
-       return size;
-}
-
-int
-main(int argc, const char *argv[])
-{
-       int i, today_ymd_stringlen, expire_ymd_stringlen;
-       time_t now, 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;
-       uint32_t status;
-       size_t file_size, store_size;
-       struct stat sb;
-
-       ymd_list = NULL;
-       bb_list = NULL;
-       aux_list = NULL;
-       bb_aux_list = NULL;
-
-       ttl = DEFAULT_TTL * SECONDS_PER_DAY;
-       max_size = DEFAULT_MAX_SIZE;
-       store_size = 0;
-       debug = 0;
+       work = DO_ASLDB | DO_MODULE;
 
        for (i = 1; i < argc; i++)
        {
                if (!strcmp(argv[i], "-a"))
                {
-                       if (((i + 1) < argc) && (argv[i + 1][0] != '-')) archive = (char *)argv[++i];
-                       else archive = PATH_ASL_ARCHIVE;
-               }
-               else if (!strcmp(argv[i], "-s"))
-               {
-                       if (((i + 1) < argc) && (argv[i + 1][0] != '-')) store_dir = (char *)argv[++i];
+                       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], "-ttl"))
+               else if (!strcmp(argv[i], "-store_ttl"))
                {
-                       if (((i + 1) < argc) && (argv[i + 1][0] != '-')) ttl = atoi(argv[++i]) * SECONDS_PER_DAY;
+                       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], "-size"))
+               else if (!strcmp(argv[i], "-module_ttl"))
                {
-                       if (((i + 1) < argc) && (argv[i + 1][0] != '-')) max_size = 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], "-d"))
+               else if (!strcmp(argv[i], "-ttl"))
                {
-                       debug = 1;
-               }
-       }
-
-       _parse_config_file(_PATH_ASL_CONF);
+                       if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
+                       {
+                               opts.ttl[LEVEL_ALL] = asl_core_str_to_time(argv[++i], SECONDS_PER_DAY);
 
-       if (debug == 1) printf("aslmanager starting\n");
+                               if (asl_store_dst == NULL) asl_store_dst = &store;
+                               asl_store_dst->ttl[LEVEL_ALL] = opts.ttl[LEVEL_ALL];
 
-       /* check archive */
-       if (archive != NULL)
-       {
-               memset(&sb, 0, sizeof(struct stat));
-               if (stat(archive, &sb) == 0)
-               {
-                       /* must be a directory */
-                       if (!S_ISDIR(sb.st_mode))
-                       {
-                               fprintf(stderr, "aslmanager error: archive %s is not a directory", archive);
-                               return -1;
+                               module_ttl = opts.ttl[LEVEL_ALL];
                        }
                }
-               else
+               else if (!strcmp(argv[i], "-size"))
                {
-                       if (errno == ENOENT)
+                       if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
                        {
-                               /* archive doesn't exist - create it */
-                               if (mkdir(archive, 0755) != 0)
-                               {
-                                       fprintf(stderr, "aslmanager error: can't create archive %s: %s\n", archive, strerror(errno));
-                                       return -1;
-                               }
-                       }
-                       else
-                       {
-                               /* stat failed for some other reason */
-                               fprintf(stderr, "aslmanager error: can't stat archive %s: %s\n", archive, strerror(errno));
-                               return -1;
+                               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;
                        }
                }
-       }
-
-       chdir(store_dir);
-
-       /* determine current time */
-       now = time(NULL);
-
-       /* ttl 0 means files never expire */
-       ymd_expire = 0;
-       if (ttl > 0) 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);
-
-       if (debug == 1) printf("Expiry Date %s\n", expire_ymd_string);
-
-       dp = opendir(store_dir);
-       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'))
+               else if (!strcmp(argv[i], "-checkpoint"))
                {
-                       ymd_list = add_to_list(ymd_list, dent->d_name, file_size);
-                       store_size += file_size;
+                       work |= DO_CHECKPT;
                }
-               else if (!strncmp(dent->d_name, "AUX.", 4) && (dent->d_name[4] >= '0') && (dent->d_name[4] <= '9') && S_ISDIR(sb.st_mode))
+               else if (!strcmp(argv[i], "-cache_delete"))
                {
-                       file_size = directory_size(dent->d_name);
-                       aux_list = add_to_list(aux_list, dent->d_name, file_size);
-                       store_size += file_size;
+                       cache_delete = true;
+                       if (((i + 1) < argc) && (argv[i + 1][0] == 'q')) cache_delete_query = true;
                }
-               else if (!strncmp(dent->d_name, "BB.AUX.", 7) && (dent->d_name[7] >= '0') && (dent->d_name[7] <= '9') && S_ISDIR(sb.st_mode))
+               else if (!strcmp(argv[i], "-module"))
                {
-                       file_size = directory_size(dent->d_name);
-                       bb_aux_list = add_to_list(bb_aux_list, dent->d_name, file_size);
-                       store_size += file_size;
+                       work &= ~DO_ASLDB;
+
+                       /* optional name follows -module */
+                       if ((i +1) < argc)
+                       {
+                               if (argv[i + 1][0] != '-') mname = argv[++i];
+                       }
                }
-               else if (!strncmp(dent->d_name, "BB.", 3) && (dent->d_name[3] >= '0') && (dent->d_name[3] <= '9'))
+               else if (!strcmp(argv[i], "-asldb"))
                {
-                       bb_list = add_to_list(bb_list, dent->d_name, file_size);
-                       store_size += file_size;
+                       work = DO_ASLDB;
                }
-               else if ((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, "..")))
-               {}
-               else if ((!strcmp(dent->d_name, "StoreData")) || (!strcmp(dent->d_name, "SweepStore")))
-               {}
-               else
+               else if (!strcmp(argv[i], "-d"))
                {
-                       fprintf(stderr, "aslmanager: unexpected file %s in ASL data store\n", dent->d_name);
+                       if (((i + i) < argc) && (argv[i+1][0] != '-')) set_debug(DEBUG_STDERR, argv[++i]);
+                       else set_debug(DEBUG_STDERR, NULL);
                }
-       }
-
-       closedir(dp);
-
-       if (debug == 1)
-       {
-               printf("Data Store Size = %lu\n", store_size);
-               printf("Data Store YMD Files\n");
-               for (e = ymd_list; e != NULL; e = e->next) printf("     %s   %lu\n", e->name, e->size);
-               printf("Data Store AUX Directories\n");
-               for (e = aux_list; e != NULL; e = e->next) printf("     %s   %lu\n", e->name, e->size);
-               printf("Data Store BB.AUX Directories\n");
-               for (e = bb_aux_list; e != NULL; e = e->next) printf("  %s   %lu\n", e->name, e->size);
-               printf("Data Store BB Files\n");
-               for (e = bb_list; e != NULL; e = e->next) printf("      %s   %lu\n", e->name, e->size);
-       }
-
-       /* Delete/achive expired YMD files */
-       if (debug == 1) printf("Start YMD File Scan\n");
-
-       e = ymd_list;
-       while (e != NULL)
-       {
-               /* stop when a file name/date is after the expire date */
-               if (strncmp(e->name, expire_ymd_string, expire_ymd_stringlen) > 0) break;
-
-               if (archive != NULL)
+               else if (!strcmp(argv[i], "-dd"))
                {
-                       str = NULL;
-                       asprintf(&str, "%s/%s", archive, e->name);
-                       if (str == NULL) return -1;
+                       dryrun = true;
 
-                       if (debug == 1) printf("  copy %s ---> %s\n", e->name, str);
-                       status = do_copy(e->name, str, archive_mode);
-                       free(str);
+                       if (((i + i) < argc) && (argv[i+1][0] != '-')) set_debug(DEBUG_STDERR, argv[++i]);
+                       else set_debug(DEBUG_STDERR, "l7");
                }
-
-               if (debug == 1) printf("  unlink %s\n", e->name);
-               unlink(e->name);
-
-               store_size -= e->size;
-               e->size = 0;
-
-               e = e->next;
        }
 
-       if (debug == 1) printf("Finished YMD FILE Scan\n");
+       if (asl_store_dst->path == NULL) asl_store_dst->path = strdup(PATH_ASL_STORE);
 
-       /* Delete/achive expired YMD AUX directories */
-       if (debug == 1) printf("Start AUX Directory Scan\n");
+       debug_log(ASL_LEVEL_ERR, "aslmanager starting%s\n", dryrun ? " dryrun" : "");
 
-       e = aux_list;
-       while (e != NULL)
+       if (cache_delete)
        {
-               /* stop when a file name/date is after the expire date */
-               if (strncmp(e->name + 4, expire_ymd_string, expire_ymd_stringlen) > 0) break;
+               size_t curr_size = 0;
 
-               if (archive != NULL)
+               if (cache_delete_task(true, &curr_size) != 0)
+               {
+                       debug_log(ASL_LEVEL_NOTICE, "cache_delete_process failed - can't determine current size\n");
+               }
+               else
                {
-                       str = NULL;
-                       asprintf(&str, "%s/%s", archive, e->name);
-                       if (str == NULL) return -1;
+                       debug_log(ASL_LEVEL_NOTICE, "cache delete current size = %lu\n", curr_size);
 
-                       if (debug == 1) printf("  copy %s ---> %s\n", e->name, str);
-                       do_dir_archive(e->name, str);
-                       free(str);
+                       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);
+                               }
+                       }
                }
 
-               if (debug == 1) printf("    Remove %s\n", e->name);
-               remove_directory(e->name);
+               asl_out_module_free(mod);
 
-               store_size -= e->size;
-               e->size = 0;
+               debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
+               debug_log(ASL_LEVEL_ERR, "aslmanager finished%s\n", dryrun ? " dryrun" : "");
+               debug_close();
 
-               e = e->next;
+               return 0;
        }
 
-       if (debug == 1) printf("Finished AUX Directory Scan\n");
-
-       /* Delete/achive expired BB.AUX directories */
-       if (debug == 1) printf("Start BB.AUX Directory Scan\n");
+       if (work & DO_ASLDB) process_asl_data_store(asl_store_dst, &opts);
 
-       e = bb_aux_list;
-       while (e != NULL)
+       if (work & DO_MODULE)
        {
-               /* 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 (work & DO_CHECKPT) checkpoint(mname);
 
-               if (archive != NULL)
+               if (mod != NULL)
                {
-                       str = NULL;
-                       asprintf(&str, "%s/%s", archive, e->name);
-                       if (str == NULL) return -1;
-
-                       if (debug == 1) printf("  copy %s ---> %s\n", e->name, str);
-                       do_dir_archive(e->name, str);
-                       free(str);
+                       for (m = mod; m != NULL; m = m->next)
+                       {
+                               if (mname == NULL)
+                               {
+                                       process_module(m, NULL);
+                               }
+                               else if ((m->name != NULL) && (!strcmp(m->name, mname)))
+                               {
+                                       process_module(m, &opts);
+                               }
+                       }
                }
-
-               if (debug == 1) printf("  remove %s\n", e->name);
-               remove_directory(e->name);
-
-               store_size -= e->size;
-               e->size = 0;
-
-               e = e->next;
        }
 
-       if (debug == 1) printf("Finished BB.AUX Directory Scan\n");
+       asl_out_module_free(mod);
 
-       /* Delete/achive expired BB files */
-       if (debug == 1) printf("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;
+       debug_log(ASL_LEVEL_NOTICE, "----------------------------------------\n");
+       debug_log(ASL_LEVEL_ERR, "aslmanager finished%s\n", dryrun ? " dryrun" : "");
+       debug_close();
 
-               if (archive != NULL)
-               {
-                       str = NULL;
-                       asprintf(&str, "%s/%s", archive, e->name);
-                       if (str == NULL) return -1;
-
-                       /* syslog -x [str] -f [e->name] */
-                       if (debug == 1) printf("  copy %s ---> %s\n", e->name, str);
-                       status = do_copy(e->name, str, archive_mode);
-                       free(str);
-               }
+       return 0;
+}
 
-               if (debug == 1) printf("  unlink %s\n", e->name);
-               unlink(e->name);
+/* 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;
 
-               store_size -= e->size;
-               e->size = 0;
+       main_task_enqueued = true;
+       xpc_transaction_begin();
 
-               e = e->next;
+       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();
+               });
        }
+}
 
-       if (debug == 1) printf("Finished BB Scan\n");
+static void
+accept_connection(xpc_connection_t peer)
+{
+       xpc_connection_set_event_handler(peer, ^(xpc_object_t request) {
+               if (xpc_get_type(request) == XPC_TYPE_DICTIONARY)
+               {
+                       uid_t uid = xpc_connection_get_euid(peer);
 
-       /* if data store is over max_size, delete/archive more YMD files */
-       if ((debug == 1) && (store_size > max_size)) printf("Additional YMD Scan\n");
+                       /* send a reply immediately */
+                       xpc_object_t reply = xpc_dictionary_create_reply(request);
+                       xpc_connection_send_message(peer, reply);
+                       xpc_release(reply);
 
-       e = ymd_list;
-       while ((e != NULL) && (store_size > max_size))
-       {
-               if (e->size != 0)
-               {
-                       /* stop when we get to today's files */
-                       if (strncmp(e->name, today_ymd_string, today_ymd_stringlen) == 0) break;
+                       /*
+                        * Some day, we may use the dictionary to pass parameters
+                        * to aslmanager, but for now, we ignore the input.
+                        */
 
-                       if (archive != NULL)
+                       if (uid == geteuid())
                        {
-                               str = NULL;
-                               asprintf(&str, "%s/%s", archive, e->name);
-                               if (str == NULL) return -1;
-
-                               /* syslog -x [str] -f [e->name] */
-                               if (debug == 1) printf("  copy %s ---> %s\n", e->name, str);
-                               status = do_copy(e->name, str, archive_mode);
-                               free(str);
+                               main_task();
                        }
+               }
+               else if (xpc_get_type(request) == XPC_TYPE_ERROR)
+               {
+                       /* disconnect */
+               }
+       });
 
-                       if (debug == 1) printf("  unlink %s\n", e->name);
-                       unlink(e->name);
+       xpc_connection_resume(peer);
+}
 
-                       store_size -= e->size;
-                       e->size = 0;
-               }
+int
+main(int argc, char *argv[])
+{
+       int64_t is_managed = 0;
 
-               e = e->next;
-       }
+       vproc_swap_integer(NULL, VPROC_GSK_IS_MANAGED, NULL, &is_managed);
 
-       /* if data store is over max_size, delete/archive more BB files */
-       if ((debug == 1) && (store_size > max_size)) printf("Additional BB Scan\n");
+       if (is_managed == 0) return cli_main(argc, argv);
 
-       e = bb_list;
-       while ((e != NULL) && (store_size > max_size))
-       {
-               if (e->size != 0)
-               {
-                       if (archive != NULL)
-                       {
-                               str = NULL;
-                               asprintf(&str, "%s/%s", archive, e->name);
-                               if (str == NULL) return -1;
+       /* Set I/O policy */
+       setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE);
 
-                               /* syslog -x [str] -f [e->name] */
-                               if (debug == 1) printf("  copy %s ---> %s\n", e->name, str);
-                               status = do_copy(e->name, str, archive_mode);
-                               free(str);
-                       }
+       /* XPC server */
+       server_queue = dispatch_queue_create("aslmanager", NULL);
 
-                       if (debug == 1) printf("  unlink %s\n", e->name);
-                       unlink(e->name);
+       work_queue = dispatch_queue_create("work queue", NULL);
 
-                       store_size -= e->size;
-                       e->size = 0;
-               }
+       /* 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);
+       });
 
-               e = e->next;
-       }
+       dispatch_resume(sig_term_src);
 
-       free_list(ymd_list);     
-       free_list(bb_list);
+       /* Handle incoming messages. */
+       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);
 
-       if (debug == 1)
-       {
-               printf("Data Store Size = %lu\n", store_size);
-               printf("aslmanager finished\n");
-       }
+       cache_delete_register();
 
-       return 0;
+       dispatch_main();
 }
-