diff options
Diffstat (limited to 'src')
33 files changed, 598 insertions, 279 deletions
diff --git a/src/basic/def.h b/src/basic/def.h index 011c7c667e..5aaba1fe87 100644 --- a/src/basic/def.h +++ b/src/basic/def.h @@ -63,13 +63,7 @@ #define UNIX_SYSTEM_BUS_ADDRESS "unix:path=/var/run/dbus/system_bus_socket" #define KERNEL_SYSTEM_BUS_ADDRESS "kernel:path=/sys/fs/kdbus/0-system/bus" - -#ifdef ENABLE_KDBUS -# define DEFAULT_SYSTEM_BUS_ADDRESS KERNEL_SYSTEM_BUS_ADDRESS ";" UNIX_SYSTEM_BUS_ADDRESS -#else -# define DEFAULT_SYSTEM_BUS_ADDRESS UNIX_SYSTEM_BUS_ADDRESS -#endif - +#define DEFAULT_SYSTEM_BUS_ADDRESS KERNEL_SYSTEM_BUS_ADDRESS ";" UNIX_SYSTEM_BUS_ADDRESS #define UNIX_USER_BUS_ADDRESS_FMT "unix:path=%s/bus" #define KERNEL_USER_BUS_ADDRESS_FMT "kernel:path=/sys/fs/kdbus/"UID_FMT"-user/bus" diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c index c09efdd2cb..5ab36825c0 100644 --- a/src/basic/exit-status.c +++ b/src/basic/exit-status.c @@ -20,6 +20,7 @@ ***/ #include <stdlib.h> +#include <signal.h> #include "exit-status.h" #include "set.h" diff --git a/src/basic/util.c b/src/basic/util.c index e0c5069ff8..727be56f58 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -5209,35 +5209,6 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { break; - case VALUE_ESCAPE: - if (c == 0) { - if (flags & UNQUOTE_RELAX) - goto finish; - return -EINVAL; - } - - if (!GREEDY_REALLOC(s, allocated, sz+7)) - return -ENOMEM; - - if (flags & UNQUOTE_CUNESCAPE) { - uint32_t u; - - r = cunescape_one(*p, (size_t) -1, &c, &u); - if (r < 0) - return -EINVAL; - - (*p) += r - 1; - - if (c != 0) - s[sz++] = c; /* normal explicit char */ - else - sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */ - } else - s[sz++] = c; - - state = VALUE; - break; - case SINGLE_QUOTE: if (c == 0) { if (flags & UNQUOTE_RELAX) @@ -5256,35 +5227,6 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { break; - case SINGLE_QUOTE_ESCAPE: - if (c == 0) { - if (flags & UNQUOTE_RELAX) - goto finish; - return -EINVAL; - } - - if (!GREEDY_REALLOC(s, allocated, sz+7)) - return -ENOMEM; - - if (flags & UNQUOTE_CUNESCAPE) { - uint32_t u; - - r = cunescape_one(*p, (size_t) -1, &c, &u); - if (r < 0) - return -EINVAL; - - (*p) += r - 1; - - if (c != 0) - s[sz++] = c; - else - sz += utf8_encode_unichar(s + sz, u); - } else - s[sz++] = c; - - state = SINGLE_QUOTE; - break; - case DOUBLE_QUOTE: if (c == 0) return -EINVAL; @@ -5301,33 +5243,56 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { break; + case SINGLE_QUOTE_ESCAPE: case DOUBLE_QUOTE_ESCAPE: + case VALUE_ESCAPE: + if (!GREEDY_REALLOC(s, allocated, sz+7)) + return -ENOMEM; + if (c == 0) { + if ((flags & UNQUOTE_CUNESCAPE_RELAX) && + (state == VALUE_ESCAPE || flags & UNQUOTE_RELAX)) { + /* If we find an unquoted trailing backslash and we're in + * UNQUOTE_CUNESCAPE_RELAX mode, keep it verbatim in the + * output. + * + * Unbalanced quotes will only be allowed in UNQUOTE_RELAX + * mode, UNQUOTE_CUNESCAP_RELAX mode does not allow them. + */ + s[sz++] = '\\'; + goto finish; + } if (flags & UNQUOTE_RELAX) goto finish; return -EINVAL; } - if (!GREEDY_REALLOC(s, allocated, sz+7)) - return -ENOMEM; - if (flags & UNQUOTE_CUNESCAPE) { uint32_t u; r = cunescape_one(*p, (size_t) -1, &c, &u); - if (r < 0) + if (r < 0) { + if (flags & UNQUOTE_CUNESCAPE_RELAX) { + s[sz++] = '\\'; + s[sz++] = c; + goto end_escape; + } return -EINVAL; + } (*p) += r - 1; if (c != 0) - s[sz++] = c; + s[sz++] = c; /* normal explicit char */ else - sz += utf8_encode_unichar(s + sz, u); + sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */ } else s[sz++] = c; - state = DOUBLE_QUOTE; +end_escape: + state = (state == SINGLE_QUOTE_ESCAPE) ? SINGLE_QUOTE : + (state == DOUBLE_QUOTE_ESCAPE) ? DOUBLE_QUOTE : + VALUE; break; case SPACE: @@ -5355,6 +5320,36 @@ finish: return 1; } +int unquote_first_word_and_warn( + const char **p, + char **ret, + UnquoteFlags flags, + const char *unit, + const char *filename, + unsigned line, + const char *rvalue) { + /* Try to unquote it, if it fails, warn about it and try again but this + * time using UNQUOTE_CUNESCAPE_RELAX to keep the backslashes verbatim + * in invalid escape sequences. */ + const char *save; + int r; + + save = *p; + r = unquote_first_word(p, ret, flags); + if (r < 0 && !(flags&UNQUOTE_CUNESCAPE_RELAX)) { + /* Retry it with UNQUOTE_CUNESCAPE_RELAX. */ + *p = save; + r = unquote_first_word(p, ret, flags|UNQUOTE_CUNESCAPE_RELAX); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue); + else + log_syntax(unit, LOG_WARNING, filename, line, EINVAL, + "Invalid escape sequences in command line: \"%s\"", rvalue); + } + return r; +} + int unquote_many_words(const char **p, UnquoteFlags flags, ...) { va_list ap; char **l; diff --git a/src/basic/util.h b/src/basic/util.h index 7aca46d777..a1d1dd15c3 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -839,11 +839,13 @@ int is_dir(const char *path, bool follow); int is_device_node(const char *path); typedef enum UnquoteFlags { - UNQUOTE_RELAX = 1, - UNQUOTE_CUNESCAPE = 2, + UNQUOTE_RELAX = 1, + UNQUOTE_CUNESCAPE = 2, + UNQUOTE_CUNESCAPE_RELAX = 4, } UnquoteFlags; int unquote_first_word(const char **p, char **ret, UnquoteFlags flags); +int unquote_first_word_and_warn(const char **p, char **ret, UnquoteFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue); int unquote_many_words(const char **p, UnquoteFlags flags, ...) _sentinel_; int free_and_strdup(char **p, const char *s); diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c index 3e398b53e9..3cc3b33ae7 100644 --- a/src/bus-proxyd/bus-proxyd.c +++ b/src/bus-proxyd/bus-proxyd.c @@ -239,11 +239,7 @@ static int parse_argv(int argc, char *argv[]) { if (!e) return log_oom(); -#ifdef ENABLE_KDBUS a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL); -#else - a = strjoin("x-machine-unix:machine=", e, NULL); -#endif if (!a) return log_oom(); diff --git a/src/bus-proxyd/proxy.c b/src/bus-proxyd/proxy.c index aa5010c1ac..28ab1c97fc 100644 --- a/src/bus-proxyd/proxy.c +++ b/src/bus-proxyd/proxy.c @@ -275,12 +275,16 @@ int proxy_set_policy(Proxy *p, SharedPolicy *sp, char **configuration) { return log_error_errno(r, "Couldn't determine bus scope: %m"); if (streq(scope, "system")) - strv = strv_new("/etc/dbus-1/system.conf", + strv = strv_new("/usr/share/dbus-1/system.conf", + "/etc/dbus-1/system.conf", + "/usr/share/dbus-1/system.d/", "/etc/dbus-1/system.d/", "/etc/dbus-1/system-local.conf", NULL); else if (streq(scope, "user")) - strv = strv_new("/etc/dbus-1/session.conf", + strv = strv_new("/usr/share/dbus-1/session.conf", + "/etc/dbus-1/session.conf", + "/usr/share/dbus-1/session.d/", "/etc/dbus-1/session.d/", "/etc/dbus-1/session-local.conf", NULL); diff --git a/src/bus-proxyd/stdio-bridge.c b/src/bus-proxyd/stdio-bridge.c index 61bc08ae33..f275f6705f 100644 --- a/src/bus-proxyd/stdio-bridge.c +++ b/src/bus-proxyd/stdio-bridge.c @@ -110,11 +110,7 @@ static int parse_argv(int argc, char *argv[]) { if (!e) return log_oom(); -#ifdef ENABLE_KDBUS a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL); -#else - a = strjoin("x-machine-unix:machine=", e, NULL); -#endif if (!a) return log_oom(); diff --git a/src/core/execute.c b/src/core/execute.c index a6ff5ac56e..94cc101738 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1514,7 +1514,6 @@ static int exec_child( } } -#ifdef ENABLE_KDBUS if (params->bus_endpoint_fd >= 0 && context->bus_endpoint) { uid_t ep_uid = (uid == UID_INVALID) ? 0 : uid; @@ -1524,7 +1523,6 @@ static int exec_child( return r; } } -#endif /* If delegation is enabled we'll pass ownership of the cgroup * (but only in systemd's own controller hierarchy!) to the diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c index f5584b6b14..e7a6bdc8c4 100644 --- a/src/core/kmod-setup.c +++ b/src/core/kmod-setup.c @@ -66,10 +66,8 @@ int kmod_setup(void) { /* this should never be a module */ { "unix", "/proc/net/unix", true, true, NULL }, -#ifdef ENABLE_KDBUS /* IPC is needed before we bring up any other services */ { "kdbus", "/sys/fs/kdbus", false, false, is_kdbus_wanted }, -#endif #ifdef HAVE_LIBIPTC /* netfilter is needed by networkd, nspawn among others, and cannot be autoloaded */ diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 66c9145aa6..aae81c80cb 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -229,9 +229,7 @@ Service.BusName, config_parse_bus_name, 0, Service.FileDescriptorStoreMax, config_parse_unsigned, 0, offsetof(Service, n_fd_store_max) Service.NotifyAccess, config_parse_notify_access, 0, offsetof(Service, notify_access) Service.Sockets, config_parse_service_sockets, 0, 0 -m4_ifdef(`ENABLE_KDBUS', -`Service.BusPolicy, config_parse_bus_endpoint_policy, 0, offsetof(Service, exec_context)', -`Service.BusPolicy, config_parse_warn_compat, DISABLED_EXPERIMENTAL, 0') +Service.BusPolicy, config_parse_bus_endpoint_policy, 0, offsetof(Service, exec_context) EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl CGROUP_CONTEXT_CONFIG_ITEMS(Service)m4_dnl KILL_CONTEXT_CONFIG_ITEMS(Service)m4_dnl diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index df5fe6fb32..a48cb4029a 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -520,9 +520,9 @@ int config_parse_exec( void *data, void *userdata) { - ExecCommand **e = data, *nce; - char *path, **n; - unsigned k; + ExecCommand **e = data; + const char *p; + bool semicolon; int r; assert(filename); @@ -532,156 +532,154 @@ int config_parse_exec( e += ltype; + rvalue += strspn(rvalue, WHITESPACE); + p = rvalue; + if (isempty(rvalue)) { /* An empty assignment resets the list */ *e = exec_command_free_list(*e); return 0; } - /* We accept an absolute path as first argument, or - * alternatively an absolute prefixed with @ to allow - * overriding of argv[0]. */ - for (;;) { + do { int i; - const char *word, *state, *reason; - size_t l; + _cleanup_strv_free_ char **n = NULL; + size_t nlen = 0, nbufsize = 0; + _cleanup_free_ ExecCommand *nce = NULL; + _cleanup_free_ char *path = NULL, *firstword = NULL; + char *f; bool separate_argv0 = false, ignore = false; - path = NULL; - nce = NULL; - n = NULL; + semicolon = false; - rvalue += strspn(rvalue, WHITESPACE); + r = unquote_first_word_and_warn(&p, &firstword, UNQUOTE_CUNESCAPE, unit, filename, line, rvalue); + if (r <= 0) + return 0; - if (rvalue[0] == 0) - break; + f = firstword; + for (i = 0; i < 2; i++) { + /* We accept an absolute path as first argument, or + * alternatively an absolute prefixed with @ to allow + * overriding of argv[0]. */ + if (*f == '-' && !ignore) + ignore = true; + else if (*f == '@' && !separate_argv0) + separate_argv0 = true; + else + break; + f ++; + } - k = 0; - FOREACH_WORD_QUOTED(word, l, rvalue, state) { - if (k == 0) { - for (i = 0; i < 2; i++) { - if (*word == '-' && !ignore) { - ignore = true; - word ++; - } - - if (*word == '@' && !separate_argv0) { - separate_argv0 = true; - word ++; - } - } - } else if (strneq(word, ";", MAX(l, 1U))) - goto found; + if (isempty(f)) { + /* First word is either "-" or "@" with no command. */ + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Empty path in command line, ignoring: \"%s\"", rvalue); + return 0; + } - k++; + if (!string_is_safe(f)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Executable path contains special characters, ignoring: %s", rvalue); + return 0; } - if (!isempty(state)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring."); + if (!path_is_absolute(f)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Executable path is not absolute, ignoring: %s", rvalue); + return 0; + } + if (endswith(f, "/")) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Executable path specifies a directory, ignoring: %s", rvalue); return 0; } - found: - /* If separate_argv0, we'll move first element to path variable */ - n = new(char*, MAX(k + !separate_argv0, 1u)); - if (!n) - return log_oom(); + if (f == firstword) { + path = firstword; + firstword = NULL; + } else { + path = strdup(f); + if (!path) + return log_oom(); + } - k = 0; - FOREACH_WORD_QUOTED(word, l, rvalue, state) { - char *c; - unsigned skip; - - if (separate_argv0 ? path == NULL : k == 0) { - /* first word, very special */ - skip = separate_argv0 + ignore; - - /* skip special chars in the beginning */ - if (l <= skip) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Empty path in command line, ignoring: \"%s\"", rvalue); - r = 0; - goto fail; - } + if (!separate_argv0) { + if (!GREEDY_REALLOC(n, nbufsize, nlen + 2)) + return log_oom(); + f = strdup(path); + if (!f) + return log_oom(); + n[nlen++] = f; + n[nlen] = NULL; + } - } else if (strneq(word, ";", MAX(l, 1U))) - /* new commandline */ - break; + path_kill_slashes(path); - else - skip = strneq(word, "\\;", MAX(l, 1U)); + for (;;) { + _cleanup_free_ char *word = NULL; - r = cunescape_length(word + skip, l - skip, UNESCAPE_RELAX, &c); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to unescape command line, ignoring: %s", rvalue); - r = 0; - goto fail; + /* Check explicitly for an unquoted semicolon as + * command separator token. */ + if (p[0] == ';' && (!p[1] || strchr(WHITESPACE, p[1]))) { + p ++; + p += strspn(p, WHITESPACE); + semicolon = true; + break; } - if (!utf8_is_valid(c)) { - log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue); - r = 0; - goto fail; + /* Check for \; explicitly, to not confuse it with \\; + * or "\;" or "\\;" etc. unquote_first_word would + * return the same for all of those. */ + if (p[0] == '\\' && p[1] == ';' && (!p[2] || strchr(WHITESPACE, p[2]))) { + p += 2; + p += strspn(p, WHITESPACE); + if (!GREEDY_REALLOC(n, nbufsize, nlen + 2)) + return log_oom(); + f = strdup(";"); + if (!f) + return log_oom(); + n[nlen++] = f; + n[nlen] = NULL; + continue; } - /* where to stuff this? */ - if (separate_argv0 && path == NULL) - path = c; - else - n[k++] = c; - } + r = unquote_first_word_and_warn(&p, &word, UNQUOTE_CUNESCAPE, unit, filename, line, rvalue); + if (r == 0) + break; + else if (r < 0) + return 0; - n[k] = NULL; + if (!GREEDY_REALLOC(n, nbufsize, nlen + 2)) + return log_oom(); + n[nlen++] = word; + n[nlen] = NULL; + word = NULL; + } - if (!n[0]) - reason = "Empty executable name or zeroeth argument"; - else if (!string_is_safe(path ?: n[0])) - reason = "Executable path contains special characters"; - else if (!path_is_absolute(path ?: n[0])) - reason = "Executable path is not absolute"; - else if (endswith(path ?: n[0], "/")) - reason = "Executable path specifies a directory"; - else - goto ok; - - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "%s, ignoring: %s", reason, rvalue); - r = 0; - goto fail; - -ok: - if (!path) { - path = strdup(n[0]); - if (!path) { - r = log_oom(); - goto fail; - } + if (!n || !n[0]) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Empty executable name or zeroeth argument, ignoring: %s", rvalue); + return 0; } nce = new0(ExecCommand, 1); - if (!nce) { - r = log_oom(); - goto fail; - } + if (!nce) + return log_oom(); nce->argv = n; nce->path = path; nce->ignore = ignore; - path_kill_slashes(nce->path); - exec_command_append_list(e, nce); - rvalue = state; - } - - return 0; + /* Do not _cleanup_free_ these. */ + n = NULL; + path = NULL; + nce = NULL; -fail: - n[k] = NULL; - strv_free(n); - free(path); - free(nce); + rvalue = p; + } while (semicolon); - return r; + return 0; } DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type"); diff --git a/src/core/manager.c b/src/core/manager.c index eb80dd1b46..a1f37bbbb3 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -731,7 +731,6 @@ static int manager_setup_notify(Manager *m) { } static int manager_setup_kdbus(Manager *m) { -#ifdef ENABLE_KDBUS _cleanup_free_ char *p = NULL; assert(m); @@ -749,7 +748,6 @@ static int manager_setup_kdbus(Manager *m) { return log_debug_errno(m->kdbus_fd, "Failed to set up kdbus: %m"); log_debug("Successfully set up kdbus on %s", p); -#endif return 0; } diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index c35248eeae..42a6b952b9 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -104,10 +104,8 @@ static const MountPoint mount_table[] = { { "efivarfs", "/sys/firmware/efi/efivars", "efivarfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, is_efi_boot, MNT_NONE }, #endif -#ifdef ENABLE_KDBUS { "kdbusfs", "/sys/fs/kdbus", "kdbusfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL, MNT_IN_CONTAINER }, -#endif }; /* These are API file systems that might be mounted by other software, diff --git a/src/core/service.c b/src/core/service.c index 71252e29e2..fa1e80b710 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -568,14 +568,12 @@ static int service_add_extras(Service *s) { s->notify_access = NOTIFY_MAIN; if (s->bus_name) { -#ifdef ENABLE_KDBUS const char *n; n = strjoina(s->bus_name, ".busname"); r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, n, NULL, true); if (r < 0) return r; -#endif r = unit_watch_bus_name(UNIT(s), s->bus_name); if (r < 0) @@ -1180,7 +1178,6 @@ static int service_spawn( } else path = UNIT(s)->cgroup_path; -#ifdef ENABLE_KDBUS if (s->exec_context.bus_endpoint) { r = bus_kernel_create_endpoint(UNIT(s)->manager->running_as == MANAGER_SYSTEM ? "system" : "user", UNIT(s)->id, &bus_endpoint_path); @@ -1192,7 +1189,6 @@ static int service_spawn( * as the service is running. */ exec_params.bus_endpoint_fd = s->bus_endpoint_fd = r; } -#endif exec_params.argv = argv; exec_params.fds = fds; diff --git a/src/import/pull.c b/src/import/pull.c index ca33d2f3fa..ca7be6be85 100644 --- a/src/import/pull.c +++ b/src/import/pull.c @@ -245,15 +245,15 @@ static int pull_dkr(int argc, char *argv[], void *userdata) { if (digest) { reference = digest + 1; name = strndupa(argv[1], digest - argv[1]); - } - - reference = strchr(argv[1], ':'); - if (reference) { - name = strndupa(argv[1], reference - argv[1]); - reference++; } else { - name = argv[1]; - reference = "latest"; + reference = strchr(argv[1], ':'); + if (reference) { + name = strndupa(argv[1], reference - argv[1]); + reference++; + } else { + name = argv[1]; + reference = "latest"; + } } if (!dkr_name_is_valid(name)) { diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c index c2fc123e42..adefa1b026 100644 --- a/src/journal/test-journal-interleaving.c +++ b/src/journal/test-journal-interleaving.c @@ -62,10 +62,19 @@ static void test_close(JournalFile *f) { static void append_number(JournalFile *f, int n, uint64_t *seqnum) { char *p; dual_timestamp ts; + static dual_timestamp previous_ts = {}; struct iovec iovec[1]; dual_timestamp_get(&ts); + if (ts.monotonic <= previous_ts.monotonic) + ts.monotonic = previous_ts.monotonic + 1; + + if (ts.realtime <= previous_ts.realtime) + ts.realtime = previous_ts.realtime + 1; + + previous_ts = ts; + assert_se(asprintf(&p, "NUMBER=%d", n) >= 0); iovec[0].iov_base = p; iovec[0].iov_len = strlen(p); diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c index e1146c692d..b5ecf2f375 100644 --- a/src/journal/test-journal-stream.c +++ b/src/journal/test-journal-stream.c @@ -80,6 +80,7 @@ int main(int argc, char *argv[]) { char *z; const void *data; size_t l; + dual_timestamp previous_ts = DUAL_TIMESTAMP_NULL; /* journal_file_open requires a valid machine id */ if (access("/etc/machine-id", F_OK) != 0) @@ -101,6 +102,14 @@ int main(int argc, char *argv[]) { dual_timestamp_get(&ts); + if (ts.monotonic <= previous_ts.monotonic) + ts.monotonic = previous_ts.monotonic + 1; + + if (ts.realtime <= previous_ts.realtime) + ts.realtime = previous_ts.realtime + 1; + + previous_ts = ts; + assert_se(asprintf(&p, "NUMBER=%u", i) >= 0); iovec[0].iov_base = p; iovec[0].iov_len = strlen(p); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 6853038b67..6a0d270739 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -928,6 +928,8 @@ static int client_initialize_time_events(sd_dhcp_client *client) { r = sd_event_source_set_priority(client->timeout_resend, client->event_priority); + if (r < 0) + goto error; r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer"); if (r < 0) diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index 0881b4779a..5dd6468707 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -1239,18 +1239,9 @@ int bus_set_address_user(sd_bus *b) { if (!ee) return -ENOMEM; -#ifdef ENABLE_KDBUS (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, getuid(), ee); -#else - (void) asprintf(&b->address, UNIX_USER_BUS_ADDRESS_FMT, ee); -#endif - } else { -#ifdef ENABLE_KDBUS + } else (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid()); -#else - return -ECONNREFUSED; -#endif - } if (!b->address) return -ENOMEM; @@ -1372,11 +1363,7 @@ int bus_set_address_system_machine(sd_bus *b, const char *machine) { if (!e) return -ENOMEM; -#ifdef ENABLE_KDBUS b->address = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL); -#else - b->address = strjoin("x-machine-unix:machine=", e, NULL); -#endif if (!b->address) return -ENOMEM; @@ -2958,10 +2945,8 @@ _public_ int sd_bus_add_match( /* Do not install server-side matches for matches * against the local service, interface or bus - * path. Also, when on kdbus don't install driver - * matches server side. */ - if (scope == BUS_MATCH_GENERIC || - (!bus->is_kernel && scope == BUS_MATCH_DRIVER)) { + * path. */ + if (scope != BUS_MATCH_LOCAL) { if (!bus->is_kernel) { /* When this is not a kernel transport, we diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c index c27b01db96..9a8d682107 100644 --- a/src/libudev/libudev-device.c +++ b/src/libudev/libudev-device.c @@ -871,7 +871,7 @@ _public_ struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_ udev_list_cleanup(&udev_device->sysattrs); FOREACH_DEVICE_SYSATTR(udev_device->device, sysattr) - udev_list_entry_add(&udev_device->properties, sysattr, NULL); + udev_list_entry_add(&udev_device->sysattrs, sysattr, NULL); udev_device->sysattrs_read = true; } diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 6720899def..21d7268120 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -36,9 +36,10 @@ #include "bus-error.h" #include "conf-parser.h" #include "clean-ipc.h" -#include "logind-user.h" #include "smack-util.h" #include "formats-util.h" +#include "label.h" +#include "logind-user.h" User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) { User *u; @@ -105,7 +106,7 @@ void user_free(User *u) { free(u); } -int user_save(User *u) { +static int user_save_internal(User *u) { _cleanup_free_ char *temp_path = NULL; _cleanup_fclose_ FILE *f = NULL; int r; @@ -113,9 +114,6 @@ int user_save(User *u) { assert(u); assert(u->state_file); - if (!u->started) - return 0; - r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0); if (r < 0) goto finish; @@ -258,6 +256,15 @@ finish: return r; } +int user_save(User *u) { + assert(u); + + if (!u->started) + return 0; + + return user_save_internal (u); +} + int user_load(User *u) { _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL; Session *s = NULL; @@ -323,7 +330,7 @@ static int user_mkdir_runtime_path(User *u) { if (path_is_mount_point(p, 0) <= 0) { _cleanup_free_ char *t = NULL; - (void) mkdir(p, 0700); + (void) mkdir_label(p, 0700); if (mac_smack_use()) r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size); @@ -351,6 +358,10 @@ static int user_mkdir_runtime_path(User *u) { goto fail; } } + + r = label_fix(p, false, false); + if (r < 0) + log_warning_errno(r, "Failed to fix label of '%s', ignoring: %m", p); } u->runtime_path = p; @@ -453,6 +464,12 @@ int user_start(User *u) { if (r < 0) return r; + /* Save the user data so far, because pam_systemd will read the + * XDG_RUNTIME_DIR out of it while starting up systemd --user. + * We need to do user_save_internal() because we have not + * "officially" started yet. */ + user_save_internal(u); + /* Spawn user systemd */ r = user_start_service(u); if (r < 0) @@ -704,7 +721,7 @@ UserState user_get_state(User *u) { if (u->stopping) return USER_CLOSING; - if (u->slice_job || u->service_job) + if (!u->started || u->slice_job || u->service_job) return USER_OPENING; if (u->sessions) { diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index b5d419000c..0ebdfdf19e 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -177,7 +177,6 @@ static int export_legacy_dbus_address( uid_t uid, const char *runtime) { -#ifdef ENABLE_KDBUS _cleanup_free_ char *s = NULL; int r; @@ -195,7 +194,7 @@ static int export_legacy_dbus_address( pam_syslog(handle, LOG_ERR, "Failed to set bus variable."); return r; } -#endif + return PAM_SUCCESS; } diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 9f026beb13..7813a0bcc7 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -509,11 +509,7 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu if (r < 0) return r; -#ifdef ENABLE_KDBUS # define ADDRESS_FMT "x-machine-kernel:pid=%1$" PID_PRI ";x-machine-unix:pid=%1$" PID_PRI -#else -# define ADDRESS_FMT "x-machine-unix:pid=%1$" PID_PRI -#endif if (asprintf(&address, ADDRESS_FMT, m->leader) < 0) return log_oom(); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 3c31629d1e..d1154de08a 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -4972,6 +4972,10 @@ finish: if (pid > 0) kill(pid, SIGKILL); + /* Try to flush whatever is still queued in the pty */ + if (master >= 0) + (void) copy_bytes(master, STDOUT_FILENO, (off_t) -1, false); + loop_remove(loop_nr, &image_fd); if (remove_subvol && arg_directory) { diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c index 466f9aa601..bd8c988751 100644 --- a/src/shared/acl-util.c +++ b/src/shared/acl-util.c @@ -223,7 +223,7 @@ int acl_search_groups(const char *path, char ***ret_groups) { return ret; } -int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) { +int parse_acl(const char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) { _cleanup_free_ char **a = NULL, **d = NULL; /* strings are not be freed */ _cleanup_strv_free_ char **split; char **entry; @@ -232,7 +232,7 @@ int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) split = strv_split(text, ","); if (!split) - return log_oom(); + return -ENOMEM; STRV_FOREACH(entry, split) { char *p; @@ -245,9 +245,9 @@ int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) r = strv_push(&d, p); else r = strv_push(&a, *entry); + if (r < 0) + return r; } - if (r < 0) - return r; if (!strv_isempty(a)) { _cleanup_free_ char *join; @@ -258,7 +258,7 @@ int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) a_acl = acl_from_text(join); if (!a_acl) - return -EINVAL; + return -errno; if (want_mask) { r = calc_acl_mask_if_needed(&a_acl); @@ -276,7 +276,7 @@ int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) d_acl = acl_from_text(join); if (!d_acl) - return -EINVAL; + return -errno; if (want_mask) { r = calc_acl_mask_if_needed(&d_acl); @@ -288,6 +288,7 @@ int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) *acl_access = a_acl; *acl_default = d_acl; a_acl = d_acl = NULL; + return 0; } diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h index c8bcc266d0..cf612e8722 100644 --- a/src/shared/acl-util.h +++ b/src/shared/acl-util.h @@ -33,7 +33,7 @@ int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry); int calc_acl_mask_if_needed(acl_t *acl_p); int add_base_acls_if_needed(acl_t *acl_p, const char *path); int acl_search_groups(const char* path, char ***ret_groups); -int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask); +int parse_acl(const char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask); int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl); /* acl_free takes multiple argument types. diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 8fcc289957..11350dad71 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -545,7 +545,6 @@ int bus_open_system_systemd(sd_bus **_bus) { * directly to the system instance, instead of going via the * bus */ -#ifdef ENABLE_KDBUS r = sd_bus_new(&bus); if (r < 0) return r; @@ -564,7 +563,6 @@ int bus_open_system_systemd(sd_bus **_bus) { } bus = sd_bus_unref(bus); -#endif r = sd_bus_new(&bus); if (r < 0) @@ -598,7 +596,6 @@ int bus_open_user_systemd(sd_bus **_bus) { assert(_bus); -#ifdef ENABLE_KDBUS r = sd_bus_new(&bus); if (r < 0) return r; @@ -616,7 +613,6 @@ int bus_open_user_systemd(sd_bus **_bus) { } bus = sd_bus_unref(bus); -#endif e = secure_getenv("XDG_RUNTIME_DIR"); if (!e) @@ -2034,15 +2030,22 @@ int bus_path_decode_unique(const char *path, const char *prefix, char **ret_send bool is_kdbus_wanted(void) { _cleanup_free_ char *value = NULL; +#ifdef ENABLE_KDBUS + const bool configured = true; +#else + const bool configured = false; +#endif + int r; - if (get_proc_cmdline_key("kdbus", NULL) <= 0) { - r = get_proc_cmdline_key("kdbus=", &value); - if (r <= 0 || parse_boolean(value) != 1) - return false; - } + if (get_proc_cmdline_key("kdbus", NULL) > 0) + return true; + + r = get_proc_cmdline_key("kdbus=", &value); + if (r <= 0) + return configured; - return true; + return parse_boolean(value) == 1; } bool is_kdbus_available(void) { diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index ac5eb16f62..068da465d9 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -274,8 +274,10 @@ static int output_short( if (r < 0) return log_error_errno(r, "Failed to get journal fields: %m"); - if (!message) + if (!message) { + log_debug("Skipping message without MESSAGE= field."); return 0; + } if (!(flags & OUTPUT_SHOW_ALL)) strip_tab_ansi(&message, &message_len); diff --git a/src/shared/watchdog.c b/src/shared/watchdog.c index 2fe4eb81cf..9d39beb340 100644 --- a/src/shared/watchdog.c +++ b/src/shared/watchdog.c @@ -60,8 +60,13 @@ static int update_timeout(void) { flags = WDIOS_ENABLECARD; r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags); - if (r < 0) - return log_warning_errno(errno, "Failed to enable hardware watchdog: %m"); + if (r < 0) { + /* ENOTTY means the watchdog is always enabled so we're fine */ + log_full(errno == ENOTTY ? LOG_DEBUG : LOG_WARNING, + "Failed to enable hardware watchdog: %m"); + if (errno != ENOTTY) + return -errno; + } r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0); if (r < 0) diff --git a/src/test/test-barrier.c b/src/test/test-barrier.c index 2d109a30e7..f37cb49c85 100644 --- a/src/test/test-barrier.c +++ b/src/test/test-barrier.c @@ -438,6 +438,16 @@ TEST_BARRIER(test_barrier_pending_exit, TEST_BARRIER_WAIT_SUCCESS(pid2)); int main(int argc, char *argv[]) { + /* + * This test uses real-time alarms and sleeps to test for CPU races + * explicitly. This is highly fragile if your system is under load. We + * already increased the BASE_TIME value to make the tests more robust, + * but that just makes the test take significantly longer. Hence, + * disable the test by default, so it will not break CI. + */ + if (argc < 2) + return EXIT_TEST_SKIP; + log_parse_environment(); log_open(); diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index a8025c825b..8358789e6f 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -145,19 +145,19 @@ static void test_config_parse_exec(void) { assert_se(r == 0); assert_se(c1->command_next == NULL); - log_info("/* no command, check for bad memory access */"); + log_info("/* no command, whitespace only, reset */"); r = config_parse_exec(NULL, "fake", 3, "section", 1, "LValue", 0, " ", &c, NULL); assert_se(r == 0); - assert_se(c1->command_next == NULL); + assert_se(c == NULL); log_info("/* ignore && honour_argv0 */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "-@/RValue///slashes3 argv0a r1", &c, NULL); assert_se(r >= 0); - c1 = c1->command_next; + c1 = c; check_execcommand(c1, "/RValue/slashes3", "argv0a", "r1", NULL, true); log_info("/* ignore && honour_argv0 */"); @@ -195,6 +195,19 @@ static void test_config_parse_exec(void) { c1 = c1->command_next; check_execcommand(c1, "/goo/goo", NULL, "boo", NULL, false); + log_info("/* two semicolons in a row */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "-@/RValue argv0 r1 ; ; " + "/goo/goo boo", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); + + /* second command fails because the executable name is ";" */ + assert_se(c1->command_next == NULL); + log_info("/* trailing semicolon */"); r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, @@ -206,6 +219,26 @@ static void test_config_parse_exec(void) { assert_se(c1->command_next == NULL); + log_info("/* trailing semicolon, no whitespace */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "-@/RValue argv0 r1 ;", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); + + assert_se(c1->command_next == NULL); + + log_info("/* trailing semicolon in single quotes */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "-@/RValue argv0 r1 ';'", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/RValue", "argv0", "r1", ";", true); + log_info("/* escaped semicolon */"); r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, @@ -218,12 +251,22 @@ static void test_config_parse_exec(void) { log_info("/* escaped semicolon with following arg */"); r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, - "/sbin/find \\; x", + "/sbin/find \\; /x", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, + "/sbin/find", NULL, ";", "/x", false); + + log_info("/* escaped semicolon as part of an expression */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "/sbin/find \\;x", &c, NULL); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, - "/sbin/find", NULL, ";", "x", false); + "/sbin/find", NULL, "\\;x", NULL, false); log_info("/* encoded semicolon */"); r = config_parse_exec(NULL, "fake", 5, "section", 1, @@ -234,6 +277,25 @@ static void test_config_parse_exec(void) { c1 = c1->command_next; check_execcommand(c1, "/bin/find", NULL, ";", NULL, false); + log_info("/* quoted semicolon */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "/bin/find \";\"", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/bin/find", NULL, ";", NULL, false); + + log_info("/* quoted semicolon with following arg */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "/sbin/find \";\" /x", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, + "/sbin/find", NULL, ";", "/x", false); + log_info("/* spaces in the filename */"); r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, diff --git a/src/test/test-util.c b/src/test/test-util.c index ed8db45115..ad9ea3bcce 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -1304,6 +1304,244 @@ static void test_unquote_first_word(void) { assert_se(streq(t, "pi\360\237\222\251le")); free(t); assert_se(p == original + 32); + + p = original = "fooo\\"; + assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(p == original + 5); + + p = original = "fooo\\"; + assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(p == original + 5); + + p = original = "fooo\\"; + assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(p == original + 5); + + p = original = "fooo\\"; + assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(unquote_first_word(&p, &t, 0) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0); + assert_se(streq(t, "foo")); + free(t); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0); + assert_se(streq(t, "foo\\")); + free(t); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0); + assert_se(streq(t, "foo\\")); + free(t); + assert_se(p == original + 5); + + p = original = "fooo\\ bar quux"; + assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) == -EINVAL); + assert_se(p == original + 5); + + p = original = "fooo\\ bar quux"; + assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "fooo\\ bar")); + free(t); + assert_se(p == original + 10); + + p = original = "\\w+@\\K[\\d.]+"; + assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\\w+@\\K[\\d.]+"; + assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "\\w+@\\K[\\d.]+")); + free(t); + assert_se(p == original + 12); + + p = original = "\\w+\\b"; + assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "\\w+\b")); + free(t); + assert_se(p == original + 5); +} + +static void test_unquote_first_word_and_warn(void) { + const char *p, *original; + char *t; + + p = original = "foobar waldo"; + assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foobar")); + free(t); + assert_se(p == original + 7); + + assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "waldo")); + free(t); + assert_se(p == original + 12); + + assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == 0); + assert_se(!t); + assert_se(p == original + 12); + + p = original = "\"foobar\" \'waldo\'"; + assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foobar")); + free(t); + assert_se(p == original + 9); + + assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "waldo")); + free(t); + assert_se(p == original + 16); + + assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == 0); + assert_se(!t); + assert_se(p == original + 16); + + p = original = "\""; + assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\'"; + assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\'fooo"; + assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\'fooo"; + assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(p == original + 5); + + p = original = " foo\\ba\\x6ar "; + assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foo\ba\x6ar")); + free(t); + assert_se(p == original + 13); + + p = original = " foo\\ba\\x6ar "; + assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foobax6ar")); + free(t); + assert_se(p == original + 13); + + p = original = " f\\u00f6o \"pi\\U0001F4A9le\" "; + assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "föo")); + free(t); + assert_se(p == original + 13); + + assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "pi\360\237\222\251le")); + free(t); + assert_se(p == original + 32); + + p = original = "fooo\\"; + assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(p == original + 5); + + p = original = "fooo\\"; + assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(p == original + 5); + + p = original = "fooo\\"; + assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foo")); + free(t); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foo")); + free(t); + assert_se(p == original + 5); + + p = original = "fooo\\ bar quux"; + assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo\\ bar")); + free(t); + assert_se(p == original + 10); + + p = original = "\\w+@\\K[\\d.]+"; + assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "\\w+@\\K[\\d.]+")); + free(t); + assert_se(p == original + 12); + + p = original = "\\w+\\b"; + assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "\\w+\b")); + free(t); + assert_se(p == original + 5); } static void test_unquote_many_words(void) { @@ -1610,6 +1848,7 @@ int main(int argc, char *argv[]) { test_glob_exists(); test_execute_directory(); test_unquote_first_word(); + test_unquote_first_word_and_warn(); test_unquote_many_words(); test_parse_proc_cmdline(); test_raw_clone(); diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 5ce11606c9..c205f1d5ec 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -43,6 +43,7 @@ #include "sd-daemon.h" #include "sd-event.h" +#include "terminal-util.h" #include "signal-util.h" #include "event-util.h" #include "netlink-util.h" @@ -435,7 +436,6 @@ static void worker_spawn(Manager *manager, struct event *event) { if (fd_lock >= 0 && flock(fd_lock, LOCK_SH|LOCK_NB) < 0) { log_debug_errno(errno, "Unable to flock(%s), skipping event handling: %m", udev_device_get_devnode(d)); fd_lock = safe_close(fd_lock); - r = -EAGAIN; goto skip; } } @@ -1687,6 +1687,10 @@ int main(int argc, char *argv[]) { log_info("starting version " VERSION); + /* connect /dev/null to stdin, stdout, stderr */ + if (log_get_max_level() < LOG_DEBUG) + (void) make_null_stdio(); + pid = fork(); switch (pid) { case 0: |