diff options
Diffstat (limited to 'src/journal')
-rw-r--r-- | src/journal/journald-audit.c | 19 | ||||
-rw-r--r-- | src/journal/journald-context.c | 151 | ||||
-rw-r--r-- | src/journal/journald-context.h | 21 | ||||
-rw-r--r-- | src/journal/journald-kmsg.c | 9 | ||||
-rw-r--r-- | src/journal/journald-native.c | 25 | ||||
-rw-r--r-- | src/journal/journald-server.c | 33 | ||||
-rw-r--r-- | src/journal/journald-server.h | 2 | ||||
-rw-r--r-- | src/journal/journald-stream.c | 28 | ||||
-rw-r--r-- | src/journal/journald-syslog.c | 24 |
9 files changed, 240 insertions, 72 deletions
diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c index 86ca56af94..2db923fb49 100644 --- a/src/journal/journald-audit.c +++ b/src/journal/journald-audit.c @@ -29,10 +29,10 @@ typedef struct MapField { const char *audit_field; const char *journal_field; - int (*map)(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov); + int (*map)(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, size_t *n_iov); } MapField; -static int map_simple_field(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) { +static int map_simple_field(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, size_t *n_iov) { _cleanup_free_ char *c = NULL; size_t l = 0, allocated = 0; const char *e; @@ -69,7 +69,7 @@ static int map_simple_field(const char *field, const char **p, struct iovec **io return 1; } -static int map_string_field_internal(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov, bool filter_printable) { +static int map_string_field_internal(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, size_t *n_iov, bool filter_printable) { _cleanup_free_ char *c = NULL; const char *s, *e; size_t l; @@ -146,15 +146,15 @@ static int map_string_field_internal(const char *field, const char **p, struct i return 1; } -static int map_string_field(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) { +static int map_string_field(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, size_t *n_iov) { return map_string_field_internal(field, p, iov, n_iov_allocated, n_iov, false); } -static int map_string_field_printable(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) { +static int map_string_field_printable(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, size_t *n_iov) { return map_string_field_internal(field, p, iov, n_iov_allocated, n_iov, true); } -static int map_generic_field(const char *prefix, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) { +static int map_generic_field(const char *prefix, const char **p, struct iovec **iov, size_t *n_iov_allocated, size_t *n_iov) { const char *e, *f; char *c, *t; int r; @@ -259,7 +259,7 @@ static int map_all_fields( bool handle_msg, struct iovec **iov, size_t *n_iov_allocated, - unsigned *n_iov) { + size_t *n_iov) { int r; @@ -331,16 +331,15 @@ static int map_all_fields( } static void process_audit_string(Server *s, int type, const char *data, size_t size) { + size_t n_iov_allocated = 0, n_iov = 0, z; _cleanup_free_ struct iovec *iov = NULL; - size_t n_iov_allocated = 0; - unsigned n_iov = 0, k; uint64_t seconds, msec, id; const char *p, *type_name; - unsigned z; char id_field[sizeof("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)], type_field[sizeof("_AUDIT_TYPE=") + DECIMAL_STR_MAX(int)], source_time_field[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)]; char *m; + int k; assert(s); diff --git a/src/journal/journald-context.c b/src/journal/journald-context.c index eaa7f2544f..3a5a97b496 100644 --- a/src/journal/journald-context.c +++ b/src/journal/journald-context.c @@ -24,9 +24,16 @@ #include "alloc-util.h" #include "audit-util.h" #include "cgroup-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "io-util.h" +#include "journal-util.h" #include "journald-context.h" #include "process-util.h" #include "string-util.h" +#include "syslog-util.h" +#include "unaligned.h" #include "user-util.h" /* This implements a metadata cache for clients, which are identified by their PID. Requesting metadata through /proc @@ -115,6 +122,8 @@ static int client_context_new(Server *s, pid_t pid, ClientContext **ret) { c->owner_uid = UID_INVALID; c->lru_index = PRIOQ_IDX_NULL; c->timestamp = USEC_INFINITY; + c->extra_fields_mtime = NSEC_INFINITY; + c->log_level_max = -1; r = hashmap_put(s->client_contexts, PID_TO_PTR(pid), c); if (r < 0) { @@ -154,6 +163,13 @@ static void client_context_reset(ClientContext *c) { c->label = mfree(c->label); c->label_size = 0; + + c->extra_fields_iovec = mfree(c->extra_fields_iovec); + c->extra_fields_n_iovec = 0; + c->extra_fields_data = mfree(c->extra_fields_data); + c->extra_fields_mtime = NSEC_INFINITY; + + c->log_level_max = -1; } static ClientContext* client_context_free(Server *s, ClientContext *c) { @@ -296,40 +312,141 @@ static int client_context_read_invocation_id( Server *s, ClientContext *c) { - _cleanup_free_ char *escaped = NULL, *slice_path = NULL; - char ids[SD_ID128_STRING_MAX]; + _cleanup_free_ char *value = NULL; const char *p; int r; assert(s); assert(c); - /* Read the invocation ID of a unit off a unit. It's stored in the "trusted.invocation_id" extended attribute - * on the cgroup path. */ + /* Read the invocation ID of a unit off a unit. PID 1 stores it in a per-unit symlink in /run/systemd/units/ */ - if (!c->unit || !c->slice) + if (!c->unit) return 0; - r = cg_slice_to_path(c->slice, &slice_path); + p = strjoina("/run/systemd/units/invocation:", c->unit); + r = readlink_malloc(p, &value); if (r < 0) return r; - escaped = cg_escape(c->unit); - if (!escaped) - return -ENOMEM; + return sd_id128_from_string(value, &c->invocation_id); +} - p = strjoina(s->cgroup_root, "/", slice_path, "/", escaped); - if (!p) - return -ENOMEM; +static int client_context_read_log_level_max( + Server *s, + ClientContext *c) { - r = cg_get_xattr(SYSTEMD_CGROUP_CONTROLLER, p, "trusted.invocation_id", ids, 32); + _cleanup_free_ char *value = NULL; + const char *p; + int r, ll; + + if (!c->unit) + return 0; + + p = strjoina("/run/systemd/units/log-level-max:", c->unit); + r = readlink_malloc(p, &value); if (r < 0) return r; - if (r != 32) + + ll = log_level_from_string(value); + if (ll < 0) return -EINVAL; - ids[32] = 0; - return sd_id128_from_string(ids, &c->invocation_id); + c->log_level_max = ll; + return 0; +} + +static int client_context_read_extra_fields( + Server *s, + ClientContext *c) { + + size_t size = 0, n_iovec = 0, n_allocated = 0, left; + _cleanup_free_ struct iovec *iovec = NULL; + _cleanup_free_ void *data = NULL; + _cleanup_fclose_ FILE *f = NULL; + struct stat st; + const char *p; + uint8_t *q; + int r; + + if (!c->unit) + return 0; + + p = strjoina("/run/systemd/units/log-extra-fields:", c->unit); + + if (c->extra_fields_mtime != NSEC_INFINITY) { + if (stat(p, &st) < 0) { + if (errno == ENOENT) + return 0; + + return -errno; + } + + if (timespec_load_nsec(&st.st_mtim) == c->extra_fields_mtime) + return 0; + } + + f = fopen(p, "re"); + if (!f) { + if (errno == ENOENT) + return 0; + + return -errno; + } + + if (fstat(fileno(f), &st) < 0) /* The file might have been replaced since the stat() above, let's get a new + * one, that matches the stuff we are reading */ + return -errno; + + r = read_full_stream(f, (char**) &data, &size); + if (r < 0) + return r; + + q = data, left = size; + while (left > 0) { + uint8_t *field, *eq; + uint64_t v, n; + + if (left < sizeof(uint64_t)) + return -EBADMSG; + + v = unaligned_read_le64(q); + if (v < 2) + return -EBADMSG; + + n = sizeof(uint64_t) + v; + if (left < n) + return -EBADMSG; + + field = q + sizeof(uint64_t); + + eq = memchr(field, '=', v); + if (!eq) + return -EBADMSG; + + if (!journal_field_valid((const char *) field, eq - field, false)) + return -EBADMSG; + + if (!GREEDY_REALLOC(iovec, n_allocated, n_iovec+1)) + return -ENOMEM; + + iovec[n_iovec++] = IOVEC_MAKE(field, v); + + left -= n, q += n; + } + + free(c->extra_fields_iovec); + free(c->extra_fields_data); + + c->extra_fields_iovec = iovec; + c->extra_fields_n_iovec = n_iovec; + c->extra_fields_data = data; + c->extra_fields_mtime = timespec_load_nsec(&st.st_mtim); + + iovec = NULL; + data = NULL; + + return 0; } static void client_context_really_refresh( @@ -356,6 +473,8 @@ static void client_context_really_refresh( (void) client_context_read_cgroup(s, c, unit_id); (void) client_context_read_invocation_id(s, c); + (void) client_context_read_log_level_max(s, c); + (void) client_context_read_extra_fields(s, c); c->timestamp = timestamp; diff --git a/src/journal/journald-context.h b/src/journal/journald-context.h index eb1e21926a..d2a3772f08 100644 --- a/src/journal/journald-context.h +++ b/src/journal/journald-context.h @@ -60,6 +60,13 @@ struct ClientContext { char *label; size_t label_size; + + int log_level_max; + + struct iovec *extra_fields_iovec; + size_t extra_fields_n_iovec; + void *extra_fields_data; + nsec_t extra_fields_mtime; }; int client_context_get( @@ -90,3 +97,17 @@ void client_context_maybe_refresh( void client_context_acquire_default(Server *s); void client_context_flush_all(Server *s); + +static inline size_t client_context_extra_fields_n_iovec(const ClientContext *c) { + return c ? c->extra_fields_n_iovec : 0; +} + +static inline bool client_context_test_priority(const ClientContext *c, int priority) { + if (!c) + return true; + + if (c->log_level_max < 0) + return true; + + return LOG_PRI(priority) <= c->log_level_max; +} diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c index a53075ac00..b4d3121a0d 100644 --- a/src/journal/journald-kmsg.c +++ b/src/journal/journald-kmsg.c @@ -109,15 +109,16 @@ static bool is_us(const char *pid) { } static void dev_kmsg_record(Server *s, const char *p, size_t l) { - struct iovec iovec[N_IOVEC_META_FIELDS + 7 + N_IOVEC_KERNEL_FIELDS + 2 + N_IOVEC_UDEV_FIELDS]; + _cleanup_free_ char *message = NULL, *syslog_priority = NULL, *syslog_pid = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *source_time = NULL, *identifier = NULL, *pid = NULL; - int priority, r; - unsigned n = 0, z = 0, j; + struct iovec iovec[N_IOVEC_META_FIELDS + 7 + N_IOVEC_KERNEL_FIELDS + 2 + N_IOVEC_UDEV_FIELDS]; + char *kernel_device = NULL; unsigned long long usec; + size_t n = 0, z = 0, j; + int priority, r; char *e, *f, *k; uint64_t serial; size_t pl; - char *kernel_device = NULL; assert(s); assert(p); diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index d1fdfccd46..5452b88ae2 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -114,19 +114,17 @@ static int server_process_entry( const struct timeval *tv, const char *label, size_t label_len) { - /* Process a single entry from a native message. - * Returns 0 if nothing special happened and the message processing should continue, - * and a negative or positive value otherwise. + /* Process a single entry from a native message. Returns 0 if nothing special happened and the message + * processing should continue, and a negative or positive value otherwise. * * Note that *remaining is altered on both success and failure. */ + size_t n = 0, j, tn = (size_t) -1, m = 0, entry_size = 0; + char *identifier = NULL, *message = NULL; struct iovec *iovec = NULL; - unsigned n = 0, j, tn = (unsigned) -1; - const char *p; - size_t m = 0, entry_size = 0; int priority = LOG_INFO; - char *identifier = NULL, *message = NULL; pid_t object_pid = 0; + const char *p; int r = 0; p = buffer; @@ -160,7 +158,10 @@ static int server_process_entry( /* A property follows */ /* n existing properties, 1 new, +1 for _TRANSPORT */ - if (!GREEDY_REALLOC(iovec, m, n + 2 + N_IOVEC_META_FIELDS + N_IOVEC_OBJECT_FIELDS)) { + if (!GREEDY_REALLOC(iovec, m, + n + 2 + + N_IOVEC_META_FIELDS + N_IOVEC_OBJECT_FIELDS + + client_context_extra_fields_n_iovec(context))) { r = log_oom(); break; } @@ -243,13 +244,17 @@ static int server_process_entry( goto finish; } + if (!client_context_test_priority(context, priority)) { + r = 0; + goto finish; + } + tn = n++; iovec[tn] = IOVEC_MAKE_STRING("_TRANSPORT=journal"); entry_size += strlen("_TRANSPORT=journal"); if (entry_size + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */ - log_debug("Entry is too big with %u properties and %zu bytes, ignoring.", - n, entry_size); + log_debug("Entry is too big with %zu properties and %zu bytes, ignoring.", n, entry_size); goto finish; } diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index e85e4e0f10..033f0b1a8b 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -753,7 +753,7 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned static void dispatch_message_real( Server *s, - struct iovec *iovec, unsigned n, unsigned m, + struct iovec *iovec, size_t n, size_t m, const ClientContext *c, const struct timeval *tv, int priority, @@ -766,7 +766,10 @@ static void dispatch_message_real( assert(s); assert(iovec); assert(n > 0); - assert(n + N_IOVEC_META_FIELDS + (pid_is_valid(object_pid) ? N_IOVEC_OBJECT_FIELDS : 0) <= m); + assert(n + + N_IOVEC_META_FIELDS + + (pid_is_valid(object_pid) ? N_IOVEC_OBJECT_FIELDS : 0) + + client_context_extra_fields_n_iovec(c) <= m); if (c) { IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->pid, pid_t, pid_is_valid, PID_FMT, "_PID"); @@ -792,6 +795,11 @@ static void dispatch_message_real( IOVEC_ADD_STRING_FIELD(iovec, n, c->user_slice, "_SYSTEMD_USER_SLICE"); IOVEC_ADD_ID128_FIELD(iovec, n, c->invocation_id, "_SYSTEMD_INVOCATION_ID"); + + if (c->extra_fields_n_iovec > 0) { + memcpy(iovec + n, c->extra_fields_iovec, c->extra_fields_n_iovec * sizeof(struct iovec)); + n += c->extra_fields_n_iovec; + } } assert(n <= m); @@ -862,14 +870,17 @@ static void dispatch_message_real( void server_driver_message(Server *s, pid_t object_pid, const char *message_id, const char *format, ...) { - struct iovec iovec[N_IOVEC_META_FIELDS + 5 + N_IOVEC_PAYLOAD_FIELDS]; - unsigned n = 0, m; + struct iovec *iovec; + size_t n = 0, k, m; va_list ap; int r; assert(s); assert(format); + m = N_IOVEC_META_FIELDS + 5 + N_IOVEC_PAYLOAD_FIELDS + client_context_extra_fields_n_iovec(s->my_context); + iovec = newa(struct iovec, m); + assert_cc(3 == LOG_FAC(LOG_DAEMON)); iovec[n++] = IOVEC_MAKE_STRING("SYSLOG_FACILITY=3"); iovec[n++] = IOVEC_MAKE_STRING("SYSLOG_IDENTIFIER=systemd-journald"); @@ -880,18 +891,18 @@ void server_driver_message(Server *s, pid_t object_pid, const char *message_id, if (message_id) iovec[n++] = IOVEC_MAKE_STRING(message_id); - m = n; + k = n; va_start(ap, format); - r = log_format_iovec(iovec, ELEMENTSOF(iovec), &n, false, 0, format, ap); + r = log_format_iovec(iovec, m, &n, false, 0, format, ap); /* Error handling below */ va_end(ap); if (r >= 0) - dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), s->my_context, NULL, LOG_INFO, object_pid); + dispatch_message_real(s, iovec, n, m, s->my_context, NULL, LOG_INFO, object_pid); - while (m < n) - free(iovec[m++].iov_base); + while (k < n) + free(iovec[k++].iov_base); if (r < 0) { /* We failed to format the message. Emit a warning instead. */ @@ -902,13 +913,13 @@ void server_driver_message(Server *s, pid_t object_pid, const char *message_id, n = 3; iovec[n++] = IOVEC_MAKE_STRING("PRIORITY=4"); iovec[n++] = IOVEC_MAKE_STRING(buf); - dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), s->my_context, NULL, LOG_INFO, object_pid); + dispatch_message_real(s, iovec, n, m, s->my_context, NULL, LOG_INFO, object_pid); } } void server_dispatch_message( Server *s, - struct iovec *iovec, unsigned n, unsigned m, + struct iovec *iovec, size_t n, size_t m, ClientContext *c, const struct timeval *tv, int priority, diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h index 5efc5fe119..f0076793e1 100644 --- a/src/journal/journald-server.h +++ b/src/journal/journald-server.h @@ -187,7 +187,7 @@ struct Server { #define N_IOVEC_OBJECT_FIELDS 14 #define N_IOVEC_PAYLOAD_FIELDS 15 -void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, ClientContext *c, const struct timeval *tv, int priority, pid_t object_pid); +void server_dispatch_message(Server *s, struct iovec *iovec, size_t n, size_t m, ClientContext *c, const struct timeval *tv, int priority, pid_t object_pid); void server_driver_message(Server *s, pid_t object_pid, const char *message_id, const char *format, ...) _sentinel_; /* gperf lookup function */ diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c index 54dd096e45..95272db863 100644 --- a/src/journal/journald-stream.c +++ b/src/journal/journald-stream.c @@ -251,22 +251,33 @@ fail: } static int stdout_stream_log(StdoutStream *s, const char *p, LineBreak line_break) { - struct iovec iovec[N_IOVEC_META_FIELDS + 7]; + struct iovec *iovec; int priority; char syslog_priority[] = "PRIORITY=\0"; char syslog_facility[sizeof("SYSLOG_FACILITY=")-1 + DECIMAL_STR_MAX(int) + 1]; _cleanup_free_ char *message = NULL, *syslog_identifier = NULL; - unsigned n = 0; + size_t n = 0, m; int r; assert(s); assert(p); + if (s->context) + (void) client_context_maybe_refresh(s->server, s->context, NULL, NULL, 0, NULL, USEC_INFINITY); + else if (pid_is_valid(s->ucred.pid)) { + r = client_context_acquire(s->server, s->ucred.pid, &s->ucred, s->label, strlen_ptr(s->label), s->unit_id, &s->context); + if (r < 0) + log_warning_errno(r, "Failed to acquire client context, ignoring: %m"); + } + priority = s->priority; if (s->level_prefix) syslog_parse_priority(&p, &priority, false); + if (!client_context_test_priority(s->context, priority)) + return 0; + if (isempty(p)) return 0; @@ -282,6 +293,9 @@ static int stdout_stream_log(StdoutStream *s, const char *p, LineBreak line_brea if (s->server->forward_to_wall) server_forward_wall(s->server, priority, s->identifier, p, &s->ucred); + m = N_IOVEC_META_FIELDS + 7 + client_context_extra_fields_n_iovec(s->context); + iovec = newa(struct iovec, m); + iovec[n++] = IOVEC_MAKE_STRING("_TRANSPORT=stdout"); iovec[n++] = IOVEC_MAKE_STRING(s->id_field); @@ -315,15 +329,7 @@ static int stdout_stream_log(StdoutStream *s, const char *p, LineBreak line_brea if (message) iovec[n++] = IOVEC_MAKE_STRING(message); - if (s->context) - (void) client_context_maybe_refresh(s->server, s->context, NULL, NULL, 0, NULL, USEC_INFINITY); - else if (pid_is_valid(s->ucred.pid)) { - r = client_context_acquire(s->server, s->ucred.pid, &s->ucred, s->label, strlen_ptr(s->label), s->unit_id, &s->context); - if (r < 0) - log_warning_errno(r, "Failed to acquire client context, ignoring: %m"); - } - - server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), s->context, NULL, priority, 0); + server_dispatch_message(s->server, iovec, n, m, s->context, NULL, priority, 0); return 0; } diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c index b3db310fbf..07f9dae67e 100644 --- a/src/journal/journald-syslog.c +++ b/src/journal/journald-syslog.c @@ -324,18 +324,27 @@ void server_process_syslog_message( syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)]; const char *message = NULL, *syslog_identifier = NULL, *syslog_pid = NULL; _cleanup_free_ char *identifier = NULL, *pid = NULL; - struct iovec iovec[N_IOVEC_META_FIELDS + 6]; int priority = LOG_USER | LOG_INFO, r; ClientContext *context = NULL; + struct iovec *iovec; const char *orig; - unsigned n = 0; + size_t n = 0, m; assert(s); assert(buf); + if (ucred && pid_is_valid(ucred->pid)) { + r = client_context_get(s, ucred->pid, ucred, label, label_len, NULL, &context); + if (r < 0) + log_warning_errno(r, "Failed to retrieve credentials for PID " PID_FMT ", ignoring: %m", ucred->pid); + } + orig = buf; syslog_parse_priority(&buf, &priority, true); + if (!client_context_test_priority(context, priority)) + return; + if (s->forward_to_syslog) forward_syslog_raw(s, priority, orig, ucred, tv); @@ -351,6 +360,9 @@ void server_process_syslog_message( if (s->forward_to_wall) server_forward_wall(s, priority, identifier, buf, ucred); + m = N_IOVEC_META_FIELDS + 6 + client_context_extra_fields_n_iovec(context); + iovec = newa(struct iovec, m); + iovec[n++] = IOVEC_MAKE_STRING("_TRANSPORT=syslog"); xsprintf(syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK); @@ -375,13 +387,7 @@ void server_process_syslog_message( if (message) iovec[n++] = IOVEC_MAKE_STRING(message); - if (ucred && pid_is_valid(ucred->pid)) { - r = client_context_get(s, ucred->pid, ucred, label, label_len, NULL, &context); - if (r < 0) - log_warning_errno(r, "Failed to retrieve credentials for PID " PID_FMT ", ignoring: %m", ucred->pid); - } - - server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), context, tv, priority, 0); + server_dispatch_message(s, iovec, n, m, context, tv, priority, 0); } int server_open_syslog_socket(Server *s) { |