X-Git-Url: https://git.saurik.com/apple/syslog.git/blobdiff_plain/c4fdb7d114b21b1b97b3777dfb8a8053693e7a91..51023e6095f291a0cf1026b76579218476e239c4:/syslogd.tproj/bsd_out.c diff --git a/syslogd.tproj/bsd_out.c b/syslogd.tproj/bsd_out.c index f4f2a55..571b998 100644 --- a/syslogd.tproj/bsd_out.c +++ b/syslogd.tproj/bsd_out.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2008 Apple Inc. All rights reserved. + * Copyright (c) 2004-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,6 +21,12 @@ * @APPLE_LICENSE_HEADER_END@ */ +#include + +#if TARGET_OS_SIMULATOR +struct _not_empty; +#else + #include #include #include @@ -52,11 +58,10 @@ #define DST_TYPE_WALL 4 #define DST_TYPE_NOTE 5 -#define CLOSE_ON_IDLE_SEC 60 +#define CLOSE_ON_IDLE_SEC 300 -static asl_msg_t *query = NULL; -static int reset = RESET_NONE; -static pthread_mutex_t reset_lock = PTHREAD_MUTEX_INITIALIZER; +static dispatch_queue_t bsd_out_queue; +static dispatch_source_t bsd_idle_timer; struct config_rule { @@ -66,10 +71,12 @@ struct config_rule int type; struct sockaddr *addr; char **facility; + uint32_t *fac_prefix_len; int *pri; uint32_t last_hash; uint32_t last_count; time_t last_time; + dispatch_source_t dup_timer; char *last_msg; TAILQ_ENTRY(config_rule) entries; }; @@ -78,35 +85,6 @@ static TAILQ_HEAD(cr, config_rule) bsd_out_rule; extern uint32_t asl_core_string_hash(const char *s, uint32_t inlen); -int bsd_out_close(); -int bsd_out_network_reset(void); -static int _parse_config_file(const char *); - -static void -_do_reset(void) -{ - pthread_mutex_lock(&reset_lock); - if (reset == RESET_NONE) - { - pthread_mutex_unlock(&reset_lock); - return; - } - - if (reset == RESET_CONFIG) - { - bsd_out_close(); - _parse_config_file(_PATH_SYSLOG_CONF); - } - else if (reset == RESET_NETWORK) - { - bsd_out_network_reset(); - } - - reset = RESET_NONE; - - pthread_mutex_unlock(&reset_lock); -} - static int _level_for_name(const char *name) { @@ -302,7 +280,7 @@ _clean_facility_name(char *s) static int _parse_line(char *s) { - char **semi, **comma; + char **semi, **comma, *star; int i, j, n, lasts, lastc, pri; struct config_rule *out; @@ -349,96 +327,45 @@ _parse_line(char *s) if (out->count == 0) { out->facility = (char **)calloc(1, sizeof(char *)); + out->fac_prefix_len = (uint32_t *)calloc(1, sizeof(uint32_t)); out->pri = (int *)calloc(1, sizeof(int)); } else { out->facility = (char **)reallocf(out->facility, (out->count + 1) * sizeof(char *)); + out->fac_prefix_len = (uint32_t *)reallocf(out->fac_prefix_len, (out->count + 1) * sizeof(uint32_t)); out->pri = (int *)reallocf(out->pri, (out->count + 1) * sizeof(int)); } if (out->facility == NULL) return -1; + if (out->fac_prefix_len == NULL) return -1; if (out->pri == NULL) return -1; out->facility[out->count] = _clean_facility_name(comma[j]); if (out->facility[out->count] == NULL) return -1; + out->fac_prefix_len[out->count] = 0; + star = strchr(out->facility[out->count], '*'); + if (star != NULL) out->fac_prefix_len[out->count] = (uint32_t)(star - out->facility[out->count]); + out->pri[out->count] = pri; out->count++; } - freeList(comma); + free_string_list(comma); } - freeList(semi); + free_string_list(semi); TAILQ_INSERT_TAIL(&bsd_out_rule, out, entries); return 0; } -static char * -bsd_log_string(const char *msg) -{ - uint32_t i, len, outlen; - char *out, *q; - uint8_t c; - - if (msg == NULL) return NULL; - - len = strlen(msg); - while ((len > 0) && (msg[len - 1] == '\n')) len--; - - if (len == 0) return NULL; - - outlen = len + 1; - for (i = 0; i < len; i++) - { - c = msg[i]; - if (isascii(c) && iscntrl(c) && (c != '\t')) outlen++; - } - - out = malloc(outlen); - if (out == NULL) return NULL; - - q = out; - - for (i = 0; i < len; i++) - { - c = msg[i]; - - if (isascii(c) && iscntrl(c)) - { - if (c == '\n') - { - *q++ = '\\'; - *q++ = 'n'; - } - else if (c == '\t') - { - *q++ = c; - } - else - { - *q++ = '^'; - *q++ = c ^ 0100; - } - } - else - { - *q++ = c; - } - } - - *q = '\0'; - - return out; -} - static int -_syslog_send_repeat_msg(struct config_rule *r) +_bsd_send_repeat_msg(struct config_rule *r) { - char vt[32], *p, *msg; + char vt[32], *msg; time_t tick; int len, status; @@ -446,15 +373,17 @@ _syslog_send_repeat_msg(struct config_rule *r) if (r->type != DST_TYPE_FILE) return 0; if (r->last_count == 0) return 0; - tick = time(NULL); - p = ctime(&tick); - if (p == NULL) return -1; + /* stop the timer */ + dispatch_suspend(r->dup_timer); - memcpy(vt, p+4, 15); - vt[15] = '\0'; + tick = time(NULL); + memset(vt, 0, sizeof(vt)); + ctime_r(&tick, vt); + vt[19] = '\0'; msg = NULL; - asprintf(&msg, "%s: --- last message repeated %u time%s ---\n", vt, r->last_count, (r->last_count == 1) ? "" : "s"); + asprintf(&msg, "%s: --- last message repeated %u time%s ---\n", vt + 4, r->last_count, (r->last_count == 1) ? "" : "s"); + r->last_count = 0; if (msg == NULL) return -1; len = strlen(msg); @@ -487,20 +416,20 @@ _syslog_send_repeat_msg(struct config_rule *r) } static int -_syslog_send(asl_msg_t *msg, struct config_rule *r, char **out, char **fwd, time_t now) +_bsd_send(asl_msg_t *msg, struct config_rule *r, char **out, char **fwd, time_t now) { - char vt[16], *so, *sf, *p, *outmsg; - const char *vtime, *vhost, *vident, *vpid, *vmsg, *vlevel, *vfacility, *vrefproc, *vrefpid; - size_t outlen, n; - time_t tick; + char *sf, *outmsg; + const char *vlevel, *vfacility; + size_t outlen; int pf, fc, status, is_dup, do_write; - FILE *pw; - uint32_t msg_hash; + uint32_t msg_hash, n; if (out == NULL) return -1; if (fwd == NULL) return -1; if (r == NULL) return -1; + _syslog_dst_open(r); + if (r->type == DST_TYPE_NOTE) { notify_post(r->dst+1); @@ -513,122 +442,8 @@ _syslog_send(asl_msg_t *msg, struct config_rule *r, char **out, char **fwd, time /* Build output string if it hasn't been built by a previous rule-match */ if (*out == NULL) { - tick = now; - vtime = asl_get(msg, ASL_KEY_TIME); - if (vtime != NULL) - { - /* aslmsg_verify converts time to seconds, but use current time if something went sour */ - tick = atol(vtime); - if (tick == 0) tick = now; - } - - p = ctime(&tick); - memcpy(vt, p+4, 15); - vt[15] = '\0'; - - vhost = asl_get(msg, ASL_KEY_HOST); - if (vhost == NULL) vhost = "localhost"; - - vident = asl_get(msg, ASL_KEY_SENDER); - if ((vident != NULL) && (!strcmp(vident, "Unknown"))) vident = NULL; - - vpid = asl_get(msg, ASL_KEY_PID); - if ((vpid != NULL) && (!strcmp(vpid, "-1"))) vpid = NULL; - - if ((vpid != NULL) && (vident == NULL)) vident = "Unknown"; - - vrefproc = asl_get(msg, ASL_KEY_REF_PROC); - vrefpid = asl_get(msg, ASL_KEY_REF_PID); - - vmsg = asl_get(msg, ASL_KEY_MSG); - if (vmsg != NULL) outmsg = bsd_log_string(vmsg); - - n = 0; - /* Time + " " */ - n += (strlen(vt) + 1); - - /* Host + " " */ - if (vhost != NULL) n += (strlen(vhost) + 1); - - /* Sender */ - if (vident != NULL) n += strlen(vident); - - /* "[" PID "]" */ - if (vpid != NULL) n += (strlen(vpid) + 2); - - /* " (" */ - if ((vrefproc != NULL) || (vrefpid != NULL)) n += 2; - - /* RefProc */ - if (vrefproc != NULL) n += strlen(vrefproc); - - /* "[" RefPID "]" */ - if (vrefpid != NULL) n += (strlen(vrefpid) + 2); - - /* ")" */ - if ((vrefproc != NULL) || (vrefpid != NULL)) n += 1; - - /* ": " */ - n += 2; - - /* Message */ - if (outmsg != NULL) n += strlen(outmsg); - - if (n == 0) return -1; - - /* "\n" + nul */ - n += 2; - - so = calloc(1, n); - if (so == NULL) return -1; - - strcat(so, vt); - strcat(so, " "); - - if (vhost != NULL) - { - strcat(so, vhost); - strcat(so, " "); - } - - if (vident != NULL) - { - strcat(so, vident); - if (vpid != NULL) - { - strcat(so, "["); - strcat(so, vpid); - strcat(so, "]"); - } - } - - if ((vrefproc != NULL) || (vrefpid != NULL)) - { - strcat(so, " ("); - - if (vrefproc != NULL) strcat(so, vrefproc); - - if (vrefpid != NULL) - { - strcat(so, "["); - strcat(so, vrefpid); - strcat(so, "]"); - } - - strcat(so, ")"); - } - - strcat(so, ": "); - - if (outmsg != NULL) - { - strcat(so, outmsg); - free(outmsg); - } - - strcat(so, "\n"); - - *out = so; + *out = asl_format_message((asl_msg_t *)msg, ASL_MSG_FMT_BSD, ASL_TIME_FMT_LCL, ASL_ENCODE_SAFE, &n); + if (*out == NULL) return -1; } /* check if message is a duplicate of the last message, and inside the dup time window */ @@ -645,10 +460,10 @@ _syslog_send(asl_msg_t *msg, struct config_rule *r, char **out, char **fwd, time if ((*fwd == NULL) && (r->type == DST_TYPE_SOCK)) { pf = 7; - vlevel = asl_get(msg, ASL_KEY_LEVEL); + vlevel = asl_msg_get_val_for_key(msg, ASL_KEY_LEVEL); if (vlevel != NULL) pf = atoi(vlevel); - fc = asl_syslog_faciliy_name_to_num(asl_get(msg, ASL_KEY_FACILITY)); + fc = asl_syslog_faciliy_name_to_num(asl_msg_get_val_for_key(msg, ASL_KEY_FACILITY)); if (fc > 0) pf |= fc; sf = NULL; @@ -658,19 +473,16 @@ _syslog_send(asl_msg_t *msg, struct config_rule *r, char **out, char **fwd, time *fwd = sf; } - outlen = 0; if (r->type == DST_TYPE_SOCK) outlen = strlen(*fwd); else outlen = strlen(*out); - _syslog_dst_open(r); - if ((r->type == DST_TYPE_FILE) || (r->type == DST_TYPE_CONS)) { /* * If current message is NOT a duplicate and r->last_count > 0 * we need to write a "last message was repeated N times" log entry */ - if ((r->type == DST_TYPE_FILE) && (is_dup == 0) && (r->last_count > 0)) _syslog_send_repeat_msg(r); + if ((r->type == DST_TYPE_FILE) && (is_dup == 0) && (r->last_count > 0)) _bsd_send_repeat_msg(r); do_write = 1; @@ -680,9 +492,26 @@ _syslog_send(asl_msg_t *msg, struct config_rule *r, char **out, char **fwd, time * The kernel printf routine already sends them to /dev/console * so writing them here would cause duplicates. */ - vfacility = asl_get(msg, ASL_KEY_FACILITY); + vfacility = asl_msg_get_val_for_key(msg, ASL_KEY_FACILITY); if ((vfacility != NULL) && (!strcmp(vfacility, FACILITY_KERNEL)) && (r->type == DST_TYPE_CONS)) do_write = 0; - if ((do_write == 1) && (r->type == DST_TYPE_FILE) && (is_dup == 1)) do_write = 0; + if ((do_write == 1) && (r->type == DST_TYPE_FILE) && (is_dup == 1)) + { + do_write = 0; + + if (r->dup_timer == NULL) + { + /* create a timer to flush dups on this file */ + r->dup_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, bsd_out_queue); + dispatch_source_set_event_handler(r->dup_timer, ^{ _bsd_send_repeat_msg(r); }); + } + + if (r->last_count == 0) + { + /* start the timer */ + dispatch_source_set_timer(r->dup_timer, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * global.bsd_max_dup_time), DISPATCH_TIME_FOREVER, 0); + dispatch_resume(r->dup_timer); + } + } if (do_write == 0) status = outlen; else status = write(r->fd, *out, outlen); @@ -714,7 +543,8 @@ _syslog_send(asl_msg_t *msg, struct config_rule *r, char **out, char **fwd, time } else if (r->type == DST_TYPE_WALL) { - pw = popen(_PATH_WALL, "w"); +#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) + FILE *pw = popen(_PATH_WALL, "w"); if (pw < 0) { asldebug("%s: error sending wall message: %s\n", MY_ID, strerror(errno)); @@ -723,6 +553,7 @@ _syslog_send(asl_msg_t *msg, struct config_rule *r, char **out, char **fwd, time fprintf(pw, "%s", *out); pclose(pw); +#endif } if (is_dup == 1) @@ -731,7 +562,7 @@ _syslog_send(asl_msg_t *msg, struct config_rule *r, char **out, char **fwd, time } else { - if (r->last_msg != NULL) free(r->last_msg); + free(r->last_msg); r->last_msg = NULL; if (*out != NULL) r->last_msg = strdup(*out + 16); @@ -745,9 +576,10 @@ _syslog_send(asl_msg_t *msg, struct config_rule *r, char **out, char **fwd, time } static int -_syslog_rule_match(asl_msg_t *msg, struct config_rule *r) +_bsd_rule_match(asl_msg_t *msg, struct config_rule *r) { - uint32_t i, test, f, pri; + uint32_t i, test, f; + int32_t pri; const char *val; if (msg == NULL) return 0; @@ -764,11 +596,19 @@ _syslog_rule_match(asl_msg_t *msg, struct config_rule *r) if ((test == 0) && (r->pri[i] == -2)) continue; f = 0; - if (strcmp(r->facility[i], "*") == 0) f = 1; - else + val = asl_msg_get_val_for_key(msg, ASL_KEY_FACILITY); + + if (strcmp(r->facility[i], "*") == 0) + { + f = 1; + } + else if ((r->fac_prefix_len[i] > 0) && (strncasecmp(r->facility[i], val, r->fac_prefix_len[i]) == 0)) + { + f = 1; + } + else if ((val != NULL) && (strcasecmp(r->facility[i], val) == 0)) { - val = asl_get(msg, ASL_KEY_FACILITY); - if ((val != NULL) && (strcasecmp(r->facility[i], val) == 0)) f = 1; + f = 1; } if (f == 0) continue; @@ -780,7 +620,7 @@ _syslog_rule_match(asl_msg_t *msg, struct config_rule *r) continue; } - val = asl_get(msg, ASL_KEY_LEVEL); + val = asl_msg_get_val_for_key(msg, ASL_KEY_LEVEL); if (val == NULL) continue; pri = atoi(val); @@ -792,96 +632,72 @@ _syslog_rule_match(asl_msg_t *msg, struct config_rule *r) return test; } -int -bsd_out_sendmsg(asl_msg_t *msg, const char *outid) +static int +_bsd_match_and_send(asl_msg_t *msg) { struct config_rule *r; char *out, *fwd; - time_t tick; - uint64_t delta; - - if (reset != RESET_NONE) _do_reset(); + time_t now; if (msg == NULL) return -1; out = NULL; fwd = NULL; - tick = time(NULL); - global.bsd_flush_time = 0; + now = time(NULL); for (r = bsd_out_rule.tqh_first; r != NULL; r = r->entries.tqe_next) { - if (_syslog_rule_match(msg, r) == 1) _syslog_send(msg, r, &out, &fwd, tick); - if ((r->type == DST_TYPE_FILE) && (r->last_count > 0)) - { - delta = tick - r->last_time; - if (delta < global.bsd_max_dup_time) - { - 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; - } - } + if (_bsd_rule_match(msg, r) == 1) _bsd_send(msg, r, &out, &fwd, now); } - if (out != NULL) free(out); - if (fwd != NULL) free(fwd); + free(out); + free(fwd); return 0; } void -bsd_close_idle_files(time_t now) +bsd_out_message(asl_msg_t *msg, int64_t msize) { - struct config_rule *r; - uint64_t delta; + if (msg == NULL) return; - for (r = bsd_out_rule.tqh_first; r != NULL; r = r->entries.tqe_next) - { - /* only applies to files */ - if (r->type != DST_TYPE_FILE) continue; + OSAtomicIncrement32(&global.bsd_queue_count); + asl_msg_retain((asl_msg_t *)msg); - /* - * If the last message repeat count is non-zero, a bsd_flush_duplicates() - * call will occur within 30 seconds. Don't bother closing the file. - */ - if (r->last_count > 0) continue; + dispatch_async(bsd_out_queue, ^{ + _bsd_match_and_send(msg); + asl_msg_release((asl_msg_t *)msg); - delta = now - r->last_time; - if (delta > CLOSE_ON_IDLE_SEC) _syslog_dst_close(r); - } + /* end of the output module chain (after asl) - decrement global memory stats */ + OSAtomicAdd64(-1ll * msize, &global.memory_size); + + OSAtomicDecrement32(&global.bsd_queue_count); + }); } -void -bsd_flush_duplicates(time_t now) +static void +_bsd_close_idle_files() { + time_t now; struct config_rule *r; uint64_t delta; - global.bsd_flush_time = 0; + now = time(NULL); for (r = bsd_out_rule.tqh_first; r != NULL; r = r->entries.tqe_next) { + /* only applies to files */ if (r->type != DST_TYPE_FILE) continue; - if (r->last_count > 0) - { - delta = now - r->last_time; - if (delta < global.bsd_max_dup_time) - { - 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 - { - _syslog_dst_open(r); - _syslog_send_repeat_msg(r); + /* + * If the last message repeat count is non-zero, a _bsd_flush_duplicates() + * call will occur within 30 seconds. Don't bother closing the file. + */ + if (r->last_count > 0) continue; - r->last_count = 0; - } - } + delta = now - r->last_time; + if (delta > CLOSE_ON_IDLE_SEC) _syslog_dst_close(r); } } @@ -908,27 +724,28 @@ _parse_config_file(const char *confname) int bsd_out_init(void) { + static dispatch_once_t once; + asldebug("%s: init\n", MY_ID); TAILQ_INIT(&bsd_out_rule); + _parse_config_file(_PATH_SYSLOG_CONF); - query = asl_new(ASL_TYPE_QUERY); - aslevent_addmatch(query, MY_ID); - aslevent_addoutput(bsd_out_sendmsg, MY_ID); + dispatch_once(&once, ^{ + bsd_out_queue = dispatch_queue_create("BSD Out Queue", NULL); - _parse_config_file(_PATH_SYSLOG_CONF); - return 0; -} + /* start a timer to close idle files */ + bsd_idle_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, bsd_out_queue); + dispatch_source_set_event_handler(bsd_idle_timer, ^{ _bsd_close_idle_files(); }); + dispatch_source_set_timer(bsd_idle_timer, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * CLOSE_ON_IDLE_SEC), NSEC_PER_SEC * CLOSE_ON_IDLE_SEC, 0); + dispatch_resume(bsd_idle_timer); + }); -int -bsd_out_reset(void) -{ - reset = global.reset; return 0; } -int -bsd_out_close(void) +static int +_bsd_out_close_internal(void) { struct config_rule *r, *n; int i; @@ -938,19 +755,30 @@ bsd_out_close(void) { n = r->entries.tqe_next; - if (r->dst != NULL) free(r->dst); - if (r->fd > 0) close(r->fd); - if (r->addr != NULL) free(r->addr); - if (r->last_msg != NULL) free(r->last_msg); + if (r->dup_timer != NULL) + { + if (r->last_count > 0) _bsd_send_repeat_msg(r); + dispatch_source_cancel(r->dup_timer); + dispatch_resume(r->dup_timer); + dispatch_release(r->dup_timer); + } + + free(r->dst); + free(r->addr); + free(r->last_msg); + free(r->fac_prefix_len); + free(r->pri); + + if (r->fd >= 0) close(r->fd); + if (r->facility != NULL) { for (i = 0; i < r->count; i++) - { - if (r->facility[i] != NULL) free(r->facility[i]); - } + free(r->facility[i]); + free(r->facility); } - if (r->pri != NULL) free(r->pri); + TAILQ_REMOVE(&bsd_out_rule, r, entries); free(r); @@ -960,18 +788,24 @@ bsd_out_close(void) } int -bsd_out_network_reset(void) +bsd_out_close(void) { - struct config_rule *r; - - for (r = bsd_out_rule.tqh_first; r != NULL; r = r->entries.tqe_next) - { - if (r->type == DST_TYPE_SOCK) - { - close(r->fd); - r->fd = -1; - } - } - + dispatch_async(bsd_out_queue, ^{ + _bsd_out_close_internal(); + }); + + return 0; +} + +int +bsd_out_reset(void) +{ + dispatch_async(bsd_out_queue, ^{ + _bsd_out_close_internal(); + bsd_out_init(); + }); + return 0; } + +#endif /* !TARGET_OS_SIMULATOR */