/*
- * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2007-2011 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* @APPLE_LICENSE_HEADER_END@
*/
+#include <TargetConditionals.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <errno.h>
+#include <dirent.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <arpa/inet.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>
+#include <bootstrap_priv.h>
#include <netdb.h>
#include <notify.h>
#include <asl.h>
+#include <asl_msg.h>
+#include <asl_msg_list.h>
#include <asl_private.h>
-#include <asl_ipc.h>
+#include "asl_ipc.h"
+#include <asl_core.h>
#include <asl_store.h>
+#include <asl_file.h>
+#include <asl_client.h>
+#include "asl_common.h"
#define MOD_CASE_FOLD 'C'
#define MOD_REGEX 'R'
#define ASL_QUERY_OP_NOT 0x1000
+#define QUERY_FLAG_SEARCH_REVERSE 0x00000001
+
#define FACILITY_CONSOLE "com.apple.console"
#define SEARCH_EOF -1
#define PROC_NOT_UNIQUE -2
#define RC_MASTER -1
-#define RC_SYSLOGD -2
#define CHUNK 64
#define forever for(;;)
#define SEND_FORMAT_LEGACY 0
#define SEND_FORMAT_ASL 1
-#define TIME_SEC 0x00000001
-#define TIME_UTC 0x00000002
-#define TIME_LCL 0x00000004
-
-#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 COMPRESS_DUPS 0x00010000
#define EXPORT 0x00000100
#define ASL_FILTER_MASK_PACE 0x0f
#define ASL_FILTER_MASK_PAC 0x07
-#define FETCH_BATCH 256
-
-#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;
-
-static asl_store_t *export = NULL;
+#define FETCH_BATCH 1024
+#define MAX_RANDOM 8192
+
+#define DB_SELECT_ASL 0
+#define DB_SELECT_STORE 1
+#define DB_SELECT_FILES 2
+#define DB_SELECT_SYSLOGD 3
+#define DB_SELECT_LEGACY 4
+
+/* STD and BSD format messages start with 'DAY MMM DD HH:MM:SS ' timestamp */
+#define STD_BSD_DATE_LEN 20
+
+/* Max message size for direct watch */
+#define MAX_DIRECT_SIZE 16384
+
+/* Buffer for direct watch data */
+#define DIRECT_BUF_SIZE 1024
+
+static asl_file_list_t *db_files = NULL;
+static asl_store_t *store = NULL;
+static asl_file_t *legacy = NULL;
+static asl_file_t *export = NULL;
+static const char *sort_key = NULL;
+static const char *sort_key_2 = NULL;
+static int sort_numeric = 0;
+static char *last_printmsg_str = NULL;
+static int last_printmsg_count = 0;
+static const char *tfmt = NULL;
+
+#if TARGET_OS_EMBEDDED
+static uint32_t dbselect = DB_SELECT_SYSLOGD;
+#else
+static uint32_t dbselect = DB_SELECT_ASL;
+#endif
/* notify SPI */
uint32_t notify_register_plain(const char *name, int *out_token);
-extern char *asl_msg_to_string(aslmsg msg, uint32_t *len);
-extern asl_msg_t *asl_msg_from_string(const char *buf);
-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);
-extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b);
+//extern asl_msg_t *asl_msg_from_string(const char *buf);
+//extern char *asl_list_to_string(asl_msg_list_t *list, uint32_t *outlen);
+//extern asl_msg_list_t *asl_list_from_string(const char *buf);
+//extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b);
+asl_msg_t *_asl_server_control_query(void);
extern time_t asl_parse_time(const char *in);
/* END PRIVATE API */
+static mach_port_t asl_server_port = MACH_PORT_NULL;
+
static const char *myname = "syslog";
-#define ASL_SERVICE_NAME "com.apple.system.logger"
-static mach_port_t asl_server_port = MACH_PORT_NULL;
+/* forward */
+asl_msg_list_t *syslogd_query(asl_msg_list_t *q, uint64_t start, int count, int dir, uint64_t *last);
+static void printmsg(FILE *f, asl_msg_t *msg, char *fmt, int pflags);
void
usage()
fprintf(stderr, " n = Notice\n");
fprintf(stderr, " i = Info\n");
fprintf(stderr, " d = Debug\n");
- fprintf(stderr, " a minus sign preceeding a single letter means \"up to\" that level\n");
+ fprintf(stderr, " a minus sign preceding a single letter means \"up to\" that level\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "%s -config [params...]\n", myname);
+ fprintf(stderr, " without params, fetch and print syslogd parameters and statistics\n");
+ fprintf(stderr, " otherwise, set or reset syslogd configuration parameters\n");
fprintf(stderr, "\n");
- fprintf(stderr, "%s -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, "%s -module [name [action]]\n", myname);
+ fprintf(stderr, " with no name, prints configuration for all ASL output modules\n");
+ fprintf(stderr, " with name and no action, prints configuration for named ASL output module\n");
+ fprintf(stderr, " supported actions - module name required, use '*' (with single quotes) for all modules:\n");
+ fprintf(stderr, " enable [01] enables (or disables with 0) named module\n");
+ fprintf(stderr, " does not apply to com.apple.asl when '*' is used\n");
+ fprintf(stderr, " checkpoint [file] checkpoints all files or specified file for named module\n");
fprintf(stderr, "\n");
- fprintf(stderr, "%s [-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, " 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, " -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");
- fprintf(stderr, " if no operator is given, default is \"%s\"\n", OP_EQ);
- fprintf(stderr, " -C alias for \"-k Facility com.apple.console\"\n");
- fprintf(stderr, " -o begins a new query\n");
- fprintf(stderr, " queries are \'OR\'ed together\n");
+ fprintf(stderr, "%s [-f file...] [-d path...] [-x file] [-w [N]] [-F format] [-nocompress] [-u] [-sort key1 [key2]] [-nsort key1 [key2]] [-k key [[op] val]]... [-o -k key [[op] val]] ...]...\n", myname);
+ fprintf(stderr, " -f read named file[s], rather than standard log message store.\n");
+ fprintf(stderr, " -d read all file in named directory path, rather than standard log message store.\n");
+ fprintf(stderr, " -x export to named ASL format file, rather than printing\n");
+ fprintf(stderr, " -w watch data store (^C to quit)\n");
+ fprintf(stderr, " prints the last N matching lines (default 10) before waiting\n");
+ fprintf(stderr, " \"-w all\" prints all matching lines before waiting\n");
+ fprintf(stderr, " \"-w boot\" prints all matching lines since last system boot before waiting\n");
+ fprintf(stderr, " -F output format may be \"std\", \"raw\", \"bsd\", or \"xml\"\n");
+ fprintf(stderr, " format may also be a string containing variables of the form\n");
+ fprintf(stderr, " $Key or $(Key) - use the latter for non-whitespace delimited variables\n");
+ fprintf(stderr, " -T timestamp format may be \"sec\" (seconds), \"utc\" (UTC), or \"local\" (local timezone)\n");
+ fprintf(stderr, " -E text encoding may be \"vis\", \"safe\", or \"none\"\n");
+ fprintf(stderr, " -nodc no duplicate message compression\n");
+ fprintf(stderr, " -u print timestamps using UTC (equivalent to \"-T utc\")\n");
+ fprintf(stderr, " -sort sort messages using value for specified key1 (secondary sort by key2 if provided)\n");
+ fprintf(stderr, " -nsort numeric sort messages using value for specified key1 (secondary sort by key2 if provided)\n");
+ fprintf(stderr, " -k key/value match\n");
+ fprintf(stderr, " if no operator or value is given, checks for the existence of the key\n");
+ fprintf(stderr, " if no operator is given, default is \"%s\"\n", OP_EQ);
+ fprintf(stderr, " -B only process log messages since last system boot\n");
+ fprintf(stderr, " -C alias for \"-k Facility com.apple.console\"\n");
+ fprintf(stderr, " -o begins a new query\n");
+ fprintf(stderr, " queries are \'OR\'ed together\n");
fprintf(stderr, "operators are zero or more modifiers followed by a comparison\n");
fprintf(stderr, " %s equal\n", OP_EQ);
fprintf(stderr, " %s not equal\n", OP_NE);
return "Unknown";
}
+int
+module_control(int argc, char *argv[])
+{
+ const char *val = NULL;
+ uint64_t last;
+ char *str;
+
+ asl_msg_t *ctl = _asl_server_control_query();
+ if (ctl == NULL)
+ {
+ fprintf(stderr, "can't get status information from syslogd\n");
+ return -1;
+ }
+
+ argc -= 2;
+ argv += 2;
+
+ if (argc < 2)
+ {
+ int first = 1;
+
+ /* print config */
+ asl_out_module_t *m = asl_out_module_init();
+ asl_out_module_t *x = m;
+
+ while (x != NULL)
+ {
+ if ((argc == 0) || (!strcmp(argv[0], x->name)))
+ {
+ asl_msg_lookup(ctl, x->name, &val, NULL);
+
+ if (first == 0) printf("\n");
+ first = 0;
+
+ if (x->name == NULL) printf("ASL out module has no name\n");
+ else printf("ASL out module: %s %s[current status: %s]\n", x->name, (x->flags & MODULE_FLAG_LOCAL) ? "local " : "", (val == NULL) ? "unknown" : val );
+
+ asl_out_module_print(stdout, x);
+ }
+
+ x = x->next;
+ }
+
+ asl_msg_release(ctl);
+ asl_out_module_free(m);
+ return 0;
+ }
+
+ /* name enable [val] */
+ /* name disable [val] */
+ if ((!strcmp(argv[1], "enable")) || (!strcmp(argv[1], "disable")))
+ {
+ int want = -1;
+ int status = -1;
+ asl_msg_t *cm;
+ asl_client_t *ac;
+
+ if (!strcmp(argv[1], "enable"))
+ {
+ if (argc < 3) want = 1;
+ else if (!strcmp(argv[2], "1")) want = 1;
+ else if (!strcmp(argv[2], "0")) want = 0;
+ else
+ {
+ printf("invalid value %s for %s %s - expecting 0 or 1\n", argv[2], argv[0], argv[1]);
+ exit(-1);
+ }
+ }
+ else
+ {
+ if (argc < 3) want = 0;
+ else if (!strcmp(argv[2], "1")) want = 0;
+ else if (!strcmp(argv[2], "0")) want = 1;
+ else
+ {
+ printf("invalid value %s for %s %s - expecting 0 or 1\n", argv[2], argv[0], argv[1]);
+ exit(-1);
+ }
+ }
+
+ asl_msg_lookup(ctl, argv[0], &val, NULL);
+ if (val != NULL)
+ {
+ if (!strcmp(val, "enabled")) status = 1;
+ else status = 0;
+ }
+
+ asl_msg_release(ctl);
+
+ if (want < 0)
+ {
+ printf("internal error: want = -1\n");
+ exit(-1);
+ }
+
+ if (want == status)
+ {
+ printf("module %s is already %s\n", argv[0], val);
+ return 0;
+ }
+
+ cm = asl_msg_new(ASL_TYPE_MSG);
+ asprintf(&str, "@ %s enable %d", argv[0], want);
+
+ if ((cm == NULL) || (str == NULL))
+ {
+ fprintf(stderr, "can't allocate memory - exiting\n");
+ exit(-1);
+ }
+
+ ac = asl_client_open(NULL, NULL, 0);
+ asl_client_set_filter(ac, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
+ asl_msg_set_key_val(cm, ASL_KEY_LEVEL, "7");
+ asl_msg_set_key_val(cm, ASL_KEY_OPTION, "control");
+ asl_msg_set_key_val(cm, ASL_KEY_MSG, str);
+ asl_client_send(ac, cm);
+
+ asl_client_release(ac);
+ asl_msg_release(cm);
+ free(str);
+ return 0;
+ }
+
+ asl_msg_release(ctl);
+
+ /* name checkpoint [file] */
+ if (!strcmp(argv[1], "checkpoint"))
+ {
+ asl_msg_list_t *q = asl_msg_list_new();
+ asl_msg_t *qm = asl_msg_new(ASL_TYPE_QUERY);
+
+ if ((q == NULL) || (qm == NULL))
+ {
+ fprintf(stderr, "can't allocate memory - exiting\n");
+ exit(-1);
+ }
+
+ asl_msg_list_append(q, qm);
+ asl_msg_release(qm);
+
+ asl_msg_set_key_val_op(qm, ASL_KEY_OPTION, "control", ASL_QUERY_OP_EQUAL);
+ asprintf(&str, "%s checkpoint%s%s", argv[0], (argc > 2) ? " " : "", (argc > 2) ? argv[2] : "");
+ asl_msg_set_key_val_op(qm, "action", str, ASL_QUERY_OP_EQUAL);
+
+ asl_msg_list_t *res = syslogd_query((asl_msg_list_t *)q, 0, 0, 1, &last);
+ free(q);
+ asl_msg_list_release(res);
+ return 0;
+ }
+
+ printf("unknown module control: %s\n", argv[1]);
+ exit(-1);
+}
+
int
procinfo(char *pname, int *pid, int *uid)
{
}
int
-rcontrol_get_string(const char *prefix, int pid, int *val)
+rcontrol_get_string(const char *name, int *val)
{
int t, status;
- char *name;
uint64_t x;
- status = NOTIFY_STATUS_OK;
-
- if (pid == RC_SYSLOGD)
- {
- status = notify_register_plain(NOTIFY_SYSTEM_ASL_FILTER, &t);
- }
- else if (pid == RC_MASTER)
- {
- status = notify_register_plain(NOTIFY_SYSTEM_MASTER, &t);
- }
- else
- {
- name = NULL;
- asprintf(&name, "%s.%d", prefix, pid);
- if (name == NULL) return NOTIFY_STATUS_FAILED;
-
- status = notify_register_plain(name, &t);
- free(name);
- }
-
+ status = notify_register_plain(name, &t);
if (status != NOTIFY_STATUS_OK) return status;
x = 0;
}
int
-rcontrol_set_string(const char *prefix, int pid, int filter)
+rcontrol_set_string(const char *name, int filter)
{
int t, status;
- char *name;
uint64_t x;
- status = NOTIFY_STATUS_OK;
-
- if (pid == RC_SYSLOGD)
- {
- status = notify_register_plain(NOTIFY_SYSTEM_ASL_FILTER, &t);
- }
- else if (pid == RC_MASTER)
- {
- status = notify_register_plain(NOTIFY_SYSTEM_MASTER, &t);
- }
- else
- {
- name = NULL;
- asprintf(&name, "%s.%d", prefix, pid);
- if (name == NULL) return NOTIFY_STATUS_FAILED;
-
- status = notify_register_plain(name, &t);
- free(name);
- }
-
+ status = notify_register_plain(name, &t);
if (status != NOTIFY_STATUS_OK) return status;
x = filter;
status = notify_set_state(t, x);
- if ((pid == RC_SYSLOGD) && (status == NOTIFY_STATUS_OK)) status = notify_post(NOTIFY_SYSTEM_ASL_FILTER);
+ notify_post(NOTIFY_RC);
notify_cancel(t);
return status;
}
return str;
}
+const char *
+rcontrol_name(pid_t pid, uid_t uid)
+{
+ static char str[1024];
+
+ if (pid == RC_MASTER) return NOTIFY_SYSTEM_MASTER;
+
+ memset(str, 0, sizeof(str));
+ if (uid == 0) snprintf(str, sizeof(str) - 1, "%s.%d", NOTIFY_PREFIX_SYSTEM, pid);
+ else snprintf(str, sizeof(str) - 1, "user.uid.%d.syslog.%d", uid, pid);
+ return str;
+}
+
int
-rcontrol_get(const char *prefix, int pid)
+rcontrol_get(pid_t pid, uid_t uid)
{
int filter, status;
- const char *name;
filter = 0;
if (pid < 0)
{
- name = "Master";
- if (pid == RC_SYSLOGD) name = "ASL Data Store";
-
- status = rcontrol_get_string(NULL, pid, &filter);
+ status = rcontrol_get_string(rcontrol_name(pid, uid), &filter);
if (status == NOTIFY_STATUS_OK)
{
- printf("%s filter mask: %s\n", name, asl_filter_string(filter));
+ printf("Master filter mask: %s\n", asl_filter_string(filter));
return 0;
}
- printf("Unable to determine %s filter mask\n", name);
+ printf("Unable to determine master filter mask\n");
return -1;
}
- status = rcontrol_get_string(prefix, pid, &filter);
+ status = rcontrol_get_string(rcontrol_name(pid, uid), &filter);
if (status == NOTIFY_STATUS_OK)
{
printf("Process %d syslog filter mask: %s\n", pid, asl_filter_string(filter));
}
int
-rcontrol_set(const char *prefix, int pid, int filter)
+rcontrol_set(pid_t pid, uid_t uid, int filter)
{
int status;
- const char *name;
+ const char *rcname;
+
+ rcname = rcontrol_name(pid, uid);
if (pid < 0)
{
- name = "Master";
- if (pid == RC_SYSLOGD) name = "ASL Data Store";
- status = rcontrol_set_string(NULL, pid, filter);
+ status = rcontrol_set_string(rcname, filter);
if (status == NOTIFY_STATUS_OK)
{
- printf("Set %s syslog filter mask: %s\n", name, asl_filter_string(filter));
+ if (pid == RC_MASTER) status = notify_post(NOTIFY_SYSTEM_MASTER);
return 0;
}
- printf("Unable to set %s syslog filter mask: %s\n", name, notify_status_string(status));
+ printf("Unable to set master syslog filter mask: %s\n", notify_status_string(status));
return -1;
}
- status = rcontrol_set_string(prefix, pid, filter);
+ status = rcontrol_set_string(rcname, filter);
if (status == NOTIFY_STATUS_OK)
{
- printf("Set process %d syslog filter mask set: %s\n", pid, asl_filter_string(filter));
+ status = notify_post(rcname);
return 0;
}
}
int
-rsend(aslmsg msg, char *rhost)
+rsend(asl_msg_t *msg, char *rhost)
{
char *str, *out;
uint32_t len, level;
char *timestr;
const char *val;
time_t tick;
- struct tm gtime;
int s;
struct sockaddr_in dst;
struct hostent *h;
level = ASL_LEVEL_DEBUG;
- val = asl_get(msg, ASL_KEY_LEVEL);
+ val = asl_msg_get_val_for_key(msg, ASL_KEY_LEVEL);
if (val != NULL) level = atoi(val);
- memset(>ime, 0, sizeof(struct tm));
- timestr = NULL;
tick = time(NULL);
- gmtime_r(&tick, >ime);
-
- /* Canonical form: YYYY.MM.DD hh:mm:ss UTC */
- asprintf(×tr, "%d.%02d.%02d %02d:%02d:%02d UTC", gtime.tm_year + 1900, gtime.tm_mon + 1, gtime.tm_mday, gtime.tm_hour, gtime.tm_min, gtime.tm_sec);
-
+ timestr = NULL;
+ asprintf(×tr, "%lu", tick);
if (timestr != NULL)
{
- asl_set(msg, ASL_KEY_TIME, timestr);
+ asl_msg_set_key_val(msg, ASL_KEY_TIME, timestr);
free(timestr);
}
- if (gethostname(myname, MAXHOSTNAMELEN) == 0) asl_set(msg, ASL_KEY_HOST, myname);
+ if (gethostname(myname, MAXHOSTNAMELEN) == 0) asl_msg_set_key_val(msg, ASL_KEY_HOST, myname);
len = 0;
- str = asl_msg_to_string(msg, &len);
+ str = asl_msg_to_string((asl_msg_t *)msg, &len);
if (str == NULL) return -1;
asprintf(&out, "%10u %s\n", len+1, str);
return -1;
}
+const char *
+asl_string_to_char_level(const char *s)
+{
+ if (s == NULL) return NULL;
+
+ if ((s[0] >= '0') && (s[0] <= '7') && (s[1] == '\0')) return s;
+
+ if (!strncasecmp(s, "em", 2)) return "0";
+ else if (!strncasecmp(s, "p", 1)) return "0";
+ else if (!strncasecmp(s, "a", 1)) return "1";
+ else if (!strncasecmp(s, "c", 1)) return "2";
+ else if (!strncasecmp(s, "er", 2)) return "3";
+ else if (!strncasecmp(s, "x", 1)) return "3";
+ else if (!strncasecmp(s, "w", 1)) return "4";
+ else if (!strncasecmp(s, "n", 1)) return "5";
+ else if (!strncasecmp(s, "i", 1)) return "6";
+ else if (!strncasecmp(s, "d", 1)) return "7";
+
+ return NULL;
+}
+
int
syslog_remote_control(int argc, char *argv[])
{
int pid, uid, status, mask;
- const char *prefix;
if ((argc < 3) || (argc > 4))
{
if ((!strcmp(argv[2], "syslogd")) || (!strcmp(argv[2], "syslog")))
{
- pid = RC_SYSLOGD;
- uid = 0;
- status = 0;
+ fprintf(stderr, "%s: does not have a filter mask\n", argv[2]);
+ return -1;
}
else if (_isanumber(argv[2]) != 0)
{
if (pid == 0) pid = RC_MASTER;
- prefix = NOTIFY_PREFIX_USER;
- if (uid == 0) prefix = NOTIFY_PREFIX_SYSTEM;
-
if (argc == 4)
{
if ((pid == RC_MASTER) && (!strcasecmp(argv[3], "off"))) mask = 0;
- else if ((pid == RC_SYSLOGD) && (!strcasecmp(argv[3], "off"))) mask = 0;
else
{
mask = asl_string_to_filter(argv[3]);
}
}
- rcontrol_set(prefix, pid, mask);
+ rcontrol_set(pid, uid, mask);
}
else
{
- rcontrol_get(prefix, pid);
+ rcontrol_get(pid, uid);
}
return 0;
syslog_send(int argc, char *argv[])
{
int i, start, kv, len, rfmt, rlevel;
- aslclient asl;
- aslmsg m;
+ asl_client_t *asl;
+ asl_msg_t *m;
char tmp[64], *str, *rhost;
kv = 0;
}
}
- asl = asl_open(myname, "syslog", 0);
- asl_set_filter(asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
+ asl = asl_client_open(myname, "syslog", 0);
+ asl_client_set_filter(asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
- m = asl_new(ASL_TYPE_MSG);
- asl_set(m, ASL_KEY_SENDER, myname);
+ m = asl_msg_new(ASL_TYPE_MSG);
+ asl_msg_set_key_val(m, ASL_KEY_SENDER, myname);
sprintf(tmp, "%d", rlevel);
- asl_set(m, ASL_KEY_LEVEL, tmp);
+ asl_msg_set_key_val(m, ASL_KEY_LEVEL, tmp);
str = NULL;
strcat(str, argv[i]);
if ((i+1) < argc) strcat(str, " ");
}
- asl_set(m, ASL_KEY_MSG, str);
+ asl_msg_set_key_val(m, ASL_KEY_MSG, str);
}
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_msg_set_key_val(m, argv[i], argv[i + 1]);
+ if (!strcmp(argv[i], ASL_KEY_LEVEL)) rlevel = atoi(argv[i + 1]);
+ }
}
if (rhost == NULL)
{
- asl_send(asl, m);
+ asl_client_send(asl, m);
}
else if (rfmt == SEND_FORMAT_ASL)
{
rlegacy(str, rlevel, rhost);
}
- asl_free(m);
+ asl_msg_release(m);
if (str != NULL) free(str);
- asl_close(asl);
+ asl_client_release(asl);
return 0;
}
-static void
-print_xml_header(FILE *f)
+int
+syslog_config(int argc, char *argv[])
{
- if (f == NULL) return;
+ int i;
+ uint32_t x;
+ uid_t uid;
+ asl_client_t *asl;
+ asl_msg_t *m;
+ asl_string_t *str;
+ const char *key, *val;
- fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
- fprintf(f, "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n");
- fprintf(f, "<plist version=\"1.0\">\n");
- fprintf(f, "<array>\n");
-}
+ if (argc == 2)
+ {
+ asl_msg_t *ctl = _asl_server_control_query();
+ if (ctl == NULL)
+ {
+ fprintf(stderr, "can't get status information from syslogd\n");
+ return -1;
+ }
-static void
-print_xml_trailer(FILE *f)
-{
- if (f == NULL) return;
+ for (x = asl_msg_fetch(ctl, 0, &key, &val, NULL); x != IndexNull; x = asl_msg_fetch(ctl, x, &key, &val, NULL))
+ {
+ printf("%s %s\n", key, val);
+ }
- fprintf(f, "</array>\n");
- fprintf(f, "</plist>\n");
+ asl_msg_release(ctl);
+ return 0;
+ }
+
+ uid = geteuid();
+ if (uid != 0)
+ {
+ fprintf(stderr, "syslogd parameters may only be set by the superuser\n");
+ return -1;
+ }
+
+ str = asl_string_new(0);
+ asl_string_append(str, "= ");
+
+ for (i = 2; i < argc; i++)
+ {
+ asl_string_append(str, argv[i]);
+ if ((i + 1) < argc) asl_string_append(str, " ");
+ }
+
+ asl = asl_client_open(myname, "syslog", 0);
+
+ m = asl_msg_new(ASL_TYPE_MSG);
+ asl_msg_set_key_val(m, ASL_KEY_LEVEL, ASL_STRING_NOTICE);
+ asl_msg_set_key_val(m, ASL_KEY_OPTION, ASL_OPT_CONTROL);
+ asl_msg_set_key_val(m, ASL_KEY_SENDER, myname);
+ asl_msg_set_key_val(m, ASL_KEY_MSG, asl_string_bytes(str));
+
+ asl_client_send(asl, m);
+
+ asl_string_release(str);
+ asl_msg_release(m);
+ asl_client_release(asl);
+
+ return 0;
}
-static void
-print_xml_str(FILE *f, const char *str)
+int
+syslog_control(int argc, char *argv[])
{
- uint32_t i;
+ int i;
+ uid_t uid;
+ asl_client_t *asl;
+ asl_msg_t *m;
+ asl_string_t *str;
- if (f == NULL) return;
- if (str == NULL) return;
+ uid = geteuid();
+ if (uid != 0)
+ {
+ fprintf(stderr, "syslog control limited to use by superuser\n");
+ return -1;
+ }
- for (i = 0; str[i] != '\0'; i++)
+ str = asl_string_new(0);
+ asl_string_append(str, "@ ");
+
+ for (i = 2; i < argc; 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]);
+ asl_string_append(str, argv[i]);
+ if ((i + 1) < argc) asl_string_append(str, " ");
}
+
+ asl = asl_client_open(myname, "syslog", 0);
+
+ m = asl_msg_new(ASL_TYPE_MSG);
+ asl_msg_set_key_val(m, ASL_KEY_LEVEL, ASL_STRING_NOTICE);
+ asl_msg_set_key_val(m, ASL_KEY_OPTION, ASL_OPT_CONTROL);
+ asl_msg_set_key_val(m, ASL_KEY_SENDER, myname);
+ asl_msg_set_key_val(m, ASL_KEY_MSG, asl_string_bytes(str));
+
+ asl_client_send(asl, m);
+
+ asl_string_release(str);
+ asl_msg_release(m);
+ asl_client_release(asl);
+
+ return 0;
}
static void
-printsafe(FILE *f, const char *str)
+print_xml_header(FILE *f)
{
- uint8_t c;
- uint32_t i;
-
if (f == NULL) return;
- if (str == NULL) return;
- for (i = 0; str[i] != '\0'; i++)
- {
- c = str[i];
+ fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ fprintf(f, "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n");
+ fprintf(f, "<plist version=\"1.0\">\n");
+ fprintf(f, "<array>\n");
+}
- 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
+print_xml_trailer(FILE *f)
+{
+ if (f == NULL) return;
+
+ fprintf(f, "</array>\n");
+ fprintf(f, "</plist>\n");
}
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;
+ const char *mf;
+ 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;
}
}
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;
else if (pflags & FORMAT_LEGACY) mf = ASL_MSG_FMT_BSD;
else if (pflags & FORMAT_XML) mf = ASL_MSG_FMT_XML;
- tf = ASL_TIME_FMT_SEC;
- if (pflags & TIME_UTC) tf = ASL_TIME_FMT_UTC;
- if (pflags & TIME_LCL) tf = ASL_TIME_FMT_LCL;
-
len = 0;
- str = asl_format_message(msg, mf, tf, &len);
- if (str != NULL)
+ str = asl_format_message((asl_msg_t *)msg, mf, tfmt, encode, &len);
+ if (str == NULL) return;
+
+ if (pflags & COMPRESS_DUPS)
+ {
+ if (last_printmsg_str != NULL)
+ {
+ if (!strcmp(str + STD_BSD_DATE_LEN, last_printmsg_str + STD_BSD_DATE_LEN))
+ {
+ last_printmsg_count++;
+ free(str);
+ }
+ else
+ {
+ if (last_printmsg_count > 0)
+ {
+ fprintf(f, "--- last message repeated %d time%s ---\n", last_printmsg_count, (last_printmsg_count == 1) ? "" : "s");
+ }
+
+ free(last_printmsg_str);
+ last_printmsg_str = str;
+ last_printmsg_count = 0;
+
+ fprintf(f, "%s", str);
+ }
+ }
+ else
+ {
+ last_printmsg_str = str;
+ last_printmsg_count = 0;
+
+ fprintf(f, "%s", str);
+ }
+ }
+ else
{
fprintf(f, "%s", str);
free(str);
}
}
-uint32_t
-send_prune(asl_search_result_t *pl)
+asl_msg_list_t *
+store_query(asl_msg_list_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);
-
- kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
- if (kstatus != KERN_SUCCESS)
+ if (store == NULL)
{
- free(str);
- return 1;
+ uint32_t status = asl_store_open_read(NULL, &store);
+ if (status != 0) return NULL;
}
- memmove(vmstr, str, len);
- free(str);
-
- sec.val[0] = -1;
- sec.val[1] = -1;
- status = 0;
+ return asl_store_match(store, q, last, start, count, 0, dir);
+}
- kstatus = _asl_server_prune(asl_server_port, (caddr_t)vmstr, len, (int *)&status, &sec);
- if (kstatus != KERN_SUCCESS) status = 1;
+asl_msg_list_t *
+file_query(asl_msg_list_t *q, uint64_t start, int count, int dir, uint64_t *last)
+{
+ return asl_file_list_match(db_files, q, last, start, count, 0, dir);;
+}
- return status;
+asl_msg_list_t *
+legacy_query(asl_msg_list_t *q, uint64_t start, int count, int dir, uint64_t *last)
+{
+ return asl_file_match(legacy, q, last, start, count, 0, dir);
}
-asl_search_result_t *
-send_query(asl_search_result_t *q, uint64_t start, int count, int dir, uint64_t *last)
+asl_msg_list_t *
+syslogd_query(asl_msg_list_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;
+ asl_msg_list_t *l;
- if (asl_server_port == MACH_PORT_NULL) return NULL;
+ if (asl_server_port == MACH_PORT_NULL)
+ {
+ kstatus = bootstrap_look_up2(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
+ if (kstatus != KERN_SUCCESS)
+ {
+ fprintf(stderr, "query failed: can't contact syslogd\n");
+ return NULL;
+ }
+ }
len = 0;
- str = asl_list_to_string(q, &len);
+ str = asl_msg_list_to_string(q, &len);
kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
if (kstatus != KERN_SUCCESS)
res = NULL;
reslen = 0;
- 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_2(asl_server_port, (caddr_t)vmstr, len, start, count, flags, (caddr_t *)&res, &reslen, last, (int *)&status);
if (res == NULL) return NULL;
- l = asl_list_from_string(res);
+ l = asl_msg_list_from_string(res);
vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
return l;
}
-asl_search_result_t *
-db_query(asl_store_t *s, asl_search_result_t *q, uint64_t qmin, uint64_t *cmax)
+void
+filter_and_print(asl_msg_t *msg, asl_msg_list_t *ql, FILE *f, char *pfmt, int pflags)
{
- uint32_t status;
- asl_search_result_t *res;
+ int i, do_match, did_match;
- res = NULL;
- status = asl_store_match(s, q, &res, cmax, qmin, 0, 1, 0, 0);
- if (status != 0) return NULL;
+ if (msg == NULL) return;
+
+ do_match = 1;
+ if (ql == NULL) do_match = 0;
+ else if (ql->count == 0) do_match = 0;
+
+ did_match = 1;
+
+ if (do_match != 0)
+ {
+ did_match = 0;
+
+ for (i = 0; (i < ql->count) && (did_match == 0); i++)
+ {
+ did_match = asl_msg_cmp(ql->msg[i], (asl_msg_t *)msg);
+ }
+ }
- return res;
+ if (did_match != 0) printmsg(f, msg, pfmt, pflags);
}
+#if TARGET_OS_EMBEDDED
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)
+syslogd_direct_watch(FILE *f, char *pfmt, int pflags, asl_msg_list_t *ql)
{
- asl_search_result_t *res;
- int i, j;
-
- if (pflags & FORMAT_XML) print_xml_header(f);
+ struct sockaddr_in address;
+ int i, bytes, sock, stream, status;
+ uint32_t n, inlen;
+ uint16_t port;
+ socklen_t addresslength;
+ char *str, buf[DIRECT_BUF_SIZE];
+ asl_msg_t *msg;
- i = 0;
- while (i < store_count)
+ if (asl_server_port == MACH_PORT_NULL)
{
- res = NULL;
- if ((dbstore[i] == NULL) && (store_raw == 0))
+ status = bootstrap_look_up(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port);
+ if (status != KERN_SUCCESS)
{
- if (count == 0)
- {
- res = send_query(ql, qmin, 0, 0, cmax);
- i++;
- }
- else
+ fprintf(stderr, "query failed: can't contact syslogd\n");
+ exit(1);
+ }
+ }
+
+ addresslength = sizeof(address);
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ port = (arc4random() % (IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO)) + IPPORT_HIFIRSTAUTO;
+
+ memset(&address, 0, addresslength);
+ address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ address.sin_family = AF_INET;
+ address.sin_port = htons(port);
+
+ status = bind(sock, (struct sockaddr *)&address, sizeof(address));
+
+ for (i = 0; (i < MAX_RANDOM) && (status < 0); i++)
+ {
+ port = (arc4random() % (IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO)) + IPPORT_HIFIRSTAUTO;
+ address.sin_port = htons(port);
+
+ status = bind(sock, (struct sockaddr *)&address, sizeof(address));
+ }
+
+ if (status < 0)
+ {
+ fprintf(stderr, "query failed: can't find a port to connect to syslogd\n");
+ exit(1);
+ }
+
+ bytes = 0;
+
+ if (listen(sock, 1) == -1)
+ {
+ perror("listen");
+ exit(1);
+ }
+
+ i = htons(port);
+ _asl_server_register_direct_watch(asl_server_port, i);
+
+ stream = accept(sock, (struct sockaddr*)&address, &addresslength);
+ if (stream == -1)
+ {
+ perror("accept");
+ exit(1);
+ }
+
+ forever
+ {
+ inlen = 0;
+ errno = 0;
+ bytes = recvfrom(stream, &n, sizeof(n), 0, NULL, NULL);
+ if (bytes <= 0)
+ {
+ fprintf(stderr, "\nrecvfrom (message length) returned %d (errno %d) - exiting\n", bytes, errno);
+ break;
+ }
+ else inlen = ntohl(n);
+
+ if (inlen == 0) continue;
+
+ str = NULL;
+ if (inlen <= DIRECT_BUF_SIZE)
+ {
+ str = buf;
+ }
+ else
+ {
+ str = calloc(1, inlen + 1);
+ if (str == NULL)
{
- res = send_query(ql, qmin, count, 0, cmax);
- if (*cmax > qmin) qmin = *cmax;
- if (res == NULL) i++;
- else if (res->count < count) i++;
+ fprintf(stderr, "\ncan't allocate memory - exiting\n");
+ close(stream);
+ close(sock);
+ exit(1);
}
}
- else
+
+ n = 0;
+ while (n < inlen)
{
- res = db_query(dbstore[i], ql, qmin, cmax);
- i++;
+ errno = 0;
+ bytes = recvfrom(stream, str + n, inlen - n, 0, NULL, NULL);
+ if (bytes <= 0)
+ {
+ fprintf(stderr, "\nrecvfrom (message body) returned %d (errno %d) at length %d of %d - exiting\n", bytes, errno, n, inlen);
+ break;
+ }
+ else n += bytes;
+ }
+
+ if (n < inlen)
+ {
+ fprintf(stderr, "\ntruncated message: expected %d bytes received %d bytes\n", inlen, n);
+ close(stream);
+ close(sock);
+ exit(1);
}
- if (res != NULL)
+ msg = asl_msg_from_string(str);
+ if (str != buf) free(str);
+ filter_and_print(msg, ql, f, pfmt, pflags);
+ asl_msg_release(msg);
+ }
+
+ close(stream);
+ close(sock);
+
+ address.sin_addr.s_addr = 0;
+}
+#endif
+
+int
+sort_compare_key(asl_msg_t *a, asl_msg_t *b, const char *key)
+{
+ const char *va, *vb;
+ uint64_t na, nb;
+
+ if (key == NULL) return 0;
+
+ va = asl_msg_get_val_for_key(a, key);
+ vb = asl_msg_get_val_for_key(b, key);
+
+ if (va == NULL) return -1;
+ if (vb == NULL) return 1;
+
+ if (sort_numeric == 1)
+ {
+ na = atoll(va);
+ nb = atoll(vb);
+ if (na < nb) return -1;
+ if (na > nb) return 1;
+ return 0;
+ }
+
+ return strcmp(va, vb);
+}
+
+int
+sort_compare(const void *ap, const void *bp)
+{
+ int cmp;
+ asl_msg_t *a, *b;
+
+ if (sort_key == NULL) return 0;
+
+ a = (asl_msg_t *)ap;
+ b = (asl_msg_t *)bp;
+
+ cmp = sort_compare_key(a, b, sort_key);
+ if ((cmp == 0) && (sort_key_2 != NULL)) cmp = sort_compare_key(a, b, sort_key_2);
+
+ return cmp;
+}
+
+void
+search_once(FILE *f, char *pfmt, int pflags, asl_msg_list_t *ql, uint64_t qmin, uint64_t *cmax, uint32_t count, uint32_t batch, int dir, uint32_t tail)
+{
+ asl_msg_list_t *res;
+ int i, more, total;
+
+ if (pflags & FORMAT_XML) print_xml_header(f);
+
+ res = NULL;
+ more = 1;
+ total = 0;
+
+ while (more == 1)
+ {
+ if (batch == 0) more = 0;
+
+ if ((dbselect == DB_SELECT_ASL) || (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 + 1;
+ else if ((dir < 0) && (*cmax < qmin)) qmin = *cmax - 1;
+
+ if (res == NULL)
+ {
+ more = 0;
+ }
+ else
{
- j = 0;
+ if ((batch > 0) && (res->count < batch)) more = 0;
+ total += res->count;
+ if ((count > 0) && (total >= count)) more = 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 (sort_key != NULL)
+ {
+ qsort(res->msg, res->count, sizeof(asl_msg_t *), sort_compare);
+ }
- aslresponse_free((aslresponse)res);
+ if ((f != NULL) || (export != NULL))
+ {
+ for (; i < res->count; i++) printmsg(f, res->msg[i], pfmt, pflags);
+ }
+
+ asl_msg_list_release(res);
}
}
+ if ((pflags & COMPRESS_DUPS) && (last_printmsg_count > 0))
+ {
+ fprintf(f, "--- last message repeated %d time%s ---\n", last_printmsg_count, (last_printmsg_count == 1) ? "" : "s");
+ free(last_printmsg_str);
+ last_printmsg_str = NULL;
+ last_printmsg_count = 0;
+ }
+
if (pflags & FORMAT_XML) print_xml_trailer(f);
}
add_op(asl_msg_t *q, char *key, char *op, char *val, uint32_t flags)
{
uint32_t o;
+ const char *qval;
if (key == NULL) return -1;
if (q == NULL) return -1;
+ qval = NULL;
+ if (strcmp(key, ASL_KEY_TIME) == 0)
+ {
+ qval = (const char *)val;
+ }
+ else if ((strcmp(key, ASL_KEY_LEVEL) == 0) && (_isanumber(val) == 0))
+ {
+ /* Convert level strings to numeric values */
+ qval = asl_string_to_char_level(val);
+ if (qval == NULL)
+ {
+ fprintf(stderr, "invalid value for \"Level\"key: %s\n", val);
+ return -1;
+ }
+ }
+
o = ASL_QUERY_OP_NULL;
+ if (val == NULL) o = ASL_QUERY_OP_TRUE;
+
if (op != NULL)
{
o = optype(op);
return -1;
}
- if ((o & ASL_QUERY_OP_NUMERIC) && (strcmp(key, ASL_KEY_TIME) != 0) && (_isanumber(val) == 0))
+ if ((qval == NULL) && (o & ASL_QUERY_OP_NUMERIC) && (_isanumber(val) == 0))
{
fprintf(stderr, "non-numeric value supplied for numeric operator %s %s %s\n", key, op, val);
return -1;
}
-
}
o |= flags;
- asl_set_query(q, key, val, o);
+ if (qval != NULL) asl_msg_set_key_val_op(q, key, qval, o);
+ else asl_msg_set_key_val_op(q, key, val, o);
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_ASL;
+
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);
}
+
+ legacy = s;
+ return DB_SELECT_LEGACY;
}
- else
+
+ 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;
+
+ /*
+ * Try opening as a data store
+ */
+ status = asl_store_open_read(name, &store);
+ if (status == 0)
{
- store_raw = 0;
+ if (name == NULL) return DB_SELECT_ASL;
+ if (!strcmp(name, PATH_ASL_STORE)) return DB_SELECT_ASL;
+ return DB_SELECT_STORE;
}
- 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 *));
-
- 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, iamroot, user_tflag, export_preserve_id, saw_dash_d, since_boot;
int notify_file, notify_token;
- asl_search_result_t *qlist, *lx, *res;
+ asl_msg_list_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;
+ pflags = FORMAT_STD | COMPRESS_DUPS;
+ encode = ASL_ENCODE_SAFE;
cq = NULL;
- dbname = _PATH_ASL_STORE;
exportname = NULL;
+ export_preserve_id = 0;
+ saw_dash_d = 0;
+ since_boot = 0;
+
+ i = asl_store_location();
+ if (i == ASL_STORE_LOCATION_MEMORY) dbselect = DB_SELECT_SYSLOGD;
if (getuid() == 0) iamroot = 1;
exit(0);
}
+ if ((!strcmp(argv[i], "-time")) || (!strcmp(argv[i], "--time")))
+ {
+ qmin = time(NULL);
+ printf("%llu\n", qmin);
+ exit(0);
+ }
+
+ if ((!strcmp(argv[i], "-config")) || (!strcmp(argv[i], "--config")))
+ {
+ syslog_config(argc, argv);
+ exit(0);
+ }
+
+ if ((!strcmp(argv[i], "-control")) || (!strcmp(argv[i], "--control")))
+ {
+ syslog_control(argc, argv);
+ exit(0);
+ }
+
+ if ((!strcmp(argv[i], "-module")) || (!strcmp(argv[i], "--module")))
+ {
+ module_control(argc, argv);
+ exit(0);
+ }
+
if (!strcmp(argv[i], "-s"))
{
syslog_send(argc, 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));
+ qlist = asl_msg_list_new();
if (qlist == NULL) exit(1);
+ cq = NULL;
+
for (i = 1; i < argc; i++)
{
- if (!strcmp(argv[i], "-db"))
+ if (!strcmp(argv[i], "-f"))
{
if ((i + 1) < argc)
{
{
if (!strcmp(argv[j], "-"))
{
- /* -db - means add syslogd search (dbstore is NULL) */
- add_store(NULL, sflags);
+ dbselect = DB_SELECT_SYSLOGD;
+ i++;
+ 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
+ {
+ dbselect = add_db_file(argv[j]);
+ i++;
+ }
+ }
+ }
+ }
+ else if (!strcmp(argv[i], "-d"))
+ {
+ saw_dash_d = i + 1;
+ if (saw_dash_d < argc)
+ {
+ for (j = saw_dash_d; j < argc; j++)
+ {
+ if (!strcmp(argv[j], "store"))
+ {
+ dbselect = add_db_dir(PATH_ASL_STORE);
+ i++;
+ }
+ else if (!strcmp(argv[j], "archive"))
+ {
+ dbselect = add_db_dir(PATH_ASL_ARCHIVE);
+ i++;
+ }
+ else if (argv[j][0] == '-')
+ {
break;
}
else
{
- add_store(argv[j], sflags);
+ dbselect = add_db_dir(argv[j]);
+ i++;
}
}
}
else
{
- /* No databases: add /var/log/asl.db */
- add_store(_PATH_ASL_STORE, sflags);
+ fprintf(stderr, "missing directory name following -d flag\n");
+ return -1;
}
}
+ else if (!strcmp(argv[i], "-b"))
+ {
+ batch = atoi(argv[++i]);
+ }
+ else if (!strcmp(argv[i], "-B"))
+ {
+ since_boot = 1;
+ }
else if (!strcmp(argv[i], "-w"))
{
watch = 1;
if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
{
i++;
- tail_count = atoi(argv[i]);
+ if (!strcmp(argv[i], "all"))
+ {
+ tail_count = (uint32_t)-1;
+ }
+ else if (!strcmp(argv[i], "boot"))
+ {
+ since_boot = 1;
+ }
+ else
+ {
+ tail_count = atoi(argv[i]);
+ }
+ }
+ }
+ else if (!strcmp(argv[i], "-sort"))
+ {
+ if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
+ {
+ i++;
+ sort_key = argv[i];
+
+ if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
+ {
+ i++;
+ sort_key_2 = argv[i];
+ }
}
+ else
+ {
+ sort_key = ASL_KEY_MSG_ID;
+ }
+
+ batch = 0;
+ }
+ else if (!strcmp(argv[i], "-nsort"))
+ {
+ if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
+ {
+ i++;
+ sort_key = argv[i];
+
+ if (((i + 1) < argc) && (argv[i + 1][0] != '-'))
+ {
+ i++;
+ sort_key_2 = argv[i];
+ }
+ }
+ else
+ {
+ sort_key = ASL_KEY_MSG_ID;
+ }
+
+ sort_numeric = 1;
+ batch = 0;
}
else if (!strcmp(argv[i], "-u"))
{
- tflags = TIME_UTC;
+ tfmt = "Z";
user_tflag = 1;
}
- else if (!strcmp(argv[i], "-x"))
+ else if ((!strcmp(argv[i], "-x")) || (!strcmp(argv[i], "-X")))
{
if ((i + 1) >= argc)
{
- aslresponse_free(qlist);
+ asl_msg_list_release(qlist);
usage();
exit(1);
}
+ if (!strcmp(argv[i], "-x")) export_preserve_id = 1;
+
exportname = argv[++i];
}
- else if (!strcmp(argv[i], "-f"))
+ else if (!strcmp(argv[i], "-E"))
{
if ((i + 1) >= argc)
{
- aslresponse_free(qlist);
+ asl_msg_list_release(qlist);
usage();
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], "xml")) encode = ASL_ENCODE_XML;
+ 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"))
{
if ((i + 1) >= argc)
{
- aslresponse_free(qlist);
+ asl_msg_list_release(qlist);
usage();
exit(1);
}
if (!strcmp(argv[i], "raw"))
{
pflags = FORMAT_RAW;
- if (user_tflag == 0) tflags = TIME_SEC;
+ if (user_tflag == 0) tfmt = "sec";
}
else if (!strcmp(argv[i], "std"))
{
- pflags = FORMAT_STD;
+ pflags = FORMAT_STD | COMPRESS_DUPS;
}
else if (!strcmp(argv[i], "bsd"))
{
- pflags = FORMAT_LEGACY;
+ pflags = FORMAT_LEGACY | COMPRESS_DUPS;
}
else if (!strcmp(argv[i], "xml"))
{
pflags = FORMAT_XML;
+ encode = ASL_ENCODE_XML;
}
else
{
{
if ((i + 1) >= argc)
{
- aslresponse_free(qlist);
+ asl_msg_list_release(qlist);
usage();
exit(1);
}
i++;
+ tfmt = argv[i];
user_tflag = 1;
-
- if (!strcmp(argv[i], "sec")) tflags = TIME_SEC;
- else if (!strcmp(argv[i], "utc")) tflags = TIME_UTC;
- else if (!strcmp(argv[i], "local")) tflags = TIME_LCL;
- else if (!strcmp(argv[i], "lcl")) tflags = TIME_LCL;
- else tflags = TIME_LCL;
+ }
+ else if (!strcmp(argv[i], "-nodc"))
+ {
+ pflags = pflags & ~COMPRESS_DUPS;
}
else if (!strcmp(argv[i], "-o"))
{
flags = 0;
- if (qlist->count == 0)
+ if (cq != NULL)
{
- qlist->msg = (asl_msg_t **)calloc(1, sizeof(asl_msg_t *));
+ asl_msg_list_append(qlist, cq);
+ asl_msg_release(cq);
+ cq = NULL;
}
- else
- {
- qlist->msg = (asl_msg_t **)reallocf(qlist->msg, (qlist->count + 1) * sizeof(asl_msg_t *));
- }
-
- if (qlist->msg == NULL) exit(1);
-
- cq = asl_new(ASL_TYPE_QUERY);
- qlist->msg[qlist->count] = cq;
- qlist->count++;
}
else if (!strcmp(argv[i], "-n"))
{
}
else if (!strcmp(argv[i], "-C"))
{
- if (qlist->count == 0)
+ if (cq != NULL)
{
- 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++;
+ asl_msg_list_append(qlist, cq);
+ asl_msg_release(cq);
+ cq = NULL;
}
+ flags = 0;
+ cq = asl_msg_new(ASL_TYPE_QUERY);
status = add_op(cq, ASL_KEY_FACILITY, OP_EQ, FACILITY_CONSOLE, flags);
+ asl_msg_list_append(qlist, cq);
+ asl_msg_release(cq);
+ cq = NULL;
- flags = 0;
if (status != 0)
{
- aslresponse_free(qlist);
+ asl_msg_list_release(qlist);
exit(1);
}
}
continue;
}
- 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++;
- }
+ if (cq == NULL) cq = asl_msg_new(ASL_TYPE_QUERY);
status = 0;
if (n == 1) status = add_op(cq, argv[i], NULL, NULL, flags);
flags = 0;
if (status != 0)
{
- aslresponse_free(qlist);
+ asl_msg_list_release(qlist);
exit(1);
}
- }
- }
-
- 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);
+ i += (n - 1);
}
-
- if (iamroot == 0)
+ else
{
- fprintf(stderr, "operation failed: can't contact syslogd server\n");
+ fprintf(stderr, "syslog: unknown option \"%s\"\n", argv[i]);
+ fprintf(stderr, "run \"syslog -help\" for usage\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 (cq != NULL)
{
- if (watch == 1)
- {
- fprintf(stderr, "Warning: -w flag has no effect when pruning\n");
- watch = 0;
- }
+ asl_msg_list_append(qlist, cq);
+ asl_msg_release(cq);
+ cq = NULL;
+ }
- if (qlist->count == 0)
- {
- fprintf(stderr, "no queries for pruning\n");
+ pflags |= encode;
- aslresponse_free(qlist);
- for (j = 0; j < store_count; j++) asl_store_close(dbstore[j]);
- if (dbstore != NULL) free(dbstore);
+ outfile = stdout;
- exit(0);
+ /*
+ * Catch and report some cases where watch (-w) doesn't work
+ */
+ if (watch == 1)
+ {
+ if (sort_key != NULL)
+ {
+ fprintf(stderr, "Warning: -w flag has no effect with -sort flag\n");
+ watch = 0;
}
- for (i = 0; i < store_count; i++)
+ if (dbselect == DB_SELECT_FILES)
{
- status = ASL_STATUS_OK;
-
- if ((dbstore[i] == NULL) && (store_raw == 0))
+ if (saw_dash_d == 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);
+ fprintf(stderr, "Warning: -w flag not supported for a set of one or more files\n");
}
else
{
- status = asl_store_prune(dbstore[i], qlist);
+ fprintf(stderr, "Warning: directory \"%s\" is not an ASL data store\n", argv[saw_dash_d]);
+ fprintf(stderr, " -w flag not supported for a set of one or more files\n");
}
- 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);
- }
+ watch = 0;
}
-
- aslresponse_free(qlist);
-
- exit(0);
}
- outfile = stdout;
-
if (exportname != NULL)
{
if (watch == 1)
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));
+ asl_msg_list_release(qlist);
+ 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;
+ if (export_preserve_id != 0) export->flags |= ASL_FILE_FLAG_PRESERVE_MSG_ID;
+
outfile = NULL;
pflags = EXPORT;
}
notify_file = -1;
notify_token = -1;
- if (watch == 1)
+ /* set starting point */
+ if (since_boot == 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
- {
- status = notify_register_file_descriptor("com.apple.system.logger.message", ¬ify_file, 0, ¬ify_token);
- if (status != NOTIFY_STATUS_OK) notify_token = -1;
- }
- }
+ /* search back for last "BOOT_TIME (ut_type == 2) record */
+ asl_msg_list_t *bt;
+ asl_msg_t *bq;
- if ((qlist->count == 0) && (watch == 1) && (store_raw == 0))
- {
- 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)
+ bt = asl_msg_list_new();
+ if (bt == NULL)
{
- aslresponse_free(lx);
+ fprintf(stderr, "\ncan't allocate memory - exiting\n");
exit(1);
}
-
- lx->msg[0] = asl_new(ASL_TYPE_QUERY);
- if (lx->msg[0] == NULL)
+
+ bq = asl_msg_new(ASL_TYPE_QUERY);
+ if (bq == NULL)
{
- aslresponse_free(lx);
+ fprintf(stderr, "\ncan't allocate memory - exiting\n");
exit(1);
}
-
- asl_set_query(lx->msg[0], "Level", "0", ASL_QUERY_OP_NUMERIC | ASL_QUERY_OP_GREATER_EQUAL);
+
+ asl_msg_list_append(bt, bq);
+ asl_msg_release(bq);
+
+ asl_msg_set_key_val_op(bq, "ut_type", "2", ASL_QUERY_OP_EQUAL);
+
+ search_once(NULL, NULL, 0, (asl_msg_list_t *)bt, -1, &qmin, 1, 1, -1, 0);
+ asl_msg_list_release(bt);
+
+ if (qmin > 0) qmin--;
+ tail_count = 0;
+ }
+ else if (watch == 1)
+ {
+ /* go back tail_count records from last record */
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, qlist, qmin, &cmax, 1, 1, -1, 0);
+
+ if (cmax >= tail_count) qmin = cmax - tail_count;
+ else qmin = 0;
+
tail_count = 0;
}
- if (qlist->count == 0)
+ if ((watch == 1) && (dbselect == DB_SELECT_ASL))
{
- 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++;
+ status = notify_register_file_descriptor("com.apple.system.logger.message", ¬ify_file, 0, ¬ify_token);
+ if (status != NOTIFY_STATUS_OK) notify_token = -1;
}
- search_once(outfile, pfmt, pflags, qlist, qmin, &cmax, batch, tail_count);
+ /* output should be line buffered */
+ if (outfile != NULL) setlinebuf(outfile);
+
+ search_once(outfile, pfmt, pflags, qlist, qmin + 1, &cmax, 0, 0, 1, tail_count);
if (watch == 1)
{
- if (notify_token == -1)
+ if (dbselect == DB_SELECT_SYSLOGD)
+ {
+#if TARGET_OS_EMBEDDED
+ syslogd_direct_watch(outfile, pfmt, pflags, qlist);
+#else
+ fprintf(stderr, "Warning: -w flag cannot be used when querying syslogd directly\n");
+ exit(1);
+#endif
+ }
+ else if (notify_token == -1)
{
forever
{
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
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_release(store);
+ if (export != NULL) asl_file_release(export);
- aslresponse_free(qlist);
+ asl_msg_list_release(qlist);
exit(0);
}