diff --git a/Makefile-man.am b/Makefile-man.am index ef5077cc5a..a900b8d25a 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -239,6 +239,7 @@ MANPAGES_ALIAS += \ man/SD_ID128_FORMAT_STR.3 \ man/SD_ID128_FORMAT_VAL.3 \ man/SD_ID128_MAKE.3 \ + man/SD_ID128_NULL.3 \ man/SD_INFO.3 \ man/SD_JOURNAL_APPEND.3 \ man/SD_JOURNAL_CURRENT_USER.3 \ @@ -395,6 +396,8 @@ MANPAGES_ALIAS += \ man/sd_id128_equal.3 \ man/sd_id128_from_string.3 \ man/sd_id128_get_boot.3 \ + man/sd_id128_get_invocation.3 \ + man/sd_id128_is_null.3 \ man/sd_id128_t.3 \ man/sd_is_mq.3 \ man/sd_is_socket.3 \ @@ -589,6 +592,7 @@ man/SD_ID128_CONST_STR.3: man/sd-id128.3 man/SD_ID128_FORMAT_STR.3: man/sd-id128.3 man/SD_ID128_FORMAT_VAL.3: man/sd-id128.3 man/SD_ID128_MAKE.3: man/sd-id128.3 +man/SD_ID128_NULL.3: man/sd-id128.3 man/SD_INFO.3: man/sd-daemon.3 man/SD_JOURNAL_APPEND.3: man/sd_journal_get_fd.3 man/SD_JOURNAL_CURRENT_USER.3: man/sd_journal_open.3 @@ -745,6 +749,8 @@ man/sd_event_unrefp.3: man/sd_event_new.3 man/sd_id128_equal.3: man/sd-id128.3 man/sd_id128_from_string.3: man/sd_id128_to_string.3 man/sd_id128_get_boot.3: man/sd_id128_get_machine.3 +man/sd_id128_get_invocation.3: man/sd_id128_get_machine.3 +man/sd_id128_is_null.3: man/sd-id128.3 man/sd_id128_t.3: man/sd-id128.3 man/sd_is_mq.3: man/sd_is_fifo.3 man/sd_is_socket.3: man/sd_is_fifo.3 @@ -1051,6 +1057,9 @@ man/SD_ID128_FORMAT_VAL.html: man/sd-id128.html man/SD_ID128_MAKE.html: man/sd-id128.html $(html-alias) +man/SD_ID128_NULL.html: man/sd-id128.html + $(html-alias) + man/SD_INFO.html: man/sd-daemon.html $(html-alias) @@ -1519,6 +1528,12 @@ man/sd_id128_from_string.html: man/sd_id128_to_string.html man/sd_id128_get_boot.html: man/sd_id128_get_machine.html $(html-alias) +man/sd_id128_get_invocation.html: man/sd_id128_get_machine.html + $(html-alias) + +man/sd_id128_is_null.html: man/sd-id128.html + $(html-alias) + man/sd_id128_t.html: man/sd-id128.html $(html-alias) diff --git a/TODO b/TODO index 752253f826..b4443ce585 100644 --- a/TODO +++ b/TODO @@ -74,6 +74,12 @@ Features: * RemoveKeyRing= to remove all keyring entries of the specified user +* ProtectReboot= that masks reboot() and kexec_load() syscalls, prohibits kill + on PID 1 with the relevant signals, and makes relevant files in /sys and + /proc (such as the sysrq stuff) unavailable + +* DeviceAllow= should also generate seccomp filters for mknod() + * Add DataDirectory=, CacheDirectory= and LogDirectory= to match RuntimeDirectory=, and create it as necessary when starting a service, owned by the right user. diff --git a/man/sd-id128.xml b/man/sd-id128.xml index ea7972055d..5f24feff8e 100644 --- a/man/sd-id128.xml +++ b/man/sd-id128.xml @@ -47,10 +47,12 @@ sd-id128 sd_id128_t SD_ID128_MAKE + SD_ID128_NULL SD_ID128_CONST_STR SD_ID128_FORMAT_STR SD_ID128_FORMAT_VAL sd_id128_equal + sd_id128_is_null APIs for processing 128-bit IDs @@ -88,8 +90,8 @@ union type: typedef union sd_id128 { - uint8_t bytes[16]; - uint64_t qwords[2]; + uint8_t bytes[16]; + uint64_t qwords[2]; } sd_id128_t; This union type allows accessing the 128-bit ID as 16 @@ -108,37 +110,46 @@ #define SD_MESSAGE_COREDUMP SD_ID128_MAKE(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1) + SD_ID128_NULL may be used to refer to the 128bit ID consisting of only NUL + bytes. + SD_ID128_CONST_STR() may be used to convert constant 128-bit IDs into constant strings for output. The following example code will output the string "fc2e22bc6ee647b6b90729ab34a250b1": int main(int argc, char *argv[]) { - puts(SD_ID128_CONST_STR(SD_MESSAGE_COREDUMP)); + puts(SD_ID128_CONST_STR(SD_MESSAGE_COREDUMP)); } - SD_ID128_FORMAT_STR and + SD_ID128_FORMAT_STR() and SD_ID128_FORMAT_VAL() may be used to format a 128-bit ID in a printf3 format string, as shown in the following example: int main(int argc, char *argv[]) { - sd_id128_t id; - id = SD_ID128_MAKE(ee,89,be,71,bd,6e,43,d6,91,e6,c5,5d,eb,03,02,07); - printf("The ID encoded in this C file is " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(id)); - return 0; + sd_id128_t id; + id = SD_ID128_MAKE(ee,89,be,71,bd,6e,43,d6,91,e6,c5,5d,eb,03,02,07); + printf("The ID encoded in this C file is " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(id)); + return 0; } Use sd_id128_equal() to compare two 128-bit IDs: int main(int argc, char *argv[]) { - sd_id128_t a, b, c; - a = SD_ID128_MAKE(ee,89,be,71,bd,6e,43,d6,91,e6,c5,5d,eb,03,02,07); - b = SD_ID128_MAKE(f2,28,88,9c,5f,09,44,15,9d,d7,04,77,58,cb,e7,3e); - c = a; - assert(sd_id128_equal(a, c)); - assert(!sd_id128_equal(a, b)); - return 0; + sd_id128_t a, b, c; + a = SD_ID128_MAKE(ee,89,be,71,bd,6e,43,d6,91,e6,c5,5d,eb,03,02,07); + b = SD_ID128_MAKE(f2,28,88,9c,5f,09,44,15,9d,d7,04,77,58,cb,e7,3e); + c = a; + assert(sd_id128_equal(a, c)); + assert(!sd_id128_equal(a, b)); + return 0; +} + + Use sd_id128_is_null() to check if an 128bit ID consists of only NUL bytes: + + int main(int argc, char *argv[]) { + assert(sd_id128_is_null(SD_ID128_NULL)); } Note that new, randomized IDs may be generated with diff --git a/man/sd_id128_get_machine.xml b/man/sd_id128_get_machine.xml index 2ad1f8f728..9a86c24aed 100644 --- a/man/sd_id128_get_machine.xml +++ b/man/sd_id128_get_machine.xml @@ -45,6 +45,7 @@ sd_id128_get_machine sd_id128_get_boot + sd_id128_get_invocation Retrieve 128-bit IDs @@ -62,6 +63,11 @@ sd_id128_t *ret + + int sd_id128_get_invocation + sd_id128_t *ret + + @@ -83,11 +89,15 @@ for more information. This function also internally caches the returned ID to make this call a cheap operation. - Note that sd_id128_get_boot() always - returns a UUID v4 compatible ID. - sd_id128_get_machine() will also return a - UUID v4-compatible ID on new installations but might not on older. - It is possible to convert the machine ID into a UUID v4-compatible + sd_id128_get_invocation() returns the invocation ID of the currently executed + service. In its current implementation, this reads and parses the $INVOCATION_ID environment + variable that the service manager sets when activating a service, see + systemd.exec5 for details. The + ID is cached internally. In future a different mechanism to determine the invocation ID may be added. + + Note that sd_id128_get_boot() and sd_id128_get_invocation() always + return UUID v4 compatible IDs. sd_id128_get_machine() will also return a UUID v4-compatible + ID on new installations but might not on older. It is possible to convert the machine ID into a UUID v4-compatible one. For more information, see machine-id5. @@ -107,11 +117,10 @@ Notes - The sd_id128_get_machine() and - sd_id128_get_boot() interfaces are available - as a shared library, which can be compiled and linked to with the - libsystemd pkg-config1 - file. + The sd_id128_get_machine(), sd_id128_get_boot() and + sd_id128_get_invocation() interfaces are available as a shared library, which can be compiled + and linked to with the libsystemd pkg-config1 file. @@ -121,8 +130,9 @@ systemd1, sd-id1283, machine-id5, - random4, - sd_id128_randomize3 + systemd.exec5, + sd_id128_randomize3, + random4 diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 5e6787338d..c73ccaa493 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1513,6 +1513,16 @@ + + $INVOCATION_ID + + Contains a randomized, unique 128bit ID identifying each runtime cycle of the unit, formatted + as 32 character hexadecimal string. A new ID is assigned each time the unit changes from an inactive state into + an activating or active state, and may be used to identify this specific runtime cycle, in particular in data + stored offline, such as the journal. The same ID is passed to all processes run as part of the + unit. + + $XDG_RUNTIME_DIR diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 9b44c5a7a5..37e6928a46 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "alloc-util.h" @@ -883,6 +884,43 @@ int cg_set_task_access( return 0; } +int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags) { + _cleanup_free_ char *fs = NULL; + int r; + + assert(path); + assert(name); + assert(value || size <= 0); + + r = cg_get_path(controller, path, NULL, &fs); + if (r < 0) + return r; + + if (setxattr(fs, name, value, size, flags) < 0) + return -errno; + + return 0; +} + +int cg_get_xattr(const char *controller, const char *path, const char *name, void *value, size_t size) { + _cleanup_free_ char *fs = NULL; + ssize_t n; + int r; + + assert(path); + assert(name); + + r = cg_get_path(controller, path, NULL, &fs); + if (r < 0) + return r; + + n = getxattr(fs, name, value, size); + if (n < 0) + return -errno; + + return (int) n; +} + int cg_pid_get_path(const char *controller, pid_t pid, char **path) { _cleanup_fclose_ FILE *f = NULL; char line[LINE_MAX]; @@ -1666,7 +1704,7 @@ int cg_path_get_slice(const char *p, char **slice) { if (!e) { char *s; - s = strdup("-.slice"); + s = strdup(SPECIAL_ROOT_SLICE); if (!s) return -ENOMEM; @@ -1821,7 +1859,7 @@ int cg_slice_to_path(const char *unit, char **ret) { assert(unit); assert(ret); - if (streq(unit, "-.slice")) { + if (streq(unit, SPECIAL_ROOT_SLICE)) { char *x; x = strdup(""); diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index 1a61c7ad22..7529c9719e 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -185,6 +185,9 @@ int cg_get_keyed_attribute(const char *controller, const char *path, const char int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid); int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid); +int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags); +int cg_get_xattr(const char *controller, const char *path, const char *name, void *value, size_t size); + int cg_install_release_agent(const char *controller, const char *agent); int cg_uninstall_release_agent(const char *controller); diff --git a/src/basic/log.c b/src/basic/log.c index 49b4598b7c..bd6c96c4f8 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -133,7 +133,7 @@ static int create_log_socket(int type) { if (fd < 0) return -errno; - fd_inc_sndbuf(fd, SNDBUF_SIZE); + (void) fd_inc_sndbuf(fd, SNDBUF_SIZE); /* We need a blocking fd here since we'd otherwise lose messages way too early. However, let's not hang forever in the @@ -330,8 +330,6 @@ static int write_to_console( const char *file, int line, const char *func, - const char *object_field, - const char *object, const char *buffer) { char location[256], prefix[1 + DECIMAL_STR_MAX(int) + 2]; @@ -343,7 +341,7 @@ static int write_to_console( return 0; if (log_target == LOG_TARGET_CONSOLE_PREFIXED) { - sprintf(prefix, "<%i>", level); + xsprintf(prefix, "<%i>", level); IOVEC_SET_STRING(iovec[n++], prefix); } @@ -390,8 +388,6 @@ static int write_to_syslog( const char *file, int line, const char *func, - const char *object_field, - const char *object, const char *buffer) { char header_priority[2 + DECIMAL_STR_MAX(int) + 1], @@ -453,8 +449,6 @@ static int write_to_kmsg( const char *file, int line, const char *func, - const char *object_field, - const char *object, const char *buffer) { char header_priority[2 + DECIMAL_STR_MAX(int) + 1], @@ -485,7 +479,8 @@ static int log_do_header( int level, int error, const char *file, int line, const char *func, - const char *object_field, const char *object) { + const char *object_field, const char *object, + const char *extra_field, const char *extra) { snprintf(header, size, "PRIORITY=%i\n" @@ -495,6 +490,7 @@ static int log_do_header( "%s%s%s" "%s%.*i%s" "%s%s%s" + "%s%s%s" "SYSLOG_IDENTIFIER=%s\n", LOG_PRI(level), LOG_FAC(level), @@ -513,6 +509,9 @@ static int log_do_header( isempty(object) ? "" : object_field, isempty(object) ? "" : object, isempty(object) ? "" : "\n", + isempty(extra) ? "" : extra_field, + isempty(extra) ? "" : extra, + isempty(extra) ? "" : "\n", program_invocation_short_name); return 0; @@ -526,6 +525,8 @@ static int write_to_journal( const char *func, const char *object_field, const char *object, + const char *extra_field, + const char *extra, const char *buffer) { char header[LINE_MAX]; @@ -535,7 +536,7 @@ static int write_to_journal( if (journal_fd < 0) return 0; - log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object); + log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object, extra_field, extra); IOVEC_SET_STRING(iovec[0], header); IOVEC_SET_STRING(iovec[1], "MESSAGE="); @@ -559,10 +560,15 @@ static int log_dispatch( const char *func, const char *object_field, const char *object, + const char *extra, + const char *extra_field, char *buffer) { assert(buffer); + if (error < 0) + error = -error; + if (log_target == LOG_TARGET_NULL) return -error; @@ -570,9 +576,6 @@ static int log_dispatch( if ((level & LOG_FACMASK) == 0) level = log_facility | LOG_PRI(level); - if (error < 0) - error = -error; - do { char *e; int k = 0; @@ -589,7 +592,7 @@ static int log_dispatch( log_target == LOG_TARGET_JOURNAL_OR_KMSG || log_target == LOG_TARGET_JOURNAL) { - k = write_to_journal(level, error, file, line, func, object_field, object, buffer); + k = write_to_journal(level, error, file, line, func, object_field, object, extra_field, extra, buffer); if (k < 0) { if (k != -EAGAIN) log_close_journal(); @@ -600,7 +603,7 @@ static int log_dispatch( if (log_target == LOG_TARGET_SYSLOG_OR_KMSG || log_target == LOG_TARGET_SYSLOG) { - k = write_to_syslog(level, error, file, line, func, object_field, object, buffer); + k = write_to_syslog(level, error, file, line, func, buffer); if (k < 0) { if (k != -EAGAIN) log_close_syslog(); @@ -615,7 +618,7 @@ static int log_dispatch( log_target == LOG_TARGET_JOURNAL_OR_KMSG || log_target == LOG_TARGET_KMSG)) { - k = write_to_kmsg(level, error, file, line, func, object_field, object, buffer); + k = write_to_kmsg(level, error, file, line, func, buffer); if (k < 0) { log_close_kmsg(); log_open_console(); @@ -623,7 +626,7 @@ static int log_dispatch( } if (k <= 0) - (void) write_to_console(level, error, file, line, func, object_field, object, buffer); + (void) write_to_console(level, error, file, line, func, buffer); buffer = e; } while (buffer); @@ -649,7 +652,7 @@ int log_dump_internal( if (_likely_(LOG_PRI(level) > log_max_level)) return -error; - return log_dispatch(level, error, file, line, func, NULL, NULL, buffer); + return log_dispatch(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer); } int log_internalv( @@ -676,7 +679,7 @@ int log_internalv( vsnprintf(buffer, sizeof(buffer), format, ap); - return log_dispatch(level, error, file, line, func, NULL, NULL, buffer); + return log_dispatch(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer); } int log_internal( @@ -705,6 +708,8 @@ int log_object_internalv( const char *func, const char *object_field, const char *object, + const char *extra_field, + const char *extra, const char *format, va_list ap) { @@ -738,7 +743,7 @@ int log_object_internalv( vsnprintf(b, l, format, ap); - return log_dispatch(level, error, file, line, func, object_field, object, buffer); + return log_dispatch(level, error, file, line, func, object_field, object, extra_field, extra, buffer); } int log_object_internal( @@ -749,13 +754,15 @@ int log_object_internal( const char *func, const char *object_field, const char *object, + const char *extra_field, + const char *extra, const char *format, ...) { va_list ap; int r; va_start(ap, format); - r = log_object_internalv(level, error, file, line, func, object_field, object, format, ap); + r = log_object_internalv(level, error, file, line, func, object_field, object, extra_field, extra, format, ap); va_end(ap); return r; @@ -780,7 +787,7 @@ static void log_assert( log_abort_msg = buffer; - log_dispatch(level, 0, file, line, func, NULL, NULL, buffer); + log_dispatch(level, 0, file, line, func, NULL, NULL, NULL, NULL, buffer); } noreturn void log_assert_failed(const char *text, const char *file, int line, const char *func) { @@ -888,7 +895,7 @@ int log_struct_internal( bool fallback = false; /* If the journal is available do structured logging */ - log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL); + log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL); IOVEC_SET_STRING(iovec[n++], header); va_start(ap, format); @@ -935,7 +942,7 @@ int log_struct_internal( if (!found) return -error; - return log_dispatch(level, error, file, line, func, NULL, NULL, buf + 8); + return log_dispatch(level, error, file, line, func, NULL, NULL, NULL, NULL, buf + 8); } int log_set_target_from_string(const char *e) { diff --git a/src/basic/log.h b/src/basic/log.h index b6356228d9..2afee20bb5 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -100,18 +100,22 @@ int log_object_internal( const char *func, const char *object_field, const char *object, - const char *format, ...) _printf_(8,9); + const char *extra_field, + const char *extra, + const char *format, ...) _printf_(10,11); int log_object_internalv( int level, int error, - const char*file, + const char *file, int line, const char *func, const char *object_field, const char *object, + const char *extra_field, + const char *extra, const char *format, - va_list ap) _printf_(8,0); + va_list ap) _printf_(9,0); int log_struct_internal( int level, diff --git a/src/basic/strv.h b/src/basic/strv.h index fec2597db0..385ad17779 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -96,10 +96,13 @@ bool strv_overlap(char **a, char **b) _pure_; #define STRV_FOREACH(s, l) \ for ((s) = (l); (s) && *(s); (s)++) -#define STRV_FOREACH_BACKWARDS(s, l) \ - STRV_FOREACH(s, l) \ - ; \ - for ((s)--; (l) && ((s) >= (l)); (s)--) +#define STRV_FOREACH_BACKWARDS(s, l) \ + for (s = ({ \ + char **_l = l; \ + _l ? _l + strv_length(_l) - 1U : NULL; \ + }); \ + (l) && ((s) >= (l)); \ + (s)--) #define STRV_FOREACH_PAIR(x, y, l) \ for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1)) diff --git a/src/core/automount.c b/src/core/automount.c index bdc0e06965..7d7a0a6e46 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -800,6 +800,10 @@ static int automount_start(Unit *u) { return r; } + r = unit_acquire_invocation_id(u); + if (r < 0) + return r; + a->result = AUTOMOUNT_SUCCESS; automount_enter_waiting(a); return 1; diff --git a/src/core/busname.c b/src/core/busname.c index a69e3831f6..b96ec09e67 100644 --- a/src/core/busname.c +++ b/src/core/busname.c @@ -639,6 +639,10 @@ static int busname_start(Unit *u) { return r; } + r = unit_acquire_invocation_id(u); + if (r < 0) + return r; + n->result = BUSNAME_SUCCESS; busname_enter_making(n); diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 7873f88785..20bdbc39d0 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -1361,6 +1361,26 @@ int unit_attach_pids_to_cgroup(Unit *u) { return 0; } +static void cgroup_xattr_apply(Unit *u) { + char ids[SD_ID128_STRING_MAX]; + int r; + + assert(u); + + if (!MANAGER_IS_SYSTEM(u->manager)) + return; + + if (sd_id128_is_null(u->invocation_id)) + return; + + r = cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, + "trusted.invocation_id", + sd_id128_to_string(u->invocation_id, ids), 32, + 0); + if (r < 0) + log_unit_warning_errno(u, r, "Failed to set invocation ID on control group %s, ignoring: %m", u->cgroup_path); +} + static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask, CGroupMask enable_mask) { assert(u); @@ -1404,6 +1424,7 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) { /* Finally, apply the necessary attributes. */ cgroup_context_apply(u, target_mask, state); + cgroup_xattr_apply(u); return 0; } diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index ea7ced2fd0..12eb55cb7f 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -464,6 +464,64 @@ static int method_get_unit_by_pid(sd_bus_message *message, void *userdata, sd_bu return sd_bus_reply_method_return(message, "o", path); } +static int method_get_unit_by_invocation_id(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *path = NULL; + Manager *m = userdata; + sd_id128_t id; + const void *a; + Unit *u; + size_t sz; + int r; + + assert(message); + assert(m); + + /* Anyone can call this method */ + + r = sd_bus_message_read_array(message, 'y', &a, &sz); + if (r < 0) + return r; + if (sz == 0) + id = SD_ID128_NULL; + else if (sz == 16) + memcpy(&id, a, sz); + else + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid invocation ID"); + + if (sd_id128_is_null(id)) { + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + pid_t pid; + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_pid(creds, &pid); + if (r < 0) + return r; + + u = manager_get_unit_by_pid(m, pid); + if (!u) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Client " PID_FMT " not member of any unit.", pid); + } else { + u = hashmap_get(m->units_by_invocation_id, &id); + if (!u) + return sd_bus_error_setf(error, BUS_ERROR_NO_UNIT_FOR_INVOCATION_ID, "No unit with the specified invocation ID " SD_ID128_FORMAT_STR " known.", SD_ID128_FORMAT_VAL(id)); + } + + r = mac_selinux_unit_access_check(u, message, "status", error); + if (r < 0) + return r; + + /* So here's a special trick: the bus path we return actually references the unit by its invocation ID instead + * of the unit name. This means it stays valid only as long as the invocation ID stays the same. */ + path = unit_dbus_path_invocation_id(u); + if (!path) + return -ENOMEM; + + return sd_bus_reply_method_return(message, "o", path); +} + static int method_load_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_free_ char *path = NULL; Manager *m = userdata; @@ -2254,6 +2312,7 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetUnitByInvocationID", "ay", "o", method_get_unit_by_invocation_id, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("LoadUnit", "s", "o", method_load_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("StartUnit", "ss", "o", method_start_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("StartUnitReplace", "sss", "o", method_start_unit_replace, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 5020dfba4b..245912fc0f 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -764,6 +764,7 @@ const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("InvocationID", "ay", bus_property_get_id128, offsetof(Unit, invocation_id), 0), SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/core/device.c b/src/core/device.c index 16e56efcc3..8a3e888e5e 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -464,6 +464,10 @@ static void device_update_found_one(Device *d, bool add, DeviceFound found, bool if (!now) return; + /* Didn't exist before, but does now? if so, generate a new invocation ID for it */ + if (previous == DEVICE_NOT_FOUND && d->found != DEVICE_NOT_FOUND) + (void) unit_acquire_invocation_id(UNIT(d)); + if (d->found & DEVICE_FOUND_UDEV) /* When the device is known to udev we consider it * plugged. */ diff --git a/src/core/execute.c b/src/core/execute.c index d5c4e60796..7079aeed6e 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1553,10 +1553,11 @@ static int build_environment( unsigned n_env = 0; char *x; + assert(u); assert(c); assert(ret); - our_env = new0(char*, 13); + our_env = new0(char*, 14); if (!our_env) return -ENOMEM; @@ -1627,6 +1628,13 @@ static int build_environment( our_env[n_env++] = x; } + if (!sd_id128_is_null(u->invocation_id)) { + if (asprintf(&x, "INVOCATION_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(u->invocation_id)) < 0) + return -ENOMEM; + + our_env[n_env++] = x; + } + if (exec_context_needs_term(c)) { const char *tty_path, *term = NULL; diff --git a/src/core/manager.c b/src/core/manager.c index c1dce62a18..3569249788 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -522,6 +522,7 @@ static void manager_clean_environment(Manager *m) { "LISTEN_FDNAMES", "WATCHDOG_PID", "WATCHDOG_USEC", + "INVOCATION_ID", NULL); } @@ -582,9 +583,15 @@ int manager_new(UnitFileScope scope, bool test_run, Manager **_m) { if (MANAGER_IS_SYSTEM(m)) { m->unit_log_field = "UNIT="; m->unit_log_format_string = "UNIT=%s"; + + m->invocation_log_field = "INVOCATION_ID="; + m->invocation_log_format_string = "INVOCATION_ID=" SD_ID128_FORMAT_STR; } else { m->unit_log_field = "USER_UNIT="; m->unit_log_format_string = "USER_UNIT=%s"; + + m->invocation_log_field = "USER_INVOCATION_ID="; + m->invocation_log_format_string = "USER_INVOCATION_ID=" SD_ID128_FORMAT_STR; } m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1; @@ -1062,6 +1069,7 @@ Manager* manager_free(Manager *m) { hashmap_free(m->dynamic_users); hashmap_free(m->units); + hashmap_free(m->units_by_invocation_id); hashmap_free(m->jobs); hashmap_free(m->watch_pids1); hashmap_free(m->watch_pids2); @@ -2268,6 +2276,7 @@ int manager_loop(Manager *m) { int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, Unit **_u) { _cleanup_free_ char *n = NULL; + sd_id128_t invocation_id; Unit *u; int r; @@ -2279,12 +2288,25 @@ int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, if (r < 0) return r; + /* Permit addressing units by invocation ID: if the passed bus path is suffixed by a 128bit ID then we use it + * as invocation ID. */ + r = sd_id128_from_string(n, &invocation_id); + if (r >= 0) { + u = hashmap_get(m->units_by_invocation_id, &invocation_id); + if (u) { + *_u = u; + return 0; + } + + return sd_bus_error_setf(e, BUS_ERROR_NO_UNIT_FOR_INVOCATION_ID, "No unit with the specified invocation ID " SD_ID128_FORMAT_STR " known.", SD_ID128_FORMAT_VAL(invocation_id)); + } + + /* If this didn't work, we use the suffix as unit name. */ r = manager_load_unit(m, n, NULL, e, &u); if (r < 0) return r; *_u = u; - return 0; } diff --git a/src/core/manager.h b/src/core/manager.h index 495440b446..29fe14e10b 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -89,6 +89,7 @@ struct Manager { /* Active jobs and units */ Hashmap *units; /* name string => Unit object n:1 */ + Hashmap *units_by_invocation_id; Hashmap *jobs; /* job id => Job object 1:1 */ /* To make it easy to iterate through the units of a specific @@ -319,6 +320,9 @@ struct Manager { const char *unit_log_field; const char *unit_log_format_string; + const char *invocation_log_field; + const char *invocation_log_format_string; + int first_boot; /* tri-state */ }; diff --git a/src/core/mount.c b/src/core/mount.c index f5e67b1d78..15619dffe3 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -1006,6 +1006,10 @@ static int mount_start(Unit *u) { return r; } + r = unit_acquire_invocation_id(u); + if (r < 0) + return r; + m->result = MOUNT_SUCCESS; m->reload_result = MOUNT_SUCCESS; m->reset_cpu_usage = true; @@ -1746,9 +1750,10 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, case MOUNT_DEAD: case MOUNT_FAILED: - /* This has just been mounted by - * somebody else, follow the state - * change. */ + + /* This has just been mounted by somebody else, follow the state change, but let's + * generate a new invocation ID for this implicitly and automatically. */ + (void) unit_acquire_invocation_id(UNIT(mount)); mount_enter_mounted(mount, MOUNT_SUCCESS); break; diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf index 647e5f736c..6caa15b0b8 100644 --- a/src/core/org.freedesktop.systemd1.conf +++ b/src/core/org.freedesktop.systemd1.conf @@ -52,6 +52,10 @@ send_interface="org.freedesktop.systemd1.Manager" send_member="GetUnitByPID"/> + + diff --git a/src/core/path.c b/src/core/path.c index 10f9b06974..83f794be89 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -577,6 +577,10 @@ static int path_start(Unit *u) { return r; } + r = unit_acquire_invocation_id(u); + if (r < 0) + return r; + path_mkdir(p); p->result = PATH_SUCCESS; diff --git a/src/core/scope.c b/src/core/scope.c index 65fa65493b..e7583f6d89 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -298,6 +298,10 @@ static int scope_start(Unit *u) { if (!u->transient && !MANAGER_IS_RELOADING(u->manager)) return -ENOENT; + r = unit_acquire_invocation_id(u); + if (r < 0) + return r; + (void) unit_realize_cgroup(u); (void) unit_reset_cpu_usage(u); diff --git a/src/core/service.c b/src/core/service.c index 98edc437a2..63045ede55 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -2033,6 +2033,10 @@ static int service_start(Unit *u) { return r; } + r = unit_acquire_invocation_id(u); + if (r < 0) + return r; + s->result = SERVICE_SUCCESS; s->reload_result = SERVICE_SUCCESS; s->main_pid_known = false; diff --git a/src/core/slice.c b/src/core/slice.c index c7700b8857..03fe797f27 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -187,10 +187,15 @@ static void slice_dump(Unit *u, FILE *f, const char *prefix) { static int slice_start(Unit *u) { Slice *t = SLICE(u); + int r; assert(t); assert(t->state == SLICE_DEAD); + r = unit_acquire_invocation_id(u); + if (r < 0) + return r; + (void) unit_realize_cgroup(u); (void) unit_reset_cpu_usage(u); diff --git a/src/core/socket.c b/src/core/socket.c index 1b4a1b3dc3..0b1c4acfec 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -2354,11 +2354,14 @@ static int socket_start(Unit *u) { return r; } + r = unit_acquire_invocation_id(u); + if (r < 0) + return r; + s->result = SOCKET_SUCCESS; s->reset_cpu_usage = true; socket_enter_start_pre(s); - return 1; } diff --git a/src/core/swap.c b/src/core/swap.c index fee9e7b0e6..b592abb9fb 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -861,6 +861,10 @@ static int swap_start(Unit *u) { return r; } + r = unit_acquire_invocation_id(u); + if (r < 0) + return r; + s->result = SWAP_SUCCESS; s->reset_cpu_usage = true; @@ -1189,6 +1193,7 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v case SWAP_DEAD: case SWAP_FAILED: + (void) unit_acquire_invocation_id(UNIT(swap)); swap_enter_active(swap, SWAP_SUCCESS); break; diff --git a/src/core/target.c b/src/core/target.c index 61a91aad07..765c1f3fa4 100644 --- a/src/core/target.c +++ b/src/core/target.c @@ -124,10 +124,15 @@ static void target_dump(Unit *u, FILE *f, const char *prefix) { static int target_start(Unit *u) { Target *t = TARGET(u); + int r; assert(t); assert(t->state == TARGET_DEAD); + r = unit_acquire_invocation_id(u); + if (r < 0) + return r; + target_set_state(t, TARGET_ACTIVE); return 1; } diff --git a/src/core/timer.c b/src/core/timer.c index e2b43f02f8..9538059c13 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -616,6 +616,10 @@ static int timer_start(Unit *u) { return r; } + r = unit_acquire_invocation_id(u); + if (r < 0) + return r; + t->last_trigger = DUAL_TIMESTAMP_NULL; /* Reenable all timers that depend on unit activation time */ @@ -632,7 +636,7 @@ static int timer_start(Unit *u) { /* The timer has never run before, * make sure a stamp file exists. */ - touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID); + (void) touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID); } t->result = TIMER_SUCCESS; diff --git a/src/core/unit.c b/src/core/unit.c index 693f75c928..690f7f7dd9 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -37,6 +37,7 @@ #include "execute.h" #include "fileio-label.h" #include "formats-util.h" +#include "id128-util.h" #include "load-dropin.h" #include "load-fragment.h" #include "log.h" @@ -521,6 +522,9 @@ void unit_free(Unit *u) { SET_FOREACH(t, u->names, i) hashmap_remove_value(u->manager->units, t, u); + if (!sd_id128_is_null(u->invocation_id)) + hashmap_remove_value(u->manager->units_by_invocation_id, &u->invocation_id, u); + if (u->job) { Job *j = u->job; job_uninstall(j); @@ -953,6 +957,10 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { SET_FOREACH(t, u->names, i) fprintf(f, "%s\tName: %s\n", prefix, t); + if (!sd_id128_is_null(u->invocation_id)) + fprintf(f, "%s\tInvocation ID: " SD_ID128_FORMAT_STR "\n", + prefix, SD_ID128_FORMAT_VAL(u->invocation_id)); + STRV_FOREACH(j, u->documentation) fprintf(f, "%s\tDocumentation: %s\n", prefix, *j); @@ -1054,7 +1062,6 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { if (u->nop_job) job_dump(u->nop_job, f, prefix2); - } /* Common implementation for multiple backends */ @@ -2392,6 +2399,15 @@ char *unit_dbus_path(Unit *u) { return unit_dbus_path_from_name(u->id); } +char *unit_dbus_path_invocation_id(Unit *u) { + assert(u); + + if (sd_id128_is_null(u->invocation_id)) + return NULL; + + return unit_dbus_path_from_name(u->invocation_id_string); +} + int unit_set_slice(Unit *u, Unit *slice) { assert(u); assert(slice); @@ -2640,6 +2656,9 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { if (gid_is_valid(u->ref_gid)) unit_serialize_item_format(u, f, "ref-gid", GID_FMT, u->ref_gid); + if (!sd_id128_is_null(u->invocation_id)) + unit_serialize_item_format(u, f, "invocation-id", SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(u->invocation_id)); + bus_track_serialize(u->bus_track, f, "ref"); if (serialize_jobs) { @@ -2914,6 +2933,19 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { if (r < 0) log_oom(); + continue; + } else if (streq(l, "invocation-id")) { + sd_id128_t id; + + r = sd_id128_from_string(v, &id); + if (r < 0) + log_unit_debug(u, "Failed to parse invocation id %s, ignoring.", v); + else { + r = unit_set_invocation_id(u, id); + if (r < 0) + log_unit_warning_errno(u, r, "Failed to set invocation ID for unit: %m"); + } + continue; } @@ -4153,3 +4185,57 @@ void unit_notify_user_lookup(Unit *u, uid_t uid, gid_t gid) { if (r > 0) bus_unit_send_change_signal(u); } + +int unit_set_invocation_id(Unit *u, sd_id128_t id) { + int r; + + assert(u); + + /* Set the invocation ID for this unit. If we cannot, this will not roll back, but reset the whole thing. */ + + if (sd_id128_equal(u->invocation_id, id)) + return 0; + + if (!sd_id128_is_null(u->invocation_id)) + (void) hashmap_remove_value(u->manager->units_by_invocation_id, &u->invocation_id, u); + + if (sd_id128_is_null(id)) { + r = 0; + goto reset; + } + + r = hashmap_ensure_allocated(&u->manager->units_by_invocation_id, &id128_hash_ops); + if (r < 0) + goto reset; + + u->invocation_id = id; + sd_id128_to_string(id, u->invocation_id_string); + + r = hashmap_put(u->manager->units_by_invocation_id, &u->invocation_id, u); + if (r < 0) + goto reset; + + return 0; + +reset: + u->invocation_id = SD_ID128_NULL; + u->invocation_id_string[0] = 0; + return r; +} + +int unit_acquire_invocation_id(Unit *u) { + sd_id128_t id; + int r; + + assert(u); + + r = sd_id128_randomize(&id); + if (r < 0) + return log_unit_error_errno(u, r, "Failed to generate invocation ID for unit: %m"); + + r = unit_set_invocation_id(u, id); + if (r < 0) + return log_unit_error_errno(u, r, "Failed to set invocation ID for unit: %m"); + + return 0; +} diff --git a/src/core/unit.h b/src/core/unit.h index 3584c16d8c..a8dd3e602c 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -207,6 +207,10 @@ struct Unit { /* How to start OnFailure units */ JobMode on_failure_job_mode; + /* The current invocation ID */ + sd_id128_t invocation_id; + char invocation_id_string[SD_ID128_STRING_MAX]; /* useful when logging */ + /* Garbage collect us we nobody wants or requires us anymore */ bool stop_when_unneeded; @@ -546,6 +550,7 @@ bool unit_job_is_applicable(Unit *u, JobType j); int set_unit_path(const char *p); char *unit_dbus_path(Unit *u); +char *unit_dbus_path_invocation_id(Unit *u); int unit_load_related_unit(Unit *u, const char *type, Unit **_found); @@ -643,12 +648,15 @@ void unit_unref_uid_gid(Unit *u, bool destroy_now); void unit_notify_user_lookup(Unit *u, uid_t uid, gid_t gid); +int unit_set_invocation_id(Unit *u, sd_id128_t id); +int unit_acquire_invocation_id(Unit *u); + /* Macros which append UNIT= or USER_UNIT= to the message */ #define log_unit_full(unit, level, error, ...) \ ({ \ const Unit *_u = (unit); \ - _u ? log_object_internal(level, error, __FILE__, __LINE__, __func__, _u->manager->unit_log_field, _u->id, ##__VA_ARGS__) : \ + _u ? log_object_internal(level, error, __FILE__, __LINE__, __func__, _u->manager->unit_log_field, _u->id, _u->manager->invocation_log_field, _u->invocation_id_string, ##__VA_ARGS__) : \ log_internal(level, error, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \ }) diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index a762558e3d..f01cf1d937 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -44,6 +44,7 @@ #include "fs-util.h" #include "hashmap.h" #include "hostname-util.h" +#include "id128-util.h" #include "io-util.h" #include "journal-authenticate.h" #include "journal-file.h" @@ -56,6 +57,7 @@ #include "journald-server.h" #include "journald-stream.h" #include "journald-syslog.h" +#include "log.h" #include "missing.h" #include "mkdir.h" #include "parse-util.h" @@ -69,7 +71,6 @@ #include "string-table.h" #include "string-util.h" #include "user-util.h" -#include "log.h" #define USER_JOURNALS_MAX 1024 @@ -675,6 +676,44 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned server_schedule_sync(s, priority); } +static int get_invocation_id(const char *cgroup_root, const char *slice, const char *unit, char **ret) { + _cleanup_free_ char *escaped = NULL, *slice_path = NULL, *p = NULL; + char *copy, ids[SD_ID128_STRING_MAX]; + int r; + + /* Read the invocation ID of a unit off a unit. It's stored in the "trusted.invocation_id" extended attribute + * on the cgroup path. */ + + r = cg_slice_to_path(slice, &slice_path); + if (r < 0) + return r; + + escaped = cg_escape(unit); + if (!escaped) + return -ENOMEM; + + p = strjoin(cgroup_root, "/", slice_path, "/", escaped, NULL); + if (!p) + return -ENOMEM; + + r = cg_get_xattr(SYSTEMD_CGROUP_CONTROLLER, p, "trusted.invocation_id", ids, 32); + if (r < 0) + return r; + if (r != 32) + return -EINVAL; + ids[32] = 0; + + if (!id128_is_valid(ids)) + return -EINVAL; + + copy = strdup(ids); + if (!copy) + return -ENOMEM; + + *ret = copy; + return 0; +} + static void dispatch_message_real( Server *s, struct iovec *iovec, unsigned n, unsigned m, @@ -713,7 +752,7 @@ static void dispatch_message_real( assert(s); assert(iovec); assert(n > 0); - assert(n + N_IOVEC_META_FIELDS + (object_pid ? N_IOVEC_OBJECT_FIELDS : 0) <= m); + assert(n + N_IOVEC_META_FIELDS + (object_pid > 0 ? N_IOVEC_OBJECT_FIELDS : 0) <= m); if (ucred) { realuid = ucred->uid; @@ -771,6 +810,7 @@ static void dispatch_message_real( r = cg_pid_get_path_shifted(ucred->pid, s->cgroup_root, &c); if (r >= 0) { + _cleanup_free_ char *raw_unit = NULL, *raw_slice = NULL; char *session = NULL; x = strjoina("_SYSTEMD_CGROUP=", c); @@ -790,9 +830,8 @@ static void dispatch_message_real( IOVEC_SET_STRING(iovec[n++], owner_uid); } - if (cg_path_get_unit(c, &t) >= 0) { - x = strjoina("_SYSTEMD_UNIT=", t); - free(t); + if (cg_path_get_unit(c, &raw_unit) >= 0) { + x = strjoina("_SYSTEMD_UNIT=", raw_unit); IOVEC_SET_STRING(iovec[n++], x); } else if (unit_id && !session) { x = strjoina("_SYSTEMD_UNIT=", unit_id); @@ -808,12 +847,25 @@ static void dispatch_message_real( IOVEC_SET_STRING(iovec[n++], x); } - if (cg_path_get_slice(c, &t) >= 0) { - x = strjoina("_SYSTEMD_SLICE=", t); + if (cg_path_get_slice(c, &raw_slice) >= 0) { + x = strjoina("_SYSTEMD_SLICE=", raw_slice); + IOVEC_SET_STRING(iovec[n++], x); + } + + if (cg_path_get_user_slice(c, &t) >= 0) { + x = strjoina("_SYSTEMD_USER_SLICE=", t); free(t); IOVEC_SET_STRING(iovec[n++], x); } + if (raw_slice && raw_unit) { + if (get_invocation_id(s->cgroup_root, raw_slice, raw_unit, &t) >= 0) { + x = strjoina("_SYSTEMD_INVOCATION_ID=", t); + free(t); + IOVEC_SET_STRING(iovec[n++], x); + } + } + free(c); } else if (unit_id) { x = strjoina("_SYSTEMD_UNIT=", unit_id); @@ -919,13 +971,25 @@ static void dispatch_message_real( IOVEC_SET_STRING(iovec[n++], x); } + if (cg_path_get_slice(c, &t) >= 0) { + x = strjoina("OBJECT_SYSTEMD_SLICE=", t); + free(t); + IOVEC_SET_STRING(iovec[n++], x); + } + + if (cg_path_get_user_slice(c, &t) >= 0) { + x = strjoina("OBJECT_SYSTEMD_USER_SLICE=", t); + free(t); + IOVEC_SET_STRING(iovec[n++], x); + } + free(c); } } assert(n <= m); if (tv) { - sprintf(source_time, "_SOURCE_REALTIME_TIMESTAMP=%llu", (unsigned long long) timeval_load(tv)); + sprintf(source_time, "_SOURCE_REALTIME_TIMESTAMP=" USEC_FMT, timeval_load(tv)); IOVEC_SET_STRING(iovec[n++], source_time); } diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h index d2a32ab422..dfb5724794 100644 --- a/src/journal/journald-server.h +++ b/src/journal/journald-server.h @@ -153,10 +153,10 @@ struct Server { #define SERVER_MACHINE_ID(s) ((s)->machine_id_field + strlen("_MACHINE_ID=")) -#define N_IOVEC_META_FIELDS 20 +#define N_IOVEC_META_FIELDS 22 #define N_IOVEC_KERNEL_FIELDS 64 #define N_IOVEC_UDEV_FIELDS 32 -#define N_IOVEC_OBJECT_FIELDS 12 +#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, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len, const char *unit_id, int priority, pid_t object_pid); diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 70ea347361..d48ef6bbe2 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -509,4 +509,5 @@ global: sd_bus_track_count_sender; sd_bus_set_exit_on_disconnect; sd_bus_get_exit_on_disconnect; + sd_id128_get_invocation; } LIBSYSTEMD_231; diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c index 9cc28ed564..d2a826bf6e 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.c +++ b/src/libsystemd/sd-bus/bus-common-errors.c @@ -27,6 +27,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_UNIT, ENOENT), SD_BUS_ERROR_MAP(BUS_ERROR_NO_UNIT_FOR_PID, ESRCH), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_UNIT_FOR_INVOCATION_ID, ENOENT), SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_EXISTS, EEXIST), SD_BUS_ERROR_MAP(BUS_ERROR_LOAD_FAILED, EIO), SD_BUS_ERROR_MAP(BUS_ERROR_JOB_FAILED, EREMOTEIO), diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index 5df21c8926..525b79fa77 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -23,6 +23,7 @@ #define BUS_ERROR_NO_SUCH_UNIT "org.freedesktop.systemd1.NoSuchUnit" #define BUS_ERROR_NO_UNIT_FOR_PID "org.freedesktop.systemd1.NoUnitForPID" +#define BUS_ERROR_NO_UNIT_FOR_INVOCATION_ID "org.freedesktop.systemd1.NoUnitForInvocationID" #define BUS_ERROR_UNIT_EXISTS "org.freedesktop.systemd1.UnitExists" #define BUS_ERROR_LOAD_FAILED "org.freedesktop.systemd1.LoadFailed" #define BUS_ERROR_JOB_FAILED "org.freedesktop.systemd1.JobFailed" diff --git a/src/libsystemd/sd-id128/id128-util.c b/src/libsystemd/sd-id128/id128-util.c index c3f527d657..337eae24b4 100644 --- a/src/libsystemd/sd-id128/id128-util.c +++ b/src/libsystemd/sd-id128/id128-util.c @@ -192,3 +192,16 @@ int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) { return id128_write_fd(fd, f, id, do_sync); } + +void id128_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, 16, state); +} + +int id128_compare_func(const void *a, const void *b) { + return memcmp(a, b, 16); +} + +const struct hash_ops id128_hash_ops = { + .hash = id128_hash_func, + .compare = id128_compare_func, +}; diff --git a/src/libsystemd/sd-id128/id128-util.h b/src/libsystemd/sd-id128/id128-util.h index 3ba59acbca..6b3855acbb 100644 --- a/src/libsystemd/sd-id128/id128-util.h +++ b/src/libsystemd/sd-id128/id128-util.h @@ -22,6 +22,8 @@ #include #include "sd-id128.h" + +#include "hash-funcs.h" #include "macro.h" char *id128_to_uuid_string(sd_id128_t id, char s[37]); @@ -43,3 +45,7 @@ int id128_read(const char *p, Id128Format f, sd_id128_t *ret); int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync); int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync); + +void id128_hash_func(const void *p, struct siphash *state); +int id128_compare_func(const void *a, const void *b) _pure_; +extern const struct hash_ops id128_hash_ops; diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c index 9f47d04e61..d4450c70a0 100644 --- a/src/libsystemd/sd-id128/sd-id128.c +++ b/src/libsystemd/sd-id128/sd-id128.c @@ -129,6 +129,28 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) { return 0; } +_public_ int sd_id128_get_invocation(sd_id128_t *ret) { + static thread_local sd_id128_t saved_invocation_id = {}; + int r; + + assert_return(ret, -EINVAL); + + if (sd_id128_is_null(saved_invocation_id)) { + const char *e; + + e = secure_getenv("INVOCATION_ID"); + if (!e) + return -ENXIO; + + r = sd_id128_from_string(e, &saved_invocation_id); + if (r < 0) + return r; + } + + *ret = saved_invocation_id; + return 0; +} + static sd_id128_t make_v4_uuid(sd_id128_t id) { /* Stolen from generate_random_uuid() of drivers/char/random.c * in the kernel sources */ diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index ba7ac04b56..5ca18ff87e 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -51,24 +51,6 @@ #include "terminal-util.h" #include "user-util.h" -static int property_get_id( - sd_bus *bus, - const char *path, - const char *interface, - const char *property, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error) { - - Machine *m = userdata; - - assert(bus); - assert(reply); - assert(m); - - return sd_bus_message_append_array(reply, 'y', &m->id, 16); -} - static int property_get_state( sd_bus *bus, const char *path, @@ -1311,7 +1293,7 @@ int bus_machine_method_open_root_directory(sd_bus_message *message, void *userda const sd_bus_vtable machine_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Id", "ay", bus_property_get_id128, offsetof(Machine, id), SD_BUS_VTABLE_PROPERTY_CONST), BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST), diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 05b2a2b323..77f72d070e 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -187,7 +187,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_unref); #define log_link_full(link, level, error, ...) \ ({ \ const Link *_l = (link); \ - _l ? log_object_internal(level, error, __FILE__, __LINE__, __func__, "INTERFACE=", _l->ifname, ##__VA_ARGS__) : \ + _l ? log_object_internal(level, error, __FILE__, __LINE__, __func__, "INTERFACE=", _l->ifname, NULL, NULL, ##__VA_ARGS__) : \ log_internal(level, error, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \ }) \ diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h index 31b55e2791..70ff947b99 100644 --- a/src/network/networkd-netdev.h +++ b/src/network/networkd-netdev.h @@ -182,7 +182,7 @@ const struct ConfigPerfItem* network_netdev_gperf_lookup(const char *key, unsign #define log_netdev_full(netdev, level, error, ...) \ ({ \ const NetDev *_n = (netdev); \ - _n ? log_object_internal(level, error, __FILE__, __LINE__, __func__, "INTERFACE=", _n->ifname, ##__VA_ARGS__) : \ + _n ? log_object_internal(level, error, __FILE__, __LINE__, __func__, "INTERFACE=", _n->ifname, NULL, NULL, ##__VA_ARGS__) : \ log_internal(level, error, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \ }) diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index e2a216a5cc..bb90c89cc2 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -1324,6 +1324,23 @@ int bus_property_get_bool( return sd_bus_message_append_basic(reply, 'b', &b); } +int bus_property_get_id128( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + sd_id128_t *id = userdata; + + if (sd_id128_is_null(*id)) /* Add an empty array if the ID is zero */ + return sd_bus_message_append(reply, "ay", 0); + else + return sd_bus_message_append_array(reply, 'y', id->bytes, 16); +} + #if __SIZEOF_SIZE_T__ != 8 int bus_property_get_size( sd_bus *bus, diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index db6b1acba2..934e0b5b77 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -79,6 +79,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool value, b int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool value, bool all); int bus_property_get_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); +int bus_property_get_id128(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); #define bus_property_get_usec ((sd_bus_property_get_t) NULL) #define bus_property_set_usec ((sd_bus_property_set_t) NULL) diff --git a/src/systemd/sd-id128.h b/src/systemd/sd-id128.h index 4dff0b9b81..ee011b1861 100644 --- a/src/systemd/sd-id128.h +++ b/src/systemd/sd-id128.h @@ -45,8 +45,8 @@ int sd_id128_from_string(const char *s, sd_id128_t *ret); int sd_id128_randomize(sd_id128_t *ret); int sd_id128_get_machine(sd_id128_t *ret); - int sd_id128_get_boot(sd_id128_t *ret); +int sd_id128_get_invocation(sd_id128_t *ret); #define SD_ID128_MAKE(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \ ((const sd_id128_t) { .bytes = { 0x##v0, 0x##v1, 0x##v2, 0x##v3, 0x##v4, 0x##v5, 0x##v6, 0x##v7, \ diff --git a/src/test/test-strv.c b/src/test/test-strv.c index ce20f2dd5b..88da69e2d7 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -453,9 +453,14 @@ static void test_strv_foreach_backwards(void) { assert_se(a); - STRV_FOREACH_BACKWARDS(check, a) { + STRV_FOREACH_BACKWARDS(check, a) assert_se(streq_ptr(*check, input_table_multiple[i--])); - } + + STRV_FOREACH_BACKWARDS(check, (char**) NULL) + assert_not_reached("Let's see that we check empty strv right, too."); + + STRV_FOREACH_BACKWARDS(check, (char**) { NULL }) + assert_not_reached("Let's see that we check empty strv right, too."); } static void test_strv_foreach_pair(void) {