From 57b0aad2c678a02fcc3e8b5756d4a13d9061babf Mon Sep 17 00:00:00 2001 From: Apple Date: Tue, 4 Nov 2008 22:39:58 +0000 Subject: [PATCH] syslog-69.0.3.tar.gz --- Makefile | 44 +- Makefile.postamble | 2 - Makefile.preamble | 1 - PB.project | 14 - aslcommon/Makefile | 61 +- aslcommon/Makefile.postamble | 1 - aslcommon/Makefile.preamble | 6 - aslcommon/PB.project | 41 - aslcommon/asl_ipc.defs | 23 + aslcommon/asl_memory.c | 1507 +++++++ aslcommon/asl_memory.h | 79 + aslcommon/asl_mini_memory.c | 1184 ++++++ aslcommon/asl_mini_memory.h | 75 + aslcommon/asl_store.c | 3892 ------------------- aslcommon/asl_store.h | 140 - aslmanager.tproj/Makefile | 12 + aslmanager.tproj/aslmanager.8 | 87 + aslmanager.tproj/aslmanager.c | 448 +++ aslmanager.tproj/com.apple.aslmanager.plist | 18 + syslogd.tproj/Makefile | 82 +- syslogd.tproj/Makefile.postamble | 125 - syslogd.tproj/Makefile.preamble | 117 - syslogd.tproj/PB.project | 41 - syslogd.tproj/asl.conf.5 | 21 + syslogd.tproj/asl_action.c | 83 +- syslogd.tproj/asl_in.c | 27 +- syslogd.tproj/bsd_in.c | 6 +- syslogd.tproj/bsd_out.c | 39 +- syslogd.tproj/daemon.c | 40 +- syslogd.tproj/daemon.h | 45 +- syslogd.tproj/dbserver.c | 499 ++- syslogd.tproj/klog_in.c | 26 +- syslogd.tproj/remote.c | 900 +++++ syslogd.tproj/syslogd.8 | 160 +- syslogd.tproj/syslogd.c | 279 +- syslogd.tproj/udp_in.c | 14 +- util.tproj/Makefile | 55 +- util.tproj/Makefile.postamble | 115 - util.tproj/Makefile.preamble | 117 - util.tproj/PB.project | 41 - util.tproj/syslog.1 | 274 +- util.tproj/syslog.c | 611 ++- 42 files changed, 5381 insertions(+), 5971 deletions(-) delete mode 100644 Makefile.postamble delete mode 100644 Makefile.preamble delete mode 100644 PB.project delete mode 100644 aslcommon/Makefile.postamble delete mode 100644 aslcommon/Makefile.preamble delete mode 100644 aslcommon/PB.project create mode 100644 aslcommon/asl_memory.c create mode 100644 aslcommon/asl_memory.h create mode 100644 aslcommon/asl_mini_memory.c create mode 100644 aslcommon/asl_mini_memory.h delete mode 100644 aslcommon/asl_store.c delete mode 100644 aslcommon/asl_store.h create mode 100644 aslmanager.tproj/Makefile create mode 100644 aslmanager.tproj/aslmanager.8 create mode 100644 aslmanager.tproj/aslmanager.c create mode 100644 aslmanager.tproj/com.apple.aslmanager.plist delete mode 100644 syslogd.tproj/Makefile.postamble delete mode 100644 syslogd.tproj/Makefile.preamble delete mode 100644 syslogd.tproj/PB.project create mode 100644 syslogd.tproj/remote.c delete mode 100644 util.tproj/Makefile.postamble delete mode 100644 util.tproj/Makefile.preamble delete mode 100644 util.tproj/PB.project diff --git a/Makefile b/Makefile index de8fc1f..ab096dd 100644 --- a/Makefile +++ b/Makefile @@ -1,42 +1,8 @@ -# -# Generated by the Apple Project Builder. -# -# NOTE: Do NOT change this file -- Project Builder maintains it. -# -# Put all of your customizations in files called Makefile.preamble -# and Makefile.postamble (both optional), and Makefile will include them. -# +Project = syslog -NAME = syslog +SubProjects = aslcommon aslmanager.tproj syslogd.tproj util.tproj -PROJECTVERSION = 2.8 -PROJECT_TYPE = Aggregate +include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make -TOOLS = syslogd.tproj util.tproj - -LIBRARIES = aslcommon - -OTHERSRCS = Makefile Makefile.preamble Makefile.postamble - -MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles -CODE_GEN_STYLE = DYNAMIC -MAKEFILE = aggregate.make -LIBS = -DEBUG_LIBS = $(LIBS) -PROF_LIBS = $(LIBS) - - - - -NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc -NEXTSTEP_JAVA_COMPILER = /usr/bin/javac - -include $(MAKEFILEDIR)/platform.make - --include Makefile.preamble - -include $(MAKEFILEDIR)/$(MAKEFILE) - --include Makefile.postamble - --include Makefile.dependencies +after_install: + $(RMDIR) "$(DSTROOT)"/scratch diff --git a/Makefile.postamble b/Makefile.postamble deleted file mode 100644 index 0a6f8b0..0000000 --- a/Makefile.postamble +++ /dev/null @@ -1,2 +0,0 @@ -after_install: - $(RM) -rf $(DSTROOT)/usr/lib diff --git a/Makefile.preamble b/Makefile.preamble deleted file mode 100644 index a6b1e76..0000000 --- a/Makefile.preamble +++ /dev/null @@ -1 +0,0 @@ -CLEAN_ALL_SUBPROJECTS = YES diff --git a/PB.project b/PB.project deleted file mode 100644 index 4f85f4f..0000000 --- a/PB.project +++ /dev/null @@ -1,14 +0,0 @@ -{ - FILESTABLE = { - OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble); - SUBPROJECTS = (syslogd.tproj, util.tproj); - }; - LANGUAGE = English; - MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; - NEXTSTEP_BUILDTOOL = /usr/bin/gnumake; - NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; - NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; - PROJECTNAME = network_cmds; - PROJECTTYPE = Aggregate; - PROJECTVERSION = 2.8; -} diff --git a/aslcommon/Makefile b/aslcommon/Makefile index 98cd622..eb99ed0 100644 --- a/aslcommon/Makefile +++ b/aslcommon/Makefile @@ -1,56 +1,13 @@ -# -# Generated by the Apple Project Builder. -# -# NOTE: Do NOT change this file -- Project Builder maintains it. -# -# Put all of your customizations in files called Makefile.preamble -# and Makefile.postamble (both optional), and Makefile will include them. -# +Project = aslcommon +ProductType = staticlib +Install_Dir = /scratch -NAME = aslcommon +CFILES = asl_memory.c asl_mini_memory.c +SERVERDEFS = asl_ipc.defs +USERDEFS = asl_ipc.defs -PROJECTVERSION = 2.8 -PROJECT_TYPE = Library +#PROJECT_HEADERS = asl_ipc.defs asl_memory.h asl_mini_memory.h asl_ipc.h -HFILES = asl_store.h +Extra_CC_Flags = -Wall -D__MigTypeCheck=1 -I. -CFILES = asl_store.c - -OTHERSRCS = Makefile Makefile.postamble Makefile.preamble asl_ipc.defs - - -MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles -CURRENTLY_ACTIVE_VERSION = YES -DEPLOY_WITH_VERSION_NAME = A -CODE_GEN_STYLE = DYNAMIC -MAKEFILE = library.make -NEXTSTEP_INSTALLDIR = /usr/lib -LIBS = -DEBUG_LIBS = $(LIBS) -PROF_LIBS = $(LIBS) - - -PUBLIC_HEADERS = - -PROJECT_HEADERS = asl_ipc.defs asl_store.h asl_ipc.h - - - -WINDOWS_PUBLIC_HEADERS_DIR = LOCAL_DEVELOPER_DIR/Headers/$(NAME) - -NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc -WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc -PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc -NEXTSTEP_JAVA_COMPILER = /usr/bin/javac -WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe -PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac - -include $(MAKEFILEDIR)/platform.make - --include Makefile.preamble - -include $(MAKEFILEDIR)/$(MAKEFILE) - --include Makefile.postamble - --include Makefile.dependencies +include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make diff --git a/aslcommon/Makefile.postamble b/aslcommon/Makefile.postamble deleted file mode 100644 index fd69f0b..0000000 --- a/aslcommon/Makefile.postamble +++ /dev/null @@ -1 +0,0 @@ -# Empty for now diff --git a/aslcommon/Makefile.preamble b/aslcommon/Makefile.preamble deleted file mode 100644 index 688b428..0000000 --- a/aslcommon/Makefile.preamble +++ /dev/null @@ -1,6 +0,0 @@ -LIBRARY_STYLE = STATIC -USE_AR = YES - -DEFSFILES = asl_ipc.defs -OTHER_OFILES += asl_ipcServer.o -OTHER_CFLAGS += -D__MigTypeCheck=1 diff --git a/aslcommon/PB.project b/aslcommon/PB.project deleted file mode 100644 index da7a519..0000000 --- a/aslcommon/PB.project +++ /dev/null @@ -1,41 +0,0 @@ -{ - DOCICONFILES = (); - FILESTABLE = { - C_FILES = (); - H_FILES = (asl_store.h); - OTHER_LIBS = (); - OTHER_LINKED = (asl_store.c); - OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, asl_ipc.defs); - PRECOMPILED_HEADERS = (); - PROJECT_HEADERS = (); - PUBLIC_HEADERS = (); - SUBPROJECTS = (); - }; - GENERATEMAIN = YES; - LANGUAGE = English; - LOCALIZABLE_FILES = {}; - NEXTSTEP_BUILDDIR = ""; - NEXTSTEP_BUILDTOOL = /bin/make; - NEXTSTEP_COMPILEROPTIONS = ""; - NEXTSTEP_INSTALLDIR = /usr/sbin; - NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; - NEXTSTEP_LINKEROPTIONS = ""; - NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; - PDO_UNIX_BUILDDIR = ""; - PDO_UNIX_BUILDTOOL = /bin/make; - PDO_UNIX_COMPILEROPTIONS = ""; - PDO_UNIX_INSTALLDIR = /usr/sbin; - PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; - PDO_UNIX_LINKEROPTIONS = ""; - PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; - PROJECTNAME = aslcommon; - PROJECTTYPE = Library; - PROJECTVERSION = 2.8; - WINDOWS_BUILDDIR = ""; - WINDOWS_BUILDTOOL = /bin/make; - WINDOWS_COMPILEROPTIONS = ""; - WINDOWS_INSTALLDIR = /usr/sbin; - WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; - WINDOWS_LINKEROPTIONS = ""; - WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; -} diff --git a/aslcommon/asl_ipc.defs b/aslcommon/asl_ipc.defs index 7d8cce9..2d1d246 100644 --- a/aslcommon/asl_ipc.defs +++ b/aslcommon/asl_ipc.defs @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2007-2008 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + #include #include diff --git a/aslcommon/asl_memory.c b/aslcommon/asl_memory.c new file mode 100644 index 0000000..5964cf0 --- /dev/null +++ b/aslcommon/asl_memory.c @@ -0,0 +1,1507 @@ +/* + * Copyright (c) 2007-2008 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_MAX_RECORDS 2000 +#define MEM_STRING_HEADER_SIZE 8 + +#define forever for(;;) +extern time_t asl_parse_time(const char *str); +extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b); + +uint32_t +asl_memory_statistics(asl_memory_t *s, aslmsg *msg) +{ + aslmsg out; + uint32_t i, n; + uint64_t size; + char str[256]; + + if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (msg == NULL) return ASL_STATUS_INVALID_ARG; + + out = (aslmsg)calloc(1, sizeof(asl_msg_t)); + if (out == NULL) return ASL_STATUS_NO_MEMORY; + + size = sizeof(asl_memory_t); + size += ((s->record_count + 1) * sizeof(mem_record_t)); + + 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); + } + + snprintf(str, sizeof(str), "%llu", size); + asl_set(out, "Size", str); + + n = 0; + for (i = 0; i < s->record_count; i++) if (s->record[i]->mid != 0) n++; + + snprintf(str, sizeof(str), "%u", n); + asl_set(out, "RecordCount", str); + + snprintf(str, sizeof(str), "%u", s->string_count); + asl_set(out, "StringCount", str); + + *msg = out; + return ASL_STATUS_OK; +} + +uint32_t +asl_memory_close(asl_memory_t *s) +{ + uint32_t i; + + if (s == NULL) return ASL_STATUS_OK; + + if (s->record != NULL) + { + for (i = 0; i < s->record_count; i++) + { + if (s->record[i] != NULL) free(s->record[i]); + s->record[i] = NULL; + } + + free(s->record); + s->record = NULL; + } + + if (s->buffer_record != NULL) free(s->buffer_record); + + if (s->string_cache != NULL) + { + for (i = 0; i < s->string_count; i++) + { + if (s->string_cache[i] != NULL) free(s->string_cache[i]); + s->string_cache[i] = NULL; + } + + free(s->string_cache); + s->string_cache = NULL; + } + + free(s); + + return ASL_STATUS_OK; +} + +uint32_t +asl_memory_open(uint32_t max_records, asl_memory_t **s) +{ + asl_memory_t *out; + uint32_t i; + + if (s == NULL) return ASL_STATUS_INVALID_ARG; + + if (max_records == 0) max_records = DEFAULT_MAX_RECORDS; + + out = calloc(1, sizeof(asl_memory_t)); + if (out == NULL) return ASL_STATUS_NO_MEMORY; + + out->record_count = max_records; + out->record = (mem_record_t **)calloc(max_records, sizeof(mem_record_t *)); + if (out->record == NULL) + { + free(out); + return ASL_STATUS_NO_MEMORY; + } + + for (i = 0; i < max_records; i++) + { + out->record[i] = (mem_record_t *)calloc(1, sizeof(mem_record_t)); + if (out->record[i] == NULL) + { + asl_memory_close(out); + return ASL_STATUS_NO_MEMORY; + } + } + + out->buffer_record = (mem_record_t *)calloc(1, sizeof(mem_record_t)); + if (out->buffer_record == NULL) + { + asl_memory_close(out); + return ASL_STATUS_NO_MEMORY; + } + + *s = out; + return ASL_STATUS_OK; +} + +static mem_string_t * +mem_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); + if (out == NULL) return NULL; + + out->hash = hash; + out->refcount = 1; + memcpy(out->str, str, len); + + return out; +} + +/* + * Find the first hash greater than or equal to a given hash in the string cache. + * Return s->string_count if hash is greater that or equal to last hash in the string cache. + * Caller must check if the hashes match or not. + * + * This routine is used both to find strings in the cache and to determine where to insert + * new strings. Note that the caller needs to do extra work after calling this routine. + */ +static uint32_t +asl_memory_string_cache_search_hash(asl_memory_t *s, uint32_t hash) +{ + uint32_t top, bot, mid, range; + mem_string_t *ms; + + if (s->string_count == 0) return 0; + if (s->string_count == 1) + { + ms = (mem_string_t *)s->string_cache[0]; + if (hash < ms->hash) return 0; + return 1; + } + + top = s->string_count - 1; + bot = 0; + mid = top / 2; + + range = top - bot; + while (range > 1) + { + ms = (mem_string_t *)s->string_cache[mid]; + + if (hash == ms->hash) + { + while (mid > 0) + { + ms = (mem_string_t *)s->string_cache[mid - 1]; + if (hash != ms->hash) break; + mid--; + } + + return mid; + } + else + { + ms = (mem_string_t *)s->string_cache[mid]; + if (hash < ms->hash) top = mid; + else bot = mid; + } + + range = top - bot; + mid = bot + (range / 2); + } + + ms = (mem_string_t *)s->string_cache[bot]; + if (hash <= ms->hash) return bot; + + ms = (mem_string_t *)s->string_cache[top]; + if (hash <= ms->hash) return top; + + return s->string_count; +} + +/* + * Search the string cache. + * If the string is in the cache, increment refcount and return it. + * If the string is not in cache and create flag is on, create a new string. + * Otherwise, return NULL. + */ +static mem_string_t * +asl_memory_string_retain(asl_memory_t *s, const char *str, int create) +{ + uint32_t i, where, hash, len; + + if (s == NULL) return NULL; + if (str == NULL) return NULL; + len = strlen(str); + + /* check the cache */ + hash = asl_core_string_hash(str, len); + where = asl_memory_string_cache_search_hash(s, hash); + + /* 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) + { + if (!strcmp(str, ((mem_string_t *)(s->string_cache[where]))->str)) + { + ((mem_string_t *)(s->string_cache[where]))->refcount++; + return s->string_cache[where]; + } + + where++; + } + } + + /* not found */ + 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]; + } + + if (s->string_cache == NULL) + { + s->string_count = 0; + return NULL; + } + + s->string_count++; + s->string_cache[where] = mem_string_new(str, len, hash); + + return s->string_cache[where]; +} + +static uint32_t +asl_memory_string_release(asl_memory_t *s, mem_string_t *m) +{ + uint32_t i, where; + + if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (m == NULL) return ASL_STATUS_OK; + + if (m->refcount > 0) m->refcount--; + if (m->refcount > 0) return ASL_STATUS_OK; + + where = asl_memory_string_cache_search_hash(s, m->hash); + if (((mem_string_t *)(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; + + where++; + if (where >= s->string_count) return ASL_STATUS_OK; + } + + for (i = where + 1; i < s->string_count; i++) s->string_cache[i - 1] = s->string_cache[i]; + + free(m); + s->string_count--; + + if (s->string_count == 0) + { + free(s->string_cache); + s->string_cache = NULL; + return ASL_STATUS_OK; + } + + s->string_cache = (void **)reallocf(s->string_cache, s->string_count * sizeof(void *)); + if (s->string_cache == NULL) + { + s->string_count = 0; + return ASL_STATUS_NO_MEMORY; + } + + return ASL_STATUS_OK; +} + +/* + * Release all a record's strings and reset it's values + */ +static void +asl_memory_record_clear(asl_memory_t *s, mem_record_t *r) +{ + uint32_t i; + + if (s == NULL) return; + if (r == NULL) return; + + asl_memory_string_release(s, r->host); + asl_memory_string_release(s, r->sender); + asl_memory_string_release(s, r->facility); + asl_memory_string_release(s, r->message); + asl_memory_string_release(s, r->refproc); + asl_memory_string_release(s, r->session); + + for (i = 0; i < r->kvcount; i++) asl_memory_string_release(s, r->kvlist[i]); + + if (r->kvlist != NULL) free(r->kvlist); + memset(r, 0, sizeof(mem_record_t)); +} + +static void +asl_memory_record_free(asl_memory_t *s, mem_record_t *r) +{ + asl_memory_record_clear(s, r); + free(r); +} + +/* + * Encode an aslmsg as a record structure. + * Creates and caches strings. + */ +static uint32_t +asl_memory_message_encode(asl_memory_t *s, asl_msg_t *msg, mem_record_t *r) +{ + uint32_t i; + mem_string_t *k, *v; + + if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (msg == NULL) return ASL_STATUS_INVALID_MESSAGE; + if (r == NULL) return ASL_STATUS_INVALID_ARG; + + memset(r, 0, sizeof(mem_record_t)); + + r->flags = 0; + r->level = ASL_LEVEL_DEBUG; + r->pid = -1; + r->uid = -2; + r->gid = -2; + r->ruid = -1; + r->rgid = -1; + r->time = (uint64_t)-1; + r->nano = (uint32_t)-1; + + for (i = 0; i < msg->count; i++) + { + if (msg->key[i] == NULL) continue; + + else if (!strcmp(msg->key[i], ASL_KEY_TIME)) + { + if (msg->val[i] != NULL) r->time = asl_parse_time(msg->val[i]); + } + else if (!strcmp(msg->key[i], ASL_KEY_TIME_NSEC)) + { + if (msg->val[i] != NULL) r->nano = atoi(msg->val[i]); + } + else if (!strcmp(msg->key[i], ASL_KEY_HOST)) + { + if (msg->val[i] != NULL) r->host = asl_memory_string_retain(s, msg->val[i], 1); + } + else if (!strcmp(msg->key[i], ASL_KEY_SENDER)) + { + if (msg->val[i] != NULL) r->sender = asl_memory_string_retain(s, msg->val[i], 1); + } + else if (!strcmp(msg->key[i], ASL_KEY_PID)) + { + if (msg->val[i] != NULL) r->pid = atoi(msg->val[i]); + } + else if (!strcmp(msg->key[i], ASL_KEY_REF_PID)) + { + if (msg->val[i] != NULL) r->refpid = atoi(msg->val[i]); + } + else if (!strcmp(msg->key[i], ASL_KEY_UID)) + { + if (msg->val[i] != NULL) r->uid = atoi(msg->val[i]); + } + else if (!strcmp(msg->key[i], ASL_KEY_GID)) + { + if (msg->val[i] != NULL) r->gid = atoi(msg->val[i]); + } + else if (!strcmp(msg->key[i], ASL_KEY_LEVEL)) + { + if (msg->val[i] != NULL) r->level = atoi(msg->val[i]); + } + else if (!strcmp(msg->key[i], ASL_KEY_MSG)) + { + if (msg->val[i] != NULL) r->message = asl_memory_string_retain(s, msg->val[i], 1); + } + else if (!strcmp(msg->key[i], ASL_KEY_FACILITY)) + { + if (msg->val[i] != NULL) r->facility = asl_memory_string_retain(s, msg->val[i], 1); + } + else if (!strcmp(msg->key[i], ASL_KEY_REF_PROC)) + { + if (msg->val[i] != NULL) r->refproc = asl_memory_string_retain(s, msg->val[i], 1); + } + else if (!strcmp(msg->key[i], ASL_KEY_SESSION)) + { + if (msg->val[i] != NULL) r->session = asl_memory_string_retain(s, msg->val[i], 1); + } + else if (!strcmp(msg->key[i], ASL_KEY_READ_UID)) + { + if (((r->flags & ASL_MSG_FLAG_READ_UID_SET) == 0) && (msg->val[i] != NULL)) + { + r->ruid = atoi(msg->val[i]); + r->flags |= ASL_MSG_FLAG_READ_UID_SET; + } + } + else if (!strcmp(msg->key[i], ASL_KEY_READ_GID)) + { + if (((r->flags & ASL_MSG_FLAG_READ_GID_SET) == 0) && (msg->val[i] != NULL)) + { + r->rgid = atoi(msg->val[i]); + r->flags |= ASL_MSG_FLAG_READ_GID_SET; + } + } + else if (!strcmp(msg->key[i], ASL_KEY_MSG_ID)) + { + /* Ignore */ + continue; + } + else + { + k = asl_memory_string_retain(s, msg->key[i], 1); + if (k == NULL) continue; + + v = NULL; + if (msg->val[i] != NULL) v = asl_memory_string_retain(s, msg->val[i], 1); + + if (r->kvcount == 0) + { + r->kvlist = (mem_string_t **)calloc(2, sizeof(mem_string_t *)); + } + else + { + r->kvlist = (mem_string_t **)realloc(r->kvlist, (r->kvcount + 2) * sizeof(mem_string_t *)); + } + + if (r->kvlist == NULL) + { + asl_memory_record_clear(s, r); + return ASL_STATUS_NO_MEMORY; + } + + r->kvlist[r->kvcount++] = k; + r->kvlist[r->kvcount++] = v; + } + } + + return ASL_STATUS_OK; +} + +uint32_t +asl_memory_save(asl_memory_t *s, aslmsg msg, uint64_t *mid) +{ + uint32_t status; + mem_record_t *t; + + 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, s->buffer_record); + 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; + + return status; +} + +/* + * Decodes a record structure. + */ +static uint32_t +asl_memory_message_decode(asl_memory_t *s, mem_record_t *r, asl_msg_t **out) +{ + uint32_t i, n; + asl_msg_t *msg; + + if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (r == NULL) return ASL_STATUS_INVALID_ARG; + if (out == NULL) return ASL_STATUS_INVALID_ARG; + + *out = NULL; + + msg = (asl_msg_t *)calloc(1, sizeof(asl_msg_t)); + if (msg == NULL) return ASL_STATUS_NO_MEMORY; + + msg->type = ASL_TYPE_MSG; + /* Level and Message ID are always set */ + msg->count = 2; + if (r->time != (uint64_t)-1) msg->count++; + if (r->nano != (uint32_t)-1) msg->count++; + if (r->host != NULL) msg->count++; + if (r->sender != NULL) msg->count++; + if (r->facility != NULL) msg->count++; + if (r->refproc != NULL) msg->count++; + if (r->session != NULL) msg->count++; + if (r->pid != -1) msg->count++; + if (r->refpid != 0) msg->count++; + if (r->uid != -2) msg->count++; + if (r->gid != -2) msg->count++; + if (r->message != NULL) msg->count++; + if (r->flags & ASL_MSG_FLAG_READ_UID_SET) msg->count++; + if (r->flags & ASL_MSG_FLAG_READ_GID_SET) msg->count++; + + msg->count += (r->kvcount / 2); + + msg->key = (char **)calloc(msg->count, sizeof(char *)); + if (msg->key == NULL) + { + free(msg); + return ASL_STATUS_NO_MEMORY; + } + + msg->val = (char **)calloc(msg->count, sizeof(char *)); + if (msg->val == NULL) + { + free(msg->key); + free(msg); + return ASL_STATUS_NO_MEMORY; + } + + n = 0; + + /* Message ID */ + msg->key[n] = strdup(ASL_KEY_MSG_ID); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + asprintf(&(msg->val[n]), "%llu", r->mid); + if (msg->val[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + n++; + + /* Level */ + msg->key[n] = strdup(ASL_KEY_LEVEL); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + asprintf(&(msg->val[n]), "%u", r->level); + if (msg->val[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + n++; + + /* Time */ + if (r->time != (uint64_t)-1) + { + msg->key[n] = strdup(ASL_KEY_TIME); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + asprintf(&(msg->val[n]), "%llu", r->time); + if (msg->val[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + n++; + } + + /* Nanoseconds */ + if (r->nano != (uint32_t)-1) + { + msg->key[n] = strdup(ASL_KEY_TIME_NSEC); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + asprintf(&(msg->val[n]), "%lu", r->nano); + if (msg->val[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + n++; + } + + /* Host */ + if (r->host != NULL) + { + msg->key[n] = strdup(ASL_KEY_HOST); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + msg->val[n] = strdup(r->host->str); + n++; + } + + /* Sender */ + if (r->sender != NULL) + { + msg->key[n] = strdup(ASL_KEY_SENDER); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + msg->val[n] = strdup(r->sender->str); + n++; + } + + /* Facility */ + if (r->facility != NULL) + { + msg->key[n] = strdup(ASL_KEY_FACILITY); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + msg->val[n] = strdup(r->facility->str); + n++; + } + + /* Ref Proc */ + if (r->refproc != NULL) + { + msg->key[n] = strdup(ASL_KEY_REF_PROC); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + msg->val[n] = strdup(r->refproc->str); + n++; + } + + /* Session */ + if (r->session != NULL) + { + msg->key[n] = strdup(ASL_KEY_SESSION); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + msg->val[n] = strdup(r->session->str); + n++; + } + + /* PID */ + if (r->pid != -1) + { + msg->key[n] = strdup(ASL_KEY_PID); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + asprintf(&(msg->val[n]), "%d", r->pid); + if (msg->val[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + n++; + } + + /* REF PID */ + if (r->refpid != 0) + { + msg->key[n] = strdup(ASL_KEY_REF_PID); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + asprintf(&(msg->val[n]), "%d", r->refpid); + if (msg->val[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + n++; + } + + /* UID */ + if (r->uid != -2) + { + msg->key[n] = strdup(ASL_KEY_UID); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + asprintf(&(msg->val[n]), "%d", r->uid); + if (msg->val[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + n++; + } + + /* GID */ + if (r->gid != -2) + { + msg->key[n] = strdup(ASL_KEY_GID); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + asprintf(&(msg->val[n]), "%d", r->gid); + if (msg->val[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + n++; + } + + /* Message */ + if (r->message != NULL) + { + msg->key[n] = strdup(ASL_KEY_MSG); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + msg->val[n] = strdup(r->message->str); + n++; + } + + /* ReadUID */ + if (r->flags & ASL_MSG_FLAG_READ_UID_SET) + { + msg->key[n] = strdup(ASL_KEY_READ_UID); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + asprintf(&(msg->val[n]), "%d", r->ruid); + if (msg->val[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + n++; + } + + /* ReadGID */ + if (r->flags & ASL_MSG_FLAG_READ_GID_SET) + { + msg->key[n] = strdup(ASL_KEY_READ_GID); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + asprintf(&(msg->val[n]), "%d", r->rgid); + if (msg->val[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + n++; + } + + /* Key - Value List */ + for (i = 0; i < r->kvcount; i++) + { + if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) msg->key[n] = strdup(r->kvlist[i]->str); + i++; + if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) msg->val[n] = strdup(r->kvlist[i]->str); + n++; + } + + *out = msg; + return ASL_STATUS_OK; +} + +uint32_t +asl_memory_fetch(asl_memory_t *s, uint64_t mid, aslmsg *msg, int32_t ruid, int32_t rgid) +{ + uint32_t i, status; + + if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (msg == NULL) return ASL_STATUS_INVALID_ARG; + + for (i = 0; i < s->record_count; i++) + { + if (s->record[i]->mid == 0) break; + + if (s->record[i]->mid == mid) + { + status = asl_core_check_access(s->record[i]->ruid, s->record[i]->rgid, ruid, rgid, s->record[i]->flags); + if (status != ASL_STATUS_OK) return status; + return asl_memory_message_decode(s, s->record[i], msg); + } + } + + return ASL_STATUS_INVALID_ID; +} + +static mem_record_t * +asl_memory_query_to_record(asl_memory_t *s, asl_msg_t *q, uint32_t *type) +{ + mem_record_t *out; + uint32_t i, j; + mem_string_t *key, *val; + + if (type == NULL) return NULL; + + if (s == NULL) + { + *type = ASL_QUERY_MATCH_ERROR; + return NULL; + } + + /* NULL query matches anything */ + *type = ASL_QUERY_MATCH_TRUE; + if (q == NULL) return NULL; + if (q->count == 0) return NULL; + + + /* we can only do fast match on equality tests */ + *type = ASL_QUERY_MATCH_SLOW; + if (q->op != NULL) + { + for (i = 0; i < q->count; i++) if (q->op[i] != ASL_QUERY_OP_EQUAL) return NULL; + } + + out = (mem_record_t *)calloc(1, sizeof(mem_record_t)); + if (out == NULL) + { + *type = ASL_QUERY_MATCH_ERROR; + return NULL; + } + + for (i = 0; i < q->count; i++) + { + if (q->key[i] == NULL) continue; + + else if (!strcmp(q->key[i], ASL_KEY_MSG_ID)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_MSG_ID) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_MSG_ID; + out->mid = atoll(q->val[i]); + } + else if (!strcmp(q->key[i], ASL_KEY_TIME)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_TIME) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_TIME; + out->time = asl_parse_time(q->val[i]); + } + else if (!strcmp(q->key[i], ASL_KEY_TIME_NSEC)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_NANO) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_NANO; + out->nano = atoll(q->val[i]); + } + else if (!strcmp(q->key[i], ASL_KEY_LEVEL)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_LEVEL) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_LEVEL; + out->level = atoi(q->val[i]); + } + else if (!strcmp(q->key[i], ASL_KEY_PID)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_PID) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_PID; + out->pid = atoi(q->val[i]); + } + else if (!strcmp(q->key[i], ASL_KEY_UID)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_UID) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_UID; + out->uid = atoi(q->val[i]); + } + else if (!strcmp(q->key[i], ASL_KEY_GID)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_GID) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_GID; + out->gid = atoi(q->val[i]); + } + else if (!strcmp(q->key[i], ASL_KEY_READ_UID)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_RUID) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_RUID; + out->ruid = atoi(q->val[i]); + } + else if (!strcmp(q->key[i], ASL_KEY_READ_GID)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_RGID) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_RGID; + out->rgid = atoi(q->val[i]); + } + else if (!strcmp(q->key[i], ASL_KEY_REF_PID)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_REF_PID) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_REF_PID; + out->refpid = atoi(q->val[i]); + } + else if (!strcmp(q->key[i], ASL_KEY_HOST)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_HOST) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_HOST; + out->host = asl_memory_string_retain(s, q->val[i], 0); + if (out->host == NULL) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_FALSE; + return NULL; + } + } + else if (!strcmp(q->key[i], ASL_KEY_SENDER)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_SENDER) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_SENDER; + out->sender = asl_memory_string_retain(s, q->val[i], 0); + if (out->sender == NULL) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_FALSE; + return NULL; + } + } + else if (!strcmp(q->key[i], ASL_KEY_FACILITY)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_FACILITY) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_FACILITY; + out->facility = asl_memory_string_retain(s, q->val[i], 0); + if (out->facility == NULL) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_FALSE; + return NULL; + } + } + else if (!strcmp(q->key[i], ASL_KEY_MSG)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_MESSAGE) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_MESSAGE; + out->message = asl_memory_string_retain(s, q->val[i], 0); + if (out->message == NULL) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_FALSE; + return NULL; + } + } + else if (!strcmp(q->key[i], ASL_KEY_REF_PROC)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_REF_PROC) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_REF_PROC; + out->refproc = asl_memory_string_retain(s, q->val[i], 0); + if (out->refproc == NULL) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_FALSE; + return NULL; + } + } + else if (!strcmp(q->key[i], ASL_KEY_SESSION)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_SESSION) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_SESSION; + out->session = asl_memory_string_retain(s, q->val[i], 0); + if (out->session == NULL) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_FALSE; + return NULL; + } + } + else + { + key = asl_memory_string_retain(s, q->key[i], 0); + if (key == NULL) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_FALSE; + return NULL; + } + + for (j = 0; j < out->kvcount; j += 2) + { + if (out->kvlist[j] == key) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + } + + val = asl_memory_string_retain(s, q->val[i], 0); + + if (out->kvcount == 0) + { + out->kvlist = (mem_string_t **)calloc(2, sizeof(mem_string_t *)); + } + else + { + out->kvlist = (mem_string_t **)realloc(out->kvlist, (out->kvcount + 2) * sizeof(mem_string_t *)); + } + + if (out->kvlist == NULL) + { + asl_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_ERROR; + return NULL; + } + + out->kvlist[out->kvcount++] = key; + out->kvlist[out->kvcount++] = val; + } + } + + return out; +} + +static uint32_t +asl_memory_fast_match(asl_memory_t *s, mem_record_t *r, uint32_t qtype, mem_record_t *q) +{ + uint32_t i, j; + + if (s == NULL) return 0; + if (r == NULL) return 0; + if (q == NULL) return 1; + + if ((qtype & ASL_QUERY_MATCH_MSG_ID) && (q->mid != r->mid)) return 0; + if ((qtype & ASL_QUERY_MATCH_TIME) && (q->time != r->time)) return 0; + if ((qtype & ASL_QUERY_MATCH_NANO) && (q->nano != r->nano)) return 0; + if ((qtype & ASL_QUERY_MATCH_LEVEL) && (q->level != r->level)) return 0; + if ((qtype & ASL_QUERY_MATCH_PID) && (q->pid != r->pid)) return 0; + if ((qtype & ASL_QUERY_MATCH_UID) && (q->uid != r->uid)) return 0; + if ((qtype & ASL_QUERY_MATCH_GID) && (q->gid != r->gid)) return 0; + if ((qtype & ASL_QUERY_MATCH_RUID) && (q->ruid != r->ruid)) return 0; + if ((qtype & ASL_QUERY_MATCH_RGID) && (q->rgid != r->rgid)) return 0; + if ((qtype & ASL_QUERY_MATCH_REF_PID) && (q->refpid != r->refpid)) return 0; + if ((qtype & ASL_QUERY_MATCH_HOST) && (q->host != r->host)) return 0; + if ((qtype & ASL_QUERY_MATCH_SENDER) && (q->sender != r->sender)) return 0; + if ((qtype & ASL_QUERY_MATCH_FACILITY) && (q->facility != r->facility)) return 0; + if ((qtype & ASL_QUERY_MATCH_MESSAGE) && (q->message != r->message)) return 0; + if ((qtype & ASL_QUERY_MATCH_REF_PROC) && (q->refproc != r->refproc)) return 0; + if ((qtype & ASL_QUERY_MATCH_SESSION) && (q->session != r->session)) return 0; + + for (i = 0; i < q->kvcount; i += 2) + { + for (j = 0; j < r->kvcount; j += 2) + { + if (q->kvlist[i] == r->kvlist[j]) + { + if (q->kvlist[i + 1] == r->kvlist[j + 1]) break; + return 0; + } + } + + if (j >= r->kvcount) return 0; + } + + return 1; +} + +static uint32_t +asl_memory_slow_match(asl_memory_t *s, mem_record_t *r, mem_record_t *q, asl_msg_t *rawq) +{ + asl_msg_t *rawm; + uint32_t status; + + rawm = NULL; + status = asl_memory_message_decode(s, r, &rawm); + if (status != ASL_STATUS_OK) return 0; + + status = 0; + if (asl_msg_cmp(rawq, rawm) != 0) status = 1; + asl_free(rawm); + return status; +} + +uint32_t +asl_memory_match(asl_memory_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, int32_t ruid, int32_t rgid) +{ + uint32_t status, i, where, start, j, do_match, did_match, rescount, *qtype; + mem_record_t **qp; + asl_msg_t *m; + + if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (res == NULL) return ASL_STATUS_INVALID_ARG; + + do_match = 1; + qp = NULL; + qtype = NULL; + rescount = 0; + + if ((query == NULL) || ((query != NULL) && (query->count == 0))) + { + do_match = 0; + } + else + { + qp = (mem_record_t **)calloc(query->count, sizeof(mem_record_t *)); + if (qp == NULL) return ASL_STATUS_NO_MEMORY; + + qtype = (uint32_t *)calloc(query->count, sizeof(uint32_t)); + if (qtype == NULL) + { + free(qp); + return ASL_STATUS_NO_MEMORY; + } + + do_match = 0; + for (i = 0; i < query->count; i++) + { + qp[i] = asl_memory_query_to_record(s, query->msg[i], &(qtype[i])); + if (qtype[i] == ASL_QUERY_MATCH_ERROR) + { + for (j = 0; j < i; j++) asl_memory_record_free(s, qp[j]); + free(qp); + free(qtype); + return ASL_STATUS_FAILED; + } + + if (qtype[i] != ASL_QUERY_MATCH_TRUE) do_match = 1; + } + } + + for (i = 0; i < s->record_count; i++) + { + if (direction >= 0) + { + where = (s->record_first + i) % s->record_count; + if (s->record[where]->mid == 0) continue; + if (s->record[where]->mid >= start_id) break; + } + else + { + where = ((s->record_count - (i + 1)) + s->record_first) % s->record_count; + if (s->record[where]->mid == 0) continue; + if (s->record[where]->mid <= start_id) break; + } + } + + if (i >= s->record_count) return ASL_STATUS_OK; + + start = where; + + /* + * loop through records + */ + for (i = 0; i < s->record_count; i++) + { + status = ASL_STATUS_INVALID_ID; + if (s->record[where]->mid != 0) status = asl_core_check_access(s->record[where]->ruid, s->record[where]->rgid, ruid, rgid, s->record[where]->flags); + if (status != ASL_STATUS_OK) + { + if (direction >= 0) + { + where++; + if (where >= s->record_count) where = 0; + } + else + { + if (where == 0) where = s->record_count - 1; + else where--; + } + + if (where == s->record_first) break; + continue; + } + + s->record[where]->flags &= ASL_MSG_FLAG_SEARCH_CLEAR; + *last_id = s->record[where]->mid; + did_match = 1; + + if (do_match != 0) + { + did_match = 0; + + for (j = 0; (j < query->count) && (did_match == 0); j++) + { + if (qtype[j] == ASL_QUERY_MATCH_TRUE) + { + did_match = 1; + } + else if (qtype[j] == ASL_QUERY_MATCH_SLOW) + { + did_match = asl_memory_slow_match(s, s->record[where], qp[j], query->msg[j]); + } + else + { + did_match = asl_memory_fast_match(s, s->record[where], qtype[j], qp[j]); + } + } + } + + if (did_match == 1) + { + s->record[where]->flags |= ASL_MSG_FLAG_SEARCH_MATCH; + rescount++; + if ((count != 0) && (rescount >= count)) break; + } + + if (direction >= 0) + { + where++; + if (where >= s->record_count) where = 0; + } + else + { + if (where == 0) where = s->record_count - 1; + else where--; + } + + if (where == s->record_first) break; + } + + if (query != NULL) + { + for (i = 0; i < query->count; i++) asl_memory_record_free(s, qp[i]); + free(qp); + free(qtype); + } + + *res = NULL; + if (rescount == 0) return ASL_STATUS_OK; + + *res = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t)); + if (*res == NULL) return ASL_STATUS_NO_MEMORY; + + (*res)->count = rescount; + + (*res)->msg = (asl_msg_t **)calloc(rescount, sizeof(asl_msg_t *)); + if ((*res)->msg == NULL) + { + free(*res); + *res = NULL; + return ASL_STATUS_NO_MEMORY; + } + + where = start; + forever + { + if (s->record[where]->flags & ASL_MSG_FLAG_SEARCH_MATCH) + { + s->record[where]->flags &= ASL_MSG_FLAG_SEARCH_CLEAR; + + status = asl_memory_message_decode(s, s->record[where], &m); + if (status != ASL_STATUS_OK) + { + aslresponse_free(*res); + *res = NULL; + return status; + } + + (*res)->msg[(*res)->curr++] = m; + if ((*res)->curr == rescount) break; + } + + if (direction >= 0) + { + where++; + if (where >= s->record_count) where = 0; + } + else + { + if (where == 0) where = s->record_count - 1; + else where--; + } + + if (where == s->record_first) break; + } + + (*res)->curr = 0; + return ASL_STATUS_OK; +} diff --git a/aslcommon/asl_memory.h b/aslcommon/asl_memory.h new file mode 100644 index 0000000..d6c99fc --- /dev/null +++ b/aslcommon/asl_memory.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2007-2008 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef __ASL_MEMORY_H__ +#define __ASL_MEMORY_H__ +#include +#include + +typedef struct +{ + uint32_t hash; + uint32_t refcount; + 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; + uint32_t kvcount; + mem_string_t *host; + mem_string_t *sender; + mem_string_t *facility; + mem_string_t *message; + mem_string_t *refproc; + mem_string_t *session; + mem_string_t **kvlist; +} mem_record_t; + +typedef struct +{ + uint32_t string_count; + void **string_cache; + uint32_t record_count; + uint32_t record_first; + mem_record_t **record; + mem_record_t *buffer_record; +} asl_memory_t; + +uint32_t asl_memory_open(uint32_t max_records, asl_memory_t **s); +uint32_t asl_memory_close(asl_memory_t *s); +uint32_t asl_memory_statistics(asl_memory_t *s, aslmsg *msg); + +uint32_t asl_memory_save(asl_memory_t *s, aslmsg msg, uint64_t *mid); +uint32_t asl_memory_fetch(asl_memory_t *s, uint64_t mid, aslmsg *msg, int32_t ruid, int32_t rgid); + +uint32_t asl_memory_match(asl_memory_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, int32_t ruid, int32_t rgid); + +#endif __ASL_MEMORY_H__ diff --git a/aslcommon/asl_mini_memory.c b/aslcommon/asl_mini_memory.c new file mode 100644 index 0000000..1f45aec --- /dev/null +++ b/aslcommon/asl_mini_memory.c @@ -0,0 +1,1184 @@ +/* + * Copyright (c) 2007-2008 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_MAX_RECORDS 256 +#define MEM_STRING_HEADER_SIZE 8 +#define CFLOG_LOCAL_TIME_KEY "CFLog Local Time" +#define CFLOG_THREAD_KEY "CFLog Thread" + +#define forever for(;;) +extern time_t asl_parse_time(const char *str); +extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b); + +uint32_t +asl_mini_memory_statistics(asl_mini_memory_t *s, aslmsg *msg) +{ + aslmsg out; + uint32_t i, n; + uint64_t size; + char str[256]; + + if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (msg == NULL) return ASL_STATUS_INVALID_ARG; + + out = (aslmsg)calloc(1, sizeof(asl_msg_t)); + if (out == NULL) return ASL_STATUS_NO_MEMORY; + + size = sizeof(asl_mini_memory_t); + size += ((s->record_count + 1) * sizeof(mini_mem_record_t)); + + for (i = 0; i < s->string_count; i++) + { + size += MEM_STRING_HEADER_SIZE; + if (((mini_mem_string_t *)s->string_cache[i])->str != NULL) size += (strlen(((mini_mem_string_t *)s->string_cache[i])->str) + 1); + } + + snprintf(str, sizeof(str), "%llu", size); + asl_set(out, "Size", str); + + n = 0; + for (i = 0; i < s->record_count; i++) if (s->record[i]->mid != 0) n++; + + snprintf(str, sizeof(str), "%u", n); + asl_set(out, "RecordCount", str); + + snprintf(str, sizeof(str), "%u", s->string_count); + asl_set(out, "StringCount", str); + + *msg = out; + return ASL_STATUS_OK; +} + +uint32_t +asl_mini_memory_close(asl_mini_memory_t *s) +{ + uint32_t i; + + if (s == NULL) return ASL_STATUS_OK; + + if (s->record != NULL) + { + for (i = 0; i < s->record_count; i++) + { + if (s->record[i] != NULL) free(s->record[i]); + s->record[i] = NULL; + } + + free(s->record); + s->record = NULL; + } + + if (s->buffer_record != NULL) free(s->buffer_record); + + if (s->string_cache != NULL) + { + for (i = 0; i < s->string_count; i++) + { + if (s->string_cache[i] != NULL) free(s->string_cache[i]); + s->string_cache[i] = NULL; + } + + free(s->string_cache); + s->string_cache = NULL; + } + + free(s); + + return ASL_STATUS_OK; +} + +uint32_t +asl_mini_memory_open(uint32_t max_records, asl_mini_memory_t **s) +{ + asl_mini_memory_t *out; + uint32_t i; + + if (s == NULL) return ASL_STATUS_INVALID_ARG; + + if (max_records == 0) max_records = DEFAULT_MAX_RECORDS; + + out = calloc(1, sizeof(asl_mini_memory_t)); + if (out == NULL) return ASL_STATUS_NO_MEMORY; + + out->record_count = max_records; + out->record = (mini_mem_record_t **)calloc(max_records, sizeof(mini_mem_record_t *)); + if (out->record == NULL) + { + free(out); + return ASL_STATUS_NO_MEMORY; + } + + for (i = 0; i < max_records; i++) + { + out->record[i] = (mini_mem_record_t *)calloc(1, sizeof(mini_mem_record_t)); + if (out->record[i] == NULL) + { + asl_mini_memory_close(out); + return ASL_STATUS_NO_MEMORY; + } + } + + out->buffer_record = (mini_mem_record_t *)calloc(1, sizeof(mini_mem_record_t)); + if (out->buffer_record == NULL) + { + asl_mini_memory_close(out); + return ASL_STATUS_NO_MEMORY; + } + + out->next_id = 1; + + *s = out; + return ASL_STATUS_OK; +} + +static mini_mem_string_t * +mem_string_new(const char *str, uint32_t len, uint32_t hash) +{ + mini_mem_string_t *out; + size_t ss; + + if (str == NULL) return NULL; + + ss = MEM_STRING_HEADER_SIZE + len + 1; + out = (mini_mem_string_t *)calloc(1, ss); + if (out == NULL) return NULL; + + out->hash = hash; + out->refcount = 1; + memcpy(out->str, str, len); + + return out; +} + +/* + * Find the first hash greater than or equal to a given hash in the string cache. + * Return s->string_count if hash is greater that or equal to last hash in the string cache. + * Caller must check if the hashes match or not. + * + * This routine is used both to find strings in the cache and to determine where to insert + * new strings. Note that the caller needs to do extra work after calling this routine. + */ +static uint32_t +asl_mini_memory_string_cache_search_hash(asl_mini_memory_t *s, uint32_t hash) +{ + uint32_t top, bot, mid, range; + mini_mem_string_t *ms; + + if (s->string_count == 0) return 0; + if (s->string_count == 1) + { + ms = (mini_mem_string_t *)s->string_cache[0]; + if (hash < ms->hash) return 0; + return 1; + } + + top = s->string_count - 1; + bot = 0; + mid = top / 2; + + range = top - bot; + while (range > 1) + { + ms = (mini_mem_string_t *)s->string_cache[mid]; + + if (hash == ms->hash) + { + while (mid > 0) + { + ms = (mini_mem_string_t *)s->string_cache[mid - 1]; + if (hash != ms->hash) break; + mid--; + } + + return mid; + } + else + { + ms = (mini_mem_string_t *)s->string_cache[mid]; + if (hash < ms->hash) top = mid; + else bot = mid; + } + + range = top - bot; + mid = bot + (range / 2); + } + + ms = (mini_mem_string_t *)s->string_cache[bot]; + if (hash <= ms->hash) return bot; + + ms = (mini_mem_string_t *)s->string_cache[top]; + if (hash <= ms->hash) return top; + + return s->string_count; +} + +/* + * Search the string cache. + * If the string is in the cache, increment refcount and return it. + * If the string is not in cache and create flag is on, create a new string. + * Otherwise, return NULL. + */ +static mini_mem_string_t * +asl_mini_memory_string_retain(asl_mini_memory_t *s, const char *str, int create) +{ + uint32_t i, where, hash, len; + + if (s == NULL) return NULL; + if (str == NULL) return NULL; + len = strlen(str); + + /* check the cache */ + hash = asl_core_string_hash(str, len); + where = asl_mini_memory_string_cache_search_hash(s, hash); + + /* asl_mini_memory_string_cache_search_hash just tells us where to look */ + if (where < s->string_count) + { + while (((mini_mem_string_t *)(s->string_cache[where]))->hash == hash) + { + if (!strcmp(str, ((mini_mem_string_t *)(s->string_cache[where]))->str)) + { + ((mini_mem_string_t *)(s->string_cache[where]))->refcount++; + return s->string_cache[where]; + } + + where++; + } + } + + /* not found */ + if (create == 0) return NULL; + + /* create a new mini_mem_string_t and insert into the cache at index 'where' */ + if (s->string_count == 0) + { + s->string_cache = (void **)calloc(1, sizeof(void *)); + } + else + { + s->string_cache = (void **)reallocf(s->string_cache, (s->string_count + 1) * sizeof(void *)); + for (i = s->string_count; i > where; i--) s->string_cache[i] = s->string_cache[i - 1]; + } + + if (s->string_cache == NULL) + { + s->string_count = 0; + return NULL; + } + + s->string_count++; + s->string_cache[where] = mem_string_new(str, len, hash); + + return s->string_cache[where]; +} + +static uint32_t +asl_mini_memory_string_release(asl_mini_memory_t *s, mini_mem_string_t *m) +{ + uint32_t i, where; + + if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (m == NULL) return ASL_STATUS_OK; + + if (m->refcount > 0) m->refcount--; + if (m->refcount > 0) return ASL_STATUS_OK; + + where = asl_mini_memory_string_cache_search_hash(s, m->hash); + if (((mini_mem_string_t *)(s->string_cache[where]))->hash != m->hash) return ASL_STATUS_OK; + + while (s->string_cache[where] != m) + { + if (((mini_mem_string_t *)(s->string_cache[where]))->hash != m->hash) return ASL_STATUS_OK; + + where++; + if (where >= s->string_count) return ASL_STATUS_OK; + } + + for (i = where + 1; i < s->string_count; i++) s->string_cache[i - 1] = s->string_cache[i]; + + free(m); + s->string_count--; + + if (s->string_count == 0) + { + free(s->string_cache); + s->string_cache = NULL; + return ASL_STATUS_OK; + } + + s->string_cache = (void **)reallocf(s->string_cache, s->string_count * sizeof(void *)); + if (s->string_cache == NULL) + { + s->string_count = 0; + return ASL_STATUS_NO_MEMORY; + } + + return ASL_STATUS_OK; +} + +/* + * Release all a record's strings and reset it's values + */ +static void +asl_mini_memory_record_clear(asl_mini_memory_t *s, mini_mem_record_t *r) +{ + uint32_t i; + + if (s == NULL) return; + if (r == NULL) return; + + asl_mini_memory_string_release(s, r->sender); + asl_mini_memory_string_release(s, r->facility); + asl_mini_memory_string_release(s, r->message); + + for (i = 0; i < r->kvcount; i++) asl_mini_memory_string_release(s, r->kvlist[i]); + + if (r->kvlist != NULL) free(r->kvlist); + memset(r, 0, sizeof(mini_mem_record_t)); +} + +static void +asl_mini_memory_record_free(asl_mini_memory_t *s, mini_mem_record_t *r) +{ + asl_mini_memory_record_clear(s, r); + free(r); +} + +/* + * Encode an aslmsg as a record structure. + * Creates and caches strings. + */ +static uint32_t +asl_mini_memory_message_encode(asl_mini_memory_t *s, asl_msg_t *msg, mini_mem_record_t *r) +{ + uint32_t i; + mini_mem_string_t *k, *v; + + if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (msg == NULL) return ASL_STATUS_INVALID_MESSAGE; + if (r == NULL) return ASL_STATUS_INVALID_ARG; + + memset(r, 0, sizeof(mini_mem_record_t)); + + r->flags = 0; + r->level = ASL_LEVEL_DEBUG; + r->pid = -1; + r->time = (uint64_t)-1; + + for (i = 0; i < msg->count; i++) + { + if (msg->key[i] == NULL) continue; + + else if (!strcmp(msg->key[i], ASL_KEY_TIME)) + { + if (msg->val[i] != NULL) r->time = asl_parse_time(msg->val[i]); + } + else if (!strcmp(msg->key[i], ASL_KEY_SENDER)) + { + if (msg->val[i] != NULL) r->sender = asl_mini_memory_string_retain(s, msg->val[i], 1); + } + else if (!strcmp(msg->key[i], ASL_KEY_PID)) + { + if (msg->val[i] != NULL) r->pid = atoi(msg->val[i]); + } + else if (!strcmp(msg->key[i], ASL_KEY_LEVEL)) + { + if (msg->val[i] != NULL) r->level = atoi(msg->val[i]); + } + else if (!strcmp(msg->key[i], ASL_KEY_MSG)) + { + if (msg->val[i] != NULL) r->message = asl_mini_memory_string_retain(s, msg->val[i], 1); + } + else if (!strcmp(msg->key[i], ASL_KEY_FACILITY)) + { + if (msg->val[i] != NULL) r->facility = asl_mini_memory_string_retain(s, msg->val[i], 1); + } + else if (!strcmp(msg->key[i], ASL_KEY_MSG_ID)) + { + /* Ignore */ + continue; + } + else if (!strcmp(msg->key[i], ASL_KEY_TIME_NSEC)) + { + /* Ignore */ + continue; + } + else if (!strcmp(msg->key[i], ASL_KEY_HOST)) + { + /* Ignore */ + continue; + } + else if (!strcmp(msg->key[i], ASL_KEY_REF_PID)) + { + /* Ignore */ + continue; + } + else if (!strcmp(msg->key[i], ASL_KEY_REF_PROC)) + { + /* Ignore */ + continue; + } + else if (!strcmp(msg->key[i], ASL_KEY_SESSION)) + { + /* Ignore */ + continue; + } + else if (!strcmp(msg->key[i], ASL_KEY_UID)) + { + /* Ignore */ + continue; + } + else if (!strcmp(msg->key[i], ASL_KEY_GID)) + { + /* Ignore */ + continue; + } + else if (!strcmp(msg->key[i], ASL_KEY_READ_UID)) + { + /* Ignore */ + continue; + } + else if (!strcmp(msg->key[i], ASL_KEY_READ_GID)) + { + /* Ignore */ + continue; + } + else if (!strcmp(msg->key[i], CFLOG_LOCAL_TIME_KEY)) + { + /* Ignore */ + continue; + } + else if (!strcmp(msg->key[i], CFLOG_THREAD_KEY)) + { + /* Ignore */ + continue; + } + else + { + k = asl_mini_memory_string_retain(s, msg->key[i], 1); + if (k == NULL) continue; + + v = NULL; + if (msg->val[i] != NULL) v = asl_mini_memory_string_retain(s, msg->val[i], 1); + + if (r->kvcount == 0) + { + r->kvlist = (mini_mem_string_t **)calloc(2, sizeof(mini_mem_string_t *)); + } + else + { + r->kvlist = (mini_mem_string_t **)realloc(r->kvlist, (r->kvcount + 2) * sizeof(mini_mem_string_t *)); + } + + if (r->kvlist == NULL) + { + asl_mini_memory_record_clear(s, r); + return ASL_STATUS_NO_MEMORY; + } + + r->kvlist[r->kvcount++] = k; + r->kvlist[r->kvcount++] = v; + } + } + + return ASL_STATUS_OK; +} + +uint32_t +asl_mini_memory_save(asl_mini_memory_t *s, aslmsg msg, uint64_t *mid) +{ + uint32_t status; + mini_mem_record_t *t; + + if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (s->buffer_record == NULL) return ASL_STATUS_INVALID_STORE; + + /* asl_mini_memory_message_encode creates and caches strings */ + status = asl_mini_memory_message_encode(s, msg, s->buffer_record); + if (status != ASL_STATUS_OK) return status; + + s->buffer_record->mid = s->next_id; + s->next_id++; + + /* clear the first record */ + t = s->record[s->record_first]; + asl_mini_memory_record_clear(s, t); + + /* add the new record to the record list (swap in the buffer record) */ + s->record[s->record_first] = s->buffer_record; + s->buffer_record = t; + + /* record list is a circular queue */ + s->record_first++; + if (s->record_first >= s->record_count) s->record_first = 0; + + *mid = s->buffer_record->mid; + + return status; +} + +/* + * Decodes a record structure. + */ +static uint32_t +asl_mini_memory_message_decode(asl_mini_memory_t *s, mini_mem_record_t *r, asl_msg_t **out) +{ + uint32_t i, n; + asl_msg_t *msg; + + if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (r == NULL) return ASL_STATUS_INVALID_ARG; + if (out == NULL) return ASL_STATUS_INVALID_ARG; + + *out = NULL; + + msg = (asl_msg_t *)calloc(1, sizeof(asl_msg_t)); + if (msg == NULL) return ASL_STATUS_NO_MEMORY; + + msg->type = ASL_TYPE_MSG; + /* Level and Message ID are always set */ + msg->count = 2; + + if (r->time != (uint64_t)-1) msg->count++; + if (r->sender != NULL) msg->count++; + if (r->facility != NULL) msg->count++; + if (r->pid != -1) msg->count++; + if (r->message != NULL) msg->count++; + + msg->count += (r->kvcount / 2); + + msg->key = (char **)calloc(msg->count, sizeof(char *)); + if (msg->key == NULL) + { + free(msg); + return ASL_STATUS_NO_MEMORY; + } + + msg->val = (char **)calloc(msg->count, sizeof(char *)); + if (msg->val == NULL) + { + free(msg->key); + free(msg); + return ASL_STATUS_NO_MEMORY; + } + + n = 0; + + /* Message ID */ + msg->key[n] = strdup(ASL_KEY_MSG_ID); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + asprintf(&(msg->val[n]), "%lu", r->mid); + if (msg->val[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + n++; + + /* Level */ + msg->key[n] = strdup(ASL_KEY_LEVEL); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + asprintf(&(msg->val[n]), "%u", r->level); + if (msg->val[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + n++; + + /* Time */ + if (r->time != (uint64_t)-1) + { + msg->key[n] = strdup(ASL_KEY_TIME); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + asprintf(&(msg->val[n]), "%llu", r->time); + if (msg->val[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + n++; + } + + /* Sender */ + if (r->sender != NULL) + { + msg->key[n] = strdup(ASL_KEY_SENDER); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + msg->val[n] = strdup(r->sender->str); + n++; + } + + /* Facility */ + if (r->facility != NULL) + { + msg->key[n] = strdup(ASL_KEY_FACILITY); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + msg->val[n] = strdup(r->facility->str); + n++; + } + + /* PID */ + if (r->pid != -1) + { + msg->key[n] = strdup(ASL_KEY_PID); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + asprintf(&(msg->val[n]), "%d", r->pid); + if (msg->val[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + n++; + } + + /* Message */ + if (r->message != NULL) + { + msg->key[n] = strdup(ASL_KEY_MSG); + if (msg->key[n] == NULL) + { + asl_free(msg); + return ASL_STATUS_NO_MEMORY; + } + + msg->val[n] = strdup(r->message->str); + n++; + } + + /* Key - Value List */ + for (i = 0; i < r->kvcount; i++) + { + if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) msg->key[n] = strdup(r->kvlist[i]->str); + i++; + if ((r->kvlist[i] != NULL) && (r->kvlist[i]->str != NULL)) msg->val[n] = strdup(r->kvlist[i]->str); + n++; + } + + *out = msg; + return ASL_STATUS_OK; +} + +uint32_t +asl_mini_memory_fetch(asl_mini_memory_t *s, uint64_t mid, aslmsg *msg) +{ + uint32_t i; + + if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (msg == NULL) return ASL_STATUS_INVALID_ARG; + + for (i = 0; i < s->record_count; i++) + { + if (s->record[i]->mid == 0) break; + if (s->record[i]->mid == mid) return asl_mini_memory_message_decode(s, s->record[i], msg); + } + + return ASL_STATUS_INVALID_ID; +} + +static mini_mem_record_t * +asl_mini_memory_query_to_record(asl_mini_memory_t *s, asl_msg_t *q, uint32_t *type) +{ + mini_mem_record_t *out; + uint32_t i, j; + mini_mem_string_t *key, *val; + + if (type == NULL) return NULL; + + if (s == NULL) + { + *type = ASL_QUERY_MATCH_ERROR; + return NULL; + } + + /* NULL query matches anything */ + *type = ASL_QUERY_MATCH_TRUE; + if (q == NULL) return NULL; + if (q->count == 0) return NULL; + + + /* we can only do fast match on equality tests */ + *type = ASL_QUERY_MATCH_SLOW; + if (q->op != NULL) + { + for (i = 0; i < q->count; i++) if (q->op[i] != ASL_QUERY_OP_EQUAL) return NULL; + } + + out = (mini_mem_record_t *)calloc(1, sizeof(mini_mem_record_t)); + if (out == NULL) + { + *type = ASL_QUERY_MATCH_ERROR; + return NULL; + } + + for (i = 0; i < q->count; i++) + { + if (q->key[i] == NULL) continue; + + else if (!strcmp(q->key[i], ASL_KEY_MSG_ID)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_MSG_ID) + { + asl_mini_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_MSG_ID; + out->mid = atoll(q->val[i]); + } + else if (!strcmp(q->key[i], ASL_KEY_TIME)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_TIME) + { + asl_mini_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_TIME; + out->time = asl_parse_time(q->val[i]); + } + else if (!strcmp(q->key[i], ASL_KEY_LEVEL)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_LEVEL) + { + asl_mini_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_LEVEL; + out->level = atoi(q->val[i]); + } + else if (!strcmp(q->key[i], ASL_KEY_PID)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_PID) + { + asl_mini_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_PID; + out->pid = atoi(q->val[i]); + } + else if (!strcmp(q->key[i], ASL_KEY_SENDER)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_SENDER) + { + asl_mini_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_SENDER; + out->sender = asl_mini_memory_string_retain(s, q->val[i], 0); + if (out->sender == NULL) + { + asl_mini_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_FALSE; + return NULL; + } + } + else if (!strcmp(q->key[i], ASL_KEY_FACILITY)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_FACILITY) + { + asl_mini_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_FACILITY; + out->facility = asl_mini_memory_string_retain(s, q->val[i], 0); + if (out->facility == NULL) + { + asl_mini_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_FALSE; + return NULL; + } + } + else if (!strcmp(q->key[i], ASL_KEY_MSG)) + { + if (q->val[i] == NULL) continue; + + if (*type & ASL_QUERY_MATCH_MESSAGE) + { + asl_mini_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + + *type |= ASL_QUERY_MATCH_MESSAGE; + out->message = asl_mini_memory_string_retain(s, q->val[i], 0); + if (out->message == NULL) + { + asl_mini_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_FALSE; + return NULL; + } + } + else + { + key = asl_mini_memory_string_retain(s, q->key[i], 0); + if (key == NULL) + { + asl_mini_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_FALSE; + return NULL; + } + + for (j = 0; j < out->kvcount; j += 2) + { + if (out->kvlist[j] == key) + { + asl_mini_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_SLOW; + return NULL; + } + } + + val = asl_mini_memory_string_retain(s, q->val[i], 0); + + if (out->kvcount == 0) + { + out->kvlist = (mini_mem_string_t **)calloc(2, sizeof(mini_mem_string_t *)); + } + else + { + out->kvlist = (mini_mem_string_t **)realloc(out->kvlist, (out->kvcount + 2) * sizeof(mini_mem_string_t *)); + } + + if (out->kvlist == NULL) + { + asl_mini_memory_record_free(s, out); + *type = ASL_QUERY_MATCH_ERROR; + return NULL; + } + + out->kvlist[out->kvcount++] = key; + out->kvlist[out->kvcount++] = val; + } + } + + return out; +} + +static uint32_t +asl_mini_memory_fast_match(asl_mini_memory_t *s, mini_mem_record_t *r, uint32_t qtype, mini_mem_record_t *q) +{ + uint32_t i, j; + + if (s == NULL) return 0; + if (r == NULL) return 0; + if (q == NULL) return 1; + + if ((qtype & ASL_QUERY_MATCH_MSG_ID) && (q->mid != r->mid)) return 0; + if ((qtype & ASL_QUERY_MATCH_TIME) && (q->time != r->time)) return 0; + if ((qtype & ASL_QUERY_MATCH_LEVEL) && (q->level != r->level)) return 0; + if ((qtype & ASL_QUERY_MATCH_PID) && (q->pid != r->pid)) return 0; + if ((qtype & ASL_QUERY_MATCH_SENDER) && (q->sender != r->sender)) return 0; + if ((qtype & ASL_QUERY_MATCH_FACILITY) && (q->facility != r->facility)) return 0; + if ((qtype & ASL_QUERY_MATCH_MESSAGE) && (q->message != r->message)) return 0; + + for (i = 0; i < q->kvcount; i += 2) + { + for (j = 0; j < r->kvcount; j += 2) + { + if (q->kvlist[i] == r->kvlist[j]) + { + if (q->kvlist[i + 1] == r->kvlist[j + 1]) break; + return 0; + } + } + + if (j >= r->kvcount) return 0; + } + + return 1; +} + +static uint32_t +asl_mini_memory_slow_match(asl_mini_memory_t *s, mini_mem_record_t *r, mini_mem_record_t *q, asl_msg_t *rawq) +{ + asl_msg_t *rawm; + uint32_t status; + + rawm = NULL; + status = asl_mini_memory_message_decode(s, r, &rawm); + if (status != ASL_STATUS_OK) return 0; + + status = 0; + if (asl_msg_cmp(rawq, rawm) != 0) status = 1; + asl_free(rawm); + return status; +} + +uint32_t +asl_mini_memory_match(asl_mini_memory_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction) +{ + uint32_t status, i, where, start, j, do_match, did_match, rescount, *qtype; + mini_mem_record_t **qp; + asl_msg_t *m; + + if (s == NULL) return ASL_STATUS_INVALID_STORE; + if (res == NULL) return ASL_STATUS_INVALID_ARG; + + do_match = 1; + qp = NULL; + qtype = NULL; + rescount = 0; + + if ((query == NULL) || ((query != NULL) && (query->count == 0))) + { + do_match = 0; + } + else + { + qp = (mini_mem_record_t **)calloc(query->count, sizeof(mini_mem_record_t *)); + if (qp == NULL) return ASL_STATUS_NO_MEMORY; + + qtype = (uint32_t *)calloc(query->count, sizeof(uint32_t)); + if (qtype == NULL) + { + free(qp); + return ASL_STATUS_NO_MEMORY; + } + + do_match = 0; + for (i = 0; i < query->count; i++) + { + qp[i] = asl_mini_memory_query_to_record(s, query->msg[i], &(qtype[i])); + if (qtype[i] == ASL_QUERY_MATCH_ERROR) + { + for (j = 0; j < i; j++) asl_mini_memory_record_free(s, qp[j]); + free(qp); + free(qtype); + return ASL_STATUS_FAILED; + } + + if (qtype[i] != ASL_QUERY_MATCH_TRUE) do_match = 1; + } + } + + for (i = 0; i < s->record_count; i++) + { + if (direction >= 0) + { + where = (s->record_first + i) % s->record_count; + if (s->record[where]->mid == 0) continue; + if (s->record[where]->mid >= start_id) break; + } + else + { + where = ((s->record_count - (i + 1)) + s->record_first) % s->record_count; + if (s->record[where]->mid == 0) continue; + if (s->record[where]->mid <= start_id) break; + } + } + + if (i >= s->record_count) return ASL_STATUS_OK; + + start = where; + + /* + * loop through records + */ + for (i = 0; i < s->record_count; i++) + { + if (s->record[where]->mid == 0) + { + if (direction >= 0) + { + where++; + if (where >= s->record_count) where = 0; + } + else + { + if (where == 0) where = s->record_count - 1; + else where--; + } + + if (where == s->record_first) break; + continue; + } + + s->record[where]->flags &= ASL_MINI_MSG_FLAG_SEARCH_CLEAR; + *last_id = s->record[where]->mid; + did_match = 1; + + if (do_match != 0) + { + did_match = 0; + + for (j = 0; (j < query->count) && (did_match == 0); j++) + { + if (qtype[j] == ASL_QUERY_MATCH_TRUE) + { + did_match = 1; + } + else if (qtype[j] == ASL_QUERY_MATCH_SLOW) + { + did_match = asl_mini_memory_slow_match(s, s->record[where], qp[j], query->msg[j]); + } + else + { + did_match = asl_mini_memory_fast_match(s, s->record[where], qtype[j], qp[j]); + } + } + } + + if (did_match == 1) + { + s->record[where]->flags |= ASL_MINI_MSG_FLAG_SEARCH_MATCH; + rescount++; + if ((count != 0) && (rescount >= count)) break; + } + + if (direction >= 0) + { + where++; + if (where >= s->record_count) where = 0; + } + else + { + if (where == 0) where = s->record_count - 1; + else where--; + } + + if (where == s->record_first) break; + } + + if (query != NULL) + { + for (i = 0; i < query->count; i++) asl_mini_memory_record_free(s, qp[i]); + free(qp); + free(qtype); + } + + *res = NULL; + if (rescount == 0) return ASL_STATUS_OK; + + *res = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t)); + if (*res == NULL) return ASL_STATUS_NO_MEMORY; + + (*res)->count = rescount; + + (*res)->msg = (asl_msg_t **)calloc(rescount, sizeof(asl_msg_t *)); + if ((*res)->msg == NULL) + { + free(*res); + *res = NULL; + return ASL_STATUS_NO_MEMORY; + } + + where = start; + forever + { + if (s->record[where]->flags & ASL_MINI_MSG_FLAG_SEARCH_MATCH) + { + s->record[where]->flags &= ASL_MINI_MSG_FLAG_SEARCH_CLEAR; + + status = asl_mini_memory_message_decode(s, s->record[where], &m); + if (status != ASL_STATUS_OK) + { + aslresponse_free(*res); + *res = NULL; + return status; + } + + (*res)->msg[(*res)->curr++] = m; + if ((*res)->curr == rescount) break; + } + + if (direction >= 0) + { + where++; + if (where >= s->record_count) where = 0; + } + else + { + if (where == 0) where = s->record_count - 1; + else where--; + } + + if (where == s->record_first) break; + } + + (*res)->curr = 0; + return ASL_STATUS_OK; +} diff --git a/aslcommon/asl_mini_memory.h b/aslcommon/asl_mini_memory.h new file mode 100644 index 0000000..b1e6b3b --- /dev/null +++ b/aslcommon/asl_mini_memory.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2007-2008 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifndef __asl_mini_memory_H__ +#define __asl_mini_memory_H__ +#include +#include + +#define ASL_MINI_MSG_FLAG_SEARCH_MATCH 0x80 +#define ASL_MINI_MSG_FLAG_SEARCH_CLEAR 0x7f + +typedef struct +{ + uint32_t hash; + uint32_t refcount; + char str[]; +} mini_mem_string_t; + +typedef struct +{ + uint32_t mid; + uint64_t time; + uint8_t level; + uint8_t flags; + uint32_t pid; + uint32_t uid; + uint32_t gid; + uint32_t kvcount; + mini_mem_string_t *sender; + mini_mem_string_t *facility; + mini_mem_string_t *message; + mini_mem_string_t **kvlist; +} mini_mem_record_t; + +typedef struct +{ + uint32_t next_id; + uint32_t string_count; + void **string_cache; + uint32_t record_count; + uint32_t record_first; + mini_mem_record_t **record; + mini_mem_record_t *buffer_record; +} asl_mini_memory_t; + +uint32_t asl_mini_memory_open(uint32_t max_records, asl_mini_memory_t **s); +uint32_t asl_mini_memory_close(asl_mini_memory_t *s); +uint32_t asl_mini_memory_statistics(asl_mini_memory_t *s, aslmsg *msg); + +uint32_t asl_mini_memory_save(asl_mini_memory_t *s, aslmsg msg, uint64_t *mid); +uint32_t asl_mini_memory_fetch(asl_mini_memory_t *s, uint64_t mid, aslmsg *msg); + +uint32_t asl_mini_memory_match(asl_mini_memory_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction); + +#endif __asl_mini_memory_H__ diff --git a/aslcommon/asl_store.c b/aslcommon/asl_store.c deleted file mode 100644 index 3e0ab84..0000000 --- a/aslcommon/asl_store.c +++ /dev/null @@ -1,3892 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define forever for(;;) - -#define FILE_MODE 0600 - -/* - * Magic Cookie for database files. - * MAXIMUM 12 CHARS! (DB_HEADER_VERS_OFFSET) - */ -#define ASL_DB_COOKIE "ASL DB" -#define ASL_DB_COOKIE_LEN 6 - -#define ASL_INDEX_NULL 0xffffffff - -#define DB_HLEN_EMPTY 0 -#define DB_HLEN_HEADER 13 -#define DB_HLEN_MESSAGE 13 -#define DB_HLEN_KVLIST 9 -#define DB_HLEN_STRING 25 -#define DB_HLEN_STRCONT 5 - -#define MSG_OFF_KEY_TYPE 0 -#define MSG_OFF_KEY_NEXT 1 -#define MSG_OFF_KEY_ID 5 -#define MSG_OFF_KEY_RUID 13 -#define MSG_OFF_KEY_RGID 17 -#define MSG_OFF_KEY_TIME 21 -#define MSG_OFF_KEY_HOST 29 -#define MSG_OFF_KEY_SENDER 37 -#define MSG_OFF_KEY_FACILITY 45 -#define MSG_OFF_KEY_LEVEL 53 -#define MSG_OFF_KEY_PID 57 -#define MSG_OFF_KEY_UID 61 -#define MSG_OFF_KEY_GID 65 -#define MSG_OFF_KEY_MSG 69 -#define MSG_OFF_KEY_FLAGS 77 - -#define mix(a, b, c) \ -{ \ - a -= b; a -= c; a ^= (c>>13); \ - b -= c; b -= a; b ^= (a<< 8); \ - c -= a; c -= b; c ^= (b>>13); \ - a -= b; a -= c; a ^= (c>>12); \ - b -= c; b -= a; b ^= (a<<16); \ - c -= a; c -= b; c ^= (b>> 5); \ - a -= b; a -= c; a ^= (c>> 3); \ - b -= c; b -= a; b ^= (a<<10); \ - c -= a; c -= b; c ^= (b>>15); \ -} - -extern time_t asl_parse_time(const char *str); -extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b); - -#define asl_msg_list_t asl_search_result_t - -#define PMSG_SEL_TIME 0x0001 -#define PMSG_SEL_HOST 0x0002 -#define PMSG_SEL_SENDER 0x0004 -#define PMSG_SEL_FACILITY 0x0008 -#define PMSG_SEL_MESSAGE 0x0010 -#define PMSG_SEL_LEVEL 0x0020 -#define PMSG_SEL_PID 0x0040 -#define PMSG_SEL_UID 0x0080 -#define PMSG_SEL_GID 0x0100 -#define PMSG_SEL_RUID 0x0200 -#define PMSG_SEL_RGID 0x0400 - -#define PMSG_FETCH_ALL 0 -#define PMSG_FETCH_STD 1 -#define PMSG_FETCH_KV 2 - -#define Q_NULL 100001 -#define Q_FAST 100002 -#define Q_SLOW 100003 -#define Q_FAIL 100004 - -#define ARCHIVE_DELETE_VS_COPY_PERCENT 5 - -typedef struct -{ - uint16_t kselect; - uint16_t vselect; - uint64_t msgid; - uint64_t time; - uint64_t host; - uint64_t sender; - uint64_t facility; - uint64_t message; - uint32_t level; - uint32_t pid; - int32_t uid; - int32_t gid; - int32_t ruid; - int32_t rgid; - uint32_t next; - uint32_t kvcount; - uint64_t *kvlist; -} pmsg_t; - -static uint64_t -_asl_htonq(uint64_t n) -{ -#ifdef __BIG_ENDIAN__ - return n; -#else - u_int32_t t; - union - { - u_int64_t q; - u_int32_t l[2]; - } x; - - x.q = n; - t = x.l[0]; - x.l[0] = htonl(x.l[1]); - x.l[1] = htonl(t); - - return x.q; -#endif -} - -static uint64_t -_asl_ntohq(uint64_t n) -{ -#ifdef __BIG_ENDIAN__ - return n; -#else - u_int32_t t; - union - { - u_int64_t q; - u_int32_t l[2]; - } x; - - x.q = n; - t = x.l[0]; - x.l[0] = ntohl(x.l[1]); - x.l[1] = ntohl(t); - - return x.q; -#endif -} - -static uint16_t -_asl_get_16(char *h) -{ - uint16_t x; - - memcpy(&x, h, 2); - return ntohs(x); -} - -static void -_asl_put_16(uint16_t i, char *h) -{ - uint16_t x; - - x = htons(i); - memcpy(h, &x, 2); -} - -static uint32_t -_asl_get_32(char *h) -{ - uint32_t x; - - memcpy(&x, h, 4); - return ntohl(x); -} - -static void -_asl_put_32(uint32_t i, char *h) -{ - uint32_t x; - - x = htonl(i); - memcpy(h, &x, 4); -} - -static uint64_t -_asl_get_64(char *h) -{ - uint64_t x; - - memcpy(&x, h, 8); - return _asl_ntohq(x); -} - -static void -_asl_put_64(uint64_t i, char *h) -{ - uint64_t x; - - x = _asl_htonq(i); - memcpy(h, &x, 8); -} - -#define header_get_next(h) _asl_get_32(h + 1) -#define header_get_id(h) _asl_get_64(h + 5) -#define header_get_refcount(h) _asl_get_32(h + 13) -#define header_get_hash(h) _asl_get_32(h + 17) - -#define header_put_next(i, h) _asl_put_32(i, h + 1) -#define header_put_id(i, h) _asl_put_64(i, h + 5) -#define header_put_refcount(i, h) _asl_put_32(i, h + 13) -#define header_put_hash(i, h) _asl_put_32(i, h + 17) - -/* - * callback for sorting slotlist - * primary sort is by xid - * secondary sort is by slot, which happens when xid is 0 - * this allows us to quickly find xids (using binary search on the xid key) - * it's also used to find slots quickly from record_chain_free() - */ -static int -slot_comp(const void *a, const void *b) -{ - slot_info_t *ai, *bi; - - if (a == NULL) - { - if (b == NULL) return 0; - return -1; - } - - if (b == NULL) return 1; - - ai = (slot_info_t *)a; - bi = (slot_info_t *)b; - - if (ai->xid < bi->xid) return -1; - - if (ai->xid == bi->xid) - { - if (ai->slot < bi->slot) return -1; - if (ai->slot == bi->slot) return 0; - return 1; - } - - return 1; -} - -/* find a slot (with xid 0) in the slot list */ -static uint32_t -slotlist_find_xid0_slot(asl_store_t *s, uint32_t slot) -{ - uint32_t top, bot, mid, range; - - if (s == NULL) return ASL_INDEX_NULL; - if (s->slot_zero_count == 0) return ASL_INDEX_NULL; - - top = s->slot_zero_count - 1; - bot = 0; - mid = top / 2; - - range = top - bot; - while (range > 1) - { - if (slot == s->slotlist[mid].slot) return mid; - else if (slot < s->slotlist[mid].slot) top = mid; - else bot = mid; - - range = top - bot; - mid = bot + (range / 2); - } - - if (slot == s->slotlist[top].slot) return top; - if (slot == s->slotlist[bot].slot) return bot; - - return ASL_INDEX_NULL; -} - -/* find an xid in the slot list */ -static uint32_t -slotlist_find(asl_store_t *s, uint64_t xid, uint32_t slot, int32_t direction) -{ - uint32_t top, bot, mid, range; - - if (s == NULL) return ASL_INDEX_NULL; - if (s->slotlist_count == 0) return ASL_INDEX_NULL; - - /* special case for xid 0: binary search for slot */ - if (xid == 0) return slotlist_find_xid0_slot(s, slot); - - top = s->slotlist_count - 1; - bot = 0; - mid = top / 2; - - range = top - bot; - while (range > 1) - { - if (xid == s->slotlist[mid].xid) return mid; - else if (xid < s->slotlist[mid].xid) top = mid; - else bot = mid; - - range = top - bot; - mid = bot + (range / 2); - } - - if (xid == s->slotlist[top].xid) return top; - if (xid == s->slotlist[bot].xid) return bot; - - if (direction == 0) return ASL_INDEX_NULL; - if (direction < 0) return bot; - return top; -} - -static uint32_t -slotlist_insert(asl_store_t *s, uint8_t type, uint32_t slot, uint64_t xid, uint32_t hash) -{ - int i, j, k; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (s->slotlist_count == 0) - { - s->slotlist = (slot_info_t *)calloc(1, sizeof(slot_info_t)); - if (s->slotlist == NULL) return ASL_STATUS_NO_MEMORY; - - s->slotlist[0].type = type; - s->slotlist[0].slot = slot; - s->slotlist[0].xid = xid; - s->slotlist[0].hash = hash; - s->slotlist_count = 1; - if (xid == 0) s->slot_zero_count = 1; - return ASL_STATUS_OK; - } - - s->slotlist = (slot_info_t *)reallocf(s->slotlist, (s->slotlist_count + 1) * sizeof(slot_info_t)); - if (s->slotlist == NULL) - { - s->slotlist_count = 0; - s->slot_zero_count = 0; - return ASL_STATUS_NO_MEMORY; - } - - /* - * slotlist is sorted in increasing order by xid - * there may be multiple xid 0 entries (empty slots) which are further sorted by slot - */ - if (xid == 0) - { - /* update empty count */ - s->slot_zero_count++; - - for (i = 0; (i < s->slotlist_count) && (s->slotlist[i].xid == 0); i++) - { - if (slot <= s->slotlist[i].slot) break; - } - } - else - { - i = s->slotlist_count - 1; - if (xid > s->slotlist[i].xid) - { - /* append XID at end of slotlist */ - i++; - } - else - { - /* usually we are adding records, so it's likely that the new xid will be large */ - for (i = s->slotlist_count; i > 0; i--) - { - if (xid > s->slotlist[i - 1].xid) break; - } - } - } - - for (j = s->slotlist_count; j > i; j--) - { - k = j - 1; - s->slotlist[j].type = s->slotlist[k].type; - s->slotlist[j].slot = s->slotlist[k].slot; - s->slotlist[j].xid = s->slotlist[k].xid; - s->slotlist[j].hash = s->slotlist[k].hash; - } - - s->slotlist[i].type = type; - s->slotlist[i].slot = slot; - s->slotlist[i].xid = xid; - s->slotlist[i].hash = hash; - s->slotlist_count++; - - return ASL_STATUS_OK; -} - -static uint32_t -slotlist_delete(asl_store_t *s, uint32_t where) -{ - uint32_t i, j, n; - - if (s->slotlist_count == 0) return ASL_STATUS_OK; - - n = s->slotlist_count - 1; - if (n == 0) - { - free(s->slotlist); - s->slotlist = NULL; - s->slotlist_count = 0; - s->slot_zero_count = 0; - return ASL_STATUS_OK; - } - - if (s->slotlist[where].xid == 0) s->slot_zero_count--; - - for (i = where, j = i + 1; i < n; i++, j++) - { - s->slotlist[i].type = s->slotlist[j].type; - s->slotlist[i].slot = s->slotlist[j].slot; - s->slotlist[i].xid = s->slotlist[j].xid; - s->slotlist[i].hash = s->slotlist[j].hash; - } - - s->slotlist_count = n; - s->slotlist = (slot_info_t *)reallocf(s->slotlist, s->slotlist_count * sizeof(slot_info_t)); - - if (s->slotlist == NULL) - { - s->slotlist_count = 0; - s->slot_zero_count = 0; - return ASL_STATUS_NO_MEMORY; - } - - return ASL_STATUS_OK; -} - -static uint32_t -slotlist_make_empty(asl_store_t *s, uint32_t where) -{ - uint32_t i, j, slot; - - if (s->slotlist_count == 0) return ASL_STATUS_OK; - if (where > s->slotlist_count) return ASL_STATUS_OK; - - /* - * Special case for asl_store_archive. - * Since we expect to be doing lots of deletions during an archive call, - * this routine only marks the type as empty. - * asl_store_archive cleans up the slotlist when it is finished. - */ - if (s->flags & ASL_STORE_FLAG_DEFER_SORT) - { - s->slotlist[where].type = DB_TYPE_EMPTY; - s->slotlist[where].hash = 0; - - s->empty_count++; - - return ASL_STATUS_OK; - } - - slot = s->slotlist[where].slot; - - /* primary sort by xid */ - for (i = where, j = where - 1; (i > 0) && (s->slotlist[j].xid != 0); i--, j--) - { - s->slotlist[i].type = s->slotlist[j].type; - s->slotlist[i].slot = s->slotlist[j].slot; - s->slotlist[i].xid = s->slotlist[j].xid; - s->slotlist[i].hash = s->slotlist[j].hash; - } - - /* xid 0 entries sorted by slot */ - for (j = i - 1; (i > 0) && (s->slotlist[j].slot > slot); i--, j--) - { - s->slotlist[i].type = s->slotlist[j].type; - s->slotlist[i].slot = s->slotlist[j].slot; - s->slotlist[i].xid = s->slotlist[j].xid; - s->slotlist[i].hash = s->slotlist[j].hash; - } - - s->slotlist[i].type = DB_TYPE_EMPTY; - s->slotlist[i].slot = slot; - s->slotlist[i].xid = 0; - s->slotlist[i].hash = 0; - - s->empty_count++; - - /* new xid=0 count */ - for (s->slot_zero_count = 0; (s->slot_zero_count < s->slotlist_count) && (s->slotlist[s->slot_zero_count].xid == 0); s->slot_zero_count++); - - return ASL_STATUS_OK; -} - -static uint32_t -slotlist_init(asl_store_t *s) -{ - uint32_t i, si, status, hash, addslot; - uint64_t xid, tick; - uint8_t t; - char tmp[DB_RECORD_LEN]; - - s->empty_count = 0; - - /* Start at first slot after the header */ - status = fseek(s->db, DB_RECORD_LEN, SEEK_SET); - if (status != 0) return ASL_STATUS_READ_FAILED; - - s->slotlist = (slot_info_t *)calloc(s->record_count, sizeof(slot_info_t)); - if (s->slotlist == NULL) return ASL_STATUS_NO_MEMORY; - - si = 0; - - for (i = 1; i < s->record_count; i++) - { - status = fread(tmp, DB_RECORD_LEN, 1, s->db); - if (status != 1) return ASL_STATUS_READ_FAILED; - - t = tmp[0]; - addslot = 0; - xid = 0; - hash = 0; - - if (t == DB_TYPE_EMPTY) - { - addslot = 1; - s->empty_count++; - } - - if (t == DB_TYPE_STRING) - { - addslot = 1; - s->string_count++; - xid = header_get_id(tmp); - hash = header_get_hash(tmp); - } - - if (t == DB_TYPE_MESSAGE) - { - addslot = 1; - s->message_count++; - xid = header_get_id(tmp); - tick = _asl_get_64(tmp + MSG_OFF_KEY_TIME); - if (tick > s->max_time) s->max_time = tick; - } - - if (addslot == 1) - { - s->slotlist[si].type = t; - s->slotlist[si].slot = i; - s->slotlist[si].xid = xid; - s->slotlist[si].hash = hash; - si++; - } - } - - s->slotlist = (slot_info_t *)reallocf(s->slotlist, si * sizeof(slot_info_t)); - if (s->slotlist == NULL) return ASL_STATUS_NO_MEMORY; - s->slotlist_count = si; - - /* slotlist is sorted by xid */ - qsort((void *)s->slotlist, s->slotlist_count, sizeof(slot_info_t), slot_comp); - - /* new xid=0 count */ - for (s->slot_zero_count = 0; (s->slot_zero_count < s->slotlist_count) && (s->slotlist[s->slot_zero_count].xid == 0); s->slot_zero_count++); - - return ASL_STATUS_OK; -} - -uint32_t -asl_store_open(const char *path, uint32_t flags, asl_store_t **out) -{ - asl_store_t *s; - struct stat sb; - int status, i, j, fd; - char cbuf[DB_RECORD_LEN]; - off_t fsize; - uint64_t next; - - memset(&sb, 0, sizeof(struct stat)); - status = stat(path, &sb); - - fsize = 0; - - if (status < 0) - { - if (errno != ENOENT) return ASL_STATUS_FAILED; - - fd = open(path, O_RDWR | O_CREAT | O_EXCL, FILE_MODE); - if (fd < 0) return ASL_STATUS_FAILED; - - memset(cbuf, 0, DB_RECORD_LEN); - memcpy(cbuf, ASL_DB_COOKIE, ASL_DB_COOKIE_LEN); - - _asl_put_32(DB_VERSION, cbuf + DB_HEADER_VERS_OFFSET); - - /* record IDs start at 1 */ - _asl_put_64(1, cbuf + DB_HEADER_MAXID_OFFSET); - - status = write(fd, cbuf, DB_RECORD_LEN); - close(fd); - if (status != DB_RECORD_LEN) return ASL_STATUS_FAILED; - - fsize = DB_RECORD_LEN; - } - else - { - fsize = sb.st_size; - } - - s = (asl_store_t *)calloc(1, sizeof(asl_store_t)); - if (s == NULL) return ASL_STATUS_NO_MEMORY; - - s->flags = flags; - - for (i = 0; i < RECORD_CACHE_SIZE; i++) - { - s->rcache[i] = malloc(DB_RECORD_LEN); - if (s->rcache[i] == NULL) - { - for (j = 0; j < i; j++) free(s->rcache[j]); - free(s); - return ASL_STATUS_NO_MEMORY; - } - } - - s->db = NULL; - if (flags & ASL_STORE_FLAG_READ_ONLY) s->db = fopen(path, "r"); - else s->db = fopen(path, "r+"); - if (s->db == NULL) - { - free(s); - return ASL_STATUS_INVALID_STORE; - } - - memset(cbuf, 0, DB_RECORD_LEN); - status = fread(cbuf, DB_RECORD_LEN, 1, s->db); - if (status != 1) - { - fclose(s->db); - free(s); - return ASL_STATUS_READ_FAILED; - } - - /* Check the database Magic Cookie */ - if (strncmp(cbuf, ASL_DB_COOKIE, ASL_DB_COOKIE_LEN)) - { - fclose(s->db); - free(s); - return ASL_STATUS_INVALID_STORE; - } - - next = 0; - memcpy(&next, cbuf + DB_HEADER_MAXID_OFFSET, 8); - s->next_id = _asl_ntohq(next); - - s->record_count = fsize / DB_RECORD_LEN; - - status = slotlist_init(s); - - for (i = 0; i < STRING_CACHE_SIZE; i++) - { - s->string_cache[i].index = ASL_INDEX_NULL; - s->string_cache[i].refcount = 0; - s->string_cache[i].str = NULL; - } - - s->db_path = strdup(path); - - *out = s; - return ASL_STATUS_OK; -} - -uint32_t -asl_store_close(asl_store_t *s) -{ - uint32_t i; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - - if (s->slotlist != NULL) free(s->slotlist); - for (i = 0; i < RECORD_CACHE_SIZE; i++) free(s->rcache[i]); - for (i = 0; i < STRING_CACHE_SIZE; i++) - { - if (s->string_cache[i].str != NULL) free(s->string_cache[i].str); - } - - if (s->db_path != NULL) free(s->db_path); - if (s->db != NULL) fclose(s->db); - free(s); - - return ASL_STATUS_OK; -} - -static char * -record_buffer_alloc(asl_store_t *s) -{ - uint32_t i; - - if (s == NULL) return calloc(1, DB_RECORD_LEN); - - for (i = 0; i < RECORD_CACHE_SIZE; i++) - { - if (s->rcache_state[i] == 0) - { - s->rcache_state[i] = 1; - memset(s->rcache[i], 0, DB_RECORD_LEN); - return s->rcache[i]; - } - } - - return calloc(1, DB_RECORD_LEN); -} - -static void -record_buffer_free(asl_store_t *s, char *p) -{ - uint32_t i; - - if (s == NULL) return free(p); - - for (i = 0; i < RECORD_CACHE_SIZE; i++) - { - if (s->rcache[i] == p) - { - s->rcache_state[i] = 0; - return; - } - } - - free(p); -} - -/* - * Finds a free (DB_TYPE_EMPTY) record slot. - * Returns the index of the free entry in the slotlist. - * Returns ASL_INDEX_NULL if no free slots are available (next write should be at end of file). - */ -static uint32_t -get_free_slot(asl_store_t *s) -{ - uint32_t i; - - if (s == NULL) return ASL_INDEX_NULL; - - if (s->empty_count == 0) return ASL_INDEX_NULL; - - for (i = 0; i < s->slotlist_count; i++) - { - if (s->slotlist[i].type == DB_TYPE_EMPTY) - { - s->empty_count--; - return i; - } - } - - /* impossible */ - s->empty_count = 0; - return ASL_INDEX_NULL; -} - -static void -record_list_free(asl_store_t *s, char **list) -{ - uint32_t i; - - if (list == NULL) return; - - for (i = 0; list[i] != NULL; i++) record_buffer_free(s, list[i]); - free(list); -} - -static uint64_t -new_id(asl_store_t *s) -{ - int status; - uint64_t n, out; - - if (s == NULL) return ASL_REF_NULL; - - status = fseek(s->db, DB_HEADER_MAXID_OFFSET, SEEK_SET); - if (status < 0) return ASL_REF_NULL; - - out = s->next_id; - s->next_id++; - - n = _asl_htonq(s->next_id); - status = fwrite(&n, 8, 1, s->db); - if (status != 1) return ASL_REF_NULL; - return out; -} - -/* - * Write each record in the list to a slot in the database. - * Fills in "next" index. - */ -static uint32_t -save_record_list(asl_store_t *s, char **list, uint32_t *start) -{ - uint32_t i, n, status, si, slot, next, rcount, hash; - uint8_t type; - off_t offset; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - - if (list == NULL) return ASL_STATUS_OK; - - for (n = 0; list[n] != NULL; n++); - - if (n == 0) return ASL_STATUS_OK; - - rcount = s->record_count; - si = get_free_slot(s); - - /* update slotlist */ - type = list[0][0]; - - if (type == DB_TYPE_STRING) s->string_count++; - if (type == DB_TYPE_MESSAGE) s->message_count++; - - next = ASL_INDEX_NULL; - if (si == ASL_INDEX_NULL) - { - next = s->record_count; - } - else if (si > s->slotlist_count) - { - return ASL_STATUS_FAILED; - } - else - { - next = s->slotlist[si].slot; - slotlist_delete(s, si); - } - - hash = 0; - if (type == DB_TYPE_STRING) hash = header_get_hash(list[0]); - - status = slotlist_insert(s, type, next, header_get_id(list[0]), hash); - if (status != ASL_STATUS_OK) return status; - - *start = next; - - for (i = 0; i < n; i++) - { - slot = next; - - next = 0; - if ((i + 1) < n) - { - si = get_free_slot(s); - if (si == ASL_INDEX_NULL) - { - next = s->record_count + 1; - } - else if (next > s->slotlist_count) - { - return ASL_STATUS_FAILED; - } - else - { - type = list[i + 1][0]; - next = s->slotlist[si].slot; - slotlist_delete(s, si); - } - } - - offset = slot * DB_RECORD_LEN; - status = fseek(s->db, offset, SEEK_SET); - if (status < 0) return ASL_STATUS_WRITE_FAILED; - - header_put_next(next, list[i]); - - status = fwrite(list[i], DB_RECORD_LEN, 1, s->db); - if (status != 1) return ASL_STATUS_WRITE_FAILED; - - if (si == ASL_INDEX_NULL) s->record_count++; - } - - fflush(s->db); - - return ASL_STATUS_OK; -} - -/* - * Converts a string into a NULL-terminated list of records. - * Sets sid to new string ID. - */ -static uint32_t -string_encode(asl_store_t *s, uint32_t hash, const char *str, uint64_t *sid, char ***list) -{ - char **outlist, *p; - const char *t; - uint32_t length, remaining, i, n, x; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (str == NULL) return ASL_STATUS_INVALID_STRING; - - *sid = new_id(s); - if (*sid == ASL_REF_NULL) return ASL_STATUS_FAILED; - - length = strlen(str) + 1; - remaining = length; - - x = DB_RECORD_LEN - DB_HLEN_STRING; - if (remaining < x) x = remaining; - remaining -= x; - n = 1; - - x = DB_RECORD_LEN - DB_HLEN_STRCONT; - n += (remaining + x - 1) / x; - - outlist = (char **)calloc(n + 1, sizeof(char *)); - if (outlist == NULL) return ASL_STATUS_NO_MEMORY; - - for (i = 0; i < n; i++) - { - outlist[i] = record_buffer_alloc(s); - if (outlist[i] == NULL) - { - n = i; - for (i = 0; i < n; i++) record_buffer_free(s, outlist[i]); - free(outlist); - return ASL_STATUS_NO_MEMORY; - } - } - - *list = outlist; - - outlist[0][0] = (char)DB_TYPE_STRING; - p = outlist[0] + 5; - - /* sid */ - _asl_put_64(*sid, p); - p += 8; - - /* refcount */ - _asl_put_32(1, p); - p += 4; - - /* hash */ - _asl_put_32(hash, p); - p += 4; - - /* string length (includes trailing nul) */ - _asl_put_32(length, p); - p += 4; - - t = str; - remaining = length; - - x = DB_RECORD_LEN - DB_HLEN_STRING; - if (remaining < x) x = remaining; - memcpy(p, t, x); - - t += x; - remaining -= x; - - x = DB_RECORD_LEN - DB_HLEN_STRCONT; - for (i = 1; i < n; i++) - { - outlist[i][0] = (char)DB_TYPE_STRCONT; - p = outlist[i] + 5; - - if (remaining < x) x = remaining; - memcpy(p, t, x); - - t += x; - remaining -= x; - } - - return ASL_STATUS_OK; -} - -/* - * Hash is used to improve string search. - */ -uint32_t -string_hash(const char *s, uint32_t inlen) -{ - uint32_t a, b, c, l, len; - - if (s == NULL) return 0; - - l = inlen; - - len = l; - a = b = 0x9e3779b9; - c = 0; - - while (len >= 12) - { - a += (s[0] + ((uint32_t)s[1]<<8) + ((uint32_t)s[ 2]<<16) + ((uint32_t)s[ 3]<<24)); - b += (s[4] + ((uint32_t)s[5]<<8) + ((uint32_t)s[ 6]<<16) + ((uint32_t)s[ 7]<<24)); - c += (s[8] + ((uint32_t)s[9]<<8) + ((uint32_t)s[10]<<16) + ((uint32_t)s[11]<<24)); - - mix(a, b, c); - - s += 12; - len -= 12; - } - - c += l; - switch(len) - { - case 11: c += ((uint32_t)s[10]<<24); - case 10: c += ((uint32_t)s[9]<<16); - case 9 : c += ((uint32_t)s[8]<<8); - - case 8 : b += ((uint32_t)s[7]<<24); - case 7 : b += ((uint32_t)s[6]<<16); - case 6 : b += ((uint32_t)s[5]<<8); - case 5 : b += s[4]; - - case 4 : a += ((uint32_t)s[3]<<24); - case 3 : a += ((uint32_t)s[2]<<16); - case 2 : a += ((uint32_t)s[1]<<8); - case 1 : a += s[0]; - } - - mix(a, b, c); - - return c; -} - -/* - * Write refcount to database and update string cache. - */ -static void -string_set_refcount(asl_store_t *s, uint32_t index, const char *str, uint32_t refcount) -{ - uint32_t slot, i, min, status, v32; - off_t offset; - - if (s == NULL) return; - - /* update the database */ - slot = s->slotlist[index].slot; - - offset = (slot * DB_RECORD_LEN) + 13; - status = fseek(s->db, offset, SEEK_SET); - - if (status < 0) return; - - v32 = htonl(refcount); - status = fwrite(&v32, 4, 1, s->db); - - min = 0; - - /* if the string is in the string cache, update the refcount there */ - for (i = 0; i < STRING_CACHE_SIZE; i++) - { - if (s->string_cache[i].index == index) - { - s->string_cache[i].refcount = refcount; - return; - } - - /* locate the minimum refcount while we're looping */ - if (s->string_cache[i].refcount < s->string_cache[min].refcount) min = i; - } - - /* bail out if the refcount is too low */ - if (s->string_cache[min].refcount > refcount) return; - - /* replace the current minimum */ - if (s->string_cache[min].str != NULL) free(s->string_cache[min].str); - - s->string_cache[min].index = index; - s->string_cache[min].refcount = refcount; - s->string_cache[min].str = strdup(str); - - if (s->string_cache[min].str == NULL) - { - s->string_cache[min].index = ASL_INDEX_NULL; - s->string_cache[min].refcount = 0; - return; - } -} - -static uint32_t -string_fetch_slot(asl_store_t *s, uint32_t slot, char **out, uint32_t *refcount) -{ - off_t offset; - uint8_t type; - uint32_t status, next, len, x, remaining; - char *outstr, *p, tmp[DB_RECORD_LEN]; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (out == NULL) return ASL_STATUS_INVALID_ARG; - - *out = NULL; - offset = slot * DB_RECORD_LEN; - status = fseek(s->db, offset, SEEK_SET); - - if (status < 0) return ASL_STATUS_READ_FAILED; - - status = fread(tmp, DB_RECORD_LEN, 1, s->db); - if (status != 1) return ASL_STATUS_READ_FAILED; - - type = tmp[0]; - if (type != DB_TYPE_STRING) return ASL_STATUS_INVALID_STRING; - - len = _asl_get_32(tmp + 21); - if (len == 0) return ASL_STATUS_OK; - - *refcount = _asl_get_32(tmp + 13); - - next = header_get_next(tmp); - - outstr = calloc(1, len); - if (outstr == NULL) return ASL_STATUS_NO_MEMORY; - - p = outstr; - remaining = len; - - x = DB_RECORD_LEN - DB_HLEN_STRING; - if (x > remaining) x = remaining; - - memcpy(p, tmp + DB_HLEN_STRING, x); - p += x; - remaining -= x; - - while ((next != 0) && (remaining > 0)) - { - offset = next * DB_RECORD_LEN; - status = fseek(s->db, offset, SEEK_SET); - - if (status < 0) - { - free(outstr); - return ASL_STATUS_READ_FAILED; - } - - status = fread(tmp, DB_RECORD_LEN, 1, s->db); - if (status != 1) - { - free(outstr); - return ASL_STATUS_READ_FAILED; - } - - next = header_get_next(tmp); - - x = DB_RECORD_LEN - DB_HLEN_STRCONT; - if (x > remaining) x = remaining; - - memcpy(p, tmp + DB_HLEN_STRCONT, x); - p += x; - remaining -= x; - } - - if ((next != 0) || (remaining != 0)) - { - free(outstr); - return ASL_STATUS_READ_FAILED; - } - - *out = outstr; - return ASL_STATUS_OK; -} - -static uint32_t -string_fetch_sid(asl_store_t *s, uint64_t sid, char **out) -{ - uint32_t i, len, ref; - uint64_t nsid; - uint8_t inls; - char *p; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (out == NULL) return ASL_STATUS_INVALID_ARG; - - *out = NULL; - if (sid == ASL_REF_NULL) return ASL_STATUS_OK; - - ref = 0; - - inls = 0; - nsid = _asl_htonq(sid); - memcpy(&inls, &nsid, 1); - if (inls & 0x80) - { - /* inline string */ - inls &= 0x0f; - len = inls; - *out = calloc(1, len); - if (*out == NULL) return ASL_STATUS_NO_MEMORY; - p = 1 + (char *)&nsid; - memcpy(*out, p, len); - return ASL_STATUS_OK; - } - - /* Find the string in the database */ - i = slotlist_find(s, sid, 0, 0); - if (i == ASL_INDEX_NULL) return ASL_STATUS_NOT_FOUND; - - return string_fetch_slot(s, s->slotlist[i].slot, out, &ref); -} - -static uint32_t -check_user_access(int32_t msgu, int32_t u) -{ - /* -1 means anyone may read */ - if (msgu == -1) return ASL_STATUS_OK; - - /* Check for exact match */ - if (msgu == u) return ASL_STATUS_OK; - - return ASL_STATUS_ACCESS_DENIED; -} - -static uint32_t -check_group_access(int32_t msgg, int32_t u, int32_t g) -{ - int check; - uuid_t uu, gu; - - /* -1 means anyone may read */ - if (msgg == -1) return ASL_STATUS_OK; - - /* Check for exact match */ - if (msgg == g) return ASL_STATUS_OK; - - /* Check if user (u) is in read group (msgg) */ - mbr_uid_to_uuid(u, uu); - mbr_gid_to_uuid(msgg, gu); - - check = 0; - mbr_check_membership(uu, gu, &check); - if (check != 0) return ASL_STATUS_OK; - - return ASL_STATUS_ACCESS_DENIED; -} - -static uint32_t -check_access(int32_t msgu, int32_t msgg, int32_t u, int32_t g, uint16_t flags) -{ - uint16_t uset, gset; - - /* root (uid 0) may always read */ - if (u == 0) return ASL_STATUS_OK; - - uset = flags & ASL_MSG_FLAG_READ_UID_SET; - gset = flags & ASL_MSG_FLAG_READ_GID_SET; - - /* if no access controls are set, anyone may read */ - if ((uset | gset) == 0) return ASL_STATUS_OK; - - /* if only uid is set, then access is only by uid match */ - if ((uset != 0) && (gset == 0)) return check_user_access(msgu, u); - - /* if only gid is set, then access is only by gid match */ - if ((uset == 0) && (gset != 0)) return check_group_access(msgg, u, g); - - /* both uid and gid are set - check user, then group */ - if ((check_user_access(msgu, u)) == ASL_STATUS_OK) return ASL_STATUS_OK; - return check_group_access(msgg, u, g); -} - -static uint32_t -pmsg_fetch(asl_store_t *s, uint32_t slot, int32_t ruid, int32_t rgid, uint32_t action, pmsg_t **pmsg) -{ - off_t offset; - uint32_t status, i, n, v32, next; - int32_t msgu, msgg; - uint64_t msgid; - uint16_t flags; - pmsg_t *out; - char *p, tmp[DB_RECORD_LEN]; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (pmsg == NULL) return ASL_STATUS_INVALID_ARG; - - out = NULL; - - if ((action == PMSG_FETCH_ALL) || (action == PMSG_FETCH_STD)) - { - *pmsg = NULL; - - offset = slot * DB_RECORD_LEN; - status = fseek(s->db, offset, SEEK_SET); - - if (status < 0) return ASL_STATUS_READ_FAILED; - - status = fread(tmp, DB_RECORD_LEN, 1, s->db); - if (status != 1) return ASL_STATUS_READ_FAILED; - - msgid = _asl_get_64(tmp + MSG_OFF_KEY_ID); - msgu = _asl_get_32(tmp + MSG_OFF_KEY_RUID); - msgg = _asl_get_32(tmp + MSG_OFF_KEY_RGID); - flags = _asl_get_16(tmp + MSG_OFF_KEY_FLAGS); - - status = check_access(msgu, msgg, ruid, rgid, flags); - if (status != ASL_STATUS_OK) return status; - - out = (pmsg_t *)calloc(1, sizeof(pmsg_t)); - if (out == NULL) return ASL_STATUS_NO_MEMORY; - - - p = tmp + 21; - - /* ID */ - out->msgid = msgid; - - /* ReadUID */ - out->ruid = msgu; - - /* ReadGID */ - out->rgid = msgg; - - /* Time */ - out->time = _asl_get_64(p); - p += 8; - - /* Host */ - out->host = _asl_get_64(p); - p += 8; - - /* Sender */ - out->sender = _asl_get_64(p); - p += 8; - - /* Facility */ - out->facility = _asl_get_64(p); - p += 8; - - /* Level */ - out->level = _asl_get_32(p); - p += 4; - - /* PID */ - out->pid = _asl_get_32(p); - p += 4; - - /* UID */ - out->uid = _asl_get_32(p); - p += 4; - - /* GID */ - out->gid = _asl_get_32(p); - p += 4; - - /* Message */ - out->message = _asl_get_64(p); - p += 8; - - next = header_get_next(tmp); - out->next = next; - - if (action == PMSG_FETCH_STD) - { - /* caller only wants "standard" keys */ - *pmsg = out; - return ASL_STATUS_OK; - } - - *pmsg = out; - } - else - { - out = *pmsg; - } - - n = 0; - next = out->next; - - while (next != 0) - { - offset = next * DB_RECORD_LEN; - status = fseek(s->db, offset, SEEK_SET); - if (status < 0) - { - *pmsg = NULL; - free(out); - return ASL_STATUS_READ_FAILED; - } - - status = fread(tmp, DB_RECORD_LEN, 1, s->db); - if (status != 1) - { - *pmsg = NULL; - free(out); - return ASL_STATUS_READ_FAILED; - } - - if (out->kvcount == 0) - { - v32 = _asl_get_32(tmp + 5); - out->kvcount = v32 * 2; - out->kvlist = (uint64_t *)calloc(out->kvcount, sizeof(uint64_t)); - if (out->kvlist == NULL) - { - *pmsg = NULL; - free(out); - return ASL_STATUS_NO_MEMORY; - } - } - - p = tmp + 9; - - for (i = 0; (i < 4) && (n < out->kvcount); i++) - { - out->kvlist[n++] = _asl_get_64(p); - p += 8; - - out->kvlist[n++] = _asl_get_64(p); - p += 8; - } - - next = header_get_next(tmp); - } - - return ASL_STATUS_OK; -} - -static uint32_t -pmsg_match(asl_store_t *s, pmsg_t *q, pmsg_t *m) -{ - uint32_t i, j; - - if (s == NULL) return 0; - if (q == NULL) return 1; - if (m == NULL) return 0; - - if (q->kselect & PMSG_SEL_TIME) - { - if (q->time == ASL_REF_NULL) return 0; - if ((q->vselect & PMSG_SEL_TIME) && (q->time != m->time)) return 0; - } - - if (q->kselect & PMSG_SEL_HOST) - { - if (q->host == ASL_REF_NULL) return 0; - if ((q->vselect & PMSG_SEL_HOST) && (q->host != m->host)) return 0; - } - - if (q->kselect & PMSG_SEL_SENDER) - { - if (q->sender == ASL_REF_NULL) return 0; - if ((q->vselect & PMSG_SEL_SENDER) && (q->sender != m->sender)) return 0; - } - - if (q->kselect & PMSG_SEL_FACILITY) - { - if (q->facility == ASL_REF_NULL) return 0; - if ((q->vselect & PMSG_SEL_FACILITY) && (q->facility != m->facility)) return 0; - } - - if (q->kselect & PMSG_SEL_MESSAGE) - { - if (q->message == ASL_REF_NULL) return 0; - if ((q->vselect & PMSG_SEL_MESSAGE) && (q->message != m->message)) return 0; - } - - if (q->kselect & PMSG_SEL_LEVEL) - { - if (q->level == ASL_INDEX_NULL) return 0; - if ((q->vselect & PMSG_SEL_LEVEL) && (q->level != m->level)) return 0; - } - - if (q->kselect & PMSG_SEL_PID) - { - if (q->pid == -1) return 0; - if ((q->vselect & PMSG_SEL_PID) && (q->pid != m->pid)) return 0; - } - - if (q->kselect & PMSG_SEL_UID) - { - if (q->uid == -2) return 0; - if ((q->vselect & PMSG_SEL_UID) && (q->uid != m->uid)) return 0; - } - - if (q->kselect & PMSG_SEL_GID) - { - if (q->gid == -2) return 0; - if ((q->vselect & PMSG_SEL_GID) && (q->gid != m->gid)) return 0; - } - - if (q->kselect & PMSG_SEL_RUID) - { - if (q->ruid == -1) return 0; - if ((q->vselect & PMSG_SEL_RUID) && (q->ruid != m->ruid)) return 0; - } - - if (q->kselect & PMSG_SEL_RGID) - { - if (q->rgid == -1) return 0; - if ((q->vselect & PMSG_SEL_RGID) && (q->rgid != m->rgid)) return 0; - } - - for (i = 0; i < q->kvcount; i += 2) - { - for (j = 0; j < m->kvcount; j += 2) - { - if (q->kvlist[i] == m->kvlist[j]) - { - if (q->kvlist[i + 1] == m->kvlist[j + 1]) break; - return 0; - } - } - - if (j >= m->kvcount) return 0; - } - - return 1; -} - -static void -free_pmsg(pmsg_t *p) -{ - if (p == NULL) return; - if (p->kvlist != NULL) free(p->kvlist); - free(p); -} - -static uint32_t -pmsg_fetch_by_id(asl_store_t *s, uint64_t msgid, int32_t ruid, int32_t rgid, pmsg_t **pmsg, uint32_t *slot) -{ - uint32_t i, status; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (msgid == ASL_REF_NULL) return ASL_STATUS_INVALID_ARG; - if (slot == NULL) return ASL_STATUS_INVALID_ARG; - - *slot = ASL_INDEX_NULL; - - i = slotlist_find(s, msgid, 0, 0); - if (i == ASL_INDEX_NULL) return ASL_STATUS_INVALID_ID; - - *slot = s->slotlist[i].slot; - - /* read the message */ - *pmsg = NULL; - status = pmsg_fetch(s, s->slotlist[i].slot, ruid, rgid, PMSG_FETCH_ALL, pmsg); - if (status != ASL_STATUS_OK) return status; - if (pmsg == NULL) return ASL_STATUS_FAILED; - - return status; -} - -static uint32_t -msg_decode(asl_store_t *s, pmsg_t *pmsg, asl_msg_t **out) -{ - uint32_t status, i, n; - char *key, *val; - asl_msg_t *msg; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (out == NULL) return ASL_STATUS_INVALID_ARG; - if (pmsg == NULL) return ASL_STATUS_INVALID_ARG; - - *out = NULL; - - msg = (asl_msg_t *)calloc(1, sizeof(asl_msg_t)); - if (msg == NULL) return ASL_STATUS_NO_MEMORY; - - msg->type = ASL_TYPE_MSG; - msg->count = 0; - if (pmsg->time != ASL_REF_NULL) msg->count++; - if (pmsg->host != ASL_REF_NULL) msg->count++; - if (pmsg->sender != ASL_REF_NULL) msg->count++; - if (pmsg->facility != ASL_REF_NULL) msg->count++; - if (pmsg->message != ASL_REF_NULL) msg->count++; - if (pmsg->level != ASL_INDEX_NULL) msg->count++; - if (pmsg->pid != -1) msg->count++; - if (pmsg->uid != -2) msg->count++; - if (pmsg->gid != -2) msg->count++; - if (pmsg->ruid != -1) msg->count++; - if (pmsg->rgid != -1) msg->count++; - - msg->count += pmsg->kvcount / 2; - - if (msg->count == 0) - { - free(msg); - return ASL_STATUS_INVALID_MESSAGE; - } - - /* Message ID */ - msg->count += 1; - - msg->key = (char **)calloc(msg->count, sizeof(char *)); - if (msg->key == NULL) - { - free(msg); - return ASL_STATUS_NO_MEMORY; - } - - msg->val = (char **)calloc(msg->count, sizeof(char *)); - if (msg->val == NULL) - { - free(msg->key); - free(msg); - return ASL_STATUS_NO_MEMORY; - } - - n = 0; - - /* Time */ - if (pmsg->time != ASL_REF_NULL) - { - msg->key[n] = strdup(ASL_KEY_TIME); - if (msg->key[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - - asprintf(&(msg->val[n]), "%llu", pmsg->time); - if (msg->val[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - n++; - } - - /* Host */ - if (pmsg->host != ASL_REF_NULL) - { - msg->key[n] = strdup(ASL_KEY_HOST); - if (msg->key[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - - status = string_fetch_sid(s, pmsg->host, &(msg->val[n])); - n++; - } - - /* Sender */ - if (pmsg->sender != ASL_REF_NULL) - { - msg->key[n] = strdup(ASL_KEY_SENDER); - if (msg->key[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - - status = string_fetch_sid(s, pmsg->sender, &(msg->val[n])); - n++; - } - - /* Facility */ - if (pmsg->facility != ASL_REF_NULL) - { - msg->key[n] = strdup(ASL_KEY_FACILITY); - if (msg->key[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - - status = string_fetch_sid(s, pmsg->facility, &(msg->val[n])); - n++; - } - - /* Level */ - if (pmsg->level != ASL_INDEX_NULL) - { - msg->key[n] = strdup(ASL_KEY_LEVEL); - if (msg->key[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - - asprintf(&(msg->val[n]), "%u", pmsg->level); - if (msg->val[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - n++; - } - - /* PID */ - if (pmsg->pid != -1) - { - msg->key[n] = strdup(ASL_KEY_PID); - if (msg->key[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - - asprintf(&(msg->val[n]), "%d", pmsg->pid); - if (msg->val[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - n++; - } - - /* UID */ - if (pmsg->uid != -2) - { - msg->key[n] = strdup(ASL_KEY_UID); - if (msg->key[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - - asprintf(&(msg->val[n]), "%d", pmsg->uid); - if (msg->val[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - n++; - } - - /* GID */ - if (pmsg->gid != -2) - { - msg->key[n] = strdup(ASL_KEY_GID); - if (msg->key[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - - asprintf(&(msg->val[n]), "%d", pmsg->gid); - if (msg->val[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - n++; - } - - /* Message */ - if (pmsg->message != ASL_REF_NULL) - { - msg->key[n] = strdup(ASL_KEY_MSG); - if (msg->key[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - - status = string_fetch_sid(s, pmsg->message, &(msg->val[n])); - n++; - } - - /* ReadUID */ - if (pmsg->ruid != -1) - { - msg->key[n] = strdup(ASL_KEY_READ_UID); - if (msg->key[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - - asprintf(&(msg->val[n]), "%d", pmsg->ruid); - if (msg->val[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - n++; - } - - /* ReadGID */ - if (pmsg->rgid != -1) - { - msg->key[n] = strdup(ASL_KEY_READ_GID); - if (msg->key[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - - asprintf(&(msg->val[n]), "%d", pmsg->rgid); - if (msg->val[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - n++; - } - - /* Message ID */ - msg->key[n] = strdup(ASL_KEY_MSG_ID); - if (msg->key[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - - asprintf(&(msg->val[n]), "%llu", pmsg->msgid); - if (msg->val[n] == NULL) - { - asl_free(msg); - return ASL_STATUS_NO_MEMORY; - } - n++; - - /* Key - Value List */ - for (i = 0; i < pmsg->kvcount; i++) - { - key = NULL; - status = string_fetch_sid(s, pmsg->kvlist[i++], &key); - if (status != ASL_STATUS_OK) - { - if (key != NULL) free(key); - continue; - } - - val = NULL; - status = string_fetch_sid(s, pmsg->kvlist[i], &val); - if (status != ASL_STATUS_OK) - { - if (key != NULL) free(key); - if (val != NULL) free(val); - continue; - } - - status = asl_set((aslmsg)msg, key, val); - if (key != NULL) free(key); - if (val != NULL) free(val); - if (status != 0) - { - asl_free(msg); - return ASL_STATUS_FAILED; - } - } - - *out = msg; - return ASL_STATUS_OK; -} - -/* - * Finds string either in the string cache or in the database - */ -static uint32_t -store_string_find(asl_store_t *s, uint32_t hash, const char *str, uint32_t *index, uint32_t *refcount) -{ - uint32_t i, status, test; - char *tmp; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (str == NULL) return ASL_STATUS_INVALID_ARG; - if (index == NULL) return ASL_STATUS_INVALID_ARG; - if (refcount == NULL) return ASL_STATUS_INVALID_ARG; - if (s->slotlist == NULL) return ASL_STATUS_FAILED; - - /* check the cache */ - for (i = 0; i < STRING_CACHE_SIZE; i++) - { - if (s->string_cache[i].index == ASL_INDEX_NULL) continue; - - test = s->slotlist[s->string_cache[i].index].hash; - if (test != hash) continue; - - if (s->string_cache[i].str == NULL) - { - /* can't happen, but clean up anyway */ - s->string_cache[i].index = ASL_INDEX_NULL; - s->string_cache[i].refcount = 0; - continue; - } - - if (strcmp(s->string_cache[i].str, str)) continue; - - /* Bingo */ - *index = s->string_cache[i].index; - *refcount = s->string_cache[i].refcount; - return ASL_STATUS_OK; - } - - /* check the database */ - for (i = 0; i < s->slotlist_count; i++) - { - if ((s->slotlist[i].type != DB_TYPE_STRING) || (s->slotlist[i].hash != hash)) continue; - - /* read the whole string */ - tmp = NULL; - *refcount = 0; - status = string_fetch_slot(s, s->slotlist[i].slot, &tmp, refcount); - if (status != ASL_STATUS_OK) return status; - if (tmp == NULL) return ASL_STATUS_FAILED; - - status = strcmp(tmp, str); - free(tmp); - if (status != 0) continue; - - /* Bingo! */ - *index = i; - return ASL_STATUS_OK; - } - - *refcount = 0; - return ASL_STATUS_FAILED; -} - -/* - * Looks up a string ID number. - * Creates the string if necessary. - * Increments the string refcount. - */ -static uint64_t -string_retain(asl_store_t *s, const char *str, uint32_t create) -{ - uint32_t status, hash, index, slot, refcount, len; - uint64_t nsid, sid; - char **recordlist, *p; - uint8_t inls; - - if (s == NULL) return ASL_REF_NULL; - if (str == NULL) return ASL_REF_NULL; - - sid = ASL_REF_NULL; - index = ASL_INDEX_NULL; - slot = ASL_INDEX_NULL; - refcount = 0; - - len = strlen(str); - if (len < 8) - { - /* inline string */ - inls = len; - inls |= 0x80; - - nsid = 0; - p = (char *)&nsid; - memcpy(p, &inls, 1); - memcpy(p + 1, str, len); - sid = _asl_ntohq(nsid); - return sid; - } - - hash = string_hash(str, len); - - /* check the database */ - status = store_string_find(s, hash, str, &index, &refcount); - if (status == ASL_STATUS_OK) - { - if (index == ASL_INDEX_NULL) return ASL_REF_NULL; - if (create == 0) return s->slotlist[index].xid; - - refcount++; - string_set_refcount(s, index, str, refcount); - return s->slotlist[index].xid; - } - - if (create == 0) return ASL_REF_NULL; - - /* create the string */ - recordlist = NULL; - status = string_encode(s, hash, str, &sid, &recordlist); - if (status != ASL_STATUS_OK) return ASL_REF_NULL; - if (recordlist == NULL) return ASL_REF_NULL; - - status = save_record_list(s, recordlist, &slot); - record_list_free(s, recordlist); - if (status != ASL_STATUS_OK) return status; - - return sid; -} - -static uint32_t -record_chain_free(asl_store_t *s, uint64_t xid, uint32_t slot, uint8_t type) -{ - uint32_t status, next, where; - off_t offset; - char zdb[DB_RECORD_LEN]; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - - if ((type == DB_TYPE_STRING) && (s->string_count > 0)) s->string_count--; - if ((type == DB_TYPE_MESSAGE) && (s->message_count > 0)) s->message_count--; - - memset(zdb, 0, DB_RECORD_LEN); - - /* - * Walk the chain and mark each slot as free. - * - * This is tricky: - * We need to know the index in the slot list for each slot used in the record. - * We are given the xid for the record, which we pass to slotlist_find - * to get the index of the first slot. The slotlist entries for all subsequent - * slots will have xid 0, since they are of type DB_TYPE_KVLIST or DB_TYPE_STRCONT. - * Since slotlist has a secondary sort by slot, we can do a binary search within the - * xid 0 entries with slotlist_find to get the slotlist index of those slots. - */ - where = slotlist_find(s, xid, 0, 0); - - next = slot; - while (next != 0) - { - /* update slotlist */ - slotlist_make_empty(s, where); - - offset = next * DB_RECORD_LEN; - - status = fseek(s->db, offset + 1, SEEK_SET); - if (status < 0) return ASL_STATUS_WRITE_FAILED; - - status = fread(&next, 4, 1, s->db); - if (status != 1) return ASL_STATUS_WRITE_FAILED; - next = ntohl(next); - - status = fseek(s->db, offset, SEEK_SET); - if (status < 0) return ASL_STATUS_WRITE_FAILED; - - status = fwrite(zdb, DB_RECORD_LEN, 1, s->db); - if (status != 1) return ASL_STATUS_WRITE_FAILED; - - if (next != 0) where = slotlist_find_xid0_slot(s, next); - } - - return ASL_STATUS_OK; -} - -/* - * Removes records. - * - * Decrements string refcount. - * Removes string if refcount becomes zero. - */ -static uint32_t -id_release(asl_store_t *s, uint64_t xid, uint32_t slot, uint8_t type) -{ - uint32_t status, refcount, v32; - uint64_t x; - char head[17]; - off_t offset; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (xid == ASL_REF_NULL) return ASL_STATUS_INVALID_ID; - if (slot == ASL_INDEX_NULL) return ASL_STATUS_INVALID_ARG; - - /* Note that record_chain_free() updates slotlist */ - - offset = slot * DB_RECORD_LEN; - status = fseek(s->db, offset, SEEK_SET); - if (status < 0) return ASL_STATUS_WRITE_FAILED; - - status = fread(head, 17, 1, s->db); - if (status != 1) return ASL_STATUS_WRITE_FAILED; - - if (head[0] != type) return ASL_STATUS_FAILED; - - x = header_get_id(head); - - if (x != xid) return ASL_STATUS_FAILED; - - /* small kludge: only strings are refcounted */ - refcount = 1; - if (type == DB_TYPE_STRING) refcount = header_get_refcount(head); - - refcount--; - if (refcount == 0) - { - return record_chain_free(s, xid, slot, type); - } - else - { - offset += 13; - status = fseek(s->db, offset, SEEK_SET); - if (status < 0) return ASL_STATUS_WRITE_FAILED; - - v32 = htonl(refcount); - status = fwrite(&v32, 4, 1, s->db); - if (status != 1) return ASL_STATUS_WRITE_FAILED; - - return ASL_STATUS_OK; - } -} - -static uint32_t -string_release(asl_store_t *s, uint64_t sid) -{ - uint32_t i; - - i = slotlist_find(s, sid, 0, 0); - if (i == ASL_INDEX_NULL) return ASL_STATUS_INVALID_ID; - - return id_release(s, sid, s->slotlist[i].slot, DB_TYPE_STRING); -} - -static uint32_t -message_release(asl_store_t *s, uint64_t xid) -{ - uint32_t i, slot, status; - pmsg_t *pmsg; - - pmsg = NULL; - slot = ASL_INDEX_NULL; - - /* read message and release strings */ - status = pmsg_fetch_by_id(s, xid, 0, 0, &pmsg, &slot); - if (status != ASL_STATUS_OK) return status; - if (pmsg == NULL) return ASL_STATUS_READ_FAILED; - - string_release(s, pmsg->host); - string_release(s, pmsg->sender); - string_release(s, pmsg->facility); - string_release(s, pmsg->message); - for (i = 0; i < pmsg->kvcount; i++) string_release(s, pmsg->kvlist[i]); - free_pmsg(pmsg); - - return id_release(s, xid, slot, DB_TYPE_MESSAGE); -} - -/* - * Convert msg into a database record (or list of records if additional key/value pairs are present). - * Returns a NULL-terminated list of records. - * - * Sets the message access control flags as follows: - * If ruid is specified (anthing other than -1), then we use that as the ReadUID and set the uid access flag - * Else if msg contains a ReadUID, we use that as the ReadUID and set the uid access flag - * Else ReadUID is -1 and we don't set the uid access flag. - * Same logic for ReadGID. - */ -static uint32_t -message_encode(asl_store_t *s, asl_msg_t *msg, int32_t ruid, int32_t rgid, uint64_t *msgid, char ***list) -{ - char **outlist, *std, *kvl, *p; - uint32_t i, kvcount, kvn, len; - uint32_t level; - uint16_t flags; - int32_t pid, uid, gid, muid, mgid; - uint64_t time_val, host_sid, sender_sid, facility_sid, message_sid, k, v; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (msg == NULL) return ASL_STATUS_INVALID_MESSAGE; - if (list == NULL) return ASL_STATUS_INVALID_ARG; - - len = 2; - - outlist = (char **)calloc(len, sizeof(char *)); - if (outlist == NULL) return ASL_STATUS_NO_MEMORY; - - std = record_buffer_alloc(s); - if (std == NULL) - { - free(outlist); - return ASL_STATUS_NO_MEMORY; - } - - *msgid = new_id(s); - if (*msgid == ASL_REF_NULL) - { - free(outlist); - free(std); - return ASL_STATUS_FAILED; - } - - flags = 0; - - muid = -1; - if (ruid != -1) - { - muid = ruid; - flags |= ASL_MSG_FLAG_READ_UID_SET; - } - - mgid = -1; - if (rgid != -1) - { - mgid = rgid; - flags |= ASL_MSG_FLAG_READ_GID_SET; - } - - outlist[0] = std; - - flags = 0; - level = ASL_INDEX_NULL; - pid = -1; - uid = -2; - gid = -2; - host_sid = ASL_REF_NULL; - sender_sid = ASL_REF_NULL; - facility_sid = ASL_REF_NULL; - message_sid = ASL_REF_NULL; - time_val = ASL_REF_NULL; - - kvcount = 0; - kvn = 0; - kvl = NULL; - p = NULL; - - for (i = 0; i < msg->count; i++) - { - if (msg->key[i] == NULL) continue; - - else if (!strcmp(msg->key[i], ASL_KEY_TIME)) - { - if (msg->val[i] != NULL) time_val = asl_parse_time(msg->val[i]); - } - else if (!strcmp(msg->key[i], ASL_KEY_HOST)) - { - if (msg->val[i] != NULL) host_sid = string_retain(s, msg->val[i], 1); - } - else if (!strcmp(msg->key[i], ASL_KEY_SENDER)) - { - if (msg->val[i] != NULL) sender_sid = string_retain(s, msg->val[i], 1); - } - else if (!strcmp(msg->key[i], ASL_KEY_PID)) - { - if (msg->val[i] != NULL) pid = atoi(msg->val[i]); - } - else if (!strcmp(msg->key[i], ASL_KEY_UID)) - { - if (msg->val[i] != NULL) uid = atoi(msg->val[i]); - } - else if (!strcmp(msg->key[i], ASL_KEY_GID)) - { - if (msg->val[i] != NULL) gid = atoi(msg->val[i]); - } - else if (!strcmp(msg->key[i], ASL_KEY_LEVEL)) - { - if (msg->val[i] != NULL) level = atoi(msg->val[i]); - } - else if (!strcmp(msg->key[i], ASL_KEY_MSG)) - { - if (msg->val[i] != NULL) message_sid = string_retain(s, msg->val[i], 1); - } - else if (!strcmp(msg->key[i], ASL_KEY_FACILITY)) - { - if (msg->val[i] != NULL) facility_sid = string_retain(s, msg->val[i], 1); - } - else if (!strcmp(msg->key[i], ASL_KEY_READ_UID)) - { - if (((flags & ASL_MSG_FLAG_READ_UID_SET) == 0) && (msg->val[i] != NULL)) - { - muid = atoi(msg->val[i]); - flags |= ASL_MSG_FLAG_READ_UID_SET; - } - } - else if (!strcmp(msg->key[i], ASL_KEY_READ_GID)) - { - if (((flags & ASL_MSG_FLAG_READ_GID_SET) == 0) && (msg->val[i] != NULL)) - { - mgid = atoi(msg->val[i]); - flags |= ASL_MSG_FLAG_READ_GID_SET; - } - } - else if (!strcmp(msg->key[i], ASL_KEY_MSG_ID)) - { - /* Ignore */ - continue; - } - else - { - k = string_retain(s, msg->key[i], 1); - if (k == ASL_REF_NULL) continue; - - v = ASL_REF_NULL; - if (msg->val[i] != NULL) v = string_retain(s, msg->val[i], 1); - - if (kvl == NULL) - { - outlist = (char **)reallocf(outlist, (len + 1) * sizeof(char *)); - if (outlist == NULL) - { - free(std); - return ASL_STATUS_NO_MEMORY; - } - - kvl = record_buffer_alloc(s); - if (kvl == NULL) - { - record_list_free(s, outlist); - return ASL_STATUS_NO_MEMORY; - } - - kvl[0] = DB_TYPE_KVLIST; - p = kvl + 9; - - outlist[len - 1] = kvl; - outlist[len] = NULL; - len++; - } - - kvcount++; - - _asl_put_64(k, p); - kvn++; - p += 8; - - _asl_put_64(v, p); - kvn++; - p += 8; - - if (kvn >= 8) - { - kvl = NULL; - kvn = 0; - } - } - } - - /* encode kvcount in first kvlist record */ - if (kvcount > 0) - { - kvl = outlist[1]; - _asl_put_32(kvcount, kvl + 5); - } - - /* encode std */ - std[0] = DB_TYPE_MESSAGE; - p = std + 5; - - _asl_put_64(*msgid, p); - p += 8; - - _asl_put_32(muid, p); - p += 4; - - _asl_put_32(mgid, p); - p += 4; - - _asl_put_64(time_val, p); - p += 8; - - _asl_put_64(host_sid, p); - p += 8; - - _asl_put_64(sender_sid, p); - p += 8; - - _asl_put_64(facility_sid, p); - p += 8; - - _asl_put_32(level, p); - p += 4; - - _asl_put_32(pid, p); - p += 4; - - _asl_put_32(uid, p); - p += 4; - - _asl_put_32(gid, p); - p += 4; - - _asl_put_64(message_sid, p); - p += 8; - - _asl_put_16(flags, p); - p += 4; - - *list = outlist; - - return ASL_STATUS_OK; -} - -uint32_t -asl_store_save(asl_store_t *s, asl_msg_t *msg, int32_t ruid, int32_t rgid, uint64_t *msgid) -{ - char **list; - uint32_t status, slot; - uint64_t tick; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (s->flags & ASL_STORE_FLAG_READ_ONLY) return ASL_STATUS_READ_ONLY; - - list = NULL; - status = message_encode(s, msg, ruid, rgid, msgid, &list); - if ((status != ASL_STATUS_OK) || (list == NULL)) return status; - - slot = 0; - status = save_record_list(s, list, &slot); - tick = _asl_get_64(list[0] + MSG_OFF_KEY_TIME); - - /* if time has gone backwards, unset the flag */ - if (tick < s->max_time) s->flags &= ~ASL_STORE_FLAG_TIME_SORTED; - else s->max_time = tick; - - record_list_free(s, list); - - return status; -} - -uint32_t -asl_store_remove(asl_store_t *s, uint64_t msgid) -{ - uint32_t status; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (s->flags & ASL_STORE_FLAG_READ_ONLY) return ASL_STATUS_READ_ONLY; - - status = message_release(s, msgid); - return status; -} - -uint32_t -asl_store_fetch(asl_store_t *s, uint64_t msgid, int32_t ruid, int32_t rgid, asl_msg_t **msg) -{ - uint32_t status, slot; - pmsg_t *pmsg; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (msgid == ASL_REF_NULL) return ASL_STATUS_INVALID_ARG; - - pmsg = NULL; - slot = ASL_INDEX_NULL; - - status = pmsg_fetch_by_id(s, msgid, ruid, rgid, &pmsg, &slot); - if (status != ASL_STATUS_OK) return status; - if (pmsg == NULL) return ASL_STATUS_FAILED; - - status = msg_decode(s, pmsg, msg); - free_pmsg(pmsg); - - return status; -} - -static uint32_t -query_to_pmsg(asl_store_t *s, asl_msg_t *q, pmsg_t **p) -{ - pmsg_t *out; - uint32_t i, j; - uint64_t ksid, vsid; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (p == NULL) return ASL_STATUS_INVALID_ARG; - - if (q == NULL) return Q_NULL; - if (q->count == 0) return Q_NULL; - - *p = NULL; - - if (q->op != NULL) - { - for (i = 0; i < q->count; i++) if (q->op[i] != ASL_QUERY_OP_EQUAL) return Q_SLOW; - } - - out = (pmsg_t *)calloc(1, sizeof(pmsg_t)); - if (out == NULL) return ASL_STATUS_NO_MEMORY; - - for (i = 0; i < q->count; i++) - { - if (q->key[i] == NULL) continue; - - else if (!strcmp(q->key[i], ASL_KEY_TIME)) - { - if (out->kselect & PMSG_SEL_TIME) - { - free_pmsg(out); - return Q_SLOW; - } - - out->kselect |= PMSG_SEL_TIME; - if (q->val[i] != NULL) - { - out->vselect |= PMSG_SEL_TIME; - out->time = asl_parse_time(q->val[i]); - } - } - else if (!strcmp(q->key[i], ASL_KEY_HOST)) - { - if (out->kselect & PMSG_SEL_HOST) - { - free_pmsg(out); - return Q_SLOW; - } - - out->kselect |= PMSG_SEL_HOST; - if (q->val[i] != NULL) - { - out->vselect |= PMSG_SEL_HOST; - out->host = string_retain(s, q->val[i], 0); - if (out->host == ASL_REF_NULL) - { - free_pmsg(out); - return Q_FAIL; - } - } - } - else if (!strcmp(q->key[i], ASL_KEY_SENDER)) - { - if (out->kselect & PMSG_SEL_SENDER) - { - free_pmsg(out); - return Q_SLOW; - } - - out->kselect |= PMSG_SEL_SENDER; - if (q->val[i] != NULL) - { - out->vselect |= PMSG_SEL_SENDER; - out->sender = string_retain(s, q->val[i], 0); - if (out->sender == ASL_REF_NULL) - { - free_pmsg(out); - return Q_FAIL; - } - } - } - else if (!strcmp(q->key[i], ASL_KEY_PID)) - { - if (out->kselect & PMSG_SEL_PID) - { - free_pmsg(out); - return Q_SLOW; - } - - out->kselect |= PMSG_SEL_PID; - if (q->val[i] != NULL) - { - out->vselect |= PMSG_SEL_PID; - out->pid = atoi(q->val[i]); - } - } - else if (!strcmp(q->key[i], ASL_KEY_UID)) - { - if (out->kselect & PMSG_SEL_UID) - { - free_pmsg(out); - return Q_SLOW; - } - - out->kselect |= PMSG_SEL_UID; - if (q->val[i] != NULL) - { - out->vselect |= PMSG_SEL_UID; - out->uid = atoi(q->val[i]); - } - } - else if (!strcmp(q->key[i], ASL_KEY_GID)) - { - if (out->kselect & PMSG_SEL_GID) - { - free_pmsg(out); - return Q_SLOW; - } - - out->kselect |= PMSG_SEL_GID; - if (q->val[i] != NULL) - { - out->vselect |= PMSG_SEL_GID; - out->gid = atoi(q->val[i]); - } - } - else if (!strcmp(q->key[i], ASL_KEY_LEVEL)) - { - if (out->kselect & PMSG_SEL_LEVEL) - { - free_pmsg(out); - return Q_SLOW; - } - - out->kselect |= PMSG_SEL_LEVEL; - if (q->val[i] != NULL) - { - out->vselect |= PMSG_SEL_LEVEL; - out->level = atoi(q->val[i]); - } - } - else if (!strcmp(q->key[i], ASL_KEY_MSG)) - { - if (out->kselect & PMSG_SEL_MESSAGE) - { - free_pmsg(out); - return Q_SLOW; - } - - out->kselect |= PMSG_SEL_MESSAGE; - if (q->val[i] != NULL) - { - out->vselect |= PMSG_SEL_MESSAGE; - out->message = string_retain(s, q->val[i], 0); - if (out->message == ASL_REF_NULL) - { - free_pmsg(out); - return Q_FAIL; - } - } - } - else if (!strcmp(q->key[i], ASL_KEY_FACILITY)) - { - if (out->kselect & PMSG_SEL_FACILITY) - { - free_pmsg(out); - return Q_SLOW; - } - - out->kselect |= PMSG_SEL_FACILITY; - if (q->val[i] != NULL) - { - out->vselect |= PMSG_SEL_FACILITY; - out->facility = string_retain(s, q->val[i], 0); - if (out->facility == ASL_REF_NULL) - { - free_pmsg(out); - return Q_FAIL; - } - } - } - else if (!strcmp(q->key[i], ASL_KEY_READ_UID)) - { - if (out->kselect & PMSG_SEL_RUID) - { - free_pmsg(out); - return Q_SLOW; - } - - out->kselect |= PMSG_SEL_RUID; - if (q->val[i] != NULL) - { - out->vselect |= PMSG_SEL_RUID; - out->ruid = atoi(q->val[i]); - } - } - else if (!strcmp(q->key[i], ASL_KEY_READ_GID)) - { - if (out->kselect & PMSG_SEL_RGID) - { - free_pmsg(out); - return Q_SLOW; - } - - out->kselect |= PMSG_SEL_RGID; - if (q->val[i] != NULL) - { - out->vselect |= PMSG_SEL_RGID; - out->rgid = atoi(q->val[i]); - } - } - else - { - ksid = string_retain(s, q->key[i], 0); - if (ksid == ASL_REF_NULL) - { - free_pmsg(out); - return Q_FAIL; - } - - for (j = 0; j < out->kvcount; j += 2) - { - if (out->kvlist[j] == ksid) - { - free_pmsg(out); - return Q_SLOW; - } - } - - vsid = ASL_REF_NULL; - if (q->val[i] != NULL) - { - vsid = string_retain(s, q->val[i], 0); - if (ksid == ASL_REF_NULL) - { - free_pmsg(out); - return Q_FAIL; - } - } - - if (out->kvcount == 0) - { - out->kvlist = (uint64_t *)calloc(2, sizeof(uint64_t)); - } - else - { - out->kvlist = (uint64_t *)reallocf(out->kvlist, (out->kvcount + 2) * sizeof(uint64_t)); - } - - if (out->kvlist == NULL) - { - free_pmsg(out); - return ASL_STATUS_NO_MEMORY; - } - - out->kvlist[out->kvcount++] = ksid; - out->kvlist[out->kvcount++] = vsid; - } - } - - *p = out; - return Q_FAST; -} - -uint32_t -msg_match(asl_store_t *s, uint32_t qtype, pmsg_t *qp, asl_msg_t *q, int32_t ruid, int32_t rgid, uint32_t slot, pmsg_t **iopm, asl_msg_t **iomsg, asl_msg_list_t **res, uint32_t *didmatch) -{ - uint32_t status, what; - - *didmatch = 0; - - if (qtype == Q_FAIL) return ASL_STATUS_OK; - - if (qtype == Q_NULL) - { - if (*iopm == NULL) - { - status = pmsg_fetch(s, slot, ruid, rgid, PMSG_FETCH_ALL, iopm); - if (status != ASL_STATUS_OK) return status; - if (*iopm == NULL) return ASL_STATUS_FAILED; - } - } - else if (qtype == Q_FAST) - { - if (qp == NULL) return ASL_STATUS_INVALID_ARG; - - what = PMSG_FETCH_STD; - if (qp->kvcount > 0) what = PMSG_FETCH_ALL; - - if (*iopm == NULL) - { - status = pmsg_fetch(s, slot, ruid, rgid, what, iopm); - if (status != ASL_STATUS_OK) return status; - if (*iopm == NULL) return ASL_STATUS_FAILED; - } - - status = pmsg_match(s, qp, *iopm); - if (status == 1) - { - if ((what == PMSG_FETCH_STD) && ((*iopm)->next != 0) && ((*iopm)->kvcount == 0)) - { - status = pmsg_fetch(s, slot, ruid, rgid, PMSG_FETCH_KV, iopm); - if (status != ASL_STATUS_OK) return status; - if (*iopm == NULL) return ASL_STATUS_FAILED; - } - } - else return ASL_STATUS_OK; - } - else if (qtype == Q_SLOW) - { - if (*iomsg == NULL) - { - if (*iopm == NULL) - { - status = pmsg_fetch(s, slot, ruid, rgid, PMSG_FETCH_ALL, iopm); - if (status != ASL_STATUS_OK) return status; - if (*iopm == NULL) return ASL_STATUS_FAILED; - } - - status = msg_decode(s, *iopm, iomsg); - if (status == ASL_STATUS_INVALID_MESSAGE) return ASL_STATUS_OK; - if (status != ASL_STATUS_OK) return status; - if (*iomsg == NULL) return ASL_STATUS_FAILED; - } - - status = 0; - if (asl_msg_cmp(q, *iomsg) != 0) status = 1; - if (status == 0) return ASL_STATUS_OK; - } - - *didmatch = 1; - - if (res == NULL) return ASL_STATUS_OK; - - if (*iomsg == NULL) - { - status = msg_decode(s, *iopm, iomsg); - if (status == ASL_STATUS_INVALID_MESSAGE) - { - *didmatch = 0; - return ASL_STATUS_OK; - } - - if (status != ASL_STATUS_OK) return status; - } - - if ((*res)->count == 0) (*res)->msg = (asl_msg_t **)calloc(1, sizeof(asl_msg_t *)); - else (*res)->msg = (asl_msg_t **)reallocf((*res)->msg, (1 + (*res)->count) * sizeof(asl_msg_t *)); - if ((*res)->msg == NULL) return ASL_STATUS_NO_MEMORY; - - (*res)->msg[(*res)->count++] = *iomsg; - - return ASL_STATUS_OK; -} - -static uint32_t -next_search_slot(asl_store_t *s, uint32_t last_si, int32_t direction) -{ - uint32_t i; - - if (direction >= 0) - { - for (i = last_si + 1; i < s->slotlist_count; i++) - { - if (s->slotlist[i].type == DB_TYPE_MESSAGE) return i; - } - - return ASL_INDEX_NULL; - } - - if (last_si == 0) return ASL_INDEX_NULL; - if (last_si > s->slotlist_count) return ASL_INDEX_NULL; - - for (i = last_si - 1; i > 0; i--) - { - if (s->slotlist[i].type == DB_TYPE_MESSAGE) return i; - } - - if (s->slotlist[0].type == DB_TYPE_MESSAGE) return 0; - - return ASL_INDEX_NULL; -} - -static uint32_t -query_list_to_pmsg_list(asl_store_t *s, asl_msg_list_t *query, uint32_t *match, pmsg_t ***qp, uint32_t **qtype, uint32_t *count) -{ - pmsg_t **outp, *pm; - uint32_t i, j, *outt; - *match = 0; - *qp = NULL; - *qtype = 0; - *count = 0; - - if (query == NULL) return ASL_STATUS_OK; - if (match == NULL) return ASL_STATUS_INVALID_ARG; - if (qp == NULL) return ASL_STATUS_INVALID_ARG; - if (qtype == NULL) return ASL_STATUS_INVALID_ARG; - if (query->msg == NULL) return ASL_STATUS_INVALID_ARG; - if (query->count == 0) return ASL_STATUS_OK; - - outp = (pmsg_t **)calloc(query->count, sizeof(pmsg_t *)); - if (outp == NULL) return ASL_STATUS_NO_MEMORY; - - outt = (uint32_t *)calloc(query->count, sizeof(uint32_t)); - if (outt == NULL) - { - free(outp); - return ASL_STATUS_NO_MEMORY; - } - - *match = 1; - - for (i = 0; i < query->count; i++) - { - pm = NULL; - outt[i] = query_to_pmsg(s, query->msg[i], &pm); - if (outt[i] <= ASL_STATUS_FAILED) - { - if (pm != NULL) free_pmsg(pm); - for (j = 0; j < i; j++) free_pmsg(outp[j]); - free(outp); - free(outt); - return ASL_STATUS_NO_MEMORY; - } - - outp[i] = pm; - } - - *count = query->count; - *qp = outp; - *qtype = outt; - return ASL_STATUS_OK; -} - -static void -match_worker_cleanup(pmsg_t **ql, uint32_t *qt, uint32_t n, asl_msg_list_t **res) -{ - uint32_t i; - - if (ql != NULL) - { - for (i = 0; i < n; i++) free_pmsg(ql[i]); - free(ql); - } - - if (qt != NULL) free(qt); - - if (res != NULL) - { - for (i = 0; i < (*res)->count; i++) asl_free((*res)->msg[i]); - free(*res); - } -} - - /* - * Input to asl_store_match is a list of queries. - * A record in the store matches if it matches any query (i.e. query list is "OR"ed) - * - * If counting up (direction is positive) find first record with ID > start_id. - * Else if counting down (direction is negative) find first record with ID < start_id. - * - * Set match flag on. - * If any query is NULL, set match flog off (skips matching below). - * Else if all queries only check "standard" keys, set std flag to on. - * - * If a query only tests equality, convert it to a pmsg_t. The conversion routine - * checks for string values that are NOT in the database. If a string is not found, - * the conversion fails and the query is markes as "never matches". Otherwise, - * the query is marked "fast". - * - * If all queries are marked as "never matches", return NULL. - * - * match loop: - * fetch record (with std flag) - * if match flag is off, decode record and add it to result. - * else for each query: - * if query is NULL (shouldn't happen) decode record and add it to result. Return to match loop. - * else if query never matches, ignore it. - * else if query is fast, use pmsg_match. If it succeeds, decode record and add it to result. Return to match loop. - * else decode record and use asl_cmp. If it succeeds, add record to result. Return to match loop. - * - * return results. - */ -static uint32_t -match_worker(asl_store_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t **idlist, uint32_t *idcount, uint64_t start_id, int32_t count, int32_t direction, int32_t ruid, int32_t rgid) -{ - uint32_t mx, si, slot, i, qcount, match, didmatch, status, *qtype; - uint64_t xid; - pmsg_t **qp, *iopmsg; - asl_msg_t *iomsg; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if ((res == NULL) && (idlist == NULL)) return ASL_STATUS_INVALID_ARG; - if (last_id == NULL) return ASL_STATUS_INVALID_ARG; - if (idcount == NULL) return ASL_STATUS_INVALID_ARG; - - if (res != NULL) *res = NULL; - if (idlist != NULL) *idlist = NULL; - - mx = 0; - - if (direction < 0) direction = -1; - else direction = 1; - - si = ASL_INDEX_NULL; - if ((direction == -1) && (start_id == ASL_REF_NULL)) si = s->slotlist_count; - else si = slotlist_find(s, start_id, 0, direction); - - si = next_search_slot(s, si, direction); - if (si == ASL_INDEX_NULL) return ASL_STATUS_OK; - if (si >= s->slotlist_count) return ASL_STATUS_FAILED; - - slot = s->slotlist[si].slot; - - status = query_list_to_pmsg_list(s, query, &match, &qp, &qtype, &qcount); - if (status != ASL_STATUS_OK) return status; - - /* - * initialize result list if we've been asked to return messages - */ - if (res != NULL) - { - *res = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t)); - if (*res == NULL) - { - match_worker_cleanup(qp, qtype, qcount, NULL); - return ASL_STATUS_NO_MEMORY; - } - } - - /* - * loop through records - */ - *idcount = 0; - while ((count == 0) || (*idcount < count)) - { - if (si == ASL_INDEX_NULL) break; - if (si >= s->slotlist_count) break; - - slot = s->slotlist[si].slot; - xid = s->slotlist[si].xid; - - *last_id = xid; - - iopmsg = NULL; - iomsg = NULL; - - didmatch = 0; - if (match == 0) - { - status = msg_match(s, Q_NULL, NULL, NULL, ruid, rgid, slot, &iopmsg, &iomsg, res, &didmatch); - free_pmsg(iopmsg); - if (didmatch == 0) - { - asl_free(iomsg); - iomsg = NULL; - } - else - { - if (idlist != NULL) - { - if (*idlist == NULL) *idlist = (uint64_t *)calloc(1, sizeof(uint64_t)); - else *idlist = (uint64_t *)reallocf(*idlist, (*idcount + 1) * sizeof(uint64_t)); - if (*idlist == NULL) status = ASL_STATUS_NO_MEMORY; - else (*idlist)[*idcount] = xid; - } - - (*idcount)++; - } - - if (status == ASL_STATUS_ACCESS_DENIED) - { - si = next_search_slot(s, si, direction); - continue; - } - else if (status != ASL_STATUS_OK) - { - match_worker_cleanup(qp, qtype, qcount, res); - return status; - } - } - else - { - for (i = 0; i < qcount; i++) - { - status = msg_match(s, qtype[i], qp[i], query->msg[i], ruid, rgid, slot, &iopmsg, &iomsg, res, &didmatch); - if (status == ASL_STATUS_ACCESS_DENIED) break; - else if (status != ASL_STATUS_OK) - { - free_pmsg(iopmsg); - asl_free(iomsg); - match_worker_cleanup(qp, qtype, qcount, res); - return status; - } - - if (didmatch == 1) - { - if (idlist != NULL) - { - if (*idlist == NULL) *idlist = (uint64_t *)calloc(1, sizeof(uint64_t)); - else *idlist = (uint64_t *)reallocf(*idlist, (*idcount + 1) * sizeof(uint64_t)); - if (*idlist == NULL) - { - match_worker_cleanup(qp, qtype, qcount, res); - return ASL_STATUS_NO_MEMORY; - } - - (*idlist)[*idcount] = xid; - } - - (*idcount)++; - break; - } - } - - free_pmsg(iopmsg); - if ((didmatch == 0) || (res == NULL)) asl_free(iomsg); - } - - si = next_search_slot(s, si, direction); - } - - match_worker_cleanup(qp, qtype, qcount, NULL); - return status; -} - -uint32_t -asl_store_match(asl_store_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, int32_t ruid, int32_t rgid) -{ - uint32_t idcount; - - idcount = 0; - return match_worker(s, query, res, last_id, NULL, &idcount, start_id, count, direction, ruid, rgid); -} - -uint32_t -asl_store_prune(asl_store_t *s, asl_msg_list_t *prune) -{ - uint64_t *idlist, max_id; - uint32_t status, i, idcount; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (s->flags & ASL_STORE_FLAG_READ_ONLY) return ASL_STATUS_READ_ONLY; - - if (prune == NULL) return ASL_STATUS_OK; - - idlist = NULL; - idcount = 0; - max_id = 0; - - status = match_worker(s, prune, NULL, &max_id, &idlist, &idcount, 0, 0, 1, 0, 0); - if (status != ASL_STATUS_OK) - { - if (idlist != NULL) free(idlist); - return status; - } - - for (i = 0; i < idcount; i++) message_release(s, idlist[i]); - if (idlist != NULL) free(idlist); - - return ASL_STATUS_OK; -} - -/* - * Compact the database. - * Removes NULL and EMPTY records by copying records to the front of the file. - */ -uint32_t -asl_store_compact(asl_store_t *s) -{ - char tmp[DB_RECORD_LEN]; - int status; - uint8_t t; - uint32_t i, j, nrecords, next, slcount, old_slcount, *record_map; - off_t offset; - slot_info_t *old_slot_list; - size_t vmrecord_map_len, vmslot_list_len; - void *vmrecord_map, *vmslot_list; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (s->flags & ASL_STORE_FLAG_READ_ONLY) return ASL_STATUS_READ_ONLY; - - status = fseek(s->db, DB_RECORD_LEN, SEEK_SET); - if (status < 0) return ASL_STATUS_READ_FAILED; - - /* - * record map is a mapping from pre-compaction record number to post-compaction record number. - * We allocate it in VM rather than on the malloc heap to keep from creating a lot of - * empty pages. - */ - nrecords = s->record_count; - - vmrecord_map_len = nrecords * sizeof(uint32_t); - vmrecord_map = mmap(0, vmrecord_map_len, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - - record_map = (uint32_t *)vmrecord_map; - if (record_map == NULL) return ASL_STATUS_NO_MEMORY; - - record_map[0] = 0; - - /* size of post-compaction slotlist */ - slcount = 0; - - /* first pass: create the record map (N.B. starting at 1 skips the header) */ - for (i = 1, j = 1; i < nrecords; i++) - { - record_map[i] = 0; - - status = fread(tmp, DB_RECORD_LEN, 1, s->db); - if (status != 1) - { - munmap(vmrecord_map, vmrecord_map_len); - return ASL_STATUS_READ_FAILED; - } - - t = tmp[0]; - - if (t == DB_TYPE_HEADER) - { - munmap(vmrecord_map, vmrecord_map_len); - return ASL_STATUS_INVALID_STORE; - } - - /* - * Only messages, kvlists, strings, and string continuations get copied. - * Empty, null, and unrecognized record types (i.e. corruption in the database) - * are skipped. This compresses out gaps and deletes bad records. - */ - if ((t != DB_TYPE_MESSAGE) && (t != DB_TYPE_KVLIST) && (t != DB_TYPE_STRING) && (t != DB_TYPE_STRCONT)) continue; - - /* count to get size of new slotlist */ - if ((t == DB_TYPE_STRING) || (t == DB_TYPE_MESSAGE)) slcount++; - - record_map[i] = j++; - } - - /* second pass: copy records and fix "next" indexes */ - for (i = 1; i < nrecords; i++) - { - offset = i * DB_RECORD_LEN; - status = fseek(s->db, offset, SEEK_SET); - if (status < 0) - { - munmap(vmrecord_map, vmrecord_map_len); - return ASL_STATUS_READ_FAILED; - } - - status = fread(tmp, DB_RECORD_LEN, 1, s->db); - if (status != 1) - { - munmap(vmrecord_map, vmrecord_map_len); - return ASL_STATUS_READ_FAILED; - } - - t = tmp[0]; - - /* only copy messages, kvlists, strings, and string continuations */ - if ((t != DB_TYPE_MESSAGE) && (t != DB_TYPE_KVLIST) && (t != DB_TYPE_STRING) && (t != DB_TYPE_STRCONT)) continue; - - next = _asl_get_32(tmp + 1); - - if (next > nrecords) next = 0; - else next = record_map[next]; - - _asl_put_32(next, tmp + 1); - - offset = record_map[i] * DB_RECORD_LEN; - status = fseek(s->db, offset, SEEK_SET); - if (status < 0) - { - munmap(vmrecord_map, vmrecord_map_len); - return ASL_STATUS_READ_FAILED; - } - - status = fwrite(tmp, DB_RECORD_LEN, 1, s->db); - if (status != 1) - { - munmap(vmrecord_map, vmrecord_map_len); - return ASL_STATUS_WRITE_FAILED; - } - } - - /* truncate file */ - s->record_count = j; - offset = s->record_count * DB_RECORD_LEN; - - status = fseek(s->db, 0, SEEK_SET); - if (status < 0) - { - munmap(vmrecord_map, vmrecord_map_len); - return ASL_STATUS_READ_FAILED; - } - - status = ftruncate(fileno(s->db), offset); - if (status != 0) - { - munmap(vmrecord_map, vmrecord_map_len); - return ASL_STATUS_WRITE_FAILED; - } - - /* - * build new slotlist - * - * We start by allocating and copying the old slotlist into VM. - * Then we realloc the old slotlist to become the new slotlist. - * Then we build the new slotlist from the values in VM. - * Finally we deallocate the VM. - * This is done so that we don't create a large malloc heap. - */ - - vmslot_list_len = s->slotlist_count * sizeof(slot_info_t); - - vmslot_list = mmap(0, vmslot_list_len, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - old_slot_list = (slot_info_t *)vmslot_list; - if (old_slot_list == NULL) - { - munmap(vmrecord_map, vmrecord_map_len); - return ASL_STATUS_NO_MEMORY; - } - - old_slcount = s->slotlist_count; - - /* copy old values to VM */ - for (i = 0; i < s->slotlist_count; i++) - { - old_slot_list[i].type = s->slotlist[i].type; - old_slot_list[i].slot = s->slotlist[i].slot; - old_slot_list[i].xid = s->slotlist[i].xid; - old_slot_list[i].hash = s->slotlist[i].hash; - } - - s->slotlist = (slot_info_t *)reallocf(s->slotlist, slcount * sizeof(slot_info_t)); - if (s->slotlist == NULL) - { - munmap(vmrecord_map, vmrecord_map_len); - munmap(vmslot_list, vmslot_list_len); - return ASL_STATUS_NO_MEMORY; - } - - s->slotlist_count = slcount; - - /* create the new compacted slotlist */ - for (i = 0, j = 0; i < old_slcount; i++) - { - t = old_slot_list[i].type; - if ((t == DB_TYPE_STRING) || (t == DB_TYPE_MESSAGE)) - { - s->slotlist[j].type = t; - s->slotlist[j].slot = record_map[old_slot_list[i].slot]; - s->slotlist[j].xid = old_slot_list[i].xid; - s->slotlist[j].hash = old_slot_list[i].hash; - j++; - } - } - - munmap(vmslot_list, vmslot_list_len); - - s->empty_count = 0; - - /* fix string cache index (which indexes into slotlist) */ - for (i = 0; i < STRING_CACHE_SIZE; i++) - { - if (s->string_cache[i].index == ASL_INDEX_NULL) continue; - s->string_cache[i].index = record_map[s->string_cache[i].index]; - } - - /* new xid=0 count */ - for (s->slot_zero_count = 0; (s->slot_zero_count < s->slotlist_count) && (s->slotlist[s->slot_zero_count].xid == 0); s->slot_zero_count++); - - munmap(vmrecord_map, vmrecord_map_len); - - return ASL_STATUS_OK; -} - -static uint32_t -write_to_archive(asl_store_t *s, asl_store_t *a, uint64_t msgid) -{ - uint32_t status; - uint64_t xid; - aslmsg msg; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (a == NULL) return ASL_STATUS_OK; - - status = asl_store_fetch(s, msgid, 0, 0, &msg); - if (status != ASL_STATUS_OK) return status; - - status = asl_store_save(a, msg, -1, -1, &xid); - asl_free(msg); - return status; -} - -static uint64_t -oldest_id(asl_store_t *s) -{ - uint32_t si; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - - si = next_search_slot(s, ASL_INDEX_NULL, 1); - if (si == ASL_INDEX_NULL) return ASL_REF_NULL; - - return s->slotlist[si].xid; -} - -/* - * Archive/remove oldest messages to make the database <= max_size - * This is slow - messages are removed one at a time. - */ -uint32_t -asl_store_truncate(asl_store_t *s, uint64_t max_size, const char *archive) -{ - uint32_t max_slots, curr_used; - uint32_t status; - uint64_t old; - asl_store_t *a; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (s->flags & ASL_STORE_FLAG_READ_ONLY) return ASL_STATUS_READ_ONLY; - - if (max_size == 0) return ASL_STATUS_OK; - - a = NULL; - - max_slots = (max_size + DB_RECORD_LEN - 1) / DB_RECORD_LEN; - curr_used = s->record_count - s->empty_count; - - if ((curr_used > max_slots) && (archive != NULL)) - { - status = asl_store_open(archive, 0, &a); - if (status != ASL_STATUS_OK) return status; - } - - while (curr_used > max_slots) - { - old = oldest_id(s); - if (old == ASL_REF_NULL) return ASL_STATUS_FAILED; - - if (archive != NULL) - { - status = write_to_archive(s, a, old); - if (status != ASL_STATUS_OK) return status; - } - - status = message_release(s, old); - if (status != ASL_STATUS_OK) return status; - - curr_used = s->record_count - s->empty_count; - } - - if (archive != NULL) asl_store_close(a); - - status = asl_store_compact(s); - return status; -} - -static uint32_t -archive_time_worker(asl_store_t *s, uint64_t cut_time, uint64_t **idlist, uint16_t **flags, uint32_t *idcount) -{ - uint32_t si, slot, status, check_sort; - uint64_t xid, t, lastt; - uint16_t rflags; - char tmp[DB_RECORD_LEN]; - off_t offset; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (idlist == NULL) return ASL_STATUS_INVALID_ARG; - if (flags == NULL) return ASL_STATUS_INVALID_ARG; - if (idcount == NULL) return ASL_STATUS_INVALID_ARG; - - *idlist = NULL; - *flags = NULL; - *idcount = 0; - si = ASL_INDEX_NULL; - - lastt = 0; - check_sort = 1; - - /* - * loop through records - * - * Note that next_search_slot() traverses slotlist, which is sorted by id numder. - * If the ASL_STORE_FLAG_TIME_SORTED flag is not set, we must search the whole database. - * If the flag is set, timestamps will increase with xid, so we stop when we get - * a message with time > cut_time. - */ - forever - { - si = next_search_slot(s, si, 1); - if (si == ASL_INDEX_NULL) break; - - slot = s->slotlist[si].slot; - xid = s->slotlist[si].xid; - - offset = slot * DB_RECORD_LEN; - status = fseek(s->db, offset, SEEK_SET); - - if (status < 0) return ASL_STATUS_READ_FAILED; - - status = fread(tmp, DB_RECORD_LEN, 1, s->db); - if (status != 1) return ASL_STATUS_READ_FAILED; - - t = _asl_get_64(tmp + MSG_OFF_KEY_TIME); - - if (lastt > t) check_sort = 0; - - if (t > cut_time) - { - if (s->flags & ASL_STORE_FLAG_TIME_SORTED) return ASL_STATUS_OK; - continue; - } - - rflags = _asl_get_16(tmp + MSG_OFF_KEY_FLAGS); - - if (*idlist == NULL) - { - *idlist = (uint64_t *)calloc(1, sizeof(uint64_t)); - *flags = (uint16_t *)calloc(1, sizeof(uint16_t)); - } - else - { - *idlist = (uint64_t *)reallocf(*idlist, (*idcount + 1) * sizeof(uint64_t)); - *flags = (uint16_t *)reallocf(*flags, (*idcount + 1) * sizeof(uint16_t)); - } - - if (*idlist == NULL) - { - if (*flags != NULL) free(*flags); - *flags = NULL; - return ASL_STATUS_NO_MEMORY; - } - - if (*flags == NULL) - { - if (*idlist != NULL) free(*idlist); - *idlist = NULL; - return ASL_STATUS_NO_MEMORY; - } - - (*idlist)[*idcount] = xid; - (*flags)[*idcount] = rflags; - (*idcount)++; - } - - /* if timestamps increase with xid, set the flag to improve subsequent search performance */ - if (check_sort == 1) s->flags |= ASL_STORE_FLAG_TIME_SORTED; - - return ASL_STATUS_OK; -} - -static uint32_t -archive_time_inverse(asl_store_t *s, uint64_t cut_time, uint64_t **idlist, uint32_t *idcount) -{ - uint32_t si, slot, status; - uint64_t xid, t, lastt; - char tmp[DB_RECORD_LEN]; - off_t offset; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (idlist == NULL) return ASL_STATUS_INVALID_ARG; - if (idcount == NULL) return ASL_STATUS_INVALID_ARG; - - *idlist = NULL; - *idcount = 0; - si = ASL_INDEX_NULL; - - lastt = 0; - - /* - * loop through records - */ - forever - { - si = next_search_slot(s, si, 1); - if (si == ASL_INDEX_NULL) break; - - slot = s->slotlist[si].slot; - xid = s->slotlist[si].xid; - - offset = slot * DB_RECORD_LEN; - status = fseek(s->db, offset, SEEK_SET); - - if (status < 0) return ASL_STATUS_READ_FAILED; - - status = fread(tmp, DB_RECORD_LEN, 1, s->db); - if (status != 1) return ASL_STATUS_READ_FAILED; - - t = _asl_get_64(tmp + MSG_OFF_KEY_TIME); - - if (t <= cut_time) continue; - - if (*idlist == NULL) - { - *idlist = (uint64_t *)calloc(1, sizeof(uint64_t)); - } - else - { - *idlist = (uint64_t *)reallocf(*idlist, (*idcount + 1) * sizeof(uint64_t)); - } - - if (*idlist == NULL) return ASL_STATUS_NO_MEMORY; - - - (*idlist)[*idcount] = xid; - (*idcount)++; - } - - return ASL_STATUS_OK; -} - -static uint32_t -archive_release(asl_store_t *s, uint64_t xid, uint64_t cut_time, uint64_t expire_ref) -{ - uint32_t i, slot, status; - uint16_t rflags; - pmsg_t *pmsg; - uint64_t expire_time; - char *str, tmp[DB_RECORD_LEN]; - off_t offset; - - pmsg = NULL; - slot = ASL_INDEX_NULL; - - /* read message and release strings */ - status = pmsg_fetch_by_id(s, xid, 0, 0, &pmsg, &slot); - if (status != ASL_STATUS_OK) return status; - if (pmsg == NULL) return ASL_STATUS_READ_FAILED; - - if (expire_ref != ASL_REF_NULL) - { - for (i = 0; i < pmsg->kvcount; i += 2) - { - if (pmsg->kvlist[i] == expire_ref) - { - str = NULL; - status = string_fetch_sid(s, pmsg->kvlist[i + 1], &str); - if (status != ASL_STATUS_OK) return status; - if (str != NULL) - { - expire_time = 0; - /* relative time not allowed - that would be cheating! */ - if (str[0] != '+') expire_time = asl_parse_time(str); - free(str); - - if (expire_time > cut_time) - { - /* expires in the future - mark as "do not archive" and don't release */ - free_pmsg(pmsg); - - offset = slot * DB_RECORD_LEN; - status = fseek(s->db, offset, SEEK_SET); - if (status < 0) return ASL_STATUS_READ_FAILED; - - status = fread(tmp, DB_RECORD_LEN, 1, s->db); - if (status != 1) return ASL_STATUS_READ_FAILED; - - rflags = _asl_get_16(tmp + MSG_OFF_KEY_FLAGS); - if ((rflags & ASL_MSG_FLAG_DO_NOT_ARCHIVE) == 0) - { - rflags |= ASL_MSG_FLAG_DO_NOT_ARCHIVE; - _asl_put_16(rflags, tmp + MSG_OFF_KEY_FLAGS); - - status = fseek(s->db, offset, SEEK_SET); - if (status < 0) return ASL_STATUS_WRITE_FAILED; - - status = fwrite(tmp, DB_RECORD_LEN, 1, s->db); - if (status != 1) return ASL_STATUS_WRITE_FAILED; - } - - return ASL_STATUS_OK; - } - } - } - } - } - - string_release(s, pmsg->host); - string_release(s, pmsg->sender); - string_release(s, pmsg->facility); - string_release(s, pmsg->message); - for (i = 0; i < pmsg->kvcount; i++) string_release(s, pmsg->kvlist[i]); - free_pmsg(pmsg); - - return id_release(s, xid, slot, DB_TYPE_MESSAGE); -} - -static char * -asl_store_mk_tmp_path() -{ - char tmp[PATH_MAX], *path; - - if (confstr(_CS_DARWIN_USER_TEMP_DIR, tmp, sizeof(tmp)) <= 0) return NULL; - - path = NULL; - asprintf(&path, "%sasl.%d.tmp", tmp, getpid()); - return path; -} - -/* - * Moves messages added at or before cut_time to an archive, - * or delete them if archive_name is NULL. - */ -uint32_t -asl_store_archive(asl_store_t *s, uint64_t cut_time, const char *archive_name) -{ - asl_store_t *archive, *newstore; - char *path, *newmapped; - uint16_t *flags; - uint32_t status, i, archive_count, save_count; - uint64_t expire_ref, *archive_list, *save_list; - size_t dbsize; - - if (s == NULL) return ASL_STATUS_INVALID_STORE; - if (s->flags & ASL_STORE_FLAG_READ_ONLY) return ASL_STATUS_READ_ONLY; - - if (cut_time == 0) return ASL_STATUS_OK; - - archive_count = 0; - archive_list = NULL; - save_count = 0; - save_list = NULL; - flags = NULL; - - s->flags = 0; - - status = archive_time_worker(s, cut_time, &archive_list, &flags, &archive_count); - if (status != ASL_STATUS_OK) return status; - - if ((archive_list == NULL) || (archive_count == 0)) - { - if (archive_list != NULL) free(archive_list); - return ASL_STATUS_OK; - } - - archive = NULL; - if (archive_name != NULL) - { - status = asl_store_open(archive_name, 0, &archive); - if (status != ASL_STATUS_OK) return status; - } - - if (archive != NULL) - { - for (i = 0; i < archive_count; i++) - { - if (flags[i] & ASL_MSG_FLAG_DO_NOT_ARCHIVE) continue; - - status = write_to_archive(s, archive, archive_list[i]); - if (status != ASL_STATUS_OK) - { - free(archive_list); - asl_store_close(archive); - return status; - } - } - - asl_store_close(archive); - } - - /* - * Deleting large numbers of records is slow. - * If the number of records to be deleted is at least 1000, and - * is ARCHIVE_DELETE_VS_COPY_PERCENT or above, we copy the records - * that should remain to a temporary archive, then replace the - * database with the temporary one. - * Note that we need to know the name of the current DB file. - */ - path = NULL; - if ((archive_count >= 1000) && (((archive_count * 100) / s->message_count) >= ARCHIVE_DELETE_VS_COPY_PERCENT) && (s->db_path != NULL)) path = asl_store_mk_tmp_path(); - if (path != NULL) - { - status = unlink(path); - if ((status != 0) && (errno != ENOENT)) - { - free(path); - path = NULL; - } - } - - if (path != NULL) - { - if (archive_list != NULL) free(archive_list); - archive_list = NULL; - archive_count = 0; - - newstore = NULL; - status = asl_store_open(path, 0, &newstore); - free(path); - path = NULL; - if (status != ASL_STATUS_OK) return status; - - /* Set the next_id so that the archive will have ids bigger than the current archive. */ - newstore->next_id = s->next_id; - - /* get a list of records that we want to keep */ - status = archive_time_inverse(s, cut_time, &save_list, &save_count); - if (status != ASL_STATUS_OK) - { - asl_store_close(newstore); - return status; - } - - if ((save_list == NULL) || (save_count == 0)) - { - if (save_list != NULL) free(save_list); - asl_store_close(newstore); - return ASL_STATUS_OK; - } - - /* save to the temp archive */ - for (i = 0; i < save_count; i++) - { - status = write_to_archive(s, newstore, save_list[i]); - if (status != ASL_STATUS_OK) - { - if (save_list != NULL) free(save_list); - asl_store_close(newstore); - return status; - } - } - - free(save_list); - save_list = NULL; - - /* try rename since it's fast, but may fail (e.g. files are on different filesystems) */ - fclose(s->db); - status = rename(newstore->db_path, s->db_path); - if (status == 0) - { - /* success */ - s->db = fopen(s->db_path, "r+"); - if (s->db == NULL) - { - /* Disaster! Can't open the database! */ - asl_store_close(newstore); - return ASL_STATUS_FAILED; - } - } - else - { - /* rename failed, copy the data */ - s->db = fopen(s->db_path, "r+"); - if (s->db == NULL) - { - /* Disaster! Can't open the database! */ - asl_store_close(newstore); - return ASL_STATUS_FAILED; - } - - dbsize = newstore->record_count * DB_RECORD_LEN; - newmapped = mmap(0, dbsize, PROT_READ, MAP_PRIVATE, fileno(newstore->db), 0); - if (newmapped == (void *)-1) - { - asl_store_close(newstore); - return ASL_STATUS_FAILED; - } - - fseek(s->db, 0, SEEK_SET); - status = ftruncate(fileno(s->db), 0); - if (status != ASL_STATUS_OK) - { - asl_store_close(newstore); - return status; - } - - status = fwrite(newmapped, dbsize, 1, s->db); - munmap(newmapped, dbsize); - if (status == 0) - { - asl_store_close(newstore); - return ASL_STATUS_FAILED; - } - } - - /* swap data in the store handles */ - if (s->slotlist != NULL) free(s->slotlist); - s->slotlist = newstore->slotlist; - newstore->slotlist = NULL; - - for (i = 0; i < RECORD_CACHE_SIZE; i++) - { - free(s->rcache[i]); - s->rcache[i] = newstore->rcache[i]; - newstore->rcache[i] = NULL; - s->rcache_state[i] = newstore->rcache_state[i]; - } - - for (i = 0; i < STRING_CACHE_SIZE; i++) - { - s->string_cache[i].index = newstore->string_cache[i].index; - s->string_cache[i].refcount = newstore->string_cache[i].refcount; - if (s->string_cache[i].str != NULL) free(s->string_cache[i].str); - s->string_cache[i].str = newstore->string_cache[i].str; - newstore->string_cache[i].str = NULL; - } - - s->flags = newstore->flags; - s->record_count = newstore->record_count; - s->message_count = newstore->message_count; - s->string_count = newstore->string_count; - s->empty_count = newstore->empty_count; - s->next_id = newstore->next_id; - s->max_time = newstore->max_time; - s->slotlist_count = newstore->slotlist_count; - s->slot_zero_count = newstore->slot_zero_count; - - fclose(newstore->db); - unlink(newstore->db_path); - free(newstore->db_path); - free(newstore); - - return ASL_STATUS_OK; - } - - expire_ref = string_retain(s, ASL_KEY_EXPIRE_TIME, 0); - - /* - * This flag turns off most of the code in slotlist_make_empty. - * We get much better performace while we delete records, - * but the slotlist has to be repaired and re-sorted afterwards. - */ - s->flags |= ASL_STORE_FLAG_DEFER_SORT; - - for (i = 0; i < archive_count; i++) - { - status = archive_release(s, archive_list[i], cut_time, expire_ref); - if (status != ASL_STATUS_OK) return status; - } - - s->flags &= ~ASL_STORE_FLAG_DEFER_SORT; - - free(archive_list); - archive_list = NULL; - archive_count = 0; - - free(flags); - flags = NULL; - - /* zero xids for slots that became empty during archive release */ - for (i = 0; i < s->slotlist_count; i++) - { - if (s->slotlist[i].type == DB_TYPE_EMPTY) s->slotlist[i].xid = 0; - } - - /* re-sort and determine the zero count */ - qsort((void *)s->slotlist, s->slotlist_count, sizeof(slot_info_t), slot_comp); - - /* new xid=0 count */ - for (s->slot_zero_count = 0; (s->slot_zero_count < s->slotlist_count) && (s->slotlist[s->slot_zero_count].xid == 0); s->slot_zero_count++); - - return ASL_STATUS_OK; -} - -const char * -asl_store_error(uint32_t code) -{ - switch (code) - { - case ASL_STATUS_OK: return "Operation Succeeded"; - case ASL_STATUS_INVALID_ARG: return "Invalid Argument"; - case ASL_STATUS_INVALID_STORE: return "Invalid Data Store"; - case ASL_STATUS_INVALID_STRING: return "Invalid String"; - case ASL_STATUS_INVALID_ID: return "Invalid ID Number"; - case ASL_STATUS_INVALID_MESSAGE: return "Invalid Message"; - case ASL_STATUS_NOT_FOUND: return "Not Found"; - case ASL_STATUS_READ_FAILED: return "Read Operation Failed"; - case ASL_STATUS_WRITE_FAILED: return "Write Operation Failed"; - case ASL_STATUS_NO_MEMORY: return "System Memory Allocation Failed"; - case ASL_STATUS_ACCESS_DENIED: return "Access Denied"; - case ASL_STATUS_READ_ONLY: return "Read Only Access"; - } - - return "Operation Failed"; -} diff --git a/aslcommon/asl_store.h b/aslcommon/asl_store.h deleted file mode 100644 index e29dee5..0000000 --- a/aslcommon/asl_store.h +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef __ASL_STORE_H__ -#define __ASL_STORE_H__ - -/* - * ASL Database - * - * Log messages are stored in 80 byte records of the form: - * - * | 1 | 4 | 8 | 4 | 4 | 8 | 8 | 8 | 8 | 4 | 4 | 4 | 4 | 8 | 2 | 1 | (80 bytes) - * | Type | Next | ID | RUID | RGID | Time | Host | Sender | Facility | LEVEL | PID | UID | GID | Message | Flags | Zero | - * - * If there are no additional key/value pairs in the message, Next will be zero. If there are additional - * key/value pairs in the database, Next is a record number for a record with the format: - * - * | 1 | 4 | 4 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 7 | (80 bytes) - * | Type | Next | Count | Key1 | Val1 | Key2 | Val2 | Key3 | Val3 | Key4 | Val4 | Zero | - * - * Additional records will be chained using the Next field, with the count field left zero. - * - * Strings stored in records of the form: - * - * | 1 | 4 | 8 | 4 | 4 | 4 | 55 | (80 bytes) - * | Type | Next | ID | Refcount | Hash | Length | String | - * - * If the string is longer than 55 bytes, Next is a record number for a record with the format: - * - * | 1 | 4 | 75 | (80 bytes) - * | Type | Next | String | - * - * The first record (header) in the database has the format: - * - * | 12 | 4 | 8 | 56 | (80 bytes) - * | Cookie | Vers | Max ID | Zero | - * - */ - -#include -#include -#include -#include - -#define ASL_STORE_FLAG_READ_ONLY 0x00000001 -#define ASL_STORE_FLAG_DEFER_SORT 0x00000002 -#define ASL_STORE_FLAG_TIME_SORTED 0x00000004 - -#define ASL_MSG_FLAG_DO_NOT_ARCHIVE 0x0001 -#define ASL_MSG_FLAG_READ_UID_SET 0x0002 -#define ASL_MSG_FLAG_READ_GID_SET 0x0004 - -#define DB_VERSION 1 -#define DB_RECORD_LEN 80 - -#define DB_HEADER_COOKIE_OFFSET 0 -#define DB_HEADER_VERS_OFFSET 12 -#define DB_HEADER_MAXID_OFFSET 16 - -#define DB_TYPE_NULL 255 -#define DB_TYPE_EMPTY 0 -#define DB_TYPE_HEADER 1 -#define DB_TYPE_MESSAGE 2 -#define DB_TYPE_KVLIST 3 -#define DB_TYPE_STRING 4 -#define DB_TYPE_STRCONT 5 - -#define ASL_REF_NULL 0xffffffffffffffffLL - -#define ASL_STATUS_OK 0 -#define ASL_STATUS_INVALID_ARG 1 -#define ASL_STATUS_INVALID_STORE 2 -#define ASL_STATUS_INVALID_STRING 3 -#define ASL_STATUS_INVALID_ID 4 -#define ASL_STATUS_INVALID_MESSAGE 5 -#define ASL_STATUS_NOT_FOUND 6 -#define ASL_STATUS_READ_FAILED 7 -#define ASL_STATUS_WRITE_FAILED 8 -#define ASL_STATUS_NO_MEMORY 9 -#define ASL_STATUS_ACCESS_DENIED 10 -#define ASL_STATUS_READ_ONLY 11 -#define ASL_STATUS_FAILED 9999 - -#define ASL_KEY_FACILITY "Facility" -#define ASL_KEY_READ_UID "ReadUID" -#define ASL_KEY_READ_GID "ReadGID" -#define ASL_KEY_EXPIRE_TIME "ASLExpireTime" -#define ASL_KEY_MSG_ID "ASLMessageID" - -#define STRING_CACHE_SIZE 100 -#define RECORD_CACHE_SIZE 8 - -typedef struct -{ - uint8_t type; - uint32_t slot; - uint64_t xid; - uint32_t hash; -} slot_info_t; - -typedef struct -{ - uint32_t index; - uint32_t refcount; - char *str; -} string_cache_entry_t; - -typedef struct -{ - uint32_t flags; - uint32_t record_count; - uint32_t message_count; - uint32_t string_count; - uint32_t empty_count; - uint64_t next_id; - uint64_t max_time; - slot_info_t *slotlist; - uint32_t slotlist_count; - uint32_t slot_zero_count; - string_cache_entry_t string_cache[STRING_CACHE_SIZE]; - char *rcache[RECORD_CACHE_SIZE]; - uint8_t rcache_state[RECORD_CACHE_SIZE]; - char *db_path; - FILE *db; -} asl_store_t; - -uint32_t asl_store_open(const char *path, uint32_t flags, asl_store_t **s); -uint32_t asl_store_close(asl_store_t *s); - -uint32_t asl_store_save(asl_store_t *s, aslmsg msg, int32_t ruid, int32_t rgid, uint64_t *msgid); -uint32_t asl_store_fetch(asl_store_t *s, uint64_t msgid, int32_t ruid, int32_t rgid, aslmsg *msg); -uint32_t asl_store_remove(asl_store_t *s, uint64_t msgid); - -uint32_t asl_store_match(asl_store_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, int32_t ruid, int32_t rgid); - -uint32_t asl_store_prune(asl_store_t *s, aslresponse prune); -uint32_t asl_store_archive(asl_store_t *s, uint64_t cut_time, const char *archive); -uint32_t asl_store_truncate(asl_store_t *s, uint64_t max_size, const char *archive); -uint32_t asl_store_compact(asl_store_t *s); - -const char *asl_store_error(uint32_t code); - -#endif /*__ASL_STORE_H__*/ diff --git a/aslmanager.tproj/Makefile b/aslmanager.tproj/Makefile new file mode 100644 index 0000000..50d5e41 --- /dev/null +++ b/aslmanager.tproj/Makefile @@ -0,0 +1,12 @@ +Project = aslmanager +ProductType = tool +Install_Dir = /usr/sbin + +CFILES = aslmanager.c +MANPAGES = aslmanager.8 +LAUNCHD_PLISTS = com.apple.aslmanager.plist + +Extra_CC_Flags = -Wall -mdynamic-no-pic -DINET6 +Extra_LD_Flags = -dead_strip + +include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make diff --git a/aslmanager.tproj/aslmanager.8 b/aslmanager.tproj/aslmanager.8 new file mode 100644 index 0000000..0fb9cfb --- /dev/null +++ b/aslmanager.tproj/aslmanager.8 @@ -0,0 +1,87 @@ +.\"Copyright (c) 2004-2008 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@ +.\" +.Dd December 7, 2007 +.Dt ASLMANAGER 8 +.Os "Mac OS X" +.Sh NAME +.Nm aslmanager +.Nd Apple System Log data store file manager +.Sh SYNOPSIS +.Nm +.Op Fl s Ar store_dir +.Op Fl a Op Ar archive_dir +.Op Fl ttl Ar days +.Op Fl size Ar max_size +.Sh DESCRIPTION +.Nm +manages files in the ASL data store written by the +.Nm syslogd +server. +.Pp +.Nm +is started automatically at various times. +It runs shortly after the +.Nm syslogd +server starts, at midnight (local time) if the system is running, +and any time a file in the ASL data store directory (/var/log/asl) reaches a maximum size limit as specified to the +.Nm syslogd +server. +.Pp +.Nm +scans through the files in the ASL data store directory /var/log/asl, or some other directory specified following the +.Fl s +flag. +Files that contain only messages that are older than the default 2 day time-to-live are either archived or removed. +The default 2 day time-to-live value may be overridden by supplying a value following the +.Fl ttl +flag. +A value of zero allows files to remain in the store with no time limit. +.Pp +A maximum size may be provided as a value following the +.Fl size +flag. +This will cause +.Nm +to archive (if +.Fl a +is specified) and remove files until the total size of the data store is +.Ar max_size +bytes or less. +Files are removed in order starting from oldest to newest. +Files with the same date are removed in standard lexigraphic sort order by file name. +.Pp +Files are either removed entirely or copied to an archive directory. +If the +.Fl a +flag is specified with no argument, files are copied to the /var/log/asl.archive directory. +An alternate directory path may be specified following the +.Fl a +flag. +.Sh SEE ALSO +.Xr syslogd 8 , +.Xr syslog 1 , +.Xr asl 3 , +.Xr syslog 3 , +.Sh HISTORY +The +.Nm +utility appeared in Mac OS X 10.5.6. diff --git a/aslmanager.tproj/aslmanager.c b/aslmanager.tproj/aslmanager.c new file mode 100644 index 0000000..38420b5 --- /dev/null +++ b/aslmanager.tproj/aslmanager.c @@ -0,0 +1,448 @@ +/* + * Copyright (c) 2007-2008 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SECONDS_PER_DAY 86400 +#define DEFAULT_MAX_SIZE 51200000 +#define DEFAULT_TTL 2 + +typedef struct name_list_s +{ + char *name; + size_t size; + struct name_list_s *next; +} name_list_t; + +void +mgr_exit(const char *store, int status) +{ + char *s; + + if (store == NULL) exit(status); + + s = NULL; + asprintf(&s, "%s/%s", store, FILE_ASL_STORE_SWEEP_SEMAPHORE); + if (s != NULL) + { + unlink(s); + free(s); + } + else exit(1); + + exit(status); +} + +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_match(const char *infile, const char *outfile, int do_ttl, time_t expire_time) +{ + asl_search_result_t q, *query, *res; + asl_msg_t *m, *qm[1]; + asl_file_t *in, *out; + uint32_t status, i; + char str[64]; + uint64_t mid; + + if (infile == NULL) return ASL_STATUS_INVALID_ARG; + if (outfile == NULL) return ASL_STATUS_INVALID_ARG; + + in = NULL; + status = asl_file_open_read(infile, &in); + if (status != ASL_STATUS_OK) return status; + + query = NULL; + q.count = 1; + q.curr = 0; + q.msg = qm; + qm[0] = NULL; + m = NULL; + + if (do_ttl == 1) + { + query = &q; + m = asl_new(ASL_TYPE_QUERY); + if (m == NULL) + { + asl_file_close(in); + return ASL_STATUS_NO_MEMORY; + } + + qm[0] = m; + + if (expire_time != 0) + { + snprintf(str, sizeof(str), "%llu", (long long unsigned int)expire_time); + if (asl_set_query(m, ASL_KEY_EXPIRE_TIME, str, ASL_QUERY_OP_NUMERIC | ASL_QUERY_OP_GREATER_EQUAL) != 0) + { + asl_file_close(in); + asl_free(m); + return ASL_STATUS_NO_MEMORY; + } + } + else + { + if (asl_set_query(m, ASL_KEY_EXPIRE_TIME, NULL, ASL_QUERY_OP_TRUE) != 0) + { + asl_file_close(in); + asl_free(m); + return ASL_STATUS_NO_MEMORY; + } + } + } + + res = NULL; + mid = 0; + status = asl_file_match(in, query, &res, &mid, 0, 0, 1); + if (m != NULL) asl_free(m); + asl_file_close(in); + + if (status != ASL_STATUS_OK) return status; + + /* + * N.B. "ASL_STATUS_NOT_FOUND" is never returned by asl_file_match. + * We use it here to signal the caller that no records were found by the match. + */ + if (res == NULL) return ASL_STATUS_NOT_FOUND; + if (res->count == 0) + { + aslresponse_free(res); + return ASL_STATUS_NOT_FOUND; + } + + out = NULL; + status = asl_file_open_write(outfile, 0644, -1, -1, &out); + if (status != ASL_STATUS_OK) return status; + + out->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(out, res->msg[i], &mid); + if (status != ASL_STATUS_OK) break; + } + + asl_file_close(out); + return status; +} + +int +main(int argc, const char *argv[]) +{ + int i, bbstrlen, debug; + const char *archive, *store_dir; + time_t now, best_before, ttl; + struct tm ctm; + char bbstr[32], *str, *p; + DIR *dp; + struct dirent *dent; + name_list_t *list, *e; + uint32_t status; + size_t file_size, store_size, max_size; + struct stat sb; + + list = NULL; + + archive = NULL; + store_dir = PATH_ASL_STORE; + ttl = DEFAULT_TTL * SECONDS_PER_DAY; + max_size = DEFAULT_MAX_SIZE; + store_size = 0; + debug = 0; + + for (i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "-a")) + { + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) archive = argv[++i]; + else archive = PATH_ASL_ARCHIVE; + } + else if (!strcmp(argv[i], "-s")) + { + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) store_dir = argv[++i]; + } + else if (!strcmp(argv[i], "-ttl")) + { + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) ttl = atoi(argv[++i]) * SECONDS_PER_DAY; + } + else if (!strcmp(argv[i], "-size")) + { + if (((i + 1) < argc) && (argv[i + 1][0] != '-')) max_size = atoi(argv[++i]); + } + else if (!strcmp(argv[i], "-d")) + { + debug = 1; + } + } + + /* check archive */ + if (archive != NULL) + { + memset(&sb, 0, sizeof(struct stat)); + if (stat(archive, &sb) == 0) + { + /* must be a directory */ + if ((sb.st_mode & S_IFDIR) == 0) + { + fprintf(stderr, "aslmanager error: archive %s is not a directory", archive); + return -1; + } + } + else + { + if (errno == ENOENT) + { + /* 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; + } + } + } + + chdir(store_dir); + + /* determine current time and time TTL ago */ + now = time(NULL); + best_before = 0; + if (ttl > 0) best_before = now - ttl; + + /* construct best before date as YYYY.MM.DD */ + memset(&ctm, 0, sizeof(struct tm)); + if (localtime_r((const time_t *)&best_before, &ctm) == NULL) mgr_exit(store_dir, 1); + + snprintf(bbstr, sizeof(bbstr), "%d.%02d.%02d.", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); + bbstrlen = strlen(bbstr); + + if (debug == 1) printf("Best Before Date %s\n", bbstr); + + dp = opendir(store_dir); + if (dp == NULL) mgr_exit(store_dir, 1); + + /* gather a list of files for dates before the best before date */ + + while ((dent = readdir(dp)) != NULL) + { + if ((dent->d_name[0] < '0') || (dent->d_name[0] > '9')) continue; + + memset(&sb, 0, sizeof(struct stat)); + file_size = 0; + if (stat(dent->d_name, &sb) == 0) file_size = sb.st_size; + store_size += file_size; + + list = add_to_list(list, dent->d_name, file_size); + } + + closedir(dp); + + if (debug == 1) + { + printf("\nData Store Size = %lu\n", store_size); + printf("\nData Store Files\n"); + for (e = list; e != NULL; e = e->next) printf(" %s %lu\n", e->name, e->size); + } + + /* copy messages in each expired file with ASLExpireTime values to LongTTL files */ + if (debug == 1) printf("\nStart Scan\n"); + + e = list; + while (e != NULL) + { + if ((store_size <= max_size) && (strncmp(e->name, bbstr, bbstrlen) >= 0)) break; + + /* find '.' after year */ + p = strchr(e->name, '.'); + if (p == NULL) continue; + + /* find '.' after month */ + p++; + p = strchr(p, '.'); + if (p == NULL) continue; + + /* find '.' after day */ + p++; + p = strchr(p, '.'); + if (p == NULL) continue; + + str = NULL; + asprintf(&str, "LongTTL%s", p); + if (str == NULL) mgr_exit(store_dir, 1); + + /* syslog -x [str] -db [e->name] -k ASLExpireTime */ + if (debug == 1) printf(" scan %s ---> %s\n", e->name, str); + else status = do_match(e->name, str, 1, 0); + + free(str); + str = NULL; + + if (archive != NULL) + { + str = NULL; + asprintf(&str, "%s/%s", archive, e->name); + if (str == NULL) mgr_exit(store_dir, 1); + + /* syslog -x [str] -db [e->name] */ + if (debug == 1) printf(" copy %s ---> %s\n", e->name, str); + else status = do_match(e->name, str, 0, 0); + free(str); + } + + if (debug == 1) printf(" unlink %s\n", e->name); + else unlink(e->name); + + store_size -= e->size; + e->size = 0; + + e = e->next; + } + + if (debug == 1) + { + printf("Finished Scan\n"); + printf("\nData Store Size = %lu\n", store_size); + } + + free_list(list); + list = NULL; + + dp = opendir(PATH_ASL_STORE); + if (dp == NULL) mgr_exit(store_dir, 1); + + /* gather a list of LongTTL files */ + + while ((dent = readdir(dp)) != NULL) + { + if (!strncmp(dent->d_name, "LongTTL.", 8)) list = add_to_list(list, dent->d_name, 0); + } + + closedir(dp); + + if (debug == 1) + { + printf("\nData Store LongTTL Files\n"); + for (e = list; e != NULL; e = e->next) printf(" %s\n", e->name); + } + + if (debug == 1) printf("\nScan for expired messages\n"); + + e = list; + while (e != NULL) + { + /* syslog -x LongTTL.new -db [e->name] -k ASLExpireTime Nge [now] */ + if (debug == 1) + { + printf(" %s\n", e->name); + } + else + { + status = do_match(e->name, "LongTTL.new", 1, now); + unlink(e->name); + if (status == ASL_STATUS_OK) rename("LongTTL.new", e->name); + } + + e = e->next; + } + + if (debug == 1) printf("Finished scan for expired messages\n"); + + free_list(list); + list = NULL; + + mgr_exit(store_dir, 0); + /* UNREACHED */ + return 0; +} + diff --git a/aslmanager.tproj/com.apple.aslmanager.plist b/aslmanager.tproj/com.apple.aslmanager.plist new file mode 100644 index 0000000..88571e6 --- /dev/null +++ b/aslmanager.tproj/com.apple.aslmanager.plist @@ -0,0 +1,18 @@ + + + + + Label + com.apple.aslmanager + ProgramArguments + + /usr/sbin/aslmanager + -size + 65536000 + + WatchPaths + + /var/log/asl/SweepStore + + + diff --git a/syslogd.tproj/Makefile b/syslogd.tproj/Makefile index 3a1fee2..bfb2043 100644 --- a/syslogd.tproj/Makefile +++ b/syslogd.tproj/Makefile @@ -1,46 +1,36 @@ -# -# Generated by the NeXT Project Builder. -# -# NOTE: Do NOT change this file -- Project Builder maintains it. -# -# Put all of your customizations in files called Makefile.preamble -# and Makefile.postamble (both optional), and Makefile will include them. -# - -NAME = syslogd - -PROJECTVERSION = 2.8 -PROJECT_TYPE = Tool - -HFILES = daemon.h - -CFILES = asl_action.c asl_in.c bsd_in.c bsd_out.c daemon.c dbserver.c klog_in.c syslogd.c udp_in.c - -OTHERSRCS = Makefile.preamble Makefile Makefile.postamble asl.conf.5 syslogd.8 syslog.conf.5 syslogd.sb com.apple.syslogd.plist - -MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles -CODE_GEN_STYLE = DYNAMIC -MAKEFILE = tool.make -NEXTSTEP_INSTALLDIR = /usr/sbin -WINDOWS_INSTALLDIR = /usr/sbin -PDO_UNIX_INSTALLDIR = /usr/sbin -LIBS = -laslcommon -DEBUG_LIBS = $(LIBS) -PROF_LIBS = $(LIBS) - -NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc -WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc -PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc -NEXTSTEP_JAVA_COMPILER = /usr/bin/javac -WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe -PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac - -include $(MAKEFILEDIR)/platform.make - --include Makefile.preamble - -include $(MAKEFILEDIR)/$(MAKEFILE) - --include Makefile.postamble - --include Makefile.dependencies +Project = syslogd +ProductType = tool +Install_Dir = /usr/sbin + +CFILES = asl_action.c asl_in.c bsd_in.c bsd_out.c daemon.c dbserver.c klog_in.c remote.c syslogd.c udp_in.c + +MANPAGES = asl.conf.5 syslogd.8 syslog.conf.5 +#syslogd.sb +LAUNCHD_PLISTS = com.apple.syslogd.plist + +Extra_CC_Flags = -Wall -mdynamic-no-pic \ + -DINET6 \ + -I"$(OBJROOT)"/aslcommon \ + -I../aslcommon \ + -I"$(SDKROOT)"/System/Library/Frameworks/System.framework/PrivateHeaders + +# Determine product configuartion +PRODUCT = $(shell tconf --product) +ifeq ($(PRODUCT),MacOSX) +Extra_CC_Flags += -DCONFIG_MAC -DREMOTE_IPV4 +endif +ifeq ($(PRODUCT),AppleTV) +Extra_CC_Flags += -DCONFIG_APPLETV -DREMOTE_IPV4 +endif +ifeq ($(PRODUCT),iPhone) +Extra_CC_Flags += -DCONFIG_IPHONE -DLOCKDOWN +endif + +Extra_LD_Flags = -dead_strip -L"$(SYMROOT)" -laslcommon + +include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make + +after_install: + $(INSTALL_DIRECTORY) "$(DSTROOT)"/private/var/log/asl + $(INSTALL_DIRECTORY) "$(DSTROOT)"/usr/share/sandbox + $(INSTALL_FILE) syslogd.sb "$(DSTROOT)"/usr/share/sandbox diff --git a/syslogd.tproj/Makefile.postamble b/syslogd.tproj/Makefile.postamble deleted file mode 100644 index 08ebe43..0000000 --- a/syslogd.tproj/Makefile.postamble +++ /dev/null @@ -1,125 +0,0 @@ -############################################################################### -# NeXT Makefile.postamble Template -# Copyright 1993, NeXT Computer, Inc. -# -# This Makefile is used for configuring the standard app makefiles associated -# with ProjectBuilder. -# -# Use this template to set attributes for a project, sub-project, bundle, or -# palette. Each node in the project's tree of sub-projects and bundles -# should have it's own Makefile.preamble and Makefile.postamble. Additional -# rules (e.g., after_install) that are defined by the developer should be -# defined in this file. -# -############################################################################### -# -# Here are the variables exported by the common "app" makefiles that can be -# used in any customizations you make to the template below: -# -# PRODUCT_ROOT - Name of top-level app-wrapper (e.g., Webster.app) -# OFILE_DIR - Directory into which .o object files are generated. -# (Note that this name is calculated based on the target -# architectures specified in Project Builder). -# DERIVED_SRC_DIR - Directory used for all other derived files -# ALL_CFLAGS - All the flags passed to the cc(1) driver for compilations -# -# NAME - name of application, bundle, subproject, palette, etc. -# LANGUAGE - langage in which the project is written (default "English") -# ENGLISH - boolean flag set iff $(LANGUAGE) = "English" -# JAPANESE - boolean flag set iff $(LANGUAGE) = "Japanese" -# LOCAL_RESOURCES - localized resources (e.g. nib's, images) of project -# GLOBAL_RESOURCES - non-localized resources of project -# PROJECTVERSION - version of ProjectBuilder that output Makefile -# APPICON - application icon file -# DOCICONS - dock icon files -# ICONSECTIONS - Specifies icon sections when linking executable -# -# CLASSES - Class implementation files in project. -# HFILES - Header files in project. -# MFILES - Other Objective-C source files in project. -# CFILES - Other C source files in project. -# PSWFILES - .psw files in the project -# PSWMFILES - .pswm files in the project -# SUBPROJECTS - Subprojects of this project -# BUNDLES - Bundle subprojects of this project -# OTHERSRCS - Other miscellaneous sources of this project -# OTHERLINKED - Source files not matching a standard source extention -# -# LIBS - Libraries to link with when making app target -# DEBUG_LIBS - Libraries to link with when making debug target -# PROF_LIBS - Libraries to link with when making profile target -# OTHERLINKEDOFILES - Other relocatable files to (always) link in. -# -# APP_MAKEFILE_DIR - Directory in which to find generic set of Makefiles -# MAKEFILEDIR - Directory in which to find $(MAKEFILE) -# MAKEFILE - Top level mechanism Makefile (e.g., app.make, bundle.make) -# INSTALLDIR - Directory app will be installed into by 'install' target - - -# Change defaults assumed by the standard app makefiles here. Edit the -# following default values as appropriate. (Note that if no Makefile.postamble -# exists, these values will have defaults set in common.make). - -# Add Makefile.preamble, Makefile.postamble, and Makefile.dependencies here if -# you would like changes to them to invalidate previous builds. The project -# depends on $(MAKEFILES) so that changes to Makefiles will trigger a re-build. -#MAKEFILES = Makefile - -# Optimization flag passed to compiler: -#OPTIMIZATION_CFLAG = -O - -# Flags always passed to compiler: -#COMMON_CFLAGS = $(PROJECT_SPECIFIC_CFLAGS) -g -Wall - -# Flags passed to compiler in normal 'app' compiles: -#NORMAL_CFLAGS = $(COMMON_CFLAGS) $(OPTIMIZATION_CFLAG) - -# Flags passed to compiler in 'debug' compiles: -#DEBUG_CFLAGS = $(COMMON_CFLAGS) -DDEBUG - -# Flags passed to compiler in 'profile' compiles -#PROFILE_CFLAGS = $(COMMON_CFLAGS) -pg $(OPTIMIZATION_CFLAG) -DPROFILE - -# Flags passed to yacc -#YFLAGS = -d - -# Ownership and permissions of files installed by 'install' target -#INSTALL_AS_USER = root # User to chown app to -#INSTALL_AS_GROUP = wheel # Group to chgrp app to -#INSTALL_PERMISSIONS = # If set, 'install' chmod's executable to this - -# Options to strip for bundles, apps with bundles, and apps without bundles, -# respectively. -#RELOCATABLE_STRIP_OPTS = -x -u -#DYLD_APP_STRIP_OPTS = -A -n -#APP_STRIP_OPTS = -#TOOL_STRIP_OPTS = -#LIBRARY_STRIP_OPTS = -x -S # Note: -S strips debugging symbols -# (Note: APP_STRIP_OPTS and TOOL_STRIP_OPTS default to empty, but -# developers doing their own dynamic loading should set this to -# $(DYLD_APP_STRIP_OPTS)). -STRIPFLAGS = -x - - -######################################################################### -# Put rules to extend the behavior of the standard Makefiles here. Typical -# user-defined rules are before_install and after_install (please don't -# redefine things like install or app, as they are owned by the top-level -# Makefile API), which are rules that get invoked before and after the install -# target runs. Such rules should be specified with the '::' syntax rather than -# a single colon. - -# a rule with which to install the man page -install-man-page: - install -d $(DSTROOT)/usr/share/man/man5 - install -d $(DSTROOT)/usr/share/man/man8 - install -c -m 444 asl.conf.5 $(DSTROOT)/usr/share/man/man5/asl.conf.5 - install -c -m 444 syslog.conf.5 $(DSTROOT)/usr/share/man/man5/syslog.conf.5 - install -c -m 444 syslogd.8 $(DSTROOT)/usr/share/man/man8/syslogd.8 - -after_install: - mkdir -p $(DSTROOT)/System/Library/LaunchDaemons - install -d $(DSTROOT)/System/Library/LaunchDaemons - install -c -m 444 com.apple.syslogd.plist $(DSTROOT)/System/Library/LaunchDaemons - mkdir -p $(DSTROOT)/usr/share/sandbox - install -m 644 syslogd.sb $(DSTROOT)/usr/share/sandbox diff --git a/syslogd.tproj/Makefile.preamble b/syslogd.tproj/Makefile.preamble deleted file mode 100644 index 890cc27..0000000 --- a/syslogd.tproj/Makefile.preamble +++ /dev/null @@ -1,117 +0,0 @@ -############################################################################### -# NeXT Makefile.preamble Template -# Copyright 1993, NeXT Computer, Inc. -# -# This Makefile is used for configuring the standard app makefiles associated -# with ProjectBuilder. -# -# Use this template to set attributes for a project, sub-project, bundle, or -# palette. Each node in the project's tree of sub-projects and bundles -# should have it's own Makefile.preamble and Makefile.postamble. -# -############################################################################### -## Configure the flags passed to $(CC) here. These flags will also be -## inherited by all nested sub-projects and bundles. Put your -I, -D, -U, and -## -L flags here. To change the default flags that get passed to ${CC} -## (e.g. change -O to -O2), see Makefile.postamble. - -# Flags passed to compiler (in addition to -g, -O, etc) -OTHER_CFLAGS = -DINET6 -I/System/Library/Frameworks/System.framework/PrivateHeaders -# Flags passed to ld (in addition to -ObjC, etc.) -OTHER_LDFLAGS = - -BUNDLELDFLAGS = # use iff project is a bundle -PALETTELDFLAGS = # use iff project is a palette - -## Specify which headers in this project should be published to the outside -## world in a flat header directory given in PUBLIC_HEADER_DIR (which will be -## prepended by DSTROOT, below. Any subset of these public headers can be -## precompiled automatically after installation, with extra user-defined flags. -PUBLIC_HEADER_DIR = -PUBLIC_HEADERS = -PUBLIC_PRECOMPILED_HEADERS = -PUBLIC_PRECOMPILED_HEADERS_CFLAGS = - -## Configure what is linked in at each level here. Libraries are only used in -## the final 'app' linking step. Final 'app' linking is only done via the -## 'app', 'debug', and 'profile' targets when they are invoked for -## the top-level app. - -# Additional libs to link apps against ('app' target) -#OTHER_LIBS = -# Additional libs to link apps against ('debug' target) -OTHER_DEBUG_LIBS = -# Additional libs to link apps against ('profile' target) -OTHER_PROF_LIBS = - -# More 'app' libraries when $(JAPANESE) = "YES" -OTHER_JAPANESE_LIBS = -# More 'debug' libraries when $(JAPANESE) = "YES" -OTHER_JAPANESE_DEBUG_LIBS = -# More 'profile' libs when $(JAPANESE) = "YES" -OTHER_JAPANESE_PROF_LIBS = - -# If this is a bundle, and you *know* the enclosing application will not -# be linking with a library which you require in your bundle code, then -# mention it here so that it gets linked into the bundle. Note that this -# is wasteful but sometimes necessary. -BUNDLE_LIBS = - -## Configure how things get built here. Additional dependencies, sourcefiles, -## derived files, and build order should be specified here. - -# Other dependencies of this project -OTHER_PRODUCT_DEPENDS = -# Built *before* building subprojects/bundles -OTHER_INITIAL_TARGETS = -# Other source files maintained by .pre/postamble -OTHER_SOURCEFILES = -# Additional files to be removed by `make clean' -OTHER_GARBAGE = -# Precompiled headers to be built before any compilation occurs (e.g., draw.p) -PRECOMPS = - -# Targets to be built before installation -OTHER_INSTALL_DEPENDS = - -# A virtual root directory (other than /) to be prepended to the $(INSTALLDIR) -# passed from ProjectBuilder. -DSTROOT = - -# Set the following to "YES" if you want the old behavior of recursively -# cleaning all nested subprojects during 'make clean'. -CLEAN_ALL_SUBPROJECTS = - -## Add more obscure source files here to cause them to be automatically -## processed by the appropriate tool. Note that these files should also be -## added to "Supporting Files" in ProjectBuilder. The desired .o files that -## result from these files should also be added to OTHER_OFILES above so they -## will be linked in. - -# .msg files that should have msgwrap run on them -MSGFILES = -# .defs files that should have mig run on them -DEFSFILES = - -# .mig files (no .defs files) that should have mig run on them -MIGFILES = - -## Add additional Help directories here (add them to the project as "Other -## Resources" in Project Builder) so that they will be compressed into .store -## files and copied into the app wrapper. If the help directories themselves -## need to also be in the app wrapper, then a cp command will need to be added -## in an after_install target. -OTHER_HELP_DIRS = - -# Don't add more rules here unless you want the first one to be the default -# target for make! Put all your targets in Makefile.postamble. - -# To include a version string, project source must exist in a directory named -# $(NAME).%d[.%d][.%d] and the following line must be uncommented. - -OTHER_GENERATED_OFILES = $(VERS_OFILE) - -# to allow installing man page after main install -AFTER_INSTALL += install-man-page - --include ../Makefile.include diff --git a/syslogd.tproj/PB.project b/syslogd.tproj/PB.project deleted file mode 100644 index 7c3db9e..0000000 --- a/syslogd.tproj/PB.project +++ /dev/null @@ -1,41 +0,0 @@ -{ - DOCICONFILES = (); - FILESTABLE = { - C_FILES = (); - H_FILES = (daemon.h); - OTHER_LIBS = (); - OTHER_LINKED = (asl_action.c, asl_in.c, bsd_in.c, bsd_out.c, daemon.c, klog_in.c, syslogd.c); - OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, com.apple.syslogd.plist, syslogd.8, syslog.conf.5); - PRECOMPILED_HEADERS = (); - PROJECT_HEADERS = (); - PUBLIC_HEADERS = (); - SUBPROJECTS = (); - }; - GENERATEMAIN = YES; - LANGUAGE = English; - LOCALIZABLE_FILES = {}; - NEXTSTEP_BUILDDIR = ""; - NEXTSTEP_BUILDTOOL = /bin/make; - NEXTSTEP_COMPILEROPTIONS = ""; - NEXTSTEP_INSTALLDIR = /usr/sbin; - NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; - NEXTSTEP_LINKEROPTIONS = ""; - NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; - PDO_UNIX_BUILDDIR = ""; - PDO_UNIX_BUILDTOOL = /bin/make; - PDO_UNIX_COMPILEROPTIONS = ""; - PDO_UNIX_INSTALLDIR = /usr/sbin; - PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; - PDO_UNIX_LINKEROPTIONS = ""; - PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; - PROJECTNAME = syslogd; - PROJECTTYPE = Tool; - PROJECTVERSION = 2.8; - WINDOWS_BUILDDIR = ""; - WINDOWS_BUILDTOOL = /bin/make; - WINDOWS_COMPILEROPTIONS = ""; - WINDOWS_INSTALLDIR = /usr/sbin; - WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; - WINDOWS_LINKEROPTIONS = ""; - WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; -} diff --git a/syslogd.tproj/asl.conf.5 b/syslogd.tproj/asl.conf.5 index 5d506b9..8ac5e56 100644 --- a/syslogd.tproj/asl.conf.5 +++ b/syslogd.tproj/asl.conf.5 @@ -1,3 +1,24 @@ +.\"Copyright (c) 2004-2008 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@ +.\" .Dd December 22, 2005 .Dt asl.conf 5 .Os "Mac OS X" diff --git a/syslogd.tproj/asl_action.c b/syslogd.tproj/asl_action.c index 699413f..0462c16 100644 --- a/syslogd.tproj/asl_action.c +++ b/syslogd.tproj/asl_action.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004-2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -34,7 +34,6 @@ #include #include #include -#include #include "daemon.h" #define _PATH_ASL_CONF "/etc/asl.conf" @@ -44,9 +43,6 @@ #define IndexNull ((uint32_t)-1) #define forever for(;;) -#define ACT_STORE_FLAG_STAY_OPEN 0x00000001 -#define ACT_STORE_FLAG_EXCLUDE_ASLDB 0x00000002 - static asl_msg_t *query = NULL; static int reset = 0; @@ -59,13 +55,6 @@ struct action_rule TAILQ_ENTRY(action_rule) entries; }; -struct store_data -{ - asl_store_t *store; - char *path; - uint32_t flags; -}; - static TAILQ_HEAD(cr, action_rule) asl_action_rule; int asl_action_close(); @@ -176,6 +165,7 @@ _parse_line(char *s) return 0; } +#ifdef NOTDEF static char * _next_word(char **s) { @@ -237,6 +227,7 @@ _next_word(char **s) out[len] = '\0'; return out; } +#endif static void _act_notify(struct action_rule *r) @@ -272,64 +263,6 @@ _act_access_control(struct action_rule *r, asl_msg_t *msg) } } -static void -_act_store(struct action_rule *r, asl_msg_t *msg) -{ - struct store_data *sd; - asl_store_t *s; - char *p, *opts; - uint32_t status; - uint64_t msgid; - - if (r == NULL) return; - if (r->options == NULL) return; - if (r->data == NULL) - { - /* Set up store data */ - sd = (struct store_data *)calloc(1, sizeof(struct store_data)); - if (sd == NULL) return; - - opts = r->options; - sd->store = NULL; - sd->path = _next_word(&opts); - if (sd->path == NULL) - { - free(sd); - return; - } - - sd->flags = 0; - while (NULL != (p = _next_word(&opts))) - { - if (!strcmp(p, "stayopen")) sd->flags |= ACT_STORE_FLAG_STAY_OPEN; - else if (!strcmp(p, "exclude_asldb")) sd->flags |= ACT_STORE_FLAG_EXCLUDE_ASLDB; - free(p); - p = NULL; - } - } - else - { - sd = (struct store_data *)r->data; - } - - if (sd->store == NULL) - { - s = NULL; - status = asl_store_open(sd->path, 0, &s); - if (status != ASL_STATUS_OK) return; - if (s == NULL) return; - sd->store = s; - } - - asl_store_save(sd->store, msg, -1, -1, &msgid); - if (!(sd->flags & ACT_STORE_FLAG_STAY_OPEN)) - { - asl_store_close(sd->store); - sd->store = NULL; - } - - if (sd->flags & ACT_STORE_FLAG_EXCLUDE_ASLDB) asl_set(msg, ASL_KEY_IGNORE, "Yes"); -} int asl_action_sendmsg(asl_msg_t *msg, const char *outid) @@ -351,7 +284,6 @@ asl_action_sendmsg(asl_msg_t *msg, const char *outid) if (r->action == NULL) continue; else if (!strcmp(r->action, "access")) _act_access_control(r, msg); else if (!strcmp(r->action, "notify")) _act_notify(r); - else if (!strcmp(r->action, "store")) _act_store(r, msg); } } @@ -404,21 +336,12 @@ int asl_action_close(void) { struct action_rule *r, *n; - struct store_data *sd; n = NULL; for (r = asl_action_rule.tqh_first; r != NULL; r = n) { n = r->entries.tqe_next; - if ((!strcmp(r->action, "store")) && (r->data != NULL)) - { - sd = (struct store_data *)r->data; - if (sd->store != NULL) asl_store_close(sd->store); - if (sd->path != NULL) free(sd->path); - free(r->data); - } - if (r->query != NULL) asl_free(r->query); if (r->action != NULL) free(r->action); if (r->options != NULL) free(r->options); diff --git a/syslogd.tproj/asl_in.c b/syslogd.tproj/asl_in.c index bc5b2b8..d62be08 100644 --- a/syslogd.tproj/asl_in.c +++ b/syslogd.tproj/asl_in.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004-2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -42,15 +42,11 @@ static int sock = -1; static asl_msg_t *query = NULL; -extern int asl_log_filter; - #define MATCH_EOF -1 #define MATCH_NULL 0 #define MATCH_TRUE 1 #define MATCH_FALSE 2 -extern int prune; - extern void db_enqueue(asl_msg_t *m); static int filter_token = -1; @@ -163,7 +159,7 @@ asl_in_acceptmsg(int fd) int aslmod_sendmsg(asl_msg_t *msg, const char *outid) { - const char *vlevel, *facility, *ignore; + const char *vlevel, *facility, *sender, *ignore; uint32_t lmask; uint64_t v64; int status, x, level, log_me; @@ -181,7 +177,7 @@ aslmod_sendmsg(asl_msg_t *msg, const char *outid) status = notify_check(filter_token, &x); if (status == NOTIFY_STATUS_OK) { - v64 = asl_log_filter; + v64 = global.asl_log_filter; status = notify_set_state(filter_token, v64); } if (status != NOTIFY_STATUS_OK) @@ -200,20 +196,23 @@ aslmod_sendmsg(asl_msg_t *msg, const char *outid) { v64 = 0; status = notify_get_state(filter_token, &v64); - if ((status == NOTIFY_STATUS_OK) && (v64 != 0)) asl_log_filter = v64; + if ((status == NOTIFY_STATUS_OK) && (v64 != 0)) global.asl_log_filter = v64; } } - log_me = 0; facility = asl_get(msg, ASL_KEY_FACILITY); + sender = asl_get(msg, ASL_KEY_SENDER); + + log_me = 0; if ((facility != NULL) && (!strcmp(facility, "kern"))) log_me = 1; + else if ((sender != NULL) && (!strcmp(sender, "launchd"))) log_me = 1; else { vlevel = asl_get(msg, ASL_KEY_LEVEL); level = 7; if (vlevel != NULL) level = atoi(vlevel); lmask = ASL_FILTER_MASK(level); - if ((lmask & asl_log_filter) != 0) log_me = 1; + if ((lmask & global.asl_log_filter) != 0) log_me = 1; } if (log_me == 1) @@ -236,13 +235,13 @@ asl_in_init(void) asldebug("%s: init\n", MY_ID); if (sock >= 0) return sock; - if (launch_dict == NULL) + if (global.launch_dict == NULL) { asldebug("%s: laucnchd dict is NULL\n", MY_ID); return -1; } - sockets_dict = launch_data_dict_lookup(launch_dict, LAUNCH_JOBKEY_SOCKETS); + sockets_dict = launch_data_dict_lookup(global.launch_dict, LAUNCH_JOBKEY_SOCKETS); if (sockets_dict == NULL) { asldebug("%s: laucnchd lookup of LAUNCH_JOBKEY_SOCKETS failed\n", MY_ID); @@ -282,7 +281,7 @@ asl_in_init(void) if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rbufsize, len) < 0) { - asldebug("%s: couldn't set receive buffer size for %s: %s\n", MY_ID, sock, _PATH_ASL_IN, strerror(errno)); + asldebug("%s: couldn't set receive buffer size for %d (%s): %s\n", MY_ID, sock, _PATH_ASL_IN, strerror(errno)); close(sock); sock = -1; return -1; @@ -316,7 +315,7 @@ asl_in_close(void) if (filter_token >= 0) notify_cancel(filter_token); filter_token = -1; - asl_log_filter = 0; + global.asl_log_filter = 0; asl_free(query); close(sock); diff --git a/syslogd.tproj/bsd_in.c b/syslogd.tproj/bsd_in.c index 75727fb..9b8a0a0 100644 --- a/syslogd.tproj/bsd_in.c +++ b/syslogd.tproj/bsd_in.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004-2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -68,13 +68,13 @@ bsd_in_init(void) asldebug("%s: init\n", MY_ID); if (sock >= 0) return sock; - if (launch_dict == NULL) + if (global.launch_dict == NULL) { asldebug("%s: laucnchd dict is NULL\n", MY_ID); return -1; } - sockets_dict = launch_data_dict_lookup(launch_dict, LAUNCH_JOBKEY_SOCKETS); + sockets_dict = launch_data_dict_lookup(global.launch_dict, LAUNCH_JOBKEY_SOCKETS); if (sockets_dict == NULL) { asldebug("%s: laucnchd lookup of LAUNCH_JOBKEY_SOCKETS failed\n", MY_ID); diff --git a/syslogd.tproj/bsd_out.c b/syslogd.tproj/bsd_out.c index 7da14d8..6e7bd2a 100644 --- a/syslogd.tproj/bsd_out.c +++ b/syslogd.tproj/bsd_out.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004-2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -55,9 +55,6 @@ static asl_msg_t *query = NULL; static int reset = 0; -extern uint64_t bsd_flush_time; -extern uint64_t bsd_max_dup_time; - struct config_rule { uint32_t count; @@ -76,7 +73,7 @@ struct config_rule static TAILQ_HEAD(cr, config_rule) bsd_out_rule; -extern uint32_t string_hash(const char *s, uint32_t inlen); +extern uint32_t asl_core_string_hash(const char *s, uint32_t inlen); int bsd_out_close(); static int _parse_config_file(const char *); @@ -699,12 +696,12 @@ _syslog_send(asl_msg_t *msg, struct config_rule *r, char **out, char **fwd, time /* check if message is a duplicate of the last message, and inside the dup time window */ is_dup = 0; - if ((bsd_max_dup_time > 0) && (*out != NULL) && (r->last_msg != NULL)) + if ((global.bsd_max_dup_time > 0) && (*out != NULL) && (r->last_msg != NULL)) { - msg_hash = string_hash(*out + 16, strlen(*out + 16)); + msg_hash = asl_core_string_hash(*out + 16, strlen(*out + 16)); if ((r->last_hash == msg_hash) && (!strcmp(r->last_msg, *out + 16))) { - if ((now - r->last_time) < bsd_max_dup_time) is_dup = 1; + if ((now - r->last_time) < global.bsd_max_dup_time) is_dup = 1; } } @@ -880,7 +877,7 @@ bsd_out_sendmsg(asl_msg_t *msg, const char *outid) fwd = NULL; tick = time(NULL); - bsd_flush_time = 0; + global.bsd_flush_time = 0; for (r = bsd_out_rule.tqh_first; r != NULL; r = r->entries.tqe_next) { @@ -888,11 +885,11 @@ bsd_out_sendmsg(asl_msg_t *msg, const char *outid) if ((r->type == DST_TYPE_FILE) && (r->last_count > 0)) { delta = tick - r->last_time; - if (delta < bsd_max_dup_time) + if (delta < global.bsd_max_dup_time) { - delta = bsd_max_dup_time - delta; - if (bsd_flush_time == 0) bsd_flush_time = delta; - else if (delta < bsd_flush_time) bsd_flush_time = delta; + delta = global.bsd_max_dup_time - delta; + if (global.bsd_flush_time == 0) global.bsd_flush_time = delta; + else if (delta < global.bsd_flush_time) global.bsd_flush_time = delta; } } } @@ -904,14 +901,12 @@ bsd_out_sendmsg(asl_msg_t *msg, const char *outid) } void -bsd_flush_duplicates() +bsd_flush_duplicates(time_t now) { struct config_rule *r; - time_t tick; uint64_t delta; - tick = time(NULL); - bsd_flush_time = 0; + global.bsd_flush_time = 0; for (r = bsd_out_rule.tqh_first; r != NULL; r = r->entries.tqe_next) { @@ -919,12 +914,12 @@ bsd_flush_duplicates() if (r->last_count > 0) { - delta = tick - r->last_time; - if (delta < bsd_max_dup_time) + delta = now - r->last_time; + if (delta < global.bsd_max_dup_time) { - delta = bsd_max_dup_time - delta; - if (bsd_flush_time == 0) bsd_flush_time = delta; - else if (delta < bsd_flush_time) bsd_flush_time = delta; + delta = global.bsd_max_dup_time - delta; + if (global.bsd_flush_time == 0) global.bsd_flush_time = delta; + else if (delta < global.bsd_flush_time) global.bsd_flush_time = delta; } else { diff --git a/syslogd.tproj/daemon.c b/syslogd.tproj/daemon.c index bfa7e45..06b7451 100644 --- a/syslogd.tproj/daemon.c +++ b/syslogd.tproj/daemon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004-2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -57,11 +57,6 @@ extern void disaster_message(asl_msg_t *m); static char myname[MAXHOSTNAMELEN + 1] = {0}; -extern const char *debug_file; -extern int debug; -extern time_t utmp_ttl; -extern time_t fs_ttl; -extern int kfd; static pthread_mutex_t event_lock = PTHREAD_MUTEX_INITIALIZER; @@ -332,7 +327,7 @@ aslmsg_verify(struct aslevent *e, asl_msg_t *msg, int32_t *kern_post_level) *kern_post_level = -1; kern = 0; - if ((e != NULL) && (e->fd == kfd)) kern = 1; + if ((e != NULL) && (e->fd == global.kfd)) kern = 1; /* Time */ now = time(NULL); @@ -463,14 +458,14 @@ aslmsg_verify(struct aslevent *e, asl_msg_t *msg, int32_t *kern_post_level) /* 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 + utmp_ttl); + snprintf(buf, sizeof(buf), "%lu", tick + global.utmp_ttl); asl_set(msg, ASL_KEY_EXPIRE_TIME, buf); } /* Set DB Expire Time for Filestsrem errors */ if (!strcmp(fac, FSLOG_VAL_FACILITY)) { - snprintf(buf, sizeof(buf), "%lu", tick + fs_ttl); + snprintf(buf, sizeof(buf), "%lu", tick + global.fs_ttl); asl_set(msg, ASL_KEY_EXPIRE_TIME, buf); } @@ -670,17 +665,17 @@ asldebug(const char *str, ...) int status; FILE *dfp; - if (debug == 0) return 0; + if (global.debug == 0) return 0; dfp = stderr; - if (debug_file != NULL) dfp = fopen(debug_file, "a"); + if (global.debug_file != NULL) dfp = fopen(global.debug_file, "a"); if (dfp == NULL) return 0; va_start(v, str); status = vfprintf(dfp, str, v); va_end(v); - if (debug_file != NULL) fclose(dfp); + if (global.debug_file != NULL) fclose(dfp); return status; } @@ -1018,6 +1013,7 @@ launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t se if (priority < ASL_LEVEL_EMERG) priority = ASL_LEVEL_EMERG; if (priority > ASL_LEVEL_DEBUG) priority = ASL_LEVEL_DEBUG; snprintf(str, sizeof(str), "%d", priority); + asl_set(m, ASL_KEY_LEVEL, str); /* Time */ @@ -1057,7 +1053,10 @@ launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t se } /* Sender */ - if (from_name != NULL) asl_set(m, ASL_KEY_SENDER, from_name); + if (from_name != NULL) + { + asl_set(m, ASL_KEY_SENDER, from_name); + } /* ReadUID */ if (sender_uid != 0) @@ -1069,14 +1068,23 @@ launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t se /* Reference Process */ if (about_name != NULL) { - if ((from_name != NULL) && (strcmp(from_name, about_name) != 0)) asl_set(m, ASL_KEY_REF_PROC, about_name); + if ((from_name != NULL) && (strcmp(from_name, about_name) != 0)) + { + asl_set(m, ASL_KEY_REF_PROC, about_name); + } } /* Session */ - if (session_name != NULL) asl_set(m, ASL_KEY_SESSION, session_name); + if (session_name != NULL) + { + asl_set(m, ASL_KEY_SESSION, session_name); + } /* Message */ - if (msg != NULL) asl_set(m, ASL_KEY_MSG, msg); + if (msg != NULL) + { + asl_set(m, ASL_KEY_MSG, msg); + } /* set retain count */ m->type |= 0x10; diff --git a/syslogd.tproj/daemon.h b/syslogd.tproj/daemon.h index 5aa0198..73a5732 100644 --- a/syslogd.tproj/daemon.h +++ b/syslogd.tproj/daemon.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004-2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -30,12 +30,16 @@ #include #include #include +#include +#include +#include #include #include #define ADDFD_FLAGS_LOCAL 0x00000001 #define ASL_DB_NOTIFICATION "com.apple.system.logger.message" +#define SELF_DB_NOTIFICATION "self.logger.message" #define ASL_KEY_READ_UID "ReadUID" #define ASL_KEY_READ_GID "ReadGID" @@ -48,16 +52,45 @@ #define _PATH_PIDFILE "/var/run/syslog.pid" #define _PATH_ASL_IN "/var/run/asl_input" -#define _PATH_ASL_DIR "/var/log" -#define _PATH_ASL_DB "/var/log/asl.db" #define _PATH_SYSLOG_CONF "/etc/syslog.conf" #define _PATH_SYSLOG_IN "/var/run/syslog" #define _PATH_KLOG "/dev/klog" #define _PATH_MODULE_LIB "/usr/lib/asl" +#define DB_TYPE_FILE 0x00000001 +#define DB_TYPE_MEMORY 0x00000002 +#define DB_TYPE_MINI 0x00000004 + #define KERN_DISASTER_LEVEL 3 -extern launch_data_t launch_dict; +struct global_s +{ + int asl_log_filter; + int restart; + int debug; + int disaster_occurred; + mach_port_t server_port; + launch_data_t launch_dict; + const char *debug_file; + int dbtype; + int did_store_sweep; + time_t start_time; + uint32_t db_file_max; + uint32_t db_memory_max; + uint32_t db_mini_max; + int kfd; + uint64_t bsd_flush_time; + uint64_t asl_store_ping_time; + uint64_t bsd_max_dup_time; + time_t utmp_ttl; + time_t fs_ttl; + asl_store_t *file_db; + asl_memory_t *memory_db; + asl_mini_memory_t *mini_db; + asl_mini_memory_t *disaster_db; +}; + +extern struct global_s global; struct module_list { @@ -100,9 +133,7 @@ int asl_syslog_faciliy_name_to_num(const char *fac); const char *asl_syslog_faciliy_num_to_name(int num); asl_msg_t *asl_input_parse(const char *in, int len, char *rhost, int flag); -uint32_t db_prune(aslresponse query); -uint32_t db_archive(time_t cut, uint64_t max); -uint32_t db_compact(void); +void db_ping_store(time_t now); /* message refcount utilities */ uint32_t asl_msg_type(asl_msg_t *m); diff --git a/syslogd.tproj/dbserver.c b/syslogd.tproj/dbserver.c index a900355..e1329b9 100644 --- a/syslogd.tproj/dbserver.c +++ b/syslogd.tproj/dbserver.c @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2007-2008 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + #include #include #include @@ -9,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -20,14 +44,12 @@ #include #include #include -#include +#include #include "daemon.h" #define forever for(;;) #define LIST_SIZE_DELTA 256 -#define MAX_PRE_DISASTER_COUNT 64 -#define MAX_DISASTER_COUNT LIST_SIZE_DELTA #define SEND_NOTIFICATION 0xfadefade @@ -35,31 +57,17 @@ #define SEARCH_FORWARD 1 #define SEARCH_BACKWARD -1 -static asl_store_t *store = NULL; -static int disaster_occurred = 0; - -extern mach_port_t server_port; -extern int archive_enable; -extern uint64_t db_curr_size; -extern uint64_t db_curr_empty; - static pthread_mutex_t db_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t queue_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t queue_cond = PTHREAD_COND_INITIALIZER; extern char *asl_list_to_string(asl_search_result_t *list, uint32_t *outlen); extern asl_search_result_t *asl_list_from_string(const char *buf); - -static time_t last_archive_sod = 0; +extern boolean_t asl_ipc_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP); static asl_search_result_t work_queue = {0, 0, NULL}; -static asl_search_result_t disaster_log = {0, 0, NULL}; -extern boolean_t asl_ipc_server -( - mach_msg_header_t *InHeadP, - mach_msg_header_t *OutHeadP -); +static time_t file_sweep_last = 0; typedef union { @@ -110,22 +118,19 @@ list_append_msg(asl_search_result_t *list, asl_msg_t *msg, uint32_t retain) } void -disaster_message(asl_msg_t *m) +db_ping_store(time_t now) { - uint32_t i; + time_t delta; - if (disaster_occurred == 0) + if ((global.dbtype & DB_TYPE_FILE) && (global.file_db != NULL)) { - /* retain last MAX_PRE_DISASTER_COUNT messages */ - while (disaster_log.count >= MAX_PRE_DISASTER_COUNT) + delta = now - file_sweep_last; + if (delta >= global.asl_store_ping_time) { - asl_msg_release(disaster_log.msg[0]); - for (i = 1; i < disaster_log.count; i++) disaster_log.msg[i - 1] = disaster_log.msg[i]; - disaster_log.count--; + asl_store_sweep_file_cache(global.file_db); + file_sweep_last = now; } } - - if (disaster_log.count < MAX_DISASTER_COUNT) list_append_msg(&disaster_log, m, 1); } void @@ -167,6 +172,79 @@ db_dequeue(uint32_t *count) return work; } +void +db_asl_open() +{ + uint32_t status; + struct stat sb; + + if ((global.dbtype & DB_TYPE_FILE) && (global.file_db == NULL)) + { + memset(&sb, 0, sizeof(struct stat)); + if (stat(PATH_ASL_STORE, &sb) == 0) + { + /* must be a directory */ + if ((sb.st_mode & S_IFDIR) == 0) + { + asldebug("error: %s is not a directory", PATH_ASL_STORE); + return; + } + } + else + { + if (errno == ENOENT) + { + /* /var/log/asl doesn't exist - create it */ + if (mkdir(PATH_ASL_STORE, 0755) != 0) + { + asldebug("error: can't create data store %s: %s\n", PATH_ASL_STORE, strerror(errno)); + return; + } + } + else + { + /* stat failed for some other reason */ + asldebug("error: can't stat data store %s: %s\n", PATH_ASL_STORE, strerror(errno)); + return; + } + } + + status = asl_store_open_write(NULL, &(global.file_db)); + if (status != ASL_STATUS_OK) + { + asldebug("asl_store_open_write: %s\n", asl_core_error(status)); + } + else + { + if (global.db_file_max != 0) asl_store_max_file_size(global.file_db, global.db_file_max); + } + + if (global.did_store_sweep == 0) + { + status = asl_store_signal_sweep(global.file_db); + if (status == ASL_STATUS_OK) global.did_store_sweep = 1; + } + } + + if ((global.dbtype & DB_TYPE_MEMORY) && (global.memory_db == NULL)) + { + status = asl_memory_open(global.db_memory_max, &(global.memory_db)); + if (status != ASL_STATUS_OK) + { + asldebug("asl_memory_open: %s\n", asl_core_error(status)); + } + } + + if ((global.dbtype & DB_TYPE_MINI) && (global.mini_db == NULL)) + { + status = asl_mini_memory_open(global.db_mini_max, &(global.mini_db)); + if (status != ASL_STATUS_OK) + { + asldebug("asl_mini_memory_open: %s\n", asl_core_error(status)); + } + } +} + /* * Takes messages off the work queue and saves them in the database. * Runs in it's own thread. @@ -184,7 +262,7 @@ db_worker() if (msg == NULL) return; msg->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSGH_BITS_ZERO); - msg->header.msgh_remote_port = server_port; + msg->header.msgh_remote_port = global.server_port; msg->header.msgh_local_port = MACH_PORT_NULL; msg->header.msgh_size = sizeof(mach_msg_empty_send_t); msg->header.msgh_id = SEND_NOTIFICATION; @@ -198,43 +276,81 @@ db_worker() pthread_mutex_lock(&db_lock); - if (store == NULL) + db_asl_open(); + + for (i = 0; i < count; i++) { - status = asl_store_open(_PATH_ASL_DB, 0, &store); - if (status != ASL_STATUS_OK) + if (global.dbtype & DB_TYPE_FILE) { - disaster_occurred = 1; - store = NULL; - } - } + status = asl_store_save(global.file_db, work[i]); + if (status != ASL_STATUS_OK) + { + /* write failed - reopen & retry */ + asldebug("asl_store_save: %s\n", asl_core_error(status)); + asl_store_close(global.file_db); + global.file_db = NULL; - for (i = 0; (i < count) && (store != NULL); i++) - { - msgid = 0; - status = ASL_STATUS_OK; + db_asl_open(); + status = asl_store_save(global.file_db, work[i]); + if (status != ASL_STATUS_OK) + { + asldebug("(retry) asl_store_save: %s\n", asl_core_error(status)); + asl_store_close(global.file_db); + global.file_db = NULL; + + global.dbtype |= DB_TYPE_MEMORY; + if (global.memory_db == NULL) + { + status = asl_memory_open(global.db_memory_max, &(global.memory_db)); + if (status != ASL_STATUS_OK) + { + asldebug("asl_memory_open: %s\n", asl_core_error(status)); + } + } + } + } + } - status = asl_store_save(store, work[i], -1, -1, &msgid); - if (status != ASL_STATUS_OK) + if (global.dbtype & DB_TYPE_MEMORY) { - /* write failed - reopen store */ - asl_store_close(store); - store = NULL; - - status = asl_store_open(_PATH_ASL_DB, 0, &store); + msgid = 0; + status = asl_memory_save(global.memory_db, work[i], &msgid); if (status != ASL_STATUS_OK) { - disaster_occurred = 1; - store = NULL; + /* save failed - reopen & retry*/ + asldebug("asl_memory_save: %s\n", asl_core_error(status)); + asl_memory_close(global.memory_db); + global.memory_db = NULL; + + db_asl_open(); + msgid = 0; + status = asl_memory_save(global.memory_db, work[i], &msgid); + if (status != ASL_STATUS_OK) + { + asldebug("(retry) asl_memory_save: %s\n", asl_core_error(status)); + asl_memory_close(global.memory_db); + global.memory_db = NULL; + } } + } - /* if the store re-opened, retry the save */ - if (store != NULL) + if (global.dbtype & DB_TYPE_MINI) + { + status = asl_mini_memory_save(global.mini_db, work[i], &msgid); + if (status != ASL_STATUS_OK) { - status = asl_store_save(store, work[i], -1, -1, &msgid); + /* save failed - reopen & retry*/ + asldebug("asl_mini_memory_save: %s\n", asl_core_error(status)); + asl_mini_memory_close(global.mini_db); + global.mini_db = NULL; + + db_asl_open(); + status = asl_mini_memory_save(global.mini_db, work[i], &msgid); if (status != ASL_STATUS_OK) { - disaster_occurred = 1; - store = NULL; + asldebug("(retry) asl_memory_save: %s\n", asl_core_error(status)); + asl_mini_memory_close(global.mini_db); + global.mini_db = NULL; } } } @@ -246,15 +362,6 @@ db_worker() } } - db_curr_size = 0; - db_curr_empty = 0; - - if (store != NULL) - { - db_curr_size = (store->record_count + 1) * DB_RECORD_LEN; - db_curr_empty = store->empty_count * DB_RECORD_LEN; - } - pthread_mutex_unlock(&db_lock); for (i = 0; i < count; i++) asl_msg_release(work[i]); @@ -264,37 +371,23 @@ db_worker() } } -static char * -disaster_query(aslresponse query, uint32_t *outlen) +void +disaster_message(asl_msg_t *msg) { - asl_search_result_t res; - uint32_t i, j, match; - char *out; - - if (outlen == NULL) return NULL; - *outlen = 0; - - if ((query == NULL) || ((query != NULL) && (query->count == 0))) return asl_list_to_string(&disaster_log, outlen); + uint64_t msgid; + uint32_t status; - memset(&res, 0, sizeof(asl_search_result_t)); + msgid = 0; - for (i = 0; i < disaster_log.count; i++) + if ((global.dbtype & DB_TYPE_MINI) == 0) { - match = 1; - - for (j = 0; (j < query->count) && (match == 1); j++) + if (global.mini_db == NULL) { - match = asl_msg_cmp(query->msg[j], disaster_log.msg[i]); + status = asl_mini_memory_open(global.db_mini_max, &(global.mini_db)); + if (status != ASL_STATUS_OK) asldebug("asl_mini_memory_open: %s\n", asl_core_error(status)); + else asl_mini_memory_save(global.mini_db, msg, &msgid); } - - if (match == 1) list_append_msg(&res, disaster_log.msg[i], 0); } - - if (res.count == 0) return NULL; - - out = asl_list_to_string((aslresponse)&res, outlen); - free(res.msg); - return out; } /* @@ -312,138 +405,19 @@ db_query(aslresponse query, aslresponse *res, uint64_t startid, int count, int f pthread_mutex_lock(&db_lock); - if (store == NULL) - { - status = asl_store_open(_PATH_ASL_DB, 0, &store); - if (status != ASL_STATUS_OK) store = NULL; - } + status = ASL_STATUS_FAILED; - status = asl_store_match(store, query, res, lastid, startid, ucount, dir, ruid, rgid); + if (global.dbtype & DB_TYPE_MEMORY) status = asl_memory_match(global.memory_db, query, res, lastid, startid, ucount, dir, ruid, rgid); + else status = asl_mini_memory_match(global.mini_db, query, res, lastid, startid, ucount, dir); pthread_mutex_unlock(&db_lock); return status; } -/* - * Prune the database. - */ -uint32_t -db_prune(aslresponse query) -{ - uint32_t status; - - if (disaster_occurred == 1) return ASL_STATUS_FAILED; - - pthread_mutex_lock(&db_lock); - - if (store == NULL) - { - status = asl_store_open(_PATH_ASL_DB, 0, &store); - if (status != ASL_STATUS_OK) store = NULL; - } - - status = asl_store_prune(store, query); - - pthread_mutex_unlock(&db_lock); - - return status; -} - -/* - * Database archiver - */ -uint32_t -db_archive(time_t cut, uint64_t max_size) -{ - time_t sod; - struct tm ctm; - char *archive_file_name; - uint32_t status; - - archive_file_name = NULL; - memset(&ctm, 0, sizeof(struct tm)); - - if (localtime_r((const time_t *)&cut, &ctm) == NULL) return ASL_STATUS_FAILED; - - if (archive_enable != 0) - { - asprintf(&archive_file_name, "%s/asl.%d.%02d.%02d.archive", _PATH_ASL_DIR, ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday); - if (archive_file_name == NULL) return ASL_STATUS_NO_MEMORY; - } - - ctm.tm_sec = 0; - ctm.tm_min = 0; - ctm.tm_hour = 0; - - sod = mktime(&ctm); - - /* if the day changed, archive message received before the start of the day */ - if (sod > last_archive_sod) - { - last_archive_sod = sod; - status = db_archive(sod - 1, 0); - /* NB return status not checked */ - } - - pthread_mutex_lock(&db_lock); - - if (store == NULL) - { - status = asl_store_open(_PATH_ASL_DB, 0, &store); - if (status != ASL_STATUS_OK) store = NULL; - } - - status = asl_store_archive(store, cut, archive_file_name); - if (status == ASL_STATUS_OK) status = asl_store_compact(store); - if ((status == ASL_STATUS_OK) && (max_size > 0)) status = asl_store_truncate(store, max_size, archive_file_name); - - db_curr_size = 0; - db_curr_empty = 0; - - if (store != NULL) - { - db_curr_size = (store->record_count + 1) * DB_RECORD_LEN; - db_curr_empty = store->empty_count * DB_RECORD_LEN; - } - - pthread_mutex_unlock(&db_lock); - - if (archive_file_name != NULL) free(archive_file_name); - - return status; -} - -uint32_t -db_compact(void) -{ - uint32_t status; - - pthread_mutex_lock(&db_lock); - - if (store == NULL) - { - status = asl_store_open(_PATH_ASL_DB, 0, &store); - if (status != ASL_STATUS_OK) - { - pthread_mutex_unlock(&db_lock); - return status; - } - } - - status = asl_store_compact(store); - - db_curr_size = (store->record_count + 1) * DB_RECORD_LEN; - db_curr_empty = store->empty_count * DB_RECORD_LEN; - - pthread_mutex_unlock(&db_lock); - - return status; -} - /* * Receives messages on the "com.apple.system.logger" mach port. - * Services database search and pruning requests. + * Services database search requests. * Runs in it's own thread. */ void @@ -481,6 +455,7 @@ database_server() if ((now.tv_sec > send_time.tv_sec) || ((now.tv_sec == send_time.tv_sec) && (now.tv_usec > send_time.tv_usec))) { notify_post(ASL_DB_NOTIFICATION); + notify_post(SELF_DB_NOTIFICATION); send_time.tv_sec = 0; send_time.tv_usec = 0; snooze = 0; @@ -495,7 +470,7 @@ database_server() request = (asl_request_msg *)calloc(1, rqs); if (request == NULL) continue; - request->head.msgh_local_port = server_port; + request->head.msgh_local_port = global.server_port; request->head.msgh_size = rqs; memset(reply, 0, rps); @@ -503,7 +478,7 @@ database_server() flags = rbits; if (snooze != 0) flags |= MACH_RCV_TIMEOUT; - kstatus = mach_msg(&(request->head), flags, 0, rqs, server_port, snooze, MACH_PORT_NULL); + kstatus = mach_msg(&(request->head), flags, 0, rqs, global.server_port, snooze, MACH_PORT_NULL); if (request->head.msgh_id == SEND_NOTIFICATION) { if (send_time.tv_sec == 0) @@ -530,17 +505,17 @@ database_server() 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 + 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 ) { aslresponse query; @@ -554,33 +529,19 @@ __asl_server_query vm_deallocate(mach_task_self(), (vm_address_t)request, requestCnt); res = NULL; - /* - * If the database went offline (i.e. the filesystem died), - * just search the disaster_log messages. - */ - if (disaster_occurred == 1) + *status = db_query(query, &res, startid, count, flags, lastid, token->val[0], token->val[1]); + + aslresponse_free(query); + if (*status != ASL_STATUS_OK) { - out = NULL; - outlen = 0; - out = disaster_query(query, &outlen); - aslresponse_free(query); + if (res != NULL) aslresponse_free(res); + return KERN_SUCCESS; } - else - { - *status = db_query(query, &res, startid, count, flags, lastid, token->val[0], token->val[1]); - aslresponse_free(query); - if (*status != ASL_STATUS_OK) - { - if (res != NULL) aslresponse_free(res); - return KERN_SUCCESS; - } - - out = NULL; - outlen = 0; - out = asl_list_to_string((asl_search_result_t *)res, &outlen); - aslresponse_free(res); - } + out = NULL; + outlen = 0; + out = asl_list_to_string((asl_search_result_t *)res, &outlen); + aslresponse_free(res); if ((out == NULL) || (outlen == 0)) return KERN_SUCCESS; @@ -604,17 +565,17 @@ __asl_server_query kern_return_t __asl_server_query_timeout ( - 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 + 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 ) { return __asl_server_query(server, request, requestCnt, startid, count, flags, reply, replyCnt, lastid, status, token); @@ -630,25 +591,5 @@ __asl_server_prune security_token_t *token ) { - aslresponse query; - - *status = ASL_STATUS_OK; - - if (request == NULL) return KERN_SUCCESS; - - query = asl_list_from_string(request); - - vm_deallocate(mach_task_self(), (vm_address_t)request, requestCnt); - - /* only root may prune the database */ - if (token->val[0] != 0) - { - *status = ASL_STATUS_FAILED; - return KERN_SUCCESS; - } - - *status = db_prune(query); - aslresponse_free(query); - return KERN_SUCCESS; } diff --git a/syslogd.tproj/klog_in.c b/syslogd.tproj/klog_in.c index 7a93c2a..92addd5 100644 --- a/syslogd.tproj/klog_in.c +++ b/syslogd.tproj/klog_in.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004-2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -39,8 +39,6 @@ #define MY_ID "klog_in" #define MAXLINE 4096 -int kfd = -1; - static int kx = 0; static char kline[MAXLINE + 1]; @@ -71,24 +69,24 @@ int klog_in_init(void) { asldebug("%s: init\n", MY_ID); - if (kfd >= 0) return kfd; + if (global.kfd >= 0) return global.kfd; - kfd = open(_PATH_KLOG, O_RDONLY, 0); - if (kfd < 0) + global.kfd = open(_PATH_KLOG, O_RDONLY, 0); + if (global.kfd < 0) { asldebug("%s: couldn't open %s: %s\n", MY_ID, _PATH_KLOG, strerror(errno)); return -1; } - if (fcntl(kfd, F_SETFL, O_NONBLOCK) < 0) + if (fcntl(global.kfd, F_SETFL, O_NONBLOCK) < 0) { - close(kfd); - kfd = -1; - asldebug("%s: couldn't set O_NONBLOCK for fd %d (%s): %s\n", MY_ID, kfd, _PATH_KLOG, strerror(errno)); + close(global.kfd); + global.kfd = -1; + asldebug("%s: couldn't set O_NONBLOCK for fd %d (%s): %s\n", MY_ID, global.kfd, _PATH_KLOG, strerror(errno)); return -1; } - return aslevent_addfd(kfd, ADDFD_FLAGS_LOCAL, klog_in_acceptmsg, NULL, NULL); + return aslevent_addfd(global.kfd, ADDFD_FLAGS_LOCAL, klog_in_acceptmsg, NULL, NULL); } int @@ -100,10 +98,10 @@ klog_in_reset(void) int klog_in_close(void) { - if (kfd < 0) return 1; + if (global.kfd < 0) return 1; - close(kfd); - kfd = -1; + close(global.kfd); + global.kfd = -1; return 0; } diff --git a/syslogd.tproj/remote.c b/syslogd.tproj/remote.c new file mode 100644 index 0000000..520c6f6 --- /dev/null +++ b/syslogd.tproj/remote.c @@ -0,0 +1,900 @@ +/* + * Copyright (c) 2004-2008 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "daemon.h" + +#define forever for(;;) + +#define MY_ID "remote" +#define MAXLINE 4096 +#define LOCKDOWN_PATH "/var/run/lockdown" +#define SYSLOG_SOCK_PATH "/var/run/lockdown/syslog.sock" +#define ASL_REMOTE_PORT 203 + +#define PRINT_STD 0 +#define PRINT_RAW 1 + +#define MAXSOCK 1 + +static int rfd4 = -1; +static int rfd6 = -1; +static int rfdl = -1; + +#ifdef NSS32 +typedef uint32_t notify_state_t; +extern int notify_set_state(int, notify_state_t); +#else +typedef uint64_t notify_state_t; +#endif + +extern char *asl_list_to_string(asl_search_result_t *list, uint32_t *outlen); +extern size_t asl_memory_size(asl_memory_t *s); +extern uint32_t db_query(aslresponse query, aslresponse *res, uint64_t startid, int count, int flags, uint64_t *lastid, int32_t ruid, int32_t rgid); + +#define SESSION_WRITE(f,x) if (write(f, x, strlen(x)) < 0) goto exit_session + +uint32_t +remote_db_size(uint32_t sel) +{ + if (sel == DB_TYPE_FILE) return global.db_file_max; + if (sel == DB_TYPE_MEMORY) return global.db_memory_max; + if (sel == DB_TYPE_MINI) return global.db_mini_max; + return 0; +} + +uint32_t +remote_db_set_size(uint32_t sel, uint32_t size) +{ + if (sel == DB_TYPE_FILE) global.db_file_max = size; + if (sel == DB_TYPE_MEMORY) global.db_memory_max = size; + if (sel == DB_TYPE_MINI) global.db_mini_max = size; + return 0; +} + +asl_msg_t * +remote_db_stats(uint32_t sel) +{ + asl_msg_t *m; + m = NULL; + + if (sel == DB_TYPE_FILE) asl_store_statistics(global.file_db, &m); + if (sel == DB_TYPE_MEMORY) asl_memory_statistics(global.memory_db, &m); + if (sel == DB_TYPE_MINI) asl_mini_memory_statistics(global.mini_db, &m); + return m; +} + +void +session(void *x) +{ + int i, *sp, s, wfd, status, pfmt, watch, wtoken, nfd, do_prompt, filter; + aslresponse res; + asl_search_result_t ql; + uint32_t outlen; + asl_msg_t *stats; + asl_msg_t *query; + asl_msg_t *qlq[1]; + char str[1024], *p, *qs, *out; + ssize_t len; + fd_set readfds; + uint64_t low_id, high_id; + notify_state_t nstate; + uint32_t dbselect; + + if (x == NULL) pthread_exit(NULL); + + sp = (int *)x; + s = *sp; + free(x); + + watch = 0; + wfd = -1; + wtoken = -1; + + dbselect = 0; + if (global.dbtype & DB_TYPE_MEMORY) dbselect = DB_TYPE_MEMORY; + else if (global.dbtype & DB_TYPE_MINI) dbselect = DB_TYPE_MINI; + else if (global.dbtype & DB_TYPE_FILE) dbselect = DB_TYPE_FILE; + + low_id = 0; + high_id = 0; + + pfmt = PRINT_STD; + query = NULL; + memset(&ql, 0, sizeof(asl_search_result_t)); + + snprintf(str, sizeof(str) - 1, "\n========================\nASL is here to serve you\n"); + if (write(s, str, strlen(str)) < 0) + { + close(s); + pthread_exit(NULL); + return; + } + + do_prompt = 1; + + forever + { + if (do_prompt > 0) + { + snprintf(str, sizeof(str) - 1, "> "); + SESSION_WRITE(s, str); + } + + do_prompt = 1; + memset(str, 0, sizeof(str)); + + FD_ZERO(&readfds); + FD_SET(s, &readfds); + nfd = s; + + if (wfd != -1) + { + FD_SET(wfd, &readfds); + if (wfd > nfd) nfd = wfd; + } + + status = select(nfd + 1, &readfds, NULL, NULL, NULL); + + if ((wfd != -1) && (FD_ISSET(wfd, &readfds))) + { + len = read(wfd, &i, sizeof(int)); + } + + if (FD_ISSET(s, &readfds)) + { + len = read(s, str, sizeof(str) - 1); + if (len <= 0) goto exit_session; + + while ((len > 1) && ((str[len - 1] == '\n') || (str[len - 1] == '\r'))) + { + str[len - 1] = '\0'; + len--; + } + + if ((!strcmp(str, "q")) || (!strcmp(str, "quit")) || (!strcmp(str, "exit"))) + { + snprintf(str, sizeof(str) - 1, "Goodbye\n"); + write(s, str, strlen(str)); + close(s); + s = -1; + break; + } + + if ((!strcmp(str, "?")) || (!strcmp(str, "help"))) + { + snprintf(str, sizeof(str) - 1, "Commands\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " quit exit session\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " select [val] get [set] current database\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " val must be \"file\", \"mem\", or \"mini\"\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " file [on/off] enable / disable file store\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " memory [on/off] enable / disable memory store\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " mini [on/off] enable / disable mini memory store\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " stats database statistics\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " flush flush database\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " dbsize [val] get [set] database size (# of records)\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " filter [val] get [set] current database filter\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " [p]anic (emergency) [a]lert [c]ritical [e]rror\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " [w]arning [n]otice [i]nfo [d]ebug\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " watch print new messages as they arrive\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " stop stop watching for new messages\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " raw use raw format for printing messages\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " std use standard format for printing messages\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " * show all log messages\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " * key val equality search for messages (single key/value pair)\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " * op key val search for matching messages (single key/value pair)\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " * [op key val] ... search for matching messages (multiple key/value pairs)\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " operators: = < > ! (not equal) T (key exists) R (regex)\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " modifiers (must follow operator):\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, " C=casefold N=numeric S=substring A=prefix Z=suffix\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, "\n"); + SESSION_WRITE(s, str); + continue; + } + else if (!strcmp(str, "stats")) + { + stats = remote_db_stats(dbselect); + out = asl_format_message(stats, ASL_MSG_FMT_RAW, ASL_TIME_FMT_SEC, ASL_ENCODE_NONE, &outlen); + write(s, out, outlen); + free(out); + asl_free(stats); + continue; + } + else if (!strcmp(str, "flush")) + {} + else if (!strncmp(str, "select", 6)) + { + p = str + 6; + while ((*p == ' ') || (*p == '\t')) p++; + if (*p == '\0') + { + if (dbselect == 0) snprintf(str, sizeof(str) - 1, "no store\n"); + else if (dbselect == DB_TYPE_FILE) snprintf(str, sizeof(str) - 1, "file store\n"); + else if (dbselect == DB_TYPE_MEMORY) snprintf(str, sizeof(str) - 1, "memory store\n"); + else if (dbselect == DB_TYPE_MINI) snprintf(str, sizeof(str) - 1, "mini memory store\n"); + SESSION_WRITE(s, str); + continue; + } + + if (!strncmp(p, "file", 4)) + { + if ((global.dbtype & DB_TYPE_FILE) == 0) + { + snprintf(str, sizeof(str) - 1, "file database is not enabled\n"); + SESSION_WRITE(s, str); + continue; + } + + dbselect = DB_TYPE_FILE; + } + else if (!strncmp(p, "mem", 3)) + { + if ((global.dbtype & DB_TYPE_MEMORY) == 0) + { + snprintf(str, sizeof(str) - 1, "memory database is not enabled\n"); + SESSION_WRITE(s, str); + continue; + } + + dbselect = DB_TYPE_MEMORY; + } + else if (!strncmp(p, "mini", 4)) + { + if ((global.dbtype & DB_TYPE_MINI) == 0) + { + if (global.mini_db != NULL) + { + snprintf(str, sizeof(str) - 1, "mini memory database is enabled for disaster messages\n"); + SESSION_WRITE(s, str); + } + else + { + snprintf(str, sizeof(str) - 1, "mini memory database is not enabled\n"); + SESSION_WRITE(s, str); + continue; + } + } + + dbselect = DB_TYPE_MINI; + } + else + { + snprintf(str, sizeof(str) - 1, "unknown database type\n"); + SESSION_WRITE(s, str); + continue; + } + + snprintf(str, sizeof(str) - 1, "OK\n"); + SESSION_WRITE(s, str); + continue; + } + else if (!strncmp(str, "file", 4)) + { + p = str + 4; + while ((*p == ' ') || (*p == '\t')) p++; + if (*p == '\0') + { + snprintf(str, sizeof(str) - 1, "file database is %senabled\n", (global.dbtype & DB_TYPE_FILE) ? "" : "not "); + SESSION_WRITE(s, str); + if ((global.dbtype & DB_TYPE_FILE) != 0) dbselect = DB_TYPE_FILE; + continue; + } + + if (!strcmp(p, "on")) global.dbtype |= DB_TYPE_FILE; + else if (!strcmp(p, "off")) global.dbtype &= ~ DB_TYPE_FILE; + + snprintf(str, sizeof(str) - 1, "OK\n"); + SESSION_WRITE(s, str); + continue; + } + else if (!strncmp(str, "memory", 6)) + { + p = str + 6; + while ((*p == ' ') || (*p == '\t')) p++; + if (*p == '\0') + { + snprintf(str, sizeof(str) - 1, "memory database is %senabled\n", (global.dbtype & DB_TYPE_MEMORY) ? "" : "not "); + SESSION_WRITE(s, str); + if ((global.dbtype & DB_TYPE_MEMORY) != 0) dbselect = DB_TYPE_MEMORY; + continue; + } + + if (!strcmp(p, "on")) global.dbtype |= DB_TYPE_MEMORY; + else if (!strcmp(p, "off")) global.dbtype &= ~ DB_TYPE_MEMORY; + + snprintf(str, sizeof(str) - 1, "OK\n"); + SESSION_WRITE(s, str); + continue; + } + else if (!strncmp(str, "mini", 4)) + { + p = str + 4; + while ((*p == ' ') || (*p == '\t')) p++; + if (*p == '\0') + { + snprintf(str, sizeof(str) - 1, "mini database is %senabled\n", (global.dbtype & DB_TYPE_MINI) ? "" : "not "); + SESSION_WRITE(s, str); + if ((global.dbtype & DB_TYPE_MINI) != 0) dbselect = DB_TYPE_MINI; + continue; + } + + if (!strcmp(p, "on")) global.dbtype |= DB_TYPE_MINI; + else if (!strcmp(p, "off")) global.dbtype &= ~ DB_TYPE_MINI; + + snprintf(str, sizeof(str) - 1, "OK\n"); + SESSION_WRITE(s, str); + continue; + } + else if (!strncmp(str, "dbsize", 6)) + { + if (dbselect == 0) + { + snprintf(str, sizeof(str) - 1, "no store\n"); + SESSION_WRITE(s, str); + continue; + } + + p = str + 6; + while ((*p == ' ') || (*p == '\t')) p++; + if (*p == '\0') + { + snprintf(str, sizeof(str) - 1, "DB size %u\n", remote_db_size(dbselect)); + SESSION_WRITE(s, str); + continue; + } + + i = atoi(p); + remote_db_set_size(dbselect, i); + + snprintf(str, sizeof(str) - 1, "OK\n"); + SESSION_WRITE(s, str); + continue; + } + else if (!strncmp(str, "filter", 6)) + { + p = str + 6; + while ((*p == ' ') || (*p == '\t')) p++; + if (*p == '\0') + { + snprintf(str, sizeof(str) - 1, "%s%s%s%s%s%s%s%s\n", + (global.asl_log_filter & ASL_FILTER_MASK_EMERG) ? "p" : "", + (global.asl_log_filter & ASL_FILTER_MASK_ALERT) ? "a" : "", + (global.asl_log_filter & ASL_FILTER_MASK_CRIT) ? "c" : "", + (global.asl_log_filter & ASL_FILTER_MASK_ERR) ? "e" : "", + (global.asl_log_filter & ASL_FILTER_MASK_WARNING) ? "w" : "", + (global.asl_log_filter & ASL_FILTER_MASK_NOTICE) ? "n" : "", + (global.asl_log_filter & ASL_FILTER_MASK_INFO) ? "i" : "", + (global.asl_log_filter & ASL_FILTER_MASK_DEBUG) ? "d" : ""); + SESSION_WRITE(s, str); + continue; + } + + filter = 0; + if ((*p >= '0') && (*p <= '7')) + { + i = atoi(p); + filter = ASL_FILTER_MASK_UPTO(i); + } + else + { + while (*p != '\0') + { + if ((*p == 'p') || (*p == 'P')) filter |= ASL_FILTER_MASK_EMERG; + else if ((*p == 'a') || (*p == 'A')) filter |= ASL_FILTER_MASK_ALERT; + else if ((*p == 'c') || (*p == 'C')) filter |= ASL_FILTER_MASK_CRIT; + else if ((*p == 'e') || (*p == 'E')) filter |= ASL_FILTER_MASK_ERR; + else if ((*p == 'w') || (*p == 'W')) filter |= ASL_FILTER_MASK_WARNING; + else if ((*p == 'n') || (*p == 'N')) filter |= ASL_FILTER_MASK_NOTICE; + else if ((*p == 'i') || (*p == 'I')) filter |= ASL_FILTER_MASK_INFO; + else if ((*p == 'd') || (*p == 'D')) filter |= ASL_FILTER_MASK_DEBUG; + p++; + } + } + + status = notify_register_check(NOTIFY_SYSTEM_ASL_FILTER, &i); + if (status != NOTIFY_STATUS_OK) + { + snprintf(str, sizeof(str) - 1, "FAILED %d\n", status); + SESSION_WRITE(s, str); + } + else + { + nstate = filter; + status = notify_set_state(i, nstate); + if (status != NOTIFY_STATUS_OK) + { + snprintf(str, sizeof(str) - 1, "FAILED %d\n", status); + SESSION_WRITE(s, str); + continue; + } + + status = notify_post(NOTIFY_SYSTEM_ASL_FILTER); + notify_cancel(i); + + global.asl_log_filter = filter; + + snprintf(str, sizeof(str) - 1, "OK\n"); + SESSION_WRITE(s, str); + } + + continue; + } + else if (!strcmp(str, "stop")) + { + if (watch == 1) + { + watch = 0; + notify_cancel(wtoken); + wfd = -1; + wtoken = -1; + + low_id = 0; + high_id = 0; + + if (query != NULL) free(query); + query = NULL; + + snprintf(str, sizeof(str) - 1, "OK\n"); + SESSION_WRITE(s, str); + continue; + } + + snprintf(str, sizeof(str) - 1, "not watching!\n"); + SESSION_WRITE(s, str); + continue; + } + else if (!strcmp(str, "raw")) + { + pfmt = PRINT_RAW; + continue; + } + else if (!strcmp(str, "std")) + { + pfmt = PRINT_STD; + continue; + } + else if (!strcmp(str, "watch")) + { + if (watch == 1) + { + snprintf(str, sizeof(str) - 1, "already watching!\n"); + SESSION_WRITE(s, str); + continue; + } + + status = notify_register_file_descriptor(SELF_DB_NOTIFICATION, &wfd, 0, &wtoken); + if (status != 0) + { + snprintf(str, sizeof(str) - 1, "notify_register_file_descriptor failed: %d\n", status); + SESSION_WRITE(s, str); + continue; + } + + watch = 1; + + snprintf(str, sizeof(str) - 1, "OK\n"); + SESSION_WRITE(s, str); + do_prompt = 2; + } + else if ((str[0] == '*') || (str[0] == 'T') || (str[0] == '=') || (str[0] == '!') || (str[0] == '<') || (str[0] == '>')) + { + memset(&ql, 0, sizeof(asl_search_result_t)); + if (query != NULL) free(query); + query = NULL; + + p = str; + if (*p == '*') p++; + while ((*p == ' ') || (*p == '\t')) p++; + + if (*p == '\0') + { + /* NULL query */ + } + else if (*p == '[') + { + qs = NULL; + asprintf(&qs, "Q %s", p); + query = asl_msg_from_string(qs); + free(qs); + } + else if ((*p == 'T') || (*p == '=') || (*p == '!') || (*p == '<') || (*p == '>') || (*p == 'R')) + { + qs = NULL; + asprintf(&qs, "Q [%s]", p); + query = asl_msg_from_string(qs); + free(qs); + } + else + { + qs = NULL; + asprintf(&qs, "Q [= %s]", p); + query = asl_msg_from_string(qs); + free(qs); + } + } + else + { + snprintf(str, sizeof(str) - 1, "unrecognized command\n"); + SESSION_WRITE(s, str); + snprintf(str, sizeof(str) - 1, "enter \"help\" for help\n"); + SESSION_WRITE(s, str); + continue; + } + } + + if (query != NULL) + { + ql.count = 1; + qlq[0] = query; + ql.msg = qlq; + } + + if (watch == 0) low_id = 0; + + memset(&res, 0, sizeof(aslresponse)); + high_id = 0; + status = db_query(&ql, (aslresponse *)&res, low_id, 0, 0, &high_id, 0, 0); + + if ((watch == 1) && (high_id >= low_id)) low_id = high_id + 1; + + if (res == NULL) + { + if (watch == 0) + { + snprintf(str, sizeof(str) - 1, "-nil-\n"); + SESSION_WRITE(s, str); + } + else + { + if (do_prompt != 2) do_prompt = 0; + } + } + else if (pfmt == PRINT_RAW) + { + if (watch == 1) + { + snprintf(str, sizeof(str) - 1, "\n"); + SESSION_WRITE(s, str); + } + + outlen = 0; + out = asl_list_to_string((asl_search_result_t *)res, &outlen); + write(s, out, outlen); + free(out); + + snprintf(str, sizeof(str) - 1, "\n"); + SESSION_WRITE(s, str); + } + else + { + if (watch == 1) + { + snprintf(str, sizeof(str) - 1, "\n"); + SESSION_WRITE(s, str); + } + + for (i = 0; i < res->count; i++) + { + out = asl_format_message(res->msg[i], ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_ENCODE_SAFE, &outlen); + write(s, out, outlen); + free(out); + } + } + + aslresponse_free(res); + } + +exit_session: + + if (s >= 0) + { + close(s); + s = -1; + } + + if (watch == 1) notify_cancel(wtoken); + if (query != NULL) asl_free(query); + pthread_exit(NULL); +} + +asl_msg_t * +remote_acceptmsg(int fd, int tcp) +{ + socklen_t fromlen; + int s, status, flags, *sp; + pthread_attr_t attr; + pthread_t t; + struct sockaddr_storage from; + + fromlen = sizeof(struct sockaddr_un); + if (tcp == 1) fromlen = sizeof(struct sockaddr_storage); + + memset(&from, 0, sizeof(from)); + + s = accept(fd, (struct sockaddr *)&from, &fromlen); + if (s == -1) + { + asldebug("%s: accept: %s\n", MY_ID, strerror(errno)); + return NULL; + } + + flags = fcntl(s, F_GETFL, 0); + flags &= ~ O_NONBLOCK; + status = fcntl(s, F_SETFL, flags); + if (status < 0) + { + asldebug("%s: fcntl: %s\n", MY_ID, strerror(errno)); + close(s); + return NULL; + } + + if (tcp == 1) + { + flags = 1; + setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(int)); + } + + sp = malloc(sizeof(int)); + if (sp == NULL) + { + asldebug("%s: malloc: %s\n", MY_ID, strerror(errno)); + close(s); + return NULL; + } + + *sp = s; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&t, &attr, (void *(*)(void *))session, (void *)sp); + pthread_attr_destroy(&attr); + + return NULL; +} + +asl_msg_t * +remote_acceptmsg_local(int fd) +{ + return remote_acceptmsg(fd, 0); +} + +asl_msg_t * +remote_acceptmsg_tcp(int fd) +{ + return remote_acceptmsg(fd, 1); +} + +int +remote_init_lockdown(void) +{ + int status, reuse, fd; + struct sockaddr_un local; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) + { + asldebug("%s: socket: %s\n", MY_ID, strerror(errno)); + return -1; + } + + reuse = 1; + status = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(int)); + if (status < 0) + { + asldebug("%s: setsockopt: %s\n", MY_ID, strerror(errno)); + close(fd); + return -1; + } + + /* make sure the lockdown directory exists */ + mkdir(LOCKDOWN_PATH, 0777); + + memset(&local, 0, sizeof(local)); + local.sun_family = AF_UNIX; + strlcpy(local.sun_path, SYSLOG_SOCK_PATH, sizeof(local.sun_path)); + unlink(local.sun_path); + + status = bind(fd, (struct sockaddr *)&local, sizeof(local.sun_family) + sizeof(local.sun_path)); + + if (status < 0) + { + asldebug("%s: bind: %s\n", MY_ID, strerror(errno)); + close(fd); + return -1; + } + + status = fcntl(fd, F_SETFL, O_NONBLOCK); + if (status < 0) + { + asldebug("%s: fcntl: %s\n", MY_ID, strerror(errno)); + close(fd); + return -1; + } + + status = listen(fd, 5); + if (status < 0) + { + asldebug("%s: listen: %s\n", MY_ID, strerror(errno)); + close(fd); + return -1; + } + + chmod(SYSLOG_SOCK_PATH, 0666); + + aslevent_addfd(fd, 0, remote_acceptmsg_local, NULL, NULL); + return fd; +} + +int +remote_init_tcp(int family) +{ + int status, reuse, fd; + struct sockaddr_in a4; + struct sockaddr_in6 a6; + struct sockaddr *s; + socklen_t len; + + fd = socket(family, SOCK_STREAM, 0); + if (fd < 0) + { + asldebug("%s: socket: %s\n", MY_ID, strerror(errno)); + return -1; + } + + reuse = 1; + status = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(int)); + if (status < 0) + { + asldebug("%s: setsockopt: %s\n", MY_ID, strerror(errno)); + close(fd); + return -1; + } + + memset(&(a4.sin_addr), 0, sizeof(struct in_addr)); + a4.sin_family = AF_INET; + a4.sin_port = htons(ASL_REMOTE_PORT); + + memset(&(a6.sin6_addr), 0, sizeof(struct in6_addr)); + a6.sin6_family = AF_INET6; + a6.sin6_port = htons(ASL_REMOTE_PORT); + + s = (struct sockaddr *)&a4; + len = sizeof(struct sockaddr_in); + + if (family == AF_INET6) + { + s = (struct sockaddr *)&a6; + len = sizeof(struct sockaddr_in6); + } + + status = bind(fd, s, len); + if (status < 0) + { + asldebug("%s: bind: %s\n", MY_ID, strerror(errno)); + close(fd); + return -1; + } + + status = fcntl(fd, F_SETFL, O_NONBLOCK); + if (status < 0) + { + asldebug("%s: fcntl: %s\n", MY_ID, strerror(errno)); + close(fd); + return -1; + } + + status = listen(fd, 5); + if (status < 0) + { + asldebug("%s: listen: %s\n", MY_ID, strerror(errno)); + close(fd); + return -1; + } + + aslevent_addfd(fd, 0, remote_acceptmsg_tcp, NULL, NULL); + return fd; +} + +int +remote_init(void) +{ + asldebug("%s: init\n", MY_ID); + +#ifdef LOCKDOWN + rfdl = remote_init_lockdown(); +#endif + +#ifdef REMOTE_IPV4 + rfd4 = remote_init_tcp(AF_INET); +#endif + +#ifdef REMOTE_IPV6 + rfd6 = remote_init_tcp(AF_INET6); +#endif + + return 0; +} + +int +remote_close(void) +{ + if (rfdl >= 0) close(rfdl); + rfdl = -1; + + if (rfd4 >= 0) close(rfd4); + rfd4 = -1; + + if (rfd6 >= 0) close(rfd6); + rfd6 = -1; + + return 0; +} + +int +remote_reset(void) +{ + remote_close(); + return remote_init(); +} diff --git a/syslogd.tproj/syslogd.8 b/syslogd.tproj/syslogd.8 index 2b355fd..b428167 100644 --- a/syslogd.tproj/syslogd.8 +++ b/syslogd.tproj/syslogd.8 @@ -1,30 +1,23 @@ -.\" Copyright (c) 2004 Apple Computer -.\" All rights reserved. +.\"Copyright (c) 2004-2008 Apple Inc. All rights reserved. .\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 4. Neither the name of Apple Computer nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. +.\"@APPLE_LICENSE_HEADER_START@ .\" -.\" THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. +.\"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@ .\" .Dd October 18, 2004 .Dt SYSLOGD 8 @@ -39,9 +32,6 @@ .Op Fl m Ar mark_interval .Op Fl c Ar log_cutoff .Op Fl l Ar lib_path -.Op Fl a -.Op Fl ttl Ar time -.Op Fl sweep Ar time .Op Fl db_max Ar size .Op Fl utmp_ttl Ar time .Op Fl fs_ttl Ar time @@ -62,15 +52,16 @@ The Apple System Log facility comprises the .Xr asl 3 API, a new .Nm -server, and the +server, the .Xr syslog 1 -command-line utility. +command-line utility, and a data store file manager, +.Xr aslmanager 8 . The system supports structured and extensible messages, permitting advanced message browsing and management through search APIs and other components of the Apple system log facility. .Pp Log messages are retained in a data store, -subject to pruning, automatic archival, and input filtering as described below, +subject to automatic archival, and input filtering as described below, to simplify the task of locating log messages and to facilitate browsing and searching. The data store is intended to become a replacement for the numerous log files that are currently found in various locations on the system. @@ -97,7 +88,10 @@ this is not normally required. Set the number of minutes between .Dq mark messages. -The default is 20 minutes. +Mark messages are normally disabled. +If +.Fl m +is specified with no arguments, mark messages will be written every 20 minutes. The .Dq mark facility is disabled if the setting is zero minutes. @@ -134,30 +128,12 @@ Specifies an alternate path for loading plug-in modules. By default, .Nm checks for plug-in modules in the directory /usr/lib/asl. -.It Fl a -Enables message archival. -Messages older than 24 hours (or as otherwise set using -.Fl ttl ) -will be copied to an archive database when they expire from the active database. -Archive databases are named /var/log/asl.yyyy.mm.dd.archive, and may be read or -searched using the -.Xr syslog 1 -command. -.It Fl ttl -Sets the time-to-live in seconds for messages in the active database. -Expired messages are removed or copied to an archive database if archival is enabled. -.It Fl sweep -Sets the interval (in seconds) for a periodic database operation that removes and -(optionally) archives expired messages. .It Fl db_max -Sets a size limit in bytes for the active database. -The size of the database is reduced by deleting oldest messages. -Deleted messages will be archived if archival is enabled. -When the database reaches its size limit, it is reduced to approximately 90% of the allowed maximum size. -This allows the database to grow for some time before the next size-reduction. +Sets the size limit in bytes for files in the data store. The default value for .Fl db_max is 25600000 bytes. +Files are closed upon reaching the maximum size, and a new file is opened for subsequent messages. .It Fl utmp_ttl Sets the time-to-live in seconds for messages used by the .Xr utmp , @@ -166,19 +142,17 @@ and .Xr lastlog subsystems. The default is 31622400 seconds (approximately 1 year). -Note that if archival is enabled, these messages will be copied to an archive file -after the regular time-to-live interval (24 hours, or as set using -.Fl ttl ) -but will persist in the active database until their own expiry time. +Note that if archival is enabled (see the +.Xr aslmanager 8 +manual), these messages will be copied to an archive +after the regular time-to-live interval, but will persist in the data store until their own expiry time. .It Fl fs_ttl Sets the time-to-live in seconds for filesystem error messages generated by the kernel. The default is 31622400 seconds (approximately 1 year). As in the case of -.Fl utmp_tt , -if archival is enabled, these messages will be copied to an archive file -after the regular time-to-live interval (24 hours, or as set using -.Fl ttl ) -but will persist in the active database until their own expiry time. +.Fl utmp_ttl , +if archival is enabled, these messages will be copied to an archive after the regular time-to-live +interval but will persist in the data store until their own expiry time. .It Fl dup_delay Sets the time to delay for coalescing duplicate message in log files. If a process logs multiple messages with the same text, @@ -280,58 +254,30 @@ option. .El .Pp .Nm -initializes its built-in modules and loads plug-ins during its start-up. -The data store is pruned approximately 5 minutes after startup. -.Pp -.Nm reinitializes in response to a HUP signal. .Sh MESSAGE EXPIRY AND ARCHIVAL .Nm -periodically removes messages from the active database, optionally copying them to an archival database. -Archival is enabled if the -.Fl a -flag is supplied. -By default, messages are removed or archived after they are 24 hours old. -The maximum age of messages in the active database may be set as the value for the -.Fl ttl -flag. -The message expiry operation runs once an hour by default, but the interval may be changed as the value for the -.Fl sweep -flag. -.Pp -After the database sweep operation, +periodically invokes the +.Nm aslmanager +utility, which manages files in the ASL data store. +Files are removed or optionally copied to an archival directory after a (default) 2 day time-to-live. +See the +.Xr aslmanager 8 +manual for details. .Nm -optionally can check the size of the database, and may be configured to remove additional messages -to limit the size of the database. -The maximum size of the database (in bytes) may be specified using the +invokes +.Nm aslmanager +shortly after it starts up, at midnight local time if it is running, +and any time that a data store file reaches the .Fl db_max -option. -If messages must be removed to limit the database size, oldest messages are removed first. -By default there is no database size limit. -.Pp -Log messages from the -.Xr utmp , -.Xr wtmp , -and -.Xr lastlog -subsystems record login, logout, shutdowns, and reboots. -These log messages are given a longer time-to-live in the active database. -The default time-to-live for these messages is 31622400 seconds (approximately one year). -This value may be changed using the -.Fl utmp_ttl -flag. -If archival is enabled, a copy of these messages will be archived at the end of the -regular time-to-live interval (24 hours, or as specified using -.Fl ttl ). -The messages will persist in the active database until their own time-to-live has expired. -.Sh DATABASE SECURITY -The data store file /var/log/asl.db is only readable by processes with UID 0. -Messages in the data store may have a read UID and GID, -so that only processes with the specified UID or GID can fetch those messages when using -.Nm asl_search . +size limit. +.Sh DATA STORE SECURITY +Messages saved in the ASL message store are written to files in /var/log/asl. +The message files are given read access controls corresponding to the read UID and GID specified in the messages themselves. Read access UID and GID settings may be attached to messages using the .Xr asl 3 library by setting a value for the "ReadUID" and/or "ReadGID" message keys. +The file permissions prevent access-controlled messages from being read by unauthorized users. .Pp Although clients are generally free to use any value for the "Facility" message key, only processes running with UID 0 may log messages with a facility value of "com.apple.system", @@ -339,7 +285,7 @@ or with a value that has "com.apple.system" as a prefix. Messages logged by non UID 0 processes that use "com.apple.system" as a facility value or prefix will be saved with the facility value "user". .Sh FILES -.Bl -tag -width /var/run/syslog.pid -compact +.Bl -tag -width /var/log/asl.archive -compact .It Pa /etc/syslog.conf bsd_out module configuration file .It Pa /etc/asl.conf @@ -352,6 +298,10 @@ name of the domain datagram log socket .It Pa /dev/klog kernel log device +.It Pa /var/log/asl +data store directory +.It Pa /var/log/asl.archive +default archive directory .El .Sh SEE ALSO .Xr syslog 1 , diff --git a/syslogd.tproj/syslogd.c b/syslogd.tproj/syslogd.c index c348e68..230655a 100644 --- a/syslogd.tproj/syslogd.c +++ b/syslogd.tproj/syslogd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004-2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -49,11 +49,8 @@ #define SERVER_STATUS_ON_DEMAND 2 #define DEFAULT_MARK_SEC 0 -#define DEFAULT_SWEEP_SEC 3600 -#define DEFAULT_FIRST_SWEEP_SEC 300 #define DEFAULT_UTMP_TTL_SEC 31622400 #define DEFAULT_FS_TTL_SEC 31622400 -#define DEFAULT_TTL_SEC 86400 #define DEFAULT_BSD_MAX_DUP_SEC 30 #define BILLION 1000000000 @@ -65,46 +62,18 @@ #define forever for(;;) static int reset = 0; -static double mach_time_factor = 1.0; - -static TAILQ_HEAD(ml, module_list) Moduleq; - -/* global */ -int asl_log_filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE); -int archive_enable = 0; -int restart = 0; -int debug = 0; -mach_port_t server_port = MACH_PORT_NULL; -launch_data_t launch_dict; -const char *debug_file = NULL; +static uint64_t time_start = 0; +static uint64_t mark_last = 0; +static uint64_t mark_time = 0; +static uint64_t time_last = 0; extern int __notify_78945668_info__; extern int _malloc_no_asl_log; -/* monitor the database */ -uint64_t db_max_size = 25600000; -uint64_t db_curr_size = 0; -uint64_t db_shrink_size; -uint64_t db_curr_empty = 0; -uint64_t db_max_empty; - -/* kernel log fd */ -extern int kfd; - -/* timers */ -uint64_t time_last = 0; -uint64_t time_start = 0; -uint64_t mark_last = 0; -uint64_t mark_time = 0; -uint64_t sweep_last = 0; -uint64_t sweep_time = DEFAULT_SWEEP_SEC; -uint64_t first_sweep_delay = DEFAULT_FIRST_SWEEP_SEC; -uint64_t bsd_flush_time = 0; -uint64_t bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC; - -time_t utmp_ttl = DEFAULT_UTMP_TTL_SEC; -time_t fs_ttl = DEFAULT_FS_TTL_SEC; -time_t ttl = DEFAULT_TTL_SEC; +static TAILQ_HEAD(ml, module_list) Moduleq; + +/* global */ +struct global_s global; /* Static Modules */ int asl_in_init(); @@ -132,6 +101,11 @@ int bsd_out_reset(); int bsd_out_close(); static int activate_bsd_out = 1; +int remote_init(); +int remote_reset(); +int remote_close(); +static int activate_remote = 0; + int udp_in_init(); int udp_in_reset(); int udp_in_close(); @@ -140,7 +114,7 @@ static int activate_udp_in = 1; extern void database_server(); extern void db_worker(); extern void launchd_drain(); -extern void bsd_flush_duplicates(); +extern void bsd_flush_duplicates(time_t now); /* * Module approach: only one type of module. This module may implement @@ -256,6 +230,25 @@ static_modules() TAILQ_INSERT_TAIL(&Moduleq, tmp, entries); } + if (activate_remote != 0) + { + tmp = calloc(1, sizeof(struct module_list)); + if (tmp == NULL) return 1; + + tmp->name = strdup("remote"); + if (tmp->name == NULL) + { + free(tmp); + return 1; + } + + tmp->module = NULL; + tmp->init = remote_init; + tmp->reset = remote_reset; + tmp->close = remote_close; + TAILQ_INSERT_TAIL(&Moduleq, tmp, entries); + } + if (activate_udp_in != 0) { tmp = calloc(1, sizeof(struct module_list)); @@ -399,15 +392,10 @@ send_reset(void) static void timed_events(struct timeval **run) { - uint64_t nanonow, now, delta, t; + uint64_t now, delta, t; static struct timeval next; - double d; - nanonow = mach_absolute_time(); - d = nanonow; - d = d * mach_time_factor; - nanonow = d; - now = nanonow / 1000000000; + now = time(NULL); *run = NULL; next.tv_sec = 0; @@ -419,9 +407,6 @@ timed_events(struct timeval **run) time_start = now; time_last = now; mark_last = now; - - /* fake sweep_last so that we plan to run first_sweep_delay seconds after startup */ - sweep_last = (now - sweep_time) + first_sweep_delay; } /* @@ -443,57 +428,32 @@ timed_events(struct timeval **run) * Reset "last" times to current time. */ time_last = now; - sweep_last = now; mark_last = now; } /* - * Run database archiver. + * Tickle bsd_out module to flush duplicates. */ - if (sweep_time > 0) + if (global.bsd_flush_time > 0) { - delta = now - sweep_last; - if (delta >= sweep_time) + bsd_flush_duplicates(now); + if (global.bsd_flush_time > 0) { - db_archive(time(NULL) - ttl, db_shrink_size); - sweep_last = now; - t = sweep_time; + if (next.tv_sec == 0) next.tv_sec = global.bsd_flush_time; + else if (global.bsd_flush_time < next.tv_sec) next.tv_sec = global.bsd_flush_time; } - else - { - t = sweep_time - delta; - } - - if (next.tv_sec == 0) next.tv_sec = t; - else if (t < next.tv_sec) next.tv_sec = t; - } - - /* - * Shrink the database if it's too large. - */ - if (db_curr_size > db_max_size) - { - db_archive(time(NULL) - ttl, db_shrink_size); - } - - /* - * Compact the database if there are too many empty slots. - */ - if (db_curr_empty > db_max_empty) - { - db_compact(); } /* - * Tickle bsd_out module to flush duplicates. + * Tickle asl_store */ - if (bsd_flush_time > 0) + if (global.asl_store_ping_time > 0) { - bsd_flush_duplicates(); - if (bsd_flush_time > 0) + db_ping_store(now); + if (global.asl_store_ping_time > 0) { - if (next.tv_sec == 0) next.tv_sec = bsd_flush_time; - else if (bsd_flush_time < next.tv_sec) next.tv_sec = bsd_flush_time; + if (next.tv_sec == 0) next.tv_sec = global.asl_store_ping_time; + else if (global.asl_store_ping_time < next.tv_sec) next.tv_sec = global.asl_store_ping_time; } } @@ -533,16 +493,16 @@ init_config() kern_return_t status; tmp = launch_data_new_string(LAUNCH_KEY_CHECKIN); - launch_dict = launch_msg(tmp); + global.launch_dict = launch_msg(tmp); launch_data_free(tmp); - if (launch_dict == NULL) + if (global.launch_dict == NULL) { fprintf(stderr, "%d launchd checkin failed\n", getpid()); exit(1); } - tmp = launch_data_dict_lookup(launch_dict, LAUNCH_JOBKEY_MACHSERVICES); + tmp = launch_data_dict_lookup(global.launch_dict, LAUNCH_JOBKEY_MACHSERVICES); if (tmp == NULL) { fprintf(stderr, "%d launchd lookup of LAUNCH_JOBKEY_MACHSERVICES failed\n", getpid()); @@ -556,9 +516,9 @@ init_config() exit(1); } - server_port = launch_data_get_machport(pdict); + global.server_port = launch_data_get_machport(pdict); - status = mach_port_insert_right(mach_task_self(), server_port, server_port, MACH_MSG_TYPE_MAKE_SEND); + status = mach_port_insert_right(mach_task_self(), global.server_port, global.server_port, MACH_MSG_TYPE_MAKE_SEND); if (status != KERN_SUCCESS) fprintf(stderr, "Warning! Can't make send right for server_port: %x\n", status); } @@ -573,40 +533,108 @@ main(int argc, const char *argv[]) pthread_attr_t attr; pthread_t t; int nctoken; - mach_timebase_info_data_t info; - double mtn, mtd; char tstr[32]; time_t now; + memset(&global, 0, sizeof(struct global_s)); + + global.asl_log_filter = ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE); + global.db_file_max = 16384000; + global.db_memory_max = 8192; + global.db_mini_max = 256; + global.bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC; + global.utmp_ttl = DEFAULT_UTMP_TTL_SEC; + global.fs_ttl = DEFAULT_FS_TTL_SEC; + global.kfd = -1; + +#ifdef CONFIG_MAC + global.dbtype = DB_TYPE_FILE; + global.db_file_max = 25600000; + global.asl_store_ping_time = 150; +#endif + +#ifdef CONFIG_APPLETV + global.dbtype = DB_TYPE_FILE; + global.db_file_max = 10240000; +#endif + +#ifdef CONFIG_IPHONE + global.dbtype = DB_TYPE_MINI; + activate_remote = 1; + activate_bsd_out = 0; +#endif + mp = _PATH_MODULE_LIB; daemonize = 0; __notify_78945668_info__ = -1; - _malloc_no_asl_log = 1; /* prevent malloc from calling ASL on error */ - kfd = -1; zto.tv_sec = 0; zto.tv_usec = 0; FD_ZERO(&kern); - debug_file = NULL; - memset(&info, 0, sizeof(mach_timebase_info_data_t)); - mach_timebase_info(&info); + /* prevent malloc from calling ASL on error */ + _malloc_no_asl_log = 1; - mtn = info.numer; - mtd = info.denom; - mach_time_factor = mtn / mtd; + /* first pass sets up default configurations */ + for (i = 1; i < argc; i++) + { + if (streq(argv[i], "-config")) + { + if (((i + 1) < argc) && (argv[i+1][0] != '-')) + { + i++; + if (streq(argv[i], "mac")) + { + global.dbtype = DB_TYPE_FILE; + global.db_file_max = 25600000; + } + else if (streq(argv[i], "appletv")) + { + global.dbtype = DB_TYPE_FILE; + global.db_file_max = 10240000; + } + else if (streq(argv[i], "iphone")) + { + global.dbtype = DB_TYPE_MINI; + activate_remote = 1; + } + } + } + } for (i = 1; i < argc; i++) { if (streq(argv[i], "-d")) { - debug = 1; - if (((i+1) < argc) && (argv[i+1][0] != '-')) debug_file = argv[++i]; + global.debug = 1; + if (((i+1) < argc) && (argv[i+1][0] != '-')) global.debug_file = argv[++i]; memset(tstr, 0, sizeof(tstr)); now = time(NULL); ctime_r(&now, tstr); tstr[19] = '\0'; asldebug("%s syslogd[%d]: Start\n", tstr, getpid()); } + else if (streq(argv[i], "-db")) + { + if (((i + 1) < argc) && (argv[i+1][0] != '-')) + { + i++; + if (streq(argv[i], "file")) + { + global.dbtype |= DB_TYPE_FILE; + if (((i + 1) < argc) && (argv[i+1][0] != '-')) global.db_file_max = atol(argv[++i]); + } + else if (streq(argv[i], "memory")) + { + global.dbtype |= DB_TYPE_MEMORY; + if (((i + 1) < argc) && (argv[i+1][0] != '-')) global.db_memory_max = atol(argv[++i]); + } + else if (streq(argv[i], "mini")) + { + global.dbtype |= DB_TYPE_MINI; + if (((i + 1) < argc) && (argv[i+1][0] != '-')) global.db_mini_max = atol(argv[++i]); + } + } + } else if (streq(argv[i], "-D")) { daemonize = 1; @@ -617,11 +645,11 @@ main(int argc, const char *argv[]) } else if (streq(argv[i], "-utmp_ttl")) { - if ((i + 1) < argc) utmp_ttl = atol(argv[++i]); + if ((i + 1) < argc) global.utmp_ttl = atol(argv[++i]); } else if (streq(argv[i], "-fs_ttl")) { - if ((i + 1) < argc) fs_ttl = atol(argv[++i]); + if ((i + 1) < argc) global.fs_ttl = atol(argv[++i]); } else if (streq(argv[i], "-l")) { @@ -632,28 +660,12 @@ main(int argc, const char *argv[]) if ((i + 1) < argc) { i++; - if ((argv[i][0] >= '0') && (argv[i][0] <= '7') && (argv[i][1] == '\0')) asl_log_filter = ASL_FILTER_MASK_UPTO(atoi(argv[i])); + if ((argv[i][0] >= '0') && (argv[i][0] <= '7') && (argv[i][1] == '\0')) global.asl_log_filter = ASL_FILTER_MASK_UPTO(atoi(argv[i])); } } - else if (streq(argv[i], "-a")) - { - archive_enable = 1; - } - else if (streq(argv[i], "-sweep")) - { - if ((i + 1) < argc) sweep_time = atoll(argv[++i]); - } else if (streq(argv[i], "-dup_delay")) { - if ((i + 1) < argc) bsd_max_dup_time = atoll(argv[++i]); - } - else if (streq(argv[i], "-ttl")) - { - if ((i + 1) < argc) ttl = atol(argv[++i]); - } - else if (streq(argv[i], "-db_max")) - { - if ((i + 1) < argc) db_max_size = atoll(argv[++i]); + if ((i + 1) < argc) global.bsd_max_dup_time = atoll(argv[++i]); } else if (streq(argv[i], "-asl_in")) { @@ -675,21 +687,24 @@ main(int argc, const char *argv[]) { if ((i + 1) < argc) activate_bsd_out = atoi(argv[++i]); } + else if (streq(argv[i], "-remote")) + { + if ((i + 1) < argc) activate_remote = atoi(argv[++i]); + } else if (streq(argv[i], "-udp_in")) { if ((i + 1) < argc) activate_udp_in = atoi(argv[++i]); } } - db_max_empty = db_max_size / 8; - db_shrink_size = db_max_size - (db_max_size / 8); + if (global.dbtype == 0) global.dbtype = DB_TYPE_FILE; TAILQ_INIT(&Moduleq); static_modules(); load_modules(mp); aslevent_init(); - if (debug == 0) + if (global.debug == 0) { if (daemonize != 0) { @@ -738,9 +753,9 @@ main(int argc, const char *argv[]) /* * drain /dev/klog first */ - if (kfd >= 0) + if (global.kfd >= 0) { - max = kfd + 1; + max = global.kfd + 1; while (select(max, &kern, NULL, NULL, &zto) > 0) { aslevent_handleevent(&kern, &wr, &ex); @@ -763,10 +778,10 @@ main(int argc, const char *argv[]) max = aslevent_fdsets(&rd, &wr, &ex) + 1; status = select(max, &rd, &wr, &ex, runloop_timer); - if ((kfd >= 0) && FD_ISSET(kfd, &rd)) + if ((global.kfd >= 0) && FD_ISSET(global.kfd, &rd)) { /* drain /dev/klog */ - max = kfd + 1; + max = global.kfd + 1; while (select(max, &kern, NULL, NULL, &zto) > 0) { diff --git a/syslogd.tproj/udp_in.c b/syslogd.tproj/udp_in.c index e398eab..bc8b52e 100644 --- a/syslogd.tproj/udp_in.c +++ b/syslogd.tproj/udp_in.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004-2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -102,33 +102,33 @@ udp_in_init(void) asldebug("%s: init\n", MY_ID); if (nsock > 0) return 0; - if (launch_dict == NULL) + if (global.launch_dict == NULL) { asldebug("%s: laucnchd dict is NULL\n", MY_ID); return -1; } - sockets_dict = launch_data_dict_lookup(launch_dict, LAUNCH_JOBKEY_SOCKETS); + sockets_dict = launch_data_dict_lookup(global.launch_dict, LAUNCH_JOBKEY_SOCKETS); if (sockets_dict == NULL) { asldebug("%s: laucnchd lookup of LAUNCH_JOBKEY_SOCKETS failed\n", MY_ID); return -1; } - + fd_array = launch_data_dict_lookup(sockets_dict, UDP_SOCKET_NAME); if (fd_array == NULL) { asldebug("%s: laucnchd lookup of UDP_SOCKET_NAME failed\n", MY_ID); return -1; } - + nsock = launch_data_array_get_count(fd_array); if (nsock <= 0) { asldebug("%s: laucnchd fd array is empty\n", MY_ID); return -1; } - + for (i = 0; i < nsock; i++) { fd_dict = launch_data_array_get_index(fd_array, i); @@ -137,7 +137,7 @@ udp_in_init(void) asldebug("%s: laucnchd file discriptor array element 0 is NULL\n", MY_ID); return -1; } - + ufd[i] = launch_data_get_fd(fd_dict); rbufsize = 128 * 1024; diff --git a/util.tproj/Makefile b/util.tproj/Makefile index 8274d83..b477cf0 100644 --- a/util.tproj/Makefile +++ b/util.tproj/Makefile @@ -1,46 +1,19 @@ -# -# Generated by the NeXT Project Builder. -# -# NOTE: Do NOT change this file -- Project Builder maintains it. -# -# Put all of your customizations in files called Makefile.preamble -# and Makefile.postamble (both optional), and Makefile will include them. -# - -NAME = syslog - -PROJECTVERSION = 2.8 -PROJECT_TYPE = Tool - -HFILES = +Project = syslog +ProductType = tool +Install_Dir = /usr/bin CFILES = syslog.c +MANPAGES = syslog.1 -OTHERSRCS = Makefile.preamble Makefile Makefile.postamble syslog.1 - -MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles -CODE_GEN_STYLE = DYNAMIC -MAKEFILE = tool.make -NEXTSTEP_INSTALLDIR = /usr/bin -WINDOWS_INSTALLDIR = /usr/bin -PDO_UNIX_INSTALLDIR = /usr/bin -LIBS = -laslcommon -DEBUG_LIBS = $(LIBS) -PROF_LIBS = $(LIBS) - -NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc -WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc -PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc -NEXTSTEP_JAVA_COMPILER = /usr/bin/javac -WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe -PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac - -include $(MAKEFILEDIR)/platform.make - --include Makefile.preamble - -include $(MAKEFILEDIR)/$(MAKEFILE) +Extra_CC_Flags = -Wall -mdynamic-no-pic \ + -DINET6 \ + -I"$(OBJROOT)"/aslcommon +Extra_LD_Flags = -dead_strip -L"$(SYMROOT)" -laslcommon --include Makefile.postamble +# Determine product configuartion +PRODUCT = $(shell tconf --product) +ifeq ($(PRODUCT),iPhone) +Extra_CC_Flags += -DCONFIG_IPHONE +endif --include Makefile.dependencies +include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make diff --git a/util.tproj/Makefile.postamble b/util.tproj/Makefile.postamble deleted file mode 100644 index 936823b..0000000 --- a/util.tproj/Makefile.postamble +++ /dev/null @@ -1,115 +0,0 @@ -############################################################################### -# NeXT Makefile.postamble Template -# Copyright 1993, NeXT Computer, Inc. -# -# This Makefile is used for configuring the standard app makefiles associated -# with ProjectBuilder. -# -# Use this template to set attributes for a project, sub-project, bundle, or -# palette. Each node in the project's tree of sub-projects and bundles -# should have it's own Makefile.preamble and Makefile.postamble. Additional -# rules (e.g., after_install) that are defined by the developer should be -# defined in this file. -# -############################################################################### -# -# Here are the variables exported by the common "app" makefiles that can be -# used in any customizations you make to the template below: -# -# PRODUCT_ROOT - Name of top-level app-wrapper (e.g., Webster.app) -# OFILE_DIR - Directory into which .o object files are generated. -# (Note that this name is calculated based on the target -# architectures specified in Project Builder). -# DERIVED_SRC_DIR - Directory used for all other derived files -# ALL_CFLAGS - All the flags passed to the cc(1) driver for compilations -# -# NAME - name of application, bundle, subproject, palette, etc. -# LANGUAGE - langage in which the project is written (default "English") -# ENGLISH - boolean flag set iff $(LANGUAGE) = "English" -# JAPANESE - boolean flag set iff $(LANGUAGE) = "Japanese" -# LOCAL_RESOURCES - localized resources (e.g. nib's, images) of project -# GLOBAL_RESOURCES - non-localized resources of project -# PROJECTVERSION - version of ProjectBuilder that output Makefile -# APPICON - application icon file -# DOCICONS - dock icon files -# ICONSECTIONS - Specifies icon sections when linking executable -# -# CLASSES - Class implementation files in project. -# HFILES - Header files in project. -# MFILES - Other Objective-C source files in project. -# CFILES - Other C source files in project. -# PSWFILES - .psw files in the project -# PSWMFILES - .pswm files in the project -# SUBPROJECTS - Subprojects of this project -# BUNDLES - Bundle subprojects of this project -# OTHERSRCS - Other miscellaneous sources of this project -# OTHERLINKED - Source files not matching a standard source extention -# -# LIBS - Libraries to link with when making app target -# DEBUG_LIBS - Libraries to link with when making debug target -# PROF_LIBS - Libraries to link with when making profile target -# OTHERLINKEDOFILES - Other relocatable files to (always) link in. -# -# APP_MAKEFILE_DIR - Directory in which to find generic set of Makefiles -# MAKEFILEDIR - Directory in which to find $(MAKEFILE) -# MAKEFILE - Top level mechanism Makefile (e.g., app.make, bundle.make) -# INSTALLDIR - Directory app will be installed into by 'install' target - - -# Change defaults assumed by the standard app makefiles here. Edit the -# following default values as appropriate. (Note that if no Makefile.postamble -# exists, these values will have defaults set in common.make). - -# Add Makefile.preamble, Makefile.postamble, and Makefile.dependencies here if -# you would like changes to them to invalidate previous builds. The project -# depends on $(MAKEFILES) so that changes to Makefiles will trigger a re-build. -#MAKEFILES = Makefile - -# Optimization flag passed to compiler: -#OPTIMIZATION_CFLAG = -O - -# Flags always passed to compiler: -#COMMON_CFLAGS = $(PROJECT_SPECIFIC_CFLAGS) -g -Wall - -# Flags passed to compiler in normal 'app' compiles: -#NORMAL_CFLAGS = $(COMMON_CFLAGS) $(OPTIMIZATION_CFLAG) - -# Flags passed to compiler in 'debug' compiles: -#DEBUG_CFLAGS = $(COMMON_CFLAGS) -DDEBUG - -# Flags passed to compiler in 'profile' compiles -#PROFILE_CFLAGS = $(COMMON_CFLAGS) -pg $(OPTIMIZATION_CFLAG) -DPROFILE - -# Flags passed to yacc -#YFLAGS = -d - -# Ownership and permissions of files installed by 'install' target -#INSTALL_AS_USER = root # User to chown app to -#INSTALL_AS_GROUP = wheel # Group to chgrp app to -#INSTALL_PERMISSIONS = # If set, 'install' chmod's executable to this - -# Options to strip for bundles, apps with bundles, and apps without bundles, -# respectively. -#RELOCATABLE_STRIP_OPTS = -x -u -#DYLD_APP_STRIP_OPTS = -A -n -#APP_STRIP_OPTS = -#TOOL_STRIP_OPTS = -#LIBRARY_STRIP_OPTS = -x -S # Note: -S strips debugging symbols -# (Note: APP_STRIP_OPTS and TOOL_STRIP_OPTS default to empty, but -# developers doing their own dynamic loading should set this to -# $(DYLD_APP_STRIP_OPTS)). -STRIPFLAGS = -x - - -######################################################################### -# Put rules to extend the behavior of the standard Makefiles here. Typical -# user-defined rules are before_install and after_install (please don't -# redefine things like install or app, as they are owned by the top-level -# Makefile API), which are rules that get invoked before and after the install -# target runs. Such rules should be specified with the '::' syntax rather than -# a single colon. - -# a rule with which to install the man page -install-man-page: - install -d $(DSTROOT)/usr/share/man/man1 - install -c -m 444 syslog.1 $(DSTROOT)/usr/share/man/man1/syslog.1 diff --git a/util.tproj/Makefile.preamble b/util.tproj/Makefile.preamble deleted file mode 100644 index 823c969..0000000 --- a/util.tproj/Makefile.preamble +++ /dev/null @@ -1,117 +0,0 @@ -############################################################################### -# NeXT Makefile.preamble Template -# Copyright 1993, NeXT Computer, Inc. -# -# This Makefile is used for configuring the standard app makefiles associated -# with ProjectBuilder. -# -# Use this template to set attributes for a project, sub-project, bundle, or -# palette. Each node in the project's tree of sub-projects and bundles -# should have it's own Makefile.preamble and Makefile.postamble. -# -############################################################################### -## Configure the flags passed to $(CC) here. These flags will also be -## inherited by all nested sub-projects and bundles. Put your -I, -D, -U, and -## -L flags here. To change the default flags that get passed to ${CC} -## (e.g. change -O to -O2), see Makefile.postamble. - -# Flags passed to compiler (in addition to -g, -O, etc) -OTHER_CFLAGS = -DINET6 -# Flags passed to ld (in addition to -ObjC, etc.) -OTHER_LDFLAGS = - -BUNDLELDFLAGS = # use iff project is a bundle -PALETTELDFLAGS = # use iff project is a palette - -## Specify which headers in this project should be published to the outside -## world in a flat header directory given in PUBLIC_HEADER_DIR (which will be -## prepended by DSTROOT, below. Any subset of these public headers can be -## precompiled automatically after installation, with extra user-defined flags. -PUBLIC_HEADER_DIR = -PUBLIC_HEADERS = -PUBLIC_PRECOMPILED_HEADERS = -PUBLIC_PRECOMPILED_HEADERS_CFLAGS = - -## Configure what is linked in at each level here. Libraries are only used in -## the final 'app' linking step. Final 'app' linking is only done via the -## 'app', 'debug', and 'profile' targets when they are invoked for -## the top-level app. - -# Additional libs to link apps against ('app' target) -#OTHER_LIBS = -# Additional libs to link apps against ('debug' target) -OTHER_DEBUG_LIBS = -# Additional libs to link apps against ('profile' target) -OTHER_PROF_LIBS = - -# More 'app' libraries when $(JAPANESE) = "YES" -OTHER_JAPANESE_LIBS = -# More 'debug' libraries when $(JAPANESE) = "YES" -OTHER_JAPANESE_DEBUG_LIBS = -# More 'profile' libs when $(JAPANESE) = "YES" -OTHER_JAPANESE_PROF_LIBS = - -# If this is a bundle, and you *know* the enclosing application will not -# be linking with a library which you require in your bundle code, then -# mention it here so that it gets linked into the bundle. Note that this -# is wasteful but sometimes necessary. -BUNDLE_LIBS = - -## Configure how things get built here. Additional dependencies, sourcefiles, -## derived files, and build order should be specified here. - -# Other dependencies of this project -OTHER_PRODUCT_DEPENDS = -# Built *before* building subprojects/bundles -OTHER_INITIAL_TARGETS = -# Other source files maintained by .pre/postamble -OTHER_SOURCEFILES = -# Additional files to be removed by `make clean' -OTHER_GARBAGE = -# Precompiled headers to be built before any compilation occurs (e.g., draw.p) -PRECOMPS = - -# Targets to be built before installation -OTHER_INSTALL_DEPENDS = - -# A virtual root directory (other than /) to be prepended to the $(INSTALLDIR) -# passed from ProjectBuilder. -DSTROOT = - -# Set the following to "YES" if you want the old behavior of recursively -# cleaning all nested subprojects during 'make clean'. -CLEAN_ALL_SUBPROJECTS = - -## Add more obscure source files here to cause them to be automatically -## processed by the appropriate tool. Note that these files should also be -## added to "Supporting Files" in ProjectBuilder. The desired .o files that -## result from these files should also be added to OTHER_OFILES above so they -## will be linked in. - -# .msg files that should have msgwrap run on them -MSGFILES = -# .defs files that should have mig run on them -DEFSFILES = - -# .mig files (no .defs files) that should have mig run on them -MIGFILES = - -## Add additional Help directories here (add them to the project as "Other -## Resources" in Project Builder) so that they will be compressed into .store -## files and copied into the app wrapper. If the help directories themselves -## need to also be in the app wrapper, then a cp command will need to be added -## in an after_install target. -OTHER_HELP_DIRS = - -# Don't add more rules here unless you want the first one to be the default -# target for make! Put all your targets in Makefile.postamble. - -# To include a version string, project source must exist in a directory named -# $(NAME).%d[.%d][.%d] and the following line must be uncommented. - -OTHER_GENERATED_OFILES = $(VERS_OFILE) - -# to allow installing man page after main install -AFTER_INSTALL += install-man-page - --include ../Makefile.include diff --git a/util.tproj/PB.project b/util.tproj/PB.project deleted file mode 100644 index 4b81855..0000000 --- a/util.tproj/PB.project +++ /dev/null @@ -1,41 +0,0 @@ -{ - DOCICONFILES = (); - FILESTABLE = { - C_FILES = (); - H_FILES = (); - OTHER_LIBS = (); - OTHER_LINKED = (syslog.c); - OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, syslog.1); - PRECOMPILED_HEADERS = (); - PROJECT_HEADERS = (); - PUBLIC_HEADERS = (); - SUBPROJECTS = (); - }; - GENERATEMAIN = YES; - LANGUAGE = English; - LOCALIZABLE_FILES = {}; - NEXTSTEP_BUILDDIR = ""; - NEXTSTEP_BUILDTOOL = /bin/make; - NEXTSTEP_COMPILEROPTIONS = ""; - NEXTSTEP_INSTALLDIR = /usr/sbin; - NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; - NEXTSTEP_LINKEROPTIONS = ""; - NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; - PDO_UNIX_BUILDDIR = ""; - PDO_UNIX_BUILDTOOL = /bin/make; - PDO_UNIX_COMPILEROPTIONS = ""; - PDO_UNIX_INSTALLDIR = /usr/sbin; - PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; - PDO_UNIX_LINKEROPTIONS = ""; - PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; - PROJECTNAME = syslogd; - PROJECTTYPE = Tool; - PROJECTVERSION = 2.8; - WINDOWS_BUILDDIR = ""; - WINDOWS_BUILDTOOL = /bin/make; - WINDOWS_COMPILEROPTIONS = ""; - WINDOWS_INSTALLDIR = /usr/sbin; - WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; - WINDOWS_LINKEROPTIONS = ""; - WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; -} diff --git a/util.tproj/syslog.1 b/util.tproj/syslog.1 index 6c7924f..e562162 100644 --- a/util.tproj/syslog.1 +++ b/util.tproj/syslog.1 @@ -1,30 +1,23 @@ -.\" Copyright (c) 2004 Apple Computer -.\" All rights reserved. +.\"Copyright (c) 2004-2008 Apple Inc. All rights reserved. .\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 4. Neither the name of Apple Computer nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. +.\"@APPLE_LICENSE_HEADER_START@ .\" -.\" THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. +.\"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@ .\" .Dd October 18, 2004 .Dt SYSLOG 1 @@ -54,27 +47,26 @@ key val .Fl C .D1 "" .Nm -.Op Fl db Op Ar file ... +.Op Fl f Ar file ... +.Op Fl d Ar dir ... .Op Fl w Op Ar n .Op Fl F Ar format .Op Fl T Ar format +.Op Fl E Ar format .Ar expression .D1 "" .Nm -.Op Fl db Op Ar file ... -.Fl x Ar expression -.D1 "" -.Nm -.Op Fl db Op Ar file ... -.Fl p Ar expression +.Op Fl f Ar file ... +.Op Fl d Ar dir ... +.Fl x Ar file Ar expression .D1 "" .Nm .Fl c Ar process Op filter .Sh DESCRIPTION .Nm -is a command-line utility for a variety of tasks relating to the Apple System Log facility. +is a command-line utility for a variety of tasks relating to the Apple System Log (ASL) facility. It provides mechanisms for sending and viewing log messages, -pruning the contents of the log message databases, +copying log messages to ASL format data store files, and for controlling the flow of log messages from client processes. .Pp When invoked with the @@ -99,6 +91,10 @@ option is used, then it must be followed by a list of keys and values. A structured message will be sent to the server with the keys and values given as arguments. If a key or a value has embedded white space, it must be enclosed in quotes. .Pp +Note that the text of the log message should be supplied as a value following the +.Dq Message +key. +.Pp If the .Fl k option is not specified, then the rest of the command line is treated as the message text. @@ -139,6 +135,10 @@ is an alias for If the .Fl l option is omitted, the log level defaults to 7 (Debug). +Note that the log message server +.Nm syslogd +filters messages based on log level. +The default filter for the ASL database excludes Debug and Info level messages. .Pp .Nm only requires one or two leading characters for a level specification. @@ -164,15 +164,17 @@ e.g. .Pp .Dl cat /var/log/system.log .Pp -Another module saves messages in an active database, -and may also be configured to keep archive databases. +Another module saves messages in a data store (/var/log/asl). .Pp If invoked with no arguments, .Nm -sends a query to -.Nm syslogd -to fetch all messages from the active database. -The messages are then printed to standard output, subject to formatting options and character encoding as described below. +fetchs all messages from the active data store. +Messages are then printed to standard output, +subject to formatting options and character encoding as described below. +Some log messages are read-access controlled, +so only messages that are readable by the user running +.Nm +will be fetched and printed. .Pp If invoked with the .Fl C @@ -187,28 +189,42 @@ option is actually an alias for the expression: .Pp See the EXPRESSIONS section below for more details. .Pp -If the system is running in single-user mode, +Individual ASL data store files may be read by providing one or more file names as arguments to the +.Fl f +option. +This may be useful when searching archived files, files on alternate disk volumes, +or files created as export files with the +.Fl x +option. +.Pp +The +.Fl d +option may be followed by a list of directory paths. .Nm -will open the ASL active database file (/var/log/asl.db) directly, rather than queying +will read or search all ASL data store files in those directories. +Any files that are not readable will be skipped. +Specifying +.Fl d +with the name +.Dq archive +will open all readable files in the default ASL archive directory /var/log/asl.archive. +Specifying +.Fl d +with the name +.Dq store +will open all readable files in the ASL store directory /var/log/asl. +.Pp +Legacy ASL database files that were written by .Nm syslogd -for messages. -The database file is opened in read-only mode, and read access permissions are required. -Specifying the -.Fl db -option with no argument also forces raw database access. -.Pp -Archive log databases may be read by providing one or more database names as arguments to the -.Fl db +on Mac OS X 10.5 (Leopard) may also be read using the +.Fl f option. -Each database is read in sequence. -As a special case, the name -.Dq - -may be used in place of a database file name. -In this case, -.Nm -will connect to -.Nm syslogd -and query for the contents of the active database. +However only one such legacy database may be read or searched at a time. +Note that a legacy database may be read and copied into a new ASL data store format file using a combination of +.Fl f +and +.Fl x +options. .Pp The .Fl w @@ -218,7 +234,7 @@ to wait for new messages. By default, .Nm prints the last 10 messages, -then waits for new messages to be added to the database. +then waits for new messages to be added to the data store. A number following the .Fl w option specifies the number of messages to print and overrides the default value of 10. @@ -232,16 +248,13 @@ This usage is similar to watching a log file using, e.g. .Pp The .Fl w -option can only be used for a single database, and when printing messages to standard output. +option can only be used when reading the system's ASL data store or when reading a single data store file, +and when printing messages to standard output. .Pp If the -.Fl x Ar database -option is specified, messages are copied to the named -.Ar database -file rather than being printed. -The -.Ar database -file will be created if it does not exist. +.Fl x Ar file +option is specified, messages are copied to the named file rather than being printed. +The file will be created if it does not exist. .Pp When called without the .Fl x @@ -252,7 +265,10 @@ except that the message priority level is printed between angle-brackets. The output format may by changed by specifying the .Fl F Ar format option. -Non-printable and control characters are encoded in the output, as described below. +Non-printable and control characters are encoded by default. +Text encoding may be controlled using the +.Fl E +option (see below). The value of .Ar format may be one of the following: @@ -329,25 +345,25 @@ The option is a short form for .Fl T Ar utc . .Pp -Control characters and non-printable characters are encoded in the output stream. -In some cases this may make messages slightly less natural in appearance. -However, the encoding is designed to preserve all the information in the log message, +By default, control characters and non-printable characters are encoded in the output stream. +In some cases this may make messages less natural in appearance. +The encoding is designed to preserve all the information in the log message, and to prevent malicious users from spoofing or obsucring information in log messages. .Pp -Output in the +Text in the .Dq std , .Dq bsd , and .Dq raw formats is encoded as it is by the -.Xr vis +.Nm vis utility with the .Fl c option. Newlines and tabs are also encoded as "\\n" and "\\t" respectively. In .Dq raw -format, space chanacters embedded in log message keys are encoded as "\\s" +format, space characters embedded in log message keys are encoded as "\\s" and embedded brackets are escaped to print as "\\[" and "\\]". .Pp XML format output requires that keys are valid UTF8 strings. @@ -361,9 +377,42 @@ where NN is the character's hexidecimal value. .Pp Values that do not contain legal UTF8 are encoded in base-64 and printed as data objects. .Pp +The +.Fl E Ar format +option may be used to explicity control the text encoding. +The value of +.Ar format +may be one of the following: +.Pp +.Bl -tag -width "safe" +.It vis +The default encoding described above. +.It safe +Encodes backspace characters as ^H. +Carriage returns are mapped to newlines. +A tab character is appended after newlines so that message text is indented. +.It none +No encoding is used. +.El +.Pp +The intent of the +.Dq safe +encoding is to prevent obvious message spoofing or damage. +The appearance of messages printed will depend on terminal settings and UTF-8 string handling. +It is possible that messages printed using the +.Dq safe +or +.Dq none +options may be garbled or subject to manipulation through the use of control characters and control sequences +embedded in user-supplied message text. +The default +.Dq vis +encoding should be used to view messages if there is any suspicion +that message text may have been used to manipulate the printed representation. +.Pp If no further command line options are specified, .Nm -displays all messages, or copies all messages to a database file. +displays all messages, or copies all messages to a data store file. However, an expression may be specified using the .Fl k and @@ -372,12 +421,17 @@ options. .Ss EXPRESSIONS Expressions specify matching criteria. They may be used to search for messages of interest. -Expressions are also required when pruning the system log file with the -.Fl p -option. .Pp -A simple expression is a list of one or more key/value pairs. -A match is made when a message has the given value for the specified key. +A simple expression +has the form: +.Pp +.Dl -k key [[op] val] +.Pp +The +.Fl k +option may be followed by one, two, or three arguments. +A single argument causes a match to occur if a message has the specified key, regardless of value. +If two arguments are specified, a match occurs when a message has exactly the specified value for a given key. For example, to find all messages sent by the portmap process: .Pp .Dl syslog -k Sender portmap @@ -390,11 +444,6 @@ option is treated as an alias for the expression: .Pp This provides a quick way to search for console messages. .Pp -The -.Fl k -option may be followed by one, two, or three arguments. -A single argument causes a match to occur if a message has the specified key, regardless of value. -If a pair of arguments is specified, a match occurs when a message has exactly the specified value for a given key. If three arguments are given, they are of the form .Fl k Ar key operation value . .Nm @@ -433,14 +482,24 @@ suffix numeric comparison .El .Pp -An simple expression matches a message if all of the key-value operations match. +More complex search expressions may be built by combining two or more simple expressions. +A complex expression that has more than one +.Dq -k key [[op] val] +term matches a message if all of the key-value operations match. Logically, the result is an AND of all of key-value operations. +For example: +.Pp +.Dl syslog -k Sender portmap -k Time ge -2h +.Pp +finds all messages sent by portmap in the last 2 hours +(-2h means "two hours ago"). +.Pp The .Fl o -option separates simple expressions and provides an OR operation. -If two or more simple expressions are given, separated by +option may be used to build even more complex searches by providing an OR operation. +If two or more sub-expressions are given, separated by .Fl o -options, then a match occurs is a message matches any of the simple expressions. +options, then a match occurs is a message matches any of the sub-expressions. For example, to find all messages which have either a .Dq Sender value of @@ -467,43 +526,6 @@ or to specify seconds, minutes, hours, days, or weeks respectively. Upper case may be used equivalently. A week is taken to be 7 complete days (i.e. 604800 seconds). -.Ss PRUNING -The Apple System Log facility saves received messages, subject to filtering criteria described in the -FILTERING CONTROLS section below. -The -.Nm syslogd -daemon deletes messages after given time-to-live values to prevent the database from growing too large. -When messages expire, they are either removed entirely, or copied to an archive database. -See the -.Xr syslogd 8 -manual for more details on archiving messages. -.Pp -Messages may be removed from either the active database or from an archive database by using the -.Fl p -option of -.Nm syslog . -The -.Fl p -option must be followed by an expression (see above). -Messages that match the expression are deleted. -.Pp -If the -.Fl db -option is not specified -.Nm -sends a request to -.Nm syslogd -to perform the requested pruning operation. -If -.Fl db -is given without a database file name, -.Nm -prunes the active database file. -This may only be done if the -.Nm syslogd -server is not running. -If one or more database file names are given, those databases are pruned subject to the specified expression. -Read and write access to the database files are required. .Ss FILTERING CONTROLS Clients of the Apple System Log facility using either the .Xr asl 3 diff --git a/util.tproj/syslog.c b/util.tproj/syslog.c index e03833e..ab2f865 100644 --- a/util.tproj/syslog.c +++ b/util.tproj/syslog.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2007-2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -40,7 +41,9 @@ #include #include #include +#include #include +#include #define MOD_CASE_FOLD 'C' #define MOD_REGEX 'R' @@ -58,6 +61,8 @@ #define ASL_QUERY_OP_NOT 0x1000 +#define QUERY_FLAG_SEARCH_REVERSE 0x00000001 + #define FACILITY_CONSOLE "com.apple.console" #define SEARCH_EOF -1 @@ -76,14 +81,14 @@ #define SEND_FORMAT_LEGACY 0 #define SEND_FORMAT_ASL 1 -#define TIME_SEC 0x00000001 -#define TIME_UTC 0x00000002 -#define TIME_LCL 0x00000004 +#define TIME_SEC 0x00000010 +#define TIME_UTC 0x00000020 +#define TIME_LCL 0x00000040 -#define FORMAT_RAW 0x00000010 -#define FORMAT_LEGACY 0x00000020 -#define FORMAT_STD 0x00000040 -#define FORMAT_XML 0x00000080 +#define FORMAT_RAW 0x00000100 +#define FORMAT_LEGACY 0x00000200 +#define FORMAT_STD 0x00000400 +#define FORMAT_XML 0x00000800 #define EXPORT 0x00000100 @@ -94,14 +99,18 @@ #define ASL_FILTER_MASK_PACE 0x0f #define ASL_FILTER_MASK_PAC 0x07 -#define FETCH_BATCH 256 +#define FETCH_BATCH 1024 -#define _PATH_ASL_STORE "/var/log/asl.db" -static asl_store_t **dbstore = NULL; -static uint32_t store_count = 0; -static uint32_t store_raw = 1; +#define DB_SELECT_STORE 0 +#define DB_SELECT_FILES 1 +#define DB_SELECT_SYSLOGD 2 +#define DB_SELECT_LEGACY 3 -static asl_store_t *export = NULL; +static asl_file_list_t *db_files = NULL; +static asl_store_t *store = NULL; +static asl_file_t *legacy = NULL; +static uint32_t dbselect = DB_SELECT_STORE; +static asl_file_t *export = NULL; /* notify SPI */ uint32_t notify_register_plain(const char *name, int *out_token); @@ -114,11 +123,11 @@ extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b); extern time_t asl_parse_time(const char *in); /* END PRIVATE API */ -static const char *myname = "syslog"; - #define ASL_SERVICE_NAME "com.apple.system.logger" static mach_port_t asl_server_port = MACH_PORT_NULL; +static const char *myname = "syslog"; + void usage() { @@ -142,21 +151,18 @@ usage() fprintf(stderr, " d = Debug\n"); fprintf(stderr, " a minus sign preceeding a single letter means \"up to\" that level\n"); fprintf(stderr, "\n"); - fprintf(stderr, "%s -p [-db [file]...] [-k key [[op] val]]... [-o -k key [[op] val]] ...]...\n", myname); - fprintf(stderr, " -db prune /var/log/asl.db or named file, rather than sending a prune command to syslogd.\n"); - fprintf(stderr, " -p prune datastore according to input expression (see below)\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "%s [-db [file]...] [-x file] [-w [N]] [-F format] [-u] [-k key [[op] val]]... [-o -k key [[op] val]] ...]...\n", myname); - fprintf(stderr, " -db read /var/log/asl.db or named file, rather than querying syslogd.\n"); - fprintf(stderr, " use \"-\" to explicitly include a connection to syslogd.\n"); - fprintf(stderr, " -x export to named database, rather than printing\n"); - fprintf(stderr, " -w watch database (^C to quit)\n"); + fprintf(stderr, "%s [-f file...] [-d path...] [-x file] [-w [N]] [-F format] [-u] [-k key [[op] val]]... [-o -k key [[op] val]] ...]...\n", myname); + fprintf(stderr, " -f read named file[s], rather than standard log message store.\n"); + fprintf(stderr, " -d read all file in named directory path, rather than standard log message store.\n"); + fprintf(stderr, " -x export to named ASL format file, rather than printing\n"); + fprintf(stderr, " -w watch data store (^C to quit)\n"); fprintf(stderr, " prints the last N matching lines (default 10) before waiting\n"); fprintf(stderr, " \"-w 0\" prints all matching lines before waiting\n"); fprintf(stderr, " -F output format may be \"std\", \"raw\", \"bsd\", or \"xml\"\n"); fprintf(stderr, " format may also be a string containing variables of the form\n"); fprintf(stderr, " $Key or $(Key) - use the latter for non-whitespace delimited variables\n"); fprintf(stderr, " -T timestamp format may be \"sec\" (seconds), \"utc\" (UTC), or \"local\" (local timezone)\n"); + fprintf(stderr, " -E text encoding may be \"vis\", \"safe\", or \"none\"\n"); fprintf(stderr, " -u print timestamps using UTC (equivalent to \"-T utc\")\n"); fprintf(stderr, " -k key/value match\n"); fprintf(stderr, " if no operator or value is given, checks for the existance of the key\n"); @@ -810,7 +816,7 @@ syslog_remote_control(int argc, char *argv[]) int syslog_send(int argc, char *argv[]) { - int i, start, kv, len, rfmt, rlevel; + int i, start, kv, len, rfmt, rlevel, filter, status; aslclient asl; aslmsg m; char tmp[64], *str, *rhost; @@ -873,11 +879,28 @@ syslog_send(int argc, char *argv[]) } else { - for (i = start + 1; i < argc; i += 2) asl_set(m, argv[i], argv[i + 1]); + for (i = start + 1; i < argc; i += 2) + { + if (!strcmp(argv[i], "-k")) i++; + asl_set(m, argv[i], argv[i + 1]); + if (!strcmp(argv[i], ASL_KEY_LEVEL)) rlevel = atoi(argv[i + 1]); + } } if (rhost == NULL) { + filter = 0; + status = rcontrol_get_string(NULL, RC_SYSLOGD, &filter); + if (status != 0) + { + fprintf(stderr, "Warning: Can't get current syslogd ASL filter value\n"); + } + else if ((ASL_FILTER_MASK(rlevel) & filter) == 0) + { + fprintf(stderr, "Warning: The current syslogd ASL filter value (%s)\n", asl_filter_string(filter)); + fprintf(stderr, " will exclude this message from the ASL database\n"); + } + asl_send(asl, m); } else if (rfmt == SEND_FORMAT_ASL) @@ -918,65 +941,24 @@ print_xml_trailer(FILE *f) fprintf(f, "\n"); } -static void -print_xml_str(FILE *f, const char *str) -{ - uint32_t i; - - if (f == NULL) return; - if (str == NULL) return; - - for (i = 0; str[i] != '\0'; i++) - { - if (str[i] == '&') fprintf(f, "&"); - else if (str[i] == '<') fprintf(f, "<"); - else if (str[i] == '>') fprintf(f, ">"); - else if (str[i] == '"') fprintf(f, """); - else if (str[i] == '\'') fprintf(f, "'"); - else fprintf(f, "%c", str[i]); - } -} - -static void -printsafe(FILE *f, const char *str) -{ - uint8_t c; - uint32_t i; - - if (f == NULL) return; - if (str == NULL) return; - - for (i = 0; str[i] != '\0'; i++) - { - c = str[i]; - - if (isascii(c) && iscntrl(c)) - { - if (c == '\n') printf("\\n"); - else if (c == '\t') printf("\t"); - else printf("^%c", c ^ 0100); - } - else printf("%c", c); - } -} - static void printmsg(FILE *f, asl_msg_t *msg, char *fmt, int pflags) { char *str; const char *mf, *tf; - uint32_t len, status; - uint64_t msgid; + uint32_t encode, len, status; + uint64_t xid; if (f == NULL) { if (export != NULL) { - status = asl_store_save(export, msg, -1, -1, &msgid); + xid = 0; + status = asl_file_save(export, msg, &xid); if (status != ASL_STATUS_OK) { - fprintf(stderr, "export database write failed: %s\n", asl_store_error(status)); - asl_store_close(export); + fprintf(stderr, "export file write failed: %s\n", asl_core_error(status)); + asl_file_close(export); export = NULL; } } @@ -984,6 +966,8 @@ printmsg(FILE *f, asl_msg_t *msg, char *fmt, int pflags) return; } + encode = pflags & 0x0000000f; + mf = ASL_MSG_FMT_RAW; if (fmt != NULL) mf = (const char *)fmt; else if (pflags & FORMAT_STD) mf = ASL_MSG_FMT_STD; @@ -995,7 +979,7 @@ printmsg(FILE *f, asl_msg_t *msg, char *fmt, int pflags) if (pflags & TIME_LCL) tf = ASL_TIME_FMT_LCL; len = 0; - str = asl_format_message(msg, mf, tf, &len); + str = asl_format_message(msg, mf, tf, encode, &len); if (str != NULL) { fprintf(f, "%s", str); @@ -1003,51 +987,71 @@ printmsg(FILE *f, asl_msg_t *msg, char *fmt, int pflags) } } -uint32_t -send_prune(asl_search_result_t *pl) +asl_search_result_t * +store_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64_t *last) { - char *str; - caddr_t vmstr; - uint32_t len, status; - kern_return_t kstatus; - security_token_t sec; - - if (asl_server_port == MACH_PORT_NULL) return 1; - - len = 0; - str = asl_list_to_string(pl, &len); + uint32_t status; + asl_search_result_t *res; - kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE); - if (kstatus != KERN_SUCCESS) + if (store == NULL) { - free(str); - return 1; + status = asl_store_open_read(NULL, &store); + if (status != 0) return NULL; } - memmove(vmstr, str, len); - free(str); + res = NULL; + status = asl_store_match(store, q, &res, last, start, count, dir); + if (status != 0) return NULL; - sec.val[0] = -1; - sec.val[1] = -1; - status = 0; + return res; +} + +asl_search_result_t * +file_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64_t *last) +{ + uint32_t status; + asl_search_result_t *res; - kstatus = _asl_server_prune(asl_server_port, (caddr_t)vmstr, len, (int *)&status, &sec); - if (kstatus != KERN_SUCCESS) status = 1; + res = NULL; + status = asl_file_list_match(db_files, q, &res, last, start, count, dir); + if (status != 0) return NULL; - return status; + return res; +} + +asl_search_result_t * +legacy_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64_t *last) +{ + uint32_t status; + asl_search_result_t *res; + + res = NULL; + status = asl_file_match(legacy, q, &res, last, start, count, dir); + if (status != 0) return NULL; + + return res; } asl_search_result_t * -send_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64_t *last) +syslogd_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64_t *last) { char *str, *res; caddr_t vmstr; uint32_t len, reslen, status; + int flags; kern_return_t kstatus; security_token_t sec; asl_search_result_t *l; - if (asl_server_port == MACH_PORT_NULL) return NULL; + if (asl_server_port == MACH_PORT_NULL) + { + kstatus = bootstrap_look_up(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port); + if (kstatus != KERN_SUCCESS) + { + fprintf(stderr, "query failed: can't contact syslogd\n"); + return NULL; + } + } len = 0; str = asl_list_to_string(q, &len); @@ -1067,8 +1071,10 @@ send_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64_t sec.val[0] = -1; sec.val[1] = -1; status = 0; + flags = 0; + if (dir < 0) flags = QUERY_FLAG_SEARCH_REVERSE; - kstatus = _asl_server_query(asl_server_port, (caddr_t)vmstr, len, start, count, dir, (caddr_t *)&res, &reslen, last, (int *)&status, &sec); + kstatus = _asl_server_query(asl_server_port, (caddr_t)vmstr, len, start, count, flags, (caddr_t *)&res, &reslen, last, (int *)&status, &sec); if (res == NULL) return NULL; l = asl_list_from_string(res); @@ -1076,63 +1082,50 @@ send_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64_t return l; } -asl_search_result_t * -db_query(asl_store_t *s, asl_search_result_t *q, uint64_t qmin, uint64_t *cmax) -{ - uint32_t status; - asl_search_result_t *res; - - res = NULL; - status = asl_store_match(s, q, &res, cmax, qmin, 0, 1, 0, 0); - if (status != 0) return NULL; - - return res; -} - void -search_once(FILE *f, char *pfmt, int pflags, asl_search_result_t *ql, uint64_t qmin, uint64_t *cmax, uint32_t count, uint32_t tail) +search_once(FILE *f, char *pfmt, int pflags, asl_search_result_t *ql, uint64_t qmin, uint64_t *cmax, uint32_t count, uint32_t batch, int dir, uint32_t tail) { asl_search_result_t *res; - int i, j; + int i, more, total; if (pflags & FORMAT_XML) print_xml_header(f); - i = 0; - while (i < store_count) + res = NULL; + more = 1; + total = 0; + + while (more == 1) { - res = NULL; - if ((dbstore[i] == NULL) && (store_raw == 0)) + if (dbselect == DB_SELECT_STORE) res = store_query(ql, qmin, batch, dir, cmax); + else if (dbselect == DB_SELECT_FILES) res = file_query(ql, qmin, batch, dir, cmax); + else if (dbselect == DB_SELECT_SYSLOGD) res = syslogd_query(ql, qmin, batch, dir, cmax); + else if (dbselect == DB_SELECT_LEGACY) res = legacy_query(ql, qmin, batch, dir, cmax); + + if ((dir >= 0) && (*cmax > qmin)) qmin = *cmax; + else if ((dir < 0) && (*cmax < qmin)) qmin = *cmax; + + if (res == NULL) { - if (count == 0) - { - res = send_query(ql, qmin, 0, 0, cmax); - i++; - } - else - { - res = send_query(ql, qmin, count, 0, cmax); - if (*cmax > qmin) qmin = *cmax; - if (res == NULL) i++; - else if (res->count < count) i++; - } + more = 0; } else { - res = db_query(dbstore[i], ql, qmin, cmax); - i++; - } + if ((batch > 0) && (res->count < batch)) more = 0; + total += res->count; + if ((count > 0) && (total >= count)) more = 0; - if (res != NULL) - { - j = 0; + i = 0; if (tail != 0) { - j = res->count - tail; + i = res->count - tail; tail = 0; - if (j < 0) j = 0; + if (i < 0) i = 0; } - for (; j < res->count; j++) printmsg(f, res->msg[j], pfmt, pflags); + if ((f != NULL) || (export != NULL)) + { + for (; i < res->count; i++) printmsg(f, res->msg[i], pfmt, pflags); + } aslresponse_free((aslresponse)res); } @@ -1287,75 +1280,121 @@ add_op(asl_msg_t *q, char *key, char *op, char *val, uint32_t flags) return 0; } -static void -add_store(const char *name, uint32_t flags) +static uint32_t +add_db_file(const char *name) { - asl_store_t *s; + asl_file_t *s; uint32_t status; + if (dbselect == DB_SELECT_LEGACY) + { + fprintf(stderr, "syslog can only read one legacy format database\n"); + fprintf(stderr, "can't combine legacy and non-legacy databases in a single search\n"); + exit(1); + } + + /* shouldn't happen */ + if (name == NULL) return DB_SELECT_STORE; + s = NULL; + status = asl_file_open_read(name, &s); + if (status != ASL_STATUS_OK) + { + fprintf(stderr, "data store file %s open failed: %s \n", name, asl_core_error(status)); + exit(1); + } - if (name != NULL) + if (s == NULL) { - status = asl_store_open(name, flags, &s); - if (status != ASL_STATUS_OK) - { - fprintf(stderr, "database %s open failed: %s \n", name, asl_store_error(status)); - exit(1); - } + fprintf(stderr, "data store file %s open failed\n", name); + exit(1); + } - if (s == NULL) + if (s->flags & ASL_FILE_FLAG_LEGACY_STORE) + { + if (db_files != NULL) { - fprintf(stderr, "database %s open failed\n", name); + fprintf(stderr, "syslog can only read a single legacy format database\n"); + fprintf(stderr, "can't combine legacy and non-legacy databases in a single search\n"); exit(1); } - } - else - { - store_raw = 0; + + legacy = s; + return DB_SELECT_LEGACY; } - if (store_count == 0) dbstore = (asl_store_t **)calloc(1, sizeof(asl_store_t *)); - else dbstore = (asl_store_t **)reallocf(dbstore, (store_count + 1) * sizeof(asl_store_t *)); + db_files = asl_file_list_add(db_files, s); + return DB_SELECT_FILES; +} + +static uint32_t +add_db_dir(const char *name) +{ + DIR *dp; + struct dirent *dent; + uint32_t status; + asl_file_t *s; + char *path; - if (dbstore == NULL) + /* + * Open all readable files + */ + dp = opendir(name); + if (dp == NULL) { - fprintf(stderr, "Can't allocate memory!\n"); + fprintf(stderr, "%s: %s\n", name, strerror(errno)); exit(1); } - dbstore[store_count] = s; - store_count++; + while ((dent = readdir(dp)) != NULL) + { + if (dent->d_name[0] == '.') continue; + + path = NULL; + asprintf(&path, "%s/%s", name, dent->d_name); + + /* + * 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. + */ + s = NULL; + status = asl_file_open_read(path, &s); + if (path != NULL) free(path); + if ((status != ASL_STATUS_OK) || (s == NULL)) continue; + + db_files = asl_file_list_add(db_files, s); + } + + closedir(dp); + + return DB_SELECT_FILES; } int main(int argc, char *argv[]) { FILE *outfile; - int i, j, n, watch, prune, status, pflags, tflags, sflags, iamroot, user_tflag; + int i, j, n, watch, status, pflags, tflags, iamroot, user_tflag; int notify_file, notify_token; - asl_search_result_t *qlist, *lx, *res; + asl_search_result_t *qlist; asl_msg_t *cq; - char *logname, *pfmt; - const char *dbname, *exportname; - uint32_t flags, tail_count, batch; + char *pfmt; + const char *exportname; + uint32_t flags, tail_count, batch, encode; uint64_t qmin, cmax; - kern_return_t kstatus; watch = 0; - prune = 0; iamroot = 0; user_tflag = 0; - logname = NULL; pfmt = NULL; flags = 0; tail_count = 0; batch = FETCH_BATCH; - sflags = ASL_STORE_FLAG_READ_ONLY; pflags = FORMAT_STD; tflags = TIME_LCL; + encode = ASL_ENCODE_ASL; cq = NULL; - dbname = _PATH_ASL_STORE; exportname = NULL; if (getuid() == 0) iamroot = 1; @@ -1368,6 +1407,13 @@ main(int argc, char *argv[]) exit(0); } + if (!strcmp(argv[i], "-time")) + { + qmin = time(NULL); + printf("%llu\n", qmin); + exit(0); + } + if (!strcmp(argv[i], "-s")) { syslog_send(argc, argv); @@ -1379,12 +1425,6 @@ main(int argc, char *argv[]) syslog_remote_control(argc, argv); exit(0); } - - if (!strcmp(argv[i], "-p")) - { - prune = 1; - sflags = 0; - } } qlist = (asl_search_result_t *)calloc(1, sizeof(asl_search_result_t)); @@ -1392,7 +1432,7 @@ main(int argc, char *argv[]) for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "-db")) + if (!strcmp(argv[i], "-f")) { if ((i + 1) < argc) { @@ -1400,30 +1440,43 @@ main(int argc, char *argv[]) { if (!strcmp(argv[j], "-")) { - /* -db - means add syslogd search (dbstore is NULL) */ - add_store(NULL, sflags); + dbselect = DB_SELECT_SYSLOGD; + break; } - else if (argv[j][0] == '-') + else if (argv[j][0] == '-') { - if (j == (i + 1)) - { - /* No databases: add /var/log/asl.db */ - add_store(_PATH_ASL_STORE, sflags); - i = j - 1; - } - break; } else { - add_store(argv[j], sflags); + dbselect = add_db_file(argv[j]); } } } - else + } + if (!strcmp(argv[i], "-d")) + { + if ((i + 1) < argc) { - /* No databases: add /var/log/asl.db */ - add_store(_PATH_ASL_STORE, sflags); + for (j = i + 1; j < argc; j++) + { + if (!strcmp(argv[j], "store")) + { + dbselect = add_db_dir(PATH_ASL_STORE); + } + else if (!strcmp(argv[j], "archive")) + { + dbselect = add_db_dir(PATH_ASL_ARCHIVE); + } + else if (argv[j][0] == '-') + { + break; + } + else + { + dbselect = add_db_dir(argv[j]); + } + } } } else if (!strcmp(argv[i], "-w")) @@ -1452,7 +1505,7 @@ main(int argc, char *argv[]) exportname = argv[++i]; } - else if (!strcmp(argv[i], "-f")) + else if (!strcmp(argv[i], "-E")) { if ((i + 1) >= argc) { @@ -1461,7 +1514,12 @@ main(int argc, char *argv[]) exit(1); } - logname = argv[++i]; + i++; + + if (!strcmp(argv[i], "vis")) encode = ASL_ENCODE_ASL; + else if (!strcmp(argv[i], "safe")) encode = ASL_ENCODE_SAFE; + else if (!strcmp(argv[i], "none")) encode = ASL_ENCODE_NONE; + else if ((argv[i][0] >= '0') && (argv[i][0] <= '9') && (argv[i][1] == '\0')) encode = atoi(argv[i]); } else if (!strcmp(argv[i], "-F")) { @@ -1609,92 +1667,7 @@ main(int argc, char *argv[]) } pflags |= tflags; - - if (store_count == 0) add_store(NULL, sflags); - - kstatus = bootstrap_look_up(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port); - if (kstatus != KERN_SUCCESS) - { - if (prune == 1) - { - fprintf(stderr, "prune operation failed: can't contact syslogd server\n"); - exit(1); - } - - if (iamroot == 0) - { - fprintf(stderr, "operation failed: can't contact syslogd server\n"); - exit(1); - } - - /* force raw access (for single-user mode when syslogd is not running) */ - if (store_raw == 0) - { - fprintf(stderr, "*** can't contact syslogd server - using read-only database access ***\n"); - add_store(_PATH_ASL_STORE, ASL_STORE_FLAG_READ_ONLY); - store_raw = 1; - } - } - - if (prune == 1) - { - if (watch == 1) - { - fprintf(stderr, "Warning: -w flag has no effect when pruning\n"); - watch = 0; - } - - if (qlist->count == 0) - { - fprintf(stderr, "no queries for pruning\n"); - - aslresponse_free(qlist); - for (j = 0; j < store_count; j++) asl_store_close(dbstore[j]); - if (dbstore != NULL) free(dbstore); - - exit(0); - } - - for (i = 0; i < store_count; i++) - { - status = ASL_STATUS_OK; - - if ((dbstore[i] == NULL) && (store_raw == 0)) - { - if (iamroot == 0) - { - fprintf(stderr, "you must be root to prune the log database\n"); - - aslresponse_free(qlist); - for (j = 0; j < store_count; j++) asl_store_close(dbstore[j]); - if (dbstore != NULL) free(dbstore); - - exit(1); - } - - status = send_prune(qlist); - } - else - { - status = asl_store_prune(dbstore[i], qlist); - } - - if (status != ASL_STATUS_OK) - { - fprintf(stderr, "database prune failed: %s\n", asl_store_error(status)); - - aslresponse_free(qlist); - for (j = 0; j < store_count; j++) asl_store_close(dbstore[j]); - if (dbstore != NULL) free(dbstore); - - exit(1); - } - } - - aslresponse_free(qlist); - - exit(0); - } + pflags |= encode; outfile = stdout; @@ -1706,14 +1679,20 @@ main(int argc, char *argv[]) watch = 0; } - status = asl_store_open(exportname, 0, &export); + status = asl_file_open_write(exportname, 0644, -1, -1, &export); if (status != ASL_STATUS_OK) { aslresponse_free(qlist); - fprintf(stderr, "export database open failed: %s\n", asl_store_error(status)); + fprintf(stderr, "export file open failed: %s\n", asl_core_error(status)); exit(1); } + /* + * allow the string cache to be unlimited to maximize string dup compression + * preserve message IDs + */ + export->flags = ASL_FILE_FLAG_UNLIMITED_CACHE | ASL_FILE_FLAG_PRESERVE_MSG_ID; + outfile = NULL; pflags = EXPORT; } @@ -1725,63 +1704,25 @@ main(int argc, char *argv[]) if (watch == 1) { - if (store_raw == 1) - { - fprintf(stderr, "Warning: -w flag can only be used to watch syslogd's active database\n"); - watch = 0; - } - else if (store_count > 1) - { - fprintf(stderr, "Warning: -w flag has no effect with multiple databases\n"); - watch = 0; - } - else + if ((dbselect == DB_SELECT_STORE) || (dbselect == DB_SELECT_SYSLOGD)) { status = notify_register_file_descriptor("com.apple.system.logger.message", ¬ify_file, 0, ¬ify_token); if (status != NOTIFY_STATUS_OK) notify_token = -1; } } - if ((qlist->count == 0) && (watch == 1) && (store_raw == 0)) + if ((qlist->count == 0) && (watch == 1)) { - lx = (asl_search_result_t *)calloc(1, sizeof(asl_search_result_t)); - if (lx == NULL) exit(1); - - lx->count = 1; - lx->msg = (asl_msg_t **)calloc(1, sizeof(asl_msg_t *)); - if (lx->msg == NULL) - { - aslresponse_free(lx); - exit(1); - } - - lx->msg[0] = asl_new(ASL_TYPE_QUERY); - if (lx->msg[0] == NULL) - { - aslresponse_free(lx); - exit(1); - } - - asl_set_query(lx->msg[0], "Level", "0", ASL_QUERY_OP_NUMERIC | ASL_QUERY_OP_GREATER_EQUAL); qmin = -1; - res = send_query(lx, qmin, 1, 1, &cmax); - aslresponse_free(lx); - aslresponse_free(res); - qmin = cmax - tail_count; + search_once(NULL, NULL, 0, NULL, qmin, &cmax, 1, 1, -1, 0); + qmin = (cmax + 1) - tail_count; tail_count = 0; } - if (qlist->count == 0) - { - qlist->msg = (asl_msg_t **)calloc(1, sizeof(asl_msg_t *)); - if (qlist->msg == NULL) exit(1); - - cq = asl_new(ASL_TYPE_QUERY); - qlist->msg[qlist->count] = cq; - qlist->count++; - } + /* output should be line buffered */ + setlinebuf(outfile); - search_once(outfile, pfmt, pflags, qlist, qmin, &cmax, batch, tail_count); + search_once(outfile, pfmt, pflags, qlist, qmin, &cmax, 0, batch, 1, tail_count); if (watch == 1) { @@ -1791,7 +1732,7 @@ main(int argc, char *argv[]) { usleep(500000); if (cmax > qmin) qmin = cmax; - search_once(outfile, pfmt, pflags, qlist, qmin, &cmax, 0, 0); + search_once(outfile, pfmt, pflags, qlist, qmin + 1, &cmax, 0, batch, 1, 0); } } else @@ -1799,14 +1740,14 @@ main(int argc, char *argv[]) while (read(notify_file, &i, 4) == 4) { if (cmax > qmin) qmin = cmax; - search_once(outfile, pfmt, pflags, qlist, qmin, &cmax, 0, 0); + search_once(outfile, pfmt, pflags, qlist, qmin + 1, &cmax, 0, batch, 1, 0); } } } - for (i = 0; i < store_count; i++) asl_store_close(dbstore[i]); - if (dbstore != NULL) free(dbstore); - if (export != NULL) asl_store_close(export); + if (db_files != NULL) asl_file_list_close(db_files); + if (store != NULL) asl_store_close(store); + if (export != NULL) asl_file_close(export); aslresponse_free(qlist); -- 2.45.2