diff options
Diffstat (limited to 'src')
272 files changed, 3026 insertions, 2072 deletions
diff --git a/src/analyze/analyze-security.c b/src/analyze/analyze-security.c index 1fc3c1e02f..a007ed1da4 100644 --- a/src/analyze/analyze-security.c +++ b/src/analyze/analyze-security.c @@ -485,24 +485,24 @@ static bool syscall_names_in_filter(Set *s, bool whitelist, const SyscallFilterS const char *syscall; NULSTR_FOREACH(syscall, f->value) { - bool b; + int id; if (syscall[0] == '@') { const SyscallFilterSet *g; - assert_se(g = syscall_filter_set_find(syscall)); - b = syscall_names_in_filter(s, whitelist, g); - } else { - int id; - /* Let's see if the system call actually exists on this platform, before complaining */ - id = seccomp_syscall_resolve_name(syscall); - if (id < 0) - continue; + assert_se(g = syscall_filter_set_find(syscall)); + if (syscall_names_in_filter(s, whitelist, g)) + return true; /* bad! */ - b = set_contains(s, syscall); + continue; } - if (whitelist == b) { + /* Let's see if the system call actually exists on this platform, before complaining */ + id = seccomp_syscall_resolve_name(syscall); + if (id < 0) + continue; + + if (set_contains(s, syscall) == whitelist) { log_debug("Offending syscall filter item: %s", syscall); return true; /* bad! */ } @@ -1859,7 +1859,6 @@ static int acquire_security_info(sd_bus *bus, const char *name, struct security_ { "PrivateNetwork", "b", NULL, offsetof(struct security_info, private_network) }, { "PrivateTmp", "b", NULL, offsetof(struct security_info, private_tmp) }, { "PrivateUsers", "b", NULL, offsetof(struct security_info, private_users) }, - { "PrivateUsers", "b", NULL, offsetof(struct security_info, private_users) }, { "ProtectControlGroups", "b", NULL, offsetof(struct security_info, protect_control_groups) }, { "ProtectHome", "s", NULL, offsetof(struct security_info, protect_home) }, { "ProtectKernelModules", "b", NULL, offsetof(struct security_info, protect_kernel_modules) }, diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 1f69b9fda1..3915b66739 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -14,6 +14,7 @@ #include "alloc-util.h" #include "analyze-security.h" #include "analyze-verify.h" +#include "build.h" #include "bus-error.h" #include "bus-unit-util.h" #include "bus-util.h" @@ -696,7 +697,7 @@ static int analyze_plot(int argc, char *argv[], void *userdata) { "<!-- that render these files properly but much slower are ImageMagick, -->\n" "<!-- gimp, inkscape, etc. To display the files on your system, just -->\n" "<!-- point your browser to this file. -->\n\n" - "<!-- This plot was generated by systemd-analyze version %-16.16s -->\n\n", PACKAGE_VERSION); + "<!-- This plot was generated by systemd-analyze version %-16.16s -->\n\n", GIT_VERSION); /* style sheet */ svg("<defs>\n <style type=\"text/css\">\n <![CDATA[\n" diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h index ff7a46793a..893a1238ff 100644 --- a/src/basic/alloc-util.h +++ b/src/basic/alloc-util.h @@ -10,20 +10,28 @@ typedef void (*free_func_t)(void *p); +/* If for some reason more than 4M are allocated on the stack, let's abort immediately. It's better than + * proceeding and smashing the stack limits. Note that by default RLIMIT_STACK is 8M on Linux. */ +#define ALLOCA_MAX (4U*1024U*1024U) + #define new(t, n) ((t*) malloc_multiply(sizeof(t), (n))) #define new0(t, n) ((t*) calloc((n) ?: 1, sizeof(t))) -#define newa(t, n) \ - ({ \ - assert(!size_multiply_overflow(sizeof(t), n)); \ - (t*) alloca(sizeof(t)*(n)); \ +#define newa(t, n) \ + ({ \ + size_t _n_ = n; \ + assert(!size_multiply_overflow(sizeof(t), _n_)); \ + assert(sizeof(t)*_n_ <= ALLOCA_MAX); \ + (t*) alloca(sizeof(t)*_n_); \ }) -#define newa0(t, n) \ - ({ \ - assert(!size_multiply_overflow(sizeof(t), n)); \ - (t*) alloca0(sizeof(t)*(n)); \ +#define newa0(t, n) \ + ({ \ + size_t _n_ = n; \ + assert(!size_multiply_overflow(sizeof(t), _n_)); \ + assert(sizeof(t)*_n_ <= ALLOCA_MAX); \ + (t*) alloca0(sizeof(t)*_n_); \ }) #define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) @@ -51,16 +59,20 @@ void* memdup_suffix0(const void *p, size_t l) _alloc_(2); #define memdupa(p, l) \ ({ \ void *_q_; \ - _q_ = alloca(l); \ - memcpy(_q_, p, l); \ + size_t _l_ = l; \ + assert(_l_ <= ALLOCA_MAX); \ + _q_ = alloca(_l_); \ + memcpy(_q_, p, _l_); \ }) #define memdupa_suffix0(p, l) \ ({ \ void *_q_; \ - _q_ = alloca(l + 1); \ - ((uint8_t*) _q_)[l] = 0; \ - memcpy(_q_, p, l); \ + size_t _l_ = l; \ + assert(_l_ <= ALLOCA_MAX); \ + _q_ = alloca(_l_ + 1); \ + ((uint8_t*) _q_)[_l_] = 0; \ + memcpy(_q_, p, _l_); \ }) static inline void freep(void *p) { @@ -116,6 +128,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); ({ \ char *_new_; \ size_t _len_ = n; \ + assert(_len_ <= ALLOCA_MAX); \ _new_ = alloca(_len_); \ (void *) memset(_new_, 0, _len_); \ }) @@ -125,16 +138,18 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); ({ \ void *_ptr_; \ size_t _mask_ = (align) - 1; \ - _ptr_ = alloca((size) + _mask_); \ + size_t _size_ = size; \ + assert(_size_ <= ALLOCA_MAX); \ + _ptr_ = alloca(_size_ + _mask_); \ (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ }) #define alloca0_align(size, align) \ ({ \ void *_new_; \ - size_t _size_ = (size); \ - _new_ = alloca_align(_size_, (align)); \ - (void*)memset(_new_, 0, _size_); \ + size_t _xsize_ = (size); \ + _new_ = alloca_align(_xsize_, (align)); \ + (void*)memset(_new_, 0, _xsize_); \ }) /* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index d08e7546d0..da4dd2a827 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -941,7 +941,7 @@ int btrfs_qgroup_destroy_recursive(int fd, uint64_t qgroupid) { /* Destroys the specified qgroup, but unassigns it from all * its parents first. Also, it recursively destroys all - * qgroups it is assgined to that have the same id part of the + * qgroups it is assigned to that have the same id part of the * qgroupid as the specified group. */ r = btrfs_qgroupid_split(qgroupid, NULL, &subvol_id); diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h index 085aca4dbc..7d848a75d3 100644 --- a/src/basic/btrfs-util.h +++ b/src/basic/btrfs-util.h @@ -28,17 +28,17 @@ typedef struct BtrfsQuotaInfo { } BtrfsQuotaInfo; typedef enum BtrfsSnapshotFlags { - BTRFS_SNAPSHOT_FALLBACK_COPY = 1, /* If the source isn't a subvolume, reflink everything */ - BTRFS_SNAPSHOT_READ_ONLY = 2, - BTRFS_SNAPSHOT_RECURSIVE = 4, - BTRFS_SNAPSHOT_QUOTA = 8, - BTRFS_SNAPSHOT_FALLBACK_DIRECTORY = 16, /* If the destination doesn't support subvolumes, reflink/copy instead */ - BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE = 32, /* When we can't create a subvolume, use the FS_IMMUTABLE attribute for indicating read-only */ + BTRFS_SNAPSHOT_FALLBACK_COPY = 1 << 0, /* If the source isn't a subvolume, reflink everything */ + BTRFS_SNAPSHOT_READ_ONLY = 1 << 1, + BTRFS_SNAPSHOT_RECURSIVE = 1 << 2, + BTRFS_SNAPSHOT_QUOTA = 1 << 3, + BTRFS_SNAPSHOT_FALLBACK_DIRECTORY = 1 << 4, /* If the destination doesn't support subvolumes, reflink/copy instead */ + BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE = 1 << 5, /* When we can't create a subvolume, use the FS_IMMUTABLE attribute for indicating read-only */ } BtrfsSnapshotFlags; typedef enum BtrfsRemoveFlags { - BTRFS_REMOVE_RECURSIVE = 1, - BTRFS_REMOVE_QUOTA = 2, + BTRFS_REMOVE_RECURSIVE = 1 << 0, + BTRFS_REMOVE_QUOTA = 1 << 1, } BtrfsRemoveFlags; int btrfs_is_filesystem(int fd); diff --git a/src/basic/build.h b/src/basic/build.h index 2c46550300..7a59059080 100644 --- a/src/basic/build.h +++ b/src/basic/build.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once +#include "version.h" + #if HAVE_PAM #define _PAM_FEATURE_ "+PAM" #else diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c index a3f3ca9f52..b944ee6ea1 100644 --- a/src/basic/capability-util.c +++ b/src/basic/capability-util.c @@ -13,6 +13,7 @@ #include "fileio.h" #include "log.h" #include "macro.h" +#include "missing_prctl.h" #include "parse-util.h" #include "user-util.h" #include "util.h" diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 830a63c185..8ce7ccb960 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -872,7 +872,7 @@ int cg_set_access( bool fatal; }; - /* cgroupsv1, aka legacy/non-unified */ + /* cgroup v1, aka legacy/non-unified */ static const struct Attribute legacy_attributes[] = { { "cgroup.procs", true }, { "tasks", false }, @@ -880,7 +880,7 @@ int cg_set_access( {}, }; - /* cgroupsv2, aka unified */ + /* cgroup v2, aka unified */ static const struct Attribute unified_attributes[] = { { "cgroup.procs", true }, { "cgroup.subtree_control", true }, @@ -2039,7 +2039,7 @@ int cg_get_keyed_attribute( char **v; int r; - /* Reads one or more fields of a cgroupsv2 keyed attribute file. The 'keys' parameter should be an strv with + /* Reads one or more fields of a cgroup v2 keyed attribute file. The 'keys' parameter should be an strv with * all keys to retrieve. The 'ret_values' parameter should be passed as string size with the same number of * entries as 'keys'. On success each entry will be set to the value of the matching key. * @@ -2491,7 +2491,7 @@ int cg_kernel_controllers(Set **ret) { static thread_local CGroupUnified unified_cache = CGROUP_UNIFIED_UNKNOWN; -/* The hybrid mode was initially implemented in v232 and simply mounted cgroup v2 on /sys/fs/cgroup/systemd. This +/* The hybrid mode was initially implemented in v232 and simply mounted cgroup2 on /sys/fs/cgroup/systemd. This * unfortunately broke other tools (such as docker) which expected the v1 "name=systemd" hierarchy on * /sys/fs/cgroup/systemd. From v233 and on, the hybrid mode mountnbs v2 on /sys/fs/cgroup/unified and maintains * "name=systemd" hierarchy on /sys/fs/cgroup/systemd for compatibility with other tools. @@ -2739,13 +2739,13 @@ bool cg_is_legacy_wanted(void) { if (wanted >= 0) return wanted; - /* Check if we have cgroups2 already mounted. */ + /* Check if we have cgroup v2 already mounted. */ if (cg_unified_flush() >= 0 && unified_cache == CGROUP_UNIFIED_ALL) return (wanted = false); /* Otherwise, assume that at least partial legacy is wanted, - * since cgroups2 should already be mounted at this point. */ + * since cgroup v2 should already be mounted at this point. */ return (wanted = true); } diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index ea9a333290..119b493dc6 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -48,13 +48,13 @@ typedef enum CGroupMask { CGROUP_MASK_BPF_FIREWALL = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_FIREWALL), CGROUP_MASK_BPF_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_DEVICES), - /* All real cgroupv1 controllers */ + /* All real cgroup v1 controllers */ CGROUP_MASK_V1 = CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT|CGROUP_MASK_BLKIO|CGROUP_MASK_MEMORY|CGROUP_MASK_DEVICES|CGROUP_MASK_PIDS, - /* All real cgroupv2 controllers */ + /* All real cgroup v2 controllers */ CGROUP_MASK_V2 = CGROUP_MASK_CPU|CGROUP_MASK_IO|CGROUP_MASK_MEMORY|CGROUP_MASK_PIDS, - /* All cgroupv2 BPF pseudo-controllers */ + /* All cgroup v2 BPF pseudo-controllers */ CGROUP_MASK_BPF = CGROUP_MASK_BPF_FIREWALL|CGROUP_MASK_BPF_DEVICES, _CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1 @@ -162,9 +162,9 @@ int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d); int cg_read_subgroup(DIR *d, char **fn); typedef enum CGroupFlags { - CGROUP_SIGCONT = 1, - CGROUP_IGNORE_SELF = 2, - CGROUP_REMOVE = 4, + CGROUP_SIGCONT = 1 << 0, + CGROUP_IGNORE_SELF = 1 << 1, + CGROUP_REMOVE = 1 << 2, } CGroupFlags; typedef void (*cg_kill_log_func_t)(pid_t pid, int sig, void *userdata); diff --git a/src/basic/copy.c b/src/basic/copy.c index 34e01ea1cf..46e02a3759 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -24,6 +24,7 @@ #include "macro.h" #include "missing.h" #include "mountpoint-util.h" +#include "stat-util.h" #include "string-util.h" #include "strv.h" #include "time-util.h" @@ -501,7 +502,7 @@ static int fd_copy_directory( _cleanup_close_ int fdf = -1, fdt = -1; _cleanup_closedir_ DIR *d = NULL; struct dirent *de; - bool created; + bool exists, created; int r; assert(st); @@ -522,13 +523,26 @@ static int fd_copy_directory( return -errno; fdf = -1; - r = mkdirat(dt, to, st->st_mode & 07777); - if (r >= 0) - created = true; - else if (errno == EEXIST && (copy_flags & COPY_MERGE)) + exists = false; + if (copy_flags & COPY_MERGE_EMPTY) { + r = dir_is_empty_at(dt, to); + if (r < 0 && r != -ENOENT) + return r; + else if (r == 1) + exists = true; + } + + if (exists) created = false; - else - return -errno; + else { + r = mkdirat(dt, to, st->st_mode & 07777); + if (r >= 0) + created = true; + else if (errno == EEXIST && (copy_flags & COPY_MERGE)) + created = false; + else + return -errno; + } fdt = openat(dt, to, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); if (fdt < 0) diff --git a/src/basic/copy.h b/src/basic/copy.h index a41b44c70a..f677021881 100644 --- a/src/basic/copy.h +++ b/src/basic/copy.h @@ -9,10 +9,11 @@ #include <sys/types.h> typedef enum CopyFlags { - COPY_REFLINK = 1 << 0, /* Try to reflink */ - COPY_MERGE = 1 << 1, /* Merge existing trees with our new one to copy */ - COPY_REPLACE = 1 << 2, /* Replace an existing file if there's one */ - COPY_SAME_MOUNT = 1 << 3, /* Don't descend recursively into other file systems, across mount point boundaries */ + COPY_REFLINK = 1 << 0, /* Try to reflink */ + COPY_MERGE = 1 << 1, /* Merge existing trees with our new one to copy */ + COPY_REPLACE = 1 << 2, /* Replace an existing file if there's one */ + COPY_SAME_MOUNT = 1 << 3, /* Don't descend recursively into other file systems, across mount point boundaries */ + COPY_MERGE_EMPTY = 1 << 4, /* Merge an existing, empty directory with our new tree to copy */ } CopyFlags; typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata); diff --git a/src/basic/env-file.c b/src/basic/env-file.c index 6a7d6746a1..7f10f9ad39 100644 --- a/src/basic/env-file.c +++ b/src/basic/env-file.c @@ -35,7 +35,6 @@ static int parse_env_file_internal( VALUE, VALUE_ESCAPE, SINGLE_QUOTE_VALUE, - SINGLE_QUOTE_VALUE_ESCAPE, DOUBLE_QUOTE_VALUE, DOUBLE_QUOTE_VALUE_ESCAPE, COMMENT, @@ -113,7 +112,7 @@ static int parse_env_file_internal( } else if (c == '\'') state = SINGLE_QUOTE_VALUE; - else if (c == '\"') + else if (c == '"') state = DOUBLE_QUOTE_VALUE; else if (c == '\\') state = VALUE_ESCAPE; @@ -186,8 +185,6 @@ static int parse_env_file_internal( case SINGLE_QUOTE_VALUE: if (c == '\'') state = PRE_VALUE; - else if (c == '\\') - state = SINGLE_QUOTE_VALUE_ESCAPE; else { if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) return -ENOMEM; @@ -197,19 +194,8 @@ static int parse_env_file_internal( break; - case SINGLE_QUOTE_VALUE_ESCAPE: - state = SINGLE_QUOTE_VALUE; - - if (!strchr(NEWLINE, c)) { - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) - return -ENOMEM; - - value[n_value++] = c; - } - break; - case DOUBLE_QUOTE_VALUE: - if (c == '\"') + if (c == '"') state = PRE_VALUE; else if (c == '\\') state = DOUBLE_QUOTE_VALUE_ESCAPE; @@ -225,12 +211,17 @@ static int parse_env_file_internal( case DOUBLE_QUOTE_VALUE_ESCAPE: state = DOUBLE_QUOTE_VALUE; - if (!strchr(NEWLINE, c)) { + if (c == '"') { if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) return -ENOMEM; - + value[n_value++] = '"'; + } else if (!strchr(NEWLINE, c)) { + if (!GREEDY_REALLOC(value, value_alloc, n_value+3)) + return -ENOMEM; + value[n_value++] = '\\'; value[n_value++] = c; } + break; case COMMENT: @@ -253,7 +244,6 @@ static int parse_env_file_internal( VALUE, VALUE_ESCAPE, SINGLE_QUOTE_VALUE, - SINGLE_QUOTE_VALUE_ESCAPE, DOUBLE_QUOTE_VALUE, DOUBLE_QUOTE_VALUE_ESCAPE)) { @@ -527,7 +517,7 @@ static void write_env_var(FILE *f, const char *v) { fwrite_unlocked(v, 1, p-v, f); if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) { - fputc_unlocked('\"', f); + fputc_unlocked('"', f); for (; *p; p++) { if (strchr(SHELL_NEED_ESCAPE, *p)) @@ -536,7 +526,7 @@ static void write_env_var(FILE *f, const char *v) { fputc_unlocked(*p, f); } - fputc_unlocked('\"', f); + fputc_unlocked('"', f); } else fputs_unlocked(p, f); diff --git a/src/basic/env-util.c b/src/basic/env-util.c index e494f65c98..fd449dcce0 100644 --- a/src/basic/env-util.c +++ b/src/basic/env-util.c @@ -339,7 +339,6 @@ char **strv_env_unset(char **l, const char *p) { } char **strv_env_unset_many(char **l, ...) { - char **f, **t; if (!l) @@ -408,7 +407,6 @@ int strv_env_replace(char ***l, char *p) { } char **strv_env_set(char **x, const char *p) { - _cleanup_strv_free_ char **ret = NULL; size_t n, m; char **k; diff --git a/src/basic/env-util.h b/src/basic/env-util.h index 4d21ea6bef..d54f99658b 100644 --- a/src/basic/env-util.h +++ b/src/basic/env-util.h @@ -13,9 +13,9 @@ bool env_value_is_valid(const char *e); bool env_assignment_is_valid(const char *e); enum { - REPLACE_ENV_USE_ENVIRONMENT = 1u, - REPLACE_ENV_ALLOW_BRACELESS = 2u, - REPLACE_ENV_ALLOW_EXTENDED = 4u, + REPLACE_ENV_USE_ENVIRONMENT = 1 << 0, + REPLACE_ENV_ALLOW_BRACELESS = 1 << 1, + REPLACE_ENV_ALLOW_EXTENDED = 1 << 2, }; char *replace_env_n(const char *format, size_t n, char **env, unsigned flags); diff --git a/src/basic/extract-word.h b/src/basic/extract-word.h index 8c63b7c306..705ebbe95b 100644 --- a/src/basic/extract-word.h +++ b/src/basic/extract-word.h @@ -4,12 +4,12 @@ #include "macro.h" typedef enum ExtractFlags { - EXTRACT_RELAX = 1, - EXTRACT_CUNESCAPE = 2, - EXTRACT_CUNESCAPE_RELAX = 4, - EXTRACT_QUOTES = 8, - EXTRACT_DONT_COALESCE_SEPARATORS = 16, - EXTRACT_RETAIN_ESCAPE = 32, + EXTRACT_RELAX = 1 << 0, + EXTRACT_CUNESCAPE = 1 << 1, + EXTRACT_CUNESCAPE_RELAX = 1 << 2, + EXTRACT_QUOTES = 1 << 3, + EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 4, + EXTRACT_RETAIN_ESCAPE = 1 << 5, } ExtractFlags; int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index c06f2fac7e..3e6ef5a06a 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -70,7 +70,7 @@ int safe_close(int fd) { return -1; } -void safe_close_pair(int p[]) { +void safe_close_pair(int p[static 2]) { assert(p); if (p[0] == p[1]) { @@ -189,6 +189,27 @@ _pure_ static bool fd_in_set(int fd, const int fdset[], size_t n_fdset) { return false; } +static int get_max_fd(void) { + struct rlimit rl; + rlim_t m; + + /* Return the highest possible fd, based RLIMIT_NOFILE, but enforcing FD_SETSIZE-1 as lower boundary + * and INT_MAX as upper boundary. */ + + if (getrlimit(RLIMIT_NOFILE, &rl) < 0) + return -errno; + + m = MAX(rl.rlim_cur, rl.rlim_max); + if (m < FD_SETSIZE) /* Let's always cover at least 1024 fds */ + return FD_SETSIZE-1; + + if (m == RLIM_INFINITY || m > INT_MAX) /* Saturate on overflow. After all fds are "int", hence can + * never be above INT_MAX */ + return INT_MAX; + + return (int) (m - 1); +} + int close_all_fds(const int except[], size_t n_except) { _cleanup_closedir_ DIR *d = NULL; struct dirent *de; @@ -198,20 +219,14 @@ int close_all_fds(const int except[], size_t n_except) { d = opendir("/proc/self/fd"); if (!d) { - struct rlimit rl; int fd, max_fd; - /* When /proc isn't available (for example in chroots) the fallback is brute forcing through the fd - * table */ - - assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0); - - if (rl.rlim_max == 0) - return -EINVAL; + /* When /proc isn't available (for example in chroots) the fallback is brute forcing through + * the fd table */ - /* Let's take special care if the resource limit is set to unlimited, or actually larger than the range - * of 'int'. Let's avoid implicit overflows. */ - max_fd = (rl.rlim_max == RLIM_INFINITY || rl.rlim_max > INT_MAX) ? INT_MAX : (int) (rl.rlim_max - 1); + max_fd = get_max_fd(); + if (max_fd < 0) + return max_fd; for (fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) { int q; diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h index 00303a7e45..4085a244d2 100644 --- a/src/basic/fd-util.h +++ b/src/basic/fd-util.h @@ -14,7 +14,7 @@ int close_nointr(int fd); int safe_close(int fd); -void safe_close_pair(int p[]); +void safe_close_pair(int p[static 2]); static inline int safe_close_above_stdio(int fd) { if (fd < 3) /* Don't close stdin/stdout/stderr, but still invalidate the fd by returning -1 */ diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index 5a4bb37b82..66e9e0046b 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -345,7 +345,7 @@ static unsigned base_bucket_hash(HashmapBase *h, const void *p) { } #define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p) -static inline void base_set_dirty(HashmapBase *h) { +static void base_set_dirty(HashmapBase *h) { h->dirty = true; } #define hashmap_set_dirty(h) base_set_dirty(HASHMAP_BASE(h)) @@ -888,7 +888,8 @@ void internal_hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_f * themselves from our hash table a second time, the entry is already gone. */ while (internal_hashmap_size(h) > 0) { - void *v, *k; + void *k = NULL; + void *v; v = internal_hashmap_first_key_and_value(h, true, &k); @@ -1515,8 +1516,11 @@ void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **r unsigned idx; idx = find_first_entry(h); - if (idx == IDX_NIL) + if (idx == IDX_NIL) { + if (ret_key) + *ret_key = NULL; return NULL; + } e = bucket_at(h, idx); key = (void*) e->key; diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h index 5bf807a76f..e16a9f9e30 100644 --- a/src/basic/hashmap.h +++ b/src/basic/hashmap.h @@ -326,7 +326,6 @@ static inline void *ordered_hashmap_first_key_and_value(OrderedHashmap *h, void return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret); } - static inline void *hashmap_steal_first(Hashmap *h) { return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL); } diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index 411efb242b..2bffe473ca 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -495,9 +495,8 @@ int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) { return 0; } -int in_addr_prefix_from_string_internal( +int in_addr_prefix_from_string( const char *p, - bool use_default_prefixlen, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) { @@ -531,13 +530,6 @@ int in_addr_prefix_from_string_internal( r = in_addr_parse_prefixlen(family, e+1, &k); if (r < 0) return r; - } else if (use_default_prefixlen) { - if (family == AF_INET) { - r = in4_addr_default_prefixlen(&buffer.in, &k); - if (r < 0) - return r; - } else - k = 0; } else k = FAMILY_ADDRESS_SIZE(family) * 8; @@ -551,7 +543,7 @@ int in_addr_prefix_from_string_internal( int in_addr_prefix_from_string_auto_internal( const char *p, - bool use_default_prefixlen, + InAddrPrefixLenMode mode, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) { @@ -582,15 +574,24 @@ int in_addr_prefix_from_string_auto_internal( r = in_addr_parse_prefixlen(family, e+1, &k); if (r < 0) return r; - } else if (use_default_prefixlen) { - if (family == AF_INET) { - r = in4_addr_default_prefixlen(&buffer.in, &k); - if (r < 0) - return r; - } else - k = 0; } else - k = FAMILY_ADDRESS_SIZE(family) * 8; + switch (mode) { + case PREFIXLEN_FULL: + k = FAMILY_ADDRESS_SIZE(family) * 8; + break; + case PREFIXLEN_REFUSE: + return -ENOANO; /* To distinguish this error from others. */ + case PREFIXLEN_LEGACY: + if (family == AF_INET) { + r = in4_addr_default_prefixlen(&buffer.in, &k); + if (r < 0) + return r; + } else + k = 0; + break; + default: + assert_not_reached("Invalid prefixlen mode"); + } if (ret_family) *ret_family = family; diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index 5de85cc422..3069790519 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -45,19 +45,17 @@ int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mas int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen); int in_addr_prefix_covers(int family, const union in_addr_union *prefix, unsigned char prefixlen, const union in_addr_union *address); int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret); -int in_addr_prefix_from_string_internal(const char *p, bool use_default_prefixlen, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen); -int in_addr_prefix_from_string_auto_internal(const char *p, bool use_default_prefixlen, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen); -static inline int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) { - return in_addr_prefix_from_string_internal(p, false, family, ret_prefix, ret_prefixlen); -} +int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen); + +typedef enum InAddrPrefixLenMode { + PREFIXLEN_FULL, /* Default to prefixlen of address size, 32 for IPv4 or 128 for IPv6, if not specified. */ + PREFIXLEN_REFUSE, /* Fail with -ENOANO if prefixlen is not specified. */ + PREFIXLEN_LEGACY, /* Default to legacy default prefixlen calculation from address if not specified. */ +} InAddrPrefixLenMode; + +int in_addr_prefix_from_string_auto_internal(const char *p, InAddrPrefixLenMode mode, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen); static inline int in_addr_prefix_from_string_auto(const char *p, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) { - return in_addr_prefix_from_string_auto_internal(p, false, ret_family, ret_prefix, ret_prefixlen); -} -static inline int in_addr_default_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) { - return in_addr_prefix_from_string_internal(p, true, family, ret_prefix, ret_prefixlen); -} -static inline int in_addr_default_prefix_from_string_auto(const char *p, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) { - return in_addr_prefix_from_string_auto_internal(p, true, ret_family, ret_prefix, ret_prefixlen); + return in_addr_prefix_from_string_auto_internal(p, PREFIXLEN_FULL, ret_family, ret_prefix, ret_prefixlen); } static inline size_t FAMILY_ADDRESS_SIZE(int family) { diff --git a/src/basic/io-util.c b/src/basic/io-util.c index 1f64cc933b..575398fbe6 100644 --- a/src/basic/io-util.c +++ b/src/basic/io-util.c @@ -8,6 +8,7 @@ #include <unistd.h> #include "io-util.h" +#include "string-util.h" #include "time-util.h" int flush_fd(int fd) { @@ -252,3 +253,12 @@ ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) { return q - (const uint8_t*) p; } + +char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value) { + char *x; + + x = strappend(field, value); + if (x) + iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(x); + return x; +} diff --git a/src/basic/io-util.h b/src/basic/io-util.h index ed189b5820..792a64ad5e 100644 --- a/src/basic/io-util.h +++ b/src/basic/io-util.h @@ -71,3 +71,5 @@ static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) { #define IOVEC_MAKE(base, len) (struct iovec) IOVEC_INIT(base, len) #define IOVEC_INIT_STRING(string) IOVEC_INIT((char*) string, strlen(string)) #define IOVEC_MAKE_STRING(string) (struct iovec) IOVEC_INIT_STRING(string) + +char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value); diff --git a/src/basic/meson.build b/src/basic/meson.build index 23b5e75bd8..e5852f32f9 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -292,7 +292,8 @@ libbasic = static_library( 'basic', basic_sources, include_directories : includes, - dependencies : [threads, + dependencies : [versiondep, + threads, libcap, libselinux, libm], diff --git a/src/basic/missing_if_link.h b/src/basic/missing_if_link.h index 07675426bb..761797f56a 100644 --- a/src/basic/missing_if_link.h +++ b/src/basic/missing_if_link.h @@ -110,6 +110,9 @@ enum ipvlan_mode { #define IFLA_MAX 51 #endif +#if !HAVE_IFLA_BOND_MODE /* linux@90af231106c0b8d223c27d35464af95cb3d9cacf (3.13) */ +#define IFLA_BOND_MODE 1 +#endif #if !HAVE_IFLA_BOND_ACTIVE_SLAVE /* linux@ec76aa49855f6d6fea5e01de179fb57dd47c619d (3.13) */ #define IFLA_BOND_ACTIVE_SLAVE 2 #endif diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h index d5d4b26acb..d1aa32218b 100644 --- a/src/basic/missing_syscall.h +++ b/src/basic/missing_syscall.h @@ -3,6 +3,7 @@ /* Missing glibc definitions to access certain kernel APIs */ +#include <errno.h> #include <fcntl.h> #include <sys/syscall.h> #include <sys/types.h> diff --git a/src/basic/path-util.h b/src/basic/path-util.h index 094aa47c01..86c5a577cb 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -131,7 +131,7 @@ char *prefix_root(const char *root, const char *path); _ret = _path; \ else { \ _l = strlen(_root) + 1 + strlen(_path) + 1; \ - _n = alloca(_l); \ + _n = newa(char, _l); \ _p = stpcpy(_n, _root); \ while (_p > _n && _p[-1] == '/') \ _p--; \ diff --git a/src/basic/prioq.c b/src/basic/prioq.c index cfd08d5d23..76b27fa0a8 100644 --- a/src/basic/prioq.c +++ b/src/basic/prioq.c @@ -259,15 +259,14 @@ int prioq_reshuffle(Prioq *q, void *data, unsigned *idx) { return 1; } -void *prioq_peek(Prioq *q) { - +void *prioq_peek_by_index(Prioq *q, unsigned idx) { if (!q) return NULL; - if (q->n_items <= 0) + if (idx >= q->n_items) return NULL; - return q->items[0].data; + return q->items[idx].data; } void *prioq_pop(Prioq *q) { diff --git a/src/basic/prioq.h b/src/basic/prioq.h index bba5c7caa4..1fb57bfa4c 100644 --- a/src/basic/prioq.h +++ b/src/basic/prioq.h @@ -19,8 +19,14 @@ int prioq_put(Prioq *q, void *data, unsigned *idx); int prioq_remove(Prioq *q, void *data, unsigned *idx); int prioq_reshuffle(Prioq *q, void *data, unsigned *idx); -void *prioq_peek(Prioq *q) _pure_; +void *prioq_peek_by_index(Prioq *q, unsigned idx) _pure_; +static inline void *prioq_peek(Prioq *q) { + return prioq_peek_by_index(q, 0); +} void *prioq_pop(Prioq *q); +#define PRIOQ_FOREACH_ITEM(q, p) \ + for (unsigned _i = 0; (p = prioq_peek_by_index(q, _i)); _i++) + unsigned prioq_size(Prioq *q) _pure_; bool prioq_isempty(Prioq *q) _pure_; diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 448503409b..78ce43b944 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -102,7 +102,8 @@ int get_process_comm(pid_t pid, char **ret) { int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) { _cleanup_fclose_ FILE *f = NULL; bool space = false; - char *k, *ans = NULL; + char *k; + _cleanup_free_ char *ans = NULL; const char *p; int c; @@ -129,6 +130,13 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + if (max_length == 0) { + /* This is supposed to be a safety guard against runaway command lines. */ + long l = sysconf(_SC_ARG_MAX); + assert(l > 0); + max_length = l; + } + if (max_length == 1) { /* If there's only room for one byte, return the empty string */ @@ -136,35 +144,9 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * if (!ans) return -ENOMEM; - *line = ans; + *line = TAKE_PTR(ans); return 0; - } else if (max_length == 0) { - size_t len = 0, allocated = 0; - - while ((c = getc(f)) != EOF) { - - if (!GREEDY_REALLOC(ans, allocated, len+3)) { - free(ans); - return -ENOMEM; - } - - if (isprint(c)) { - if (space) { - ans[len++] = ' '; - space = false; - } - - ans[len++] = c; - } else if (len > 0) - space = true; - } - - if (len > 0) - ans[len] = '\0'; - else - ans = mfree(ans); - } else { bool dotdotdot = false; size_t left; @@ -227,7 +209,7 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * _cleanup_free_ char *t = NULL; int h; - free(ans); + ans = mfree(ans); if (!comm_fallback) return -ENOENT; @@ -236,37 +218,42 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * if (h < 0) return h; - if (max_length == 0) - ans = strjoin("[", t, "]"); - else { - size_t l; - - l = strlen(t); + size_t l = strlen(t); - if (l + 3 <= max_length) - ans = strjoin("[", t, "]"); - else if (max_length <= 6) { + if (l + 3 <= max_length) { + ans = strjoin("[", t, "]"); + if (!ans) + return -ENOMEM; - ans = new(char, max_length); - if (!ans) - return -ENOMEM; + } else if (max_length <= 6) { + ans = new(char, max_length); + if (!ans) + return -ENOMEM; - memcpy(ans, "[...]", max_length-1); - ans[max_length-1] = 0; - } else { - t[max_length - 6] = 0; + memcpy(ans, "[...]", max_length-1); + ans[max_length-1] = 0; + } else { + t[max_length - 6] = 0; - /* Chop off final spaces */ - delete_trailing_chars(t, WHITESPACE); + /* Chop off final spaces */ + delete_trailing_chars(t, WHITESPACE); - ans = strjoin("[", t, "...]"); - } + ans = strjoin("[", t, "...]"); + if (!ans) + return -ENOMEM; } - if (!ans) - return -ENOMEM; + + *line = TAKE_PTR(ans); + return 0; } - *line = ans; + k = realloc(ans, strlen(ans) + 1); + if (!k) + return -ENOMEM; + + ans = NULL; + *line = k; + return 0; } diff --git a/src/basic/process-util.h b/src/basic/process-util.h index 496e14d3de..c85ea30ecc 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -24,8 +24,8 @@ if (_pid_ == 0) { \ _r_ = ("/proc/self/" field); \ } else { \ - _r_ = alloca(STRLEN("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \ - sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \ + _r_ = newa(char, STRLEN("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \ + sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \ } \ _r_; \ }) diff --git a/src/basic/procfs-util.c b/src/basic/procfs-util.c index a159e344b3..7aaf95bfce 100644 --- a/src/basic/procfs-util.c +++ b/src/basic/procfs-util.c @@ -201,13 +201,11 @@ int procfs_cpu_get_usage(nsec_t *ret) { return 0; } -int procfs_memory_get_current(uint64_t *ret) { +int procfs_memory_get(uint64_t *ret_total, uint64_t *ret_used) { uint64_t mem_total = UINT64_MAX, mem_free = UINT64_MAX; _cleanup_fclose_ FILE *f = NULL; int r; - assert(ret); - f = fopen("/proc/meminfo", "re"); if (!f) return -errno; @@ -262,6 +260,9 @@ int procfs_memory_get_current(uint64_t *ret) { if (mem_free > mem_total) return -EINVAL; - *ret = (mem_total - mem_free) * 1024U; + if (ret_total) + *ret_total = mem_total * 1024U; + if (ret_used) + *ret_used = (mem_total - mem_free) * 1024U; return 0; } diff --git a/src/basic/procfs-util.h b/src/basic/procfs-util.h index f697ed92bc..5a44e9eff7 100644 --- a/src/basic/procfs-util.h +++ b/src/basic/procfs-util.h @@ -11,4 +11,7 @@ int procfs_tasks_get_current(uint64_t *ret); int procfs_cpu_get_usage(nsec_t *ret); -int procfs_memory_get_current(uint64_t *ret); +int procfs_memory_get(uint64_t *ret_total, uint64_t *ret_used); +static inline int procfs_memory_get_used(uint64_t *ret) { + return procfs_memory_get(NULL, ret); +} diff --git a/src/basic/siphash24.c b/src/basic/siphash24.c index 30c228a78a..61180819b1 100644 --- a/src/basic/siphash24.c +++ b/src/basic/siphash24.c @@ -23,13 +23,13 @@ #include "siphash24.h" #include "unaligned.h" -static inline uint64_t rotate_left(uint64_t x, uint8_t b) { +static uint64_t rotate_left(uint64_t x, uint8_t b) { assert(b < 64); return (x << b) | (x >> (64 - b)); } -static inline void sipround(struct siphash *state) { +static void sipround(struct siphash *state) { assert(state); state->v0 += state->v1; @@ -48,7 +48,7 @@ static inline void sipround(struct siphash *state) { state->v2 = rotate_left(state->v2, 32); } -void siphash24_init(struct siphash *state, const uint8_t k[16]) { +void siphash24_init(struct siphash *state, const uint8_t k[static 16]) { uint64_t k0, k1; assert(state); @@ -187,7 +187,7 @@ uint64_t siphash24_finalize(struct siphash *state) { return state->v0 ^ state->v1 ^ state->v2 ^ state->v3; } -uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]) { +uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[static 16]) { struct siphash state; assert(in); diff --git a/src/basic/siphash24.h b/src/basic/siphash24.h index 70a4a03f6a..67c4f7560c 100644 --- a/src/basic/siphash24.h +++ b/src/basic/siphash24.h @@ -15,14 +15,14 @@ struct siphash { size_t inlen; }; -void siphash24_init(struct siphash *state, const uint8_t k[16]); +void siphash24_init(struct siphash *state, const uint8_t k[static 16]); void siphash24_compress(const void *in, size_t inlen, struct siphash *state); #define siphash24_compress_byte(byte, state) siphash24_compress((const uint8_t[]) { (byte) }, 1, (state)) uint64_t siphash24_finalize(struct siphash *state); -uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]); +uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[static 16]); -static inline uint64_t siphash24_string(const char *s, const uint8_t k[16]) { +static inline uint64_t siphash24_string(const char *s, const uint8_t k[static 16]) { return siphash24(s, strlen(s) + 1, k); } diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index 57700e2388..ea2bbc368b 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -67,13 +67,22 @@ int is_device_node(const char *path) { return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode)); } -int dir_is_empty(const char *path) { - _cleanup_closedir_ DIR *d; +int dir_is_empty_at(int dir_fd, const char *path) { + _cleanup_close_ int fd = -1; + _cleanup_closedir_ DIR *d = NULL; struct dirent *de; - d = opendir(path); + if (path) + fd = openat(dir_fd, path, O_RDONLY|O_DIRECTORY|O_CLOEXEC); + else + fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); + if (fd < 0) + return -errno; + + d = fdopendir(fd); if (!d) return -errno; + fd = -1; FOREACH_DIRENT(de, d, return -errno) return 0; @@ -338,7 +347,6 @@ int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret) { return -ENOMEM; return 0; - } int device_path_make_canonical(mode_t mode, dev_t devno, char **ret) { diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h index 0a08e642b5..74fb7251b3 100644 --- a/src/basic/stat-util.h +++ b/src/basic/stat-util.h @@ -15,7 +15,10 @@ int is_dir(const char *path, bool follow); int is_dir_fd(int fd); int is_device_node(const char *path); -int dir_is_empty(const char *path); +int dir_is_empty_at(int dir_fd, const char *path); +static inline int dir_is_empty(const char *path) { + return dir_is_empty_at(AT_FDCWD, path); +} static inline int dir_is_populated(const char *path) { int r; diff --git a/src/basic/string-util.c b/src/basic/string-util.c index 05469ac01f..93917bc0f0 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -742,7 +742,7 @@ char *strreplace(const char *text, const char *old_string, const char *new_strin return ret; } -static void advance_offsets(ssize_t diff, size_t offsets[2], size_t shift[2], size_t size) { +static void advance_offsets(ssize_t diff, size_t offsets[static 2], size_t shift[static 2], size_t size) { if (!offsets) return; diff --git a/src/basic/string-util.h b/src/basic/string-util.h index a5b5a16a5d..38070abb22 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -6,6 +6,7 @@ #include <stddef.h> #include <string.h> +#include "alloc-util.h" #include "macro.h" /* What is interpreted as whitespace? */ @@ -111,7 +112,7 @@ char *strjoin_real(const char *x, ...) _sentinel_; size_t _i_; \ for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ _len_ += strlen(_appendees_[_i_]); \ - _p_ = _d_ = alloca(_len_ + 1); \ + _p_ = _d_ = newa(char, _len_ + 1); \ for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ _p_ = stpcpy(_p_, _appendees_[_i_]); \ *_p_ = 0; \ diff --git a/src/basic/strv.h b/src/basic/strv.h index aa4cd4aaca..392cab65be 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -156,17 +156,10 @@ void strv_print(char **l); _found; \ }) -#define FOREACH_STRING(x, ...) \ - for (char **_l = ({ \ - char **_ll = STRV_MAKE(__VA_ARGS__); \ - x = _ll ? _ll[0] : NULL; \ - _ll; \ - }); \ - _l && *_l; \ - x = ({ \ - _l ++; \ - _l[0]; \ - })) +#define FOREACH_STRING(x, y, ...) \ + for (char **_l = STRV_MAKE(({ x = y; }), ##__VA_ARGS__); \ + x; \ + x = *(++_l)) char **strv_reverse(char **l); char **strv_shell_escape(char **l, const char *bad); diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 557c75debc..62cdc305f9 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -24,7 +24,6 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" -#include "serialize.h" #include "stat-util.h" #include "string-util.h" #include "strv.h" diff --git a/src/basic/tmpfile-util.c b/src/basic/tmpfile-util.c index 669eb2666c..bc92d6a6de 100644 --- a/src/basic/tmpfile-util.c +++ b/src/basic/tmpfile-util.c @@ -8,6 +8,7 @@ #include "hexdecoct.h" #include "macro.h" #include "memfd-util.h" +#include "missing_fcntl.h" #include "missing_syscall.h" #include "path-util.h" #include "process-util.h" diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h index d373f03aca..0629db3f67 100644 --- a/src/basic/unit-name.h +++ b/src/basic/unit-name.h @@ -9,9 +9,9 @@ #define UNIT_NAME_MAX 256 typedef enum UnitNameFlags { - UNIT_NAME_PLAIN = 1, /* Allow foo.service */ - UNIT_NAME_INSTANCE = 2, /* Allow foo@bar.service */ - UNIT_NAME_TEMPLATE = 4, /* Allow foo@.service */ + UNIT_NAME_PLAIN = 1 << 0, /* Allow foo.service */ + UNIT_NAME_INSTANCE = 1 << 1, /* Allow foo@bar.service */ + UNIT_NAME_TEMPLATE = 1 << 2, /* Allow foo@.service */ UNIT_NAME_ANY = UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE, } UnitNameFlags; @@ -50,8 +50,8 @@ int unit_name_from_path_instance(const char *prefix, const char *path, const cha int unit_name_to_path(const char *name, char **ret); typedef enum UnitNameMangle { - UNIT_NAME_MANGLE_GLOB = 1, - UNIT_NAME_MANGLE_WARN = 2, + UNIT_NAME_MANGLE_GLOB = 1 << 0, + UNIT_NAME_MANGLE_WARN = 1 << 1, } UnitNameMangle; int unit_name_mangle_with_suffix(const char *name, UnitNameMangle flags, const char *suffix, char **ret); diff --git a/src/basic/user-util.c b/src/basic/user-util.c index d410c9068b..260f3d2057 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -87,7 +87,7 @@ char *getusername_malloc(void) { return uid_to_name(getuid()); } -static inline bool is_nologin_shell(const char *shell) { +static bool is_nologin_shell(const char *shell) { return PATH_IN_SET(shell, /* 'nologin' is the friendliest way to disable logins for a user account. It prints a nice @@ -733,10 +733,6 @@ int maybe_setgroups(size_t size, const gid_t *list) { } bool synthesize_nobody(void) { - -#ifdef NOLEGACY - return true; -#else /* Returns true when we shall synthesize the "nobody" user (which we do by default). This can be turned off by * touching /etc/systemd/dont-synthesize-nobody in order to provide upgrade compatibility with legacy systems * that used the "nobody" user name and group name for other UIDs/GIDs than 65534. @@ -750,7 +746,6 @@ bool synthesize_nobody(void) { cache = access("/etc/systemd/dont-synthesize-nobody", F_OK) < 0; return cache; -#endif } int putpwent_sane(const struct passwd *pw, FILE *stream) { diff --git a/src/basic/util.c b/src/basic/util.c index c4f12a6daa..e577c93e60 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -557,7 +557,7 @@ uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) { } int version(void) { - puts(PACKAGE_STRING "\n" + puts("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n" SYSTEMD_FEATURES); return 0; } diff --git a/src/basic/util.h b/src/basic/util.h index f009d37d4c..dc33d66067 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -174,12 +174,21 @@ static inline void *mempset(void *s, int c, size_t n) { } static inline void _reset_errno_(int *saved_errno) { + if (*saved_errno < 0) /* Invalidated by UNPROTECT_ERRNO? */ + return; + errno = *saved_errno; } #define PROTECT_ERRNO \ _cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno +#define UNPROTECT_ERRNO \ + do { \ + errno = _saved_errno_; \ + _saved_errno_ = -1; \ + } while (false) + static inline int negative_errno(void) { /* This helper should be used to shut up gcc if you know 'errno' is * negative. Instead of "return -errno;", use "return negative_errno();" diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 4719eeaf4b..9bf6895831 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -17,7 +17,7 @@ #endif /* magic string to find in the binary image */ -static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-boot " PACKAGE_VERSION " ####"; +static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-boot " GIT_VERSION " ####"; static const EFI_GUID global_guid = EFI_GLOBAL_VARIABLE; @@ -361,7 +361,7 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) { uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK); uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); - Print(L"systemd-boot version: " PACKAGE_VERSION "\n"); + Print(L"systemd-boot version: " GIT_VERSION "\n"); Print(L"architecture: " EFI_MACHINE_TYPE_NAME "\n"); Print(L"loaded image: %s\n", loaded_image_path); Print(L"UEFI specification: %d.%02d\n", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); @@ -804,7 +804,7 @@ static BOOLEAN menu_run( break; case KEYPRESS(0, 0, 'v'): - status = PoolPrint(L"systemd-boot " PACKAGE_VERSION " (" EFI_MACHINE_TYPE_NAME "), UEFI Specification %d.%02d, Vendor %s %d.%02d", + status = PoolPrint(L"systemd-boot " GIT_VERSION " (" EFI_MACHINE_TYPE_NAME "), UEFI Specification %d.%02d, Vendor %s %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff, ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); break; @@ -1000,7 +1000,7 @@ skip: value++; /* unquote */ - if (value[0] == '\"' && line[linelen-1] == '\"') { + if (value[0] == '"' && line[linelen-1] == '"') { value++; line[linelen-1] = '\0'; } @@ -2097,7 +2097,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { InitializeLib(image, sys_table); init_usec = time_usec(); efivar_set_time_usec(L"LoaderTimeInitUSec", init_usec); - efivar_set(L"LoaderInfo", L"systemd-boot " PACKAGE_VERSION, FALSE); + efivar_set(L"LoaderInfo", L"systemd-boot " GIT_VERSION, FALSE); infostr = PoolPrint(L"%s %d.%02d", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); efivar_set(L"LoaderFirmwareInfo", infostr, FALSE); diff --git a/src/boot/efi/disk.c b/src/boot/efi/disk.c index a31b7bb478..49ee81b4d7 100644 --- a/src/boot/efi/disk.c +++ b/src/boot/efi/disk.c @@ -5,7 +5,7 @@ #include "util.h" -EFI_STATUS disk_get_part_uuid(EFI_HANDLE *handle, CHAR16 uuid[37]) { +EFI_STATUS disk_get_part_uuid(EFI_HANDLE *handle, CHAR16 uuid[static 37]) { EFI_DEVICE_PATH *device_path; /* export the device path this image is started from */ diff --git a/src/boot/efi/disk.h b/src/boot/efi/disk.h index 2a0b8ff2a7..41c4cce434 100644 --- a/src/boot/efi/disk.h +++ b/src/boot/efi/disk.h @@ -1,4 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -EFI_STATUS disk_get_part_uuid(EFI_HANDLE *handle, CHAR16 uuid[37]); +EFI_STATUS disk_get_part_uuid(EFI_HANDLE *handle, CHAR16 uuid[static 37]); diff --git a/src/boot/efi/linux.c b/src/boot/efi/linux.c index d1605523d8..5b4c085880 100644 --- a/src/boot/efi/linux.c +++ b/src/boot/efi/linux.c @@ -52,7 +52,7 @@ struct SetupHeader { #ifdef __x86_64__ typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct SetupHeader *setup); -static inline VOID linux_efi_handover(EFI_HANDLE image, struct SetupHeader *setup) { +static VOID linux_efi_handover(EFI_HANDLE image, struct SetupHeader *setup) { handover_f handover; asm volatile ("cli"); @@ -61,7 +61,7 @@ static inline VOID linux_efi_handover(EFI_HANDLE image, struct SetupHeader *setu } #else typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct SetupHeader *setup) __attribute__((regparm(0))); -static inline VOID linux_efi_handover(EFI_HANDLE image, struct SetupHeader *setup) { +static VOID linux_efi_handover(EFI_HANDLE image, struct SetupHeader *setup) { handover_f handover; handover = (handover_f)((UINTN)setup->code32_start + setup->handover_offset); diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build index aa897c62a1..2140151844 100644 --- a/src/boot/efi/meson.build +++ b/src/boot/efi/meson.build @@ -78,7 +78,6 @@ endif if have_gnu_efi efi_conf = configuration_data() - efi_conf.set_quoted('PACKAGE_VERSION', meson.project_version()) efi_conf.set_quoted('EFI_MACHINE_TYPE_NAME', EFI_MACHINE_TYPE_NAME) efi_conf.set10('ENABLE_TPM', get_option('tpm')) efi_conf.set('SD_TPM_PCR', get_option('tpm-pcrindex')) @@ -117,7 +116,8 @@ if have_gnu_efi '-Wno-missing-field-initializers', '-isystem', efi_incdir, '-isystem', join_paths(efi_incdir, gnu_efi_path_arch), - '-include', efi_config_h] + '-include', efi_config_h, + '-include', version_h] if efi_arch == 'x86_64' compile_args += ['-mno-red-zone', '-mno-sse', @@ -194,9 +194,7 @@ if have_gnu_efi '-j', '.data', '-j', '.dynamic', '-j', '.dynsym', - '-j', '.rel', - '-j', '.rela', - '-j', '.reloc'] + '-j', '.rel*'] + efi_format + ['@INPUT@', '@OUTPUT@'], install : true, diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c index d11e555748..6b07879971 100644 --- a/src/boot/efi/stub.c +++ b/src/boot/efi/stub.c @@ -12,7 +12,7 @@ #include "util.h" /* magic string to find in the binary image */ -static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-stub " PACKAGE_VERSION " ####"; +static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-stub " GIT_VERSION " ####"; static const EFI_GUID global_guid = EFI_GLOBAL_VARIABLE; @@ -117,7 +117,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { /* add StubInfo */ if (efivar_get_raw(&global_guid, L"StubInfo", &b, &size) != EFI_SUCCESS) - efivar_set(L"StubInfo", L"systemd-stub " PACKAGE_VERSION, FALSE); + efivar_set(L"StubInfo", L"systemd-stub " GIT_VERSION, FALSE); if (szs[3] > 0) graphics_splash((UINT8 *)((UINTN)loaded_image->ImageBase + addrs[3]), szs[3], NULL); diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c index 96b4177495..08d9e70c96 100644 --- a/src/busctl/busctl.c +++ b/src/busctl/busctl.c @@ -67,7 +67,7 @@ static int json_transform_message(sd_bus_message *m, JsonVariant **ret); static void json_dump_with_flags(JsonVariant *v, FILE *f); static int acquire_bus(bool set_monitor, sd_bus **ret) { - _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL; int r; r = sd_bus_new(&bus); diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index 5abfab03de..b3bda30cec 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -104,7 +104,7 @@ static const char *maybe_format_bytes(char *buf, size_t l, bool is_valid, uint64 static bool is_root_cgroup(const char *path) { - /* Returns true if the specified path belongs to the root cgroup. The root cgroup is special on cgroupsv2 as it + /* Returns true if the specified path belongs to the root cgroup. The root cgroup is special on cgroup v2 as it * carries only very few attributes in order not to export multiple truth about system state as most * information is available elsewhere in /proc anyway. We need to be able to deal with that, and need to get * our data from different sources in that case. @@ -291,7 +291,7 @@ static int process( } else if (streq(controller, "memory")) { if (is_root_cgroup(path)) { - r = procfs_memory_get_current(&g->memory); + r = procfs_memory_get_used(&g->memory); if (r < 0) return r; } else { diff --git a/src/core/automount.c b/src/core/automount.c index de8010bf2e..6a8373920e 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -48,7 +48,7 @@ struct expire_data { int ioctl_fd; }; -static inline void expire_data_free(struct expire_data *data) { +static void expire_data_free(struct expire_data *data) { if (!data) return; @@ -578,10 +578,13 @@ static void automount_enter_waiting(Automount *a) { goto fail; } - if (pipe2(p, O_NONBLOCK|O_CLOEXEC) < 0) { + if (pipe2(p, O_CLOEXEC) < 0) { r = -errno; goto fail; } + r = fd_nonblock(p[0], true); + if (r < 0) + goto fail; xsprintf(options, "fd=%i,pgrp="PID_FMT",minproto=5,maxproto=5,direct", p[1], getpgrp()); xsprintf(name, "systemd-"PID_FMT, getpid_cached()); diff --git a/src/core/bpf-devices.c b/src/core/bpf-devices.c index dade7f0490..81e91fcb36 100644 --- a/src/core/bpf-devices.c +++ b/src/core/bpf-devices.c @@ -202,7 +202,6 @@ int cgroup_apply_device_bpf(Unit *u, BPFProgram *prog, CGroupDevicePolicy policy if (r < 0) return log_error_errno(r, "Failed to determine cgroup path: %m"); - r = bpf_program_cgroup_attach(prog, BPF_CGROUP_DEVICE, path, BPF_F_ALLOW_MULTI); if (r < 0) return log_error_errno(r, "Attaching device control BPF program to cgroup %s failed: %m", path); diff --git a/src/core/cgroup.c b/src/core/cgroup.c index a7ce3fceaa..18d470b6d6 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -396,26 +396,31 @@ static void cgroup_xattr_apply(Unit *u) { } static int lookup_block_device(const char *p, dev_t *ret) { - struct stat st = {}; + dev_t rdev, dev = 0; + mode_t mode; int r; assert(p); assert(ret); - r = device_path_parse_major_minor(p, &st.st_mode, &st.st_rdev); + r = device_path_parse_major_minor(p, &mode, &rdev); if (r == -ENODEV) { /* not a parsable device node, need to go to disk */ + struct stat st; if (stat(p, &st) < 0) return log_warning_errno(errno, "Couldn't stat device '%s': %m", p); + rdev = (dev_t)st.st_rdev; + dev = (dev_t)st.st_dev; + mode = st.st_mode; } else if (r < 0) return log_warning_errno(r, "Failed to parse major/minor from path '%s': %m", p); - if (S_ISCHR(st.st_mode)) { + if (S_ISCHR(mode)) { log_warning("Device node '%s' is a character device, but block device needed.", p); return -ENOTBLK; - } else if (S_ISBLK(st.st_mode)) - *ret = st.st_rdev; - else if (major(st.st_dev) != 0) - *ret = st.st_dev; /* If this is not a device node then use the block device this file is stored on */ + } else if (S_ISBLK(mode)) + *ret = rdev; + else if (major(dev) != 0) + *ret = dev; /* If this is not a device node then use the block device this file is stored on */ else { /* If this is btrfs, getting the backing block device is a bit harder */ r = btrfs_get_block_device(p, ret); @@ -436,7 +441,8 @@ static int lookup_block_device(const char *p, dev_t *ret) { } static int whitelist_device(BPFProgram *prog, const char *path, const char *node, const char *acc) { - struct stat st = {}; + dev_t rdev; + mode_t mode; int r; assert(path); @@ -445,11 +451,12 @@ static int whitelist_device(BPFProgram *prog, const char *path, const char *node /* Some special handling for /dev/block/%u:%u, /dev/char/%u:%u, /run/systemd/inaccessible/chr and * /run/systemd/inaccessible/blk paths. Instead of stat()ing these we parse out the major/minor directly. This * means clients can use these path without the device node actually around */ - r = device_path_parse_major_minor(node, &st.st_mode, &st.st_rdev); + r = device_path_parse_major_minor(node, &mode, &rdev); if (r < 0) { if (r != -ENODEV) return log_warning_errno(r, "Couldn't parse major/minor from device path '%s': %m", node); + struct stat st; if (stat(node, &st) < 0) return log_warning_errno(errno, "Couldn't stat device %s: %m", node); @@ -457,22 +464,24 @@ static int whitelist_device(BPFProgram *prog, const char *path, const char *node log_warning("%s is not a device.", node); return -ENODEV; } + rdev = (dev_t) st.st_rdev; + mode = st.st_mode; } if (cg_all_unified() > 0) { if (!prog) return 0; - return cgroup_bpf_whitelist_device(prog, S_ISCHR(st.st_mode) ? BPF_DEVCG_DEV_CHAR : BPF_DEVCG_DEV_BLOCK, - major(st.st_rdev), minor(st.st_rdev), acc); + return cgroup_bpf_whitelist_device(prog, S_ISCHR(mode) ? BPF_DEVCG_DEV_CHAR : BPF_DEVCG_DEV_BLOCK, + major(rdev), minor(rdev), acc); } else { char buf[2+DECIMAL_STR_MAX(dev_t)*2+2+4]; sprintf(buf, "%c %u:%u %s", - S_ISCHR(st.st_mode) ? 'c' : 'b', - major(st.st_rdev), minor(st.st_rdev), + S_ISCHR(mode) ? 'c' : 'b', + major(rdev), minor(rdev), acc); /* Changing the devices list of a populated cgroup might result in EINVAL, hence ignore EINVAL here. */ @@ -881,7 +890,7 @@ static void cgroup_context_apply( /* In fully unified mode these attributes don't exist on the host cgroup root. On legacy the weights exist, but * setting the weight makes very little sense on the host root cgroup, as there are no other cgroups at this * level. The quota exists there too, but any attempt to write to it is refused with EINVAL. Inside of - * containers we want to leave control of these to the container manager (and if cgroupsv2 delegation is used + * containers we want to leave control of these to the container manager (and if cgroup v2 delegation is used * we couldn't even write to them if we wanted to). */ if ((apply_mask & CGROUP_MASK_CPU) && !is_local_root) { @@ -925,7 +934,7 @@ static void cgroup_context_apply( } } - /* The 'io' controller attributes are not exported on the host's root cgroup (being a pure cgroupsv2 + /* The 'io' controller attributes are not exported on the host's root cgroup (being a pure cgroup v2 * controller), and in case of containers we want to leave control of these attributes to the container manager * (and we couldn't access that stuff anyway, even if we tried if proper delegation is used). */ if ((apply_mask & CGROUP_MASK_IO) && !is_local_root) { @@ -1067,7 +1076,7 @@ static void cgroup_context_apply( /* In unified mode 'memory' attributes do not exist on the root cgroup. In legacy mode 'memory.limit_in_bytes' * exists on the root cgroup, but any writes to it are refused with EINVAL. And if we run in a container we - * want to leave control to the container manager (and if proper cgroupsv2 delegation is used we couldn't even + * want to leave control to the container manager (and if proper cgroup v2 delegation is used we couldn't even * write to this if we wanted to.) */ if ((apply_mask & CGROUP_MASK_MEMORY) && !is_local_root) { @@ -1109,7 +1118,7 @@ static void cgroup_context_apply( } } - /* On cgroupsv2 we can apply BPF everywhere. On cgroupsv1 we apply it everywhere except for the root of + /* On cgroup v2 we can apply BPF everywhere. On cgroup v1 we apply it everywhere except for the root of * containers, where we leave this to the manager */ if ((apply_mask & (CGROUP_MASK_DEVICES | CGROUP_MASK_BPF_DEVICES)) && (is_host_root || cg_all_unified() > 0 || !is_local_root)) { @@ -1841,14 +1850,14 @@ static bool unit_has_mask_realized( /* Returns true if this unit is fully realized. We check four things: * * 1. Whether the cgroup was created at all - * 2. Whether the cgroup was created in all the hierarchies we need it to be created in (in case of cgroupsv1) - * 3. Whether the cgroup has all the right controllers enabled (in case of cgroupsv2) + * 2. Whether the cgroup was created in all the hierarchies we need it to be created in (in case of cgroup v1) + * 3. Whether the cgroup has all the right controllers enabled (in case of cgroup v2) * 4. Whether the invalidation mask is currently zero * * If you wonder why we mask the target realization and enable mask with CGROUP_MASK_V1/CGROUP_MASK_V2: note - * that there are three sets of bitmasks: CGROUP_MASK_V1 (for real cgroupv1 controllers), CGROUP_MASK_V2 (for - * real cgroupv2 controllers) and CGROUP_MASK_BPF (for BPF-based pseudo-controllers). Now, cgroup_realized_mask - * is only matters for cgroupsv1 controllers, and cgroup_enabled_mask only used for cgroupsv2, and if they + * that there are three sets of bitmasks: CGROUP_MASK_V1 (for real cgroup v1 controllers), CGROUP_MASK_V2 (for + * real cgroup v2 controllers) and CGROUP_MASK_BPF (for BPF-based pseudo-controllers). Now, cgroup_realized_mask + * is only matters for cgroup v1 controllers, and cgroup_enabled_mask only used for cgroup v2, and if they * differ in the others, we don't really care. (After all, the cgroup_enabled_mask tracks with controllers are * enabled through cgroup.subtree_control, and since the BPF pseudo-controllers don't show up there, they * simply don't matter. */ @@ -2771,7 +2780,7 @@ int unit_get_memory_current(Unit *u, uint64_t *ret) { /* The root cgroup doesn't expose this information, let's get it from /proc instead */ if (unit_has_host_root_cgroup(u)) - return procfs_memory_get_current(ret); + return procfs_memory_get_used(ret); if ((u->cgroup_realized_mask & CGROUP_MASK_MEMORY) == 0) return -ENODATA; diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 8da07adfe7..88e4c6bb95 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -43,7 +43,7 @@ static UnitFileFlags unit_file_bools_to_flags(bool runtime, bool force) { (force ? UNIT_FILE_FORCE : 0); } -static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_version, "s", PACKAGE_VERSION); +static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_version, "s", GIT_VERSION); static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_features, "s", SYSTEMD_FEATURES); static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_architecture, "s", architecture_to_string(uname_architecture())); static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_log_target, "s", log_target_to_string(log_get_target())); diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index ec61ea2772..0904cc09c0 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -320,29 +320,35 @@ static int bus_service_set_transient_property( if (r < 0) return r; - n = path_make_absolute(v, u->manager->prefix[EXEC_DIRECTORY_RUNTIME]); - if (!n) - return -ENOMEM; + if (!isempty(v)) { + n = path_make_absolute(v, u->manager->prefix[EXEC_DIRECTORY_RUNTIME]); + if (!n) + return -ENOMEM; - path_simplify(n, true); + path_simplify(n, true); - if (!path_is_normalized(n)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PIDFile= path '%s' is not valid", n); + if (!path_is_normalized(n)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PIDFile= path '%s' is not valid", n); - e = path_startswith(n, "/var/run/"); - if (e) { - char *z; + e = path_startswith(n, "/var/run/"); + if (e) { + char *z; - z = strjoin("/run/", e); - if (!z) - return log_oom(); + z = strjoin("/run/", e); + if (!z) + return log_oom(); - if (!UNIT_WRITE_FLAGS_NOOP(flags)) - log_unit_notice(u, "Transient unit's PIDFile= property references path below legacy directory /var/run, updating %s → %s; please update client accordingly.", n, z); + if (!UNIT_WRITE_FLAGS_NOOP(flags)) + log_unit_notice(u, "Transient unit's PIDFile= property references path below legacy directory /var/run, updating %s → %s; please update client accordingly.", n, z); - free_and_replace(s->pid_file, z); - } else + free_and_replace(n, z); + } + } + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { free_and_replace(s->pid_file, n); + unit_write_settingf(u, flags, name, "%s=%s", name, strempty(s->pid_file)); + } return 1; } diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 37cf9d204c..83ac7ad110 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -134,11 +134,11 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_VTABLE_END }; -static inline bool check_size_t_truncation(uint64_t t) { +static bool check_size_t_truncation(uint64_t t) { return (size_t) t == t; } -static inline const char* socket_protocol_to_string(int32_t i) { +static const char* socket_protocol_to_string(int32_t i) { if (i == IPPROTO_IP) return ""; diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 968166ee60..17c2003c8f 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -1385,9 +1385,9 @@ static int bus_set_transient_emergency_action( system = MANAGER_IS_SYSTEM(u->manager); r = parse_emergency_action(s, system, &v); - if (v < 0) + if (r < 0) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, - v == -EOPNOTSUPP ? "EmergencyAction setting invalid for manager type: %s" + r == -EOPNOTSUPP ? "%s setting invalid for manager type: %s" : "Invalid %s setting: %s", name, s); diff --git a/src/core/dbus.c b/src/core/dbus.c index 5908ad792a..255b86e7a4 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -611,7 +611,7 @@ static int bus_setup_disconnected_match(Manager *m, sd_bus *bus) { } static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL; _cleanup_close_ int nfd = -1; Manager *m = userdata; sd_id128_t id; @@ -876,7 +876,7 @@ static int bus_setup_api(Manager *m, sd_bus *bus) { } int bus_init_api(Manager *m) { - _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL; int r; if (m->api_bus) @@ -940,7 +940,7 @@ static int bus_setup_system(Manager *m, sd_bus *bus) { } int bus_init_system(Manager *m) { - _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL; int r; if (m->system_bus) @@ -1080,8 +1080,7 @@ static void destroy_bus(Manager *m, sd_bus **bus) { sd_bus_flush(*bus); /* And destroy the object */ - sd_bus_close(*bus); - *bus = sd_bus_unref(*bus); + *bus = sd_bus_close_unref(*bus); } void bus_done_api(Manager *m) { diff --git a/src/core/device.c b/src/core/device.c index 960f403718..b006add405 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -631,7 +631,7 @@ static int device_process_new(Manager *m, sd_device *dev) { if (r == -ENOMEM) return log_oom(); if (r < 0) - return log_device_warning_errno(dev, r, "Failed to add parse SYSTEMD_ALIAS property: %m"); + return log_device_warning_errno(dev, r, "Failed to parse SYSTEMD_ALIAS property: %m"); if (!path_is_absolute(word)) log_device_warning(dev, "SYSTEMD_ALIAS is not an absolute path, ignoring: %s", word); diff --git a/src/core/dynamic-user.c b/src/core/dynamic-user.c index 089461a18a..530df70b80 100644 --- a/src/core/dynamic-user.c +++ b/src/core/dynamic-user.c @@ -35,7 +35,7 @@ static DynamicUser* dynamic_user_free(DynamicUser *d) { return mfree(d); } -static int dynamic_user_add(Manager *m, const char *name, int storage_socket[2], DynamicUser **ret) { +static int dynamic_user_add(Manager *m, const char *name, int storage_socket[static 2], DynamicUser **ret) { DynamicUser *d; int r; diff --git a/src/core/execute.c b/src/core/execute.c index 595a3c6eca..a7082310ba 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1595,7 +1595,7 @@ static int apply_lock_personality(const Unit* u, const ExecContext *c) { #endif -static void do_idle_pipe_dance(int idle_pipe[4]) { +static void do_idle_pipe_dance(int idle_pipe[static 4]) { assert(idle_pipe); idle_pipe[1] = safe_close(idle_pipe[1]); @@ -2160,8 +2160,21 @@ static int setup_exec_directory( r = mkdir_label(p, context->directories[type].mode); if (r < 0 && r != -EEXIST) goto fail; - if (r == -EEXIST && !context->dynamic_user) - continue; + if (r == -EEXIST) { + struct stat st; + + if (stat(p, &st) < 0) { + r = -errno; + goto fail; + } + if (((st.st_mode ^ context->directories[type].mode) & 07777) != 0) + log_warning("%s \'%s\' already exists but the mode is different. " + "(filesystem: %o %sMode: %o)", + exec_directory_type_to_string(type), *rt, + st.st_mode & 07777, exec_directory_type_to_string(type), context->directories[type].mode & 07777); + if (!context->dynamic_user) + continue; + } } /* Don't change the owner of the configuration directory, as in the common case it is not written to by @@ -2618,7 +2631,7 @@ out: return r; } -static void append_socket_pair(int *array, size_t *n, const int pair[2]) { +static void append_socket_pair(int *array, size_t *n, const int pair[static 2]) { assert(array); assert(n); @@ -3137,9 +3150,9 @@ static int exec_child( } } - /* If delegation is enabled we'll pass ownership of the cgroup to the user of the new process. On cgroupsv1 + /* If delegation is enabled we'll pass ownership of the cgroup to the user of the new process. On cgroup v1 * this is only about systemd's own hierarchy, i.e. not the controller hierarchies, simply because that's not - * safe. On cgroupsv2 there's only one hierarchy anyway, and delegation is safe there, hence in that case only + * safe. On cgroup v2 there's only one hierarchy anyway, and delegation is safe there, hence in that case only * touch a single hierarchy too. */ if (params->cgroup_path && context->user && (params->flags & EXEC_CGROUP_DELEGATE)) { r = cg_set_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, uid, gid); @@ -3226,7 +3239,24 @@ static int exec_child( #endif } + if (needs_sandboxing) { + int which_failed; + + /* Let's set the resource limits before we call into PAM, so that pam_limits wins over what + * is set here. (See below.) */ + + r = setrlimit_closest_all((const struct rlimit* const *) context->rlimit, &which_failed); + if (r < 0) { + *exit_status = EXIT_LIMITS; + return log_unit_error_errno(unit, r, "Failed to adjust resource limit RLIMIT_%s: %m", rlimit_to_string(which_failed)); + } + } + if (needs_setuid) { + + /* Let's call into PAM after we set up our own idea of resource limits to that pam_limits + * wins here. (See above.) */ + if (context->pam_name && username) { r = setup_pam(context->pam_name, username, uid, gid, context->tty_path, &accum_env, fds, n_fds); if (r < 0) { @@ -3343,15 +3373,10 @@ static int exec_child( if (needs_sandboxing) { uint64_t bset; - int which_failed; - - r = setrlimit_closest_all((const struct rlimit* const *) context->rlimit, &which_failed); - if (r < 0) { - *exit_status = EXIT_LIMITS; - return log_unit_error_errno(unit, r, "Failed to adjust resource limit RLIMIT_%s: %m", rlimit_to_string(which_failed)); - } - /* Set the RTPRIO resource limit to 0, but only if nothing else was explicitly requested. */ + /* Set the RTPRIO resource limit to 0, but only if nothing else was explicitly + * requested. (Note this is placed after the general resource limit initialization, see + * above, in order to take precedence.) */ if (context->restrict_realtime && !context->rlimit[RLIMIT_RTPRIO]) { if (setrlimit(RLIMIT_RTPRIO, &RLIMIT_MAKE_CONST(0)) < 0) { *exit_status = EXIT_LIMITS; @@ -3942,7 +3967,7 @@ const char* exec_context_fdname(const ExecContext *c, int fd_index) { } } -static int exec_context_named_iofds(const ExecContext *c, const ExecParameters *p, int named_iofds[3]) { +static int exec_context_named_iofds(const ExecContext *c, const ExecParameters *p, int named_iofds[static 3]) { size_t i, targets; const char* stdio_fdname[3]; size_t n_fds; diff --git a/src/core/job.c b/src/core/job.c index f635b7e933..59bb9d2162 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -151,6 +151,8 @@ void job_uninstall(Job *j) { unit_add_to_gc_queue(j->unit); + unit_add_to_dbus_queue(j->unit); /* The Job property of the unit has changed now */ + hashmap_remove_value(j->manager->jobs, UINT32_TO_PTR(j->id), j); j->installed = false; } @@ -206,8 +208,9 @@ Job* job_install(Job *j) { (job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) { job_merge_into_installed(uj, j); log_unit_debug(uj->unit, - "Merged into installed job %s/%s as %u", - uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id); + "Merged %s/%s into installed job %s/%s as %"PRIu32, + j->unit->id, job_type_to_string(j->type), uj->unit->id, + job_type_to_string(uj->type), uj->id); return uj; } else { /* already running and not safe to merge into */ @@ -216,8 +219,8 @@ Job* job_install(Job *j) { * not currently possible to have more than one installed job per unit. */ job_merge_into_installed(uj, j); log_unit_debug(uj->unit, - "Merged into running job, re-running: %s/%s as %u", - uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id); + "Merged into running job, re-running: %s/%s as %"PRIu32, + uj->unit->id, job_type_to_string(uj->type), uj->id); job_set_state(uj, JOB_WAITING); return uj; diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 4ebe92fd45..44f00a3046 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3749,7 +3749,7 @@ int config_parse_exec_directories( if (path_startswith(k, "private")) { log_syntax(unit, LOG_ERR, filename, line, 0, - "%s= path can't be 'private', ingoring assignment: %s", lvalue, word); + "%s= path can't be 'private', ignoring assignment: %s", lvalue, word); continue; } @@ -4254,6 +4254,12 @@ int config_parse_pid_file( assert(rvalue); assert(u); + if (isempty(rvalue)) { + /* An empty assignment removes already set value. */ + *s = mfree(*s); + return 0; + } + r = unit_full_printf(u, rvalue, &k); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue); diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c index 584fb220a1..aa4a89c17a 100644 --- a/src/core/locale-setup.c +++ b/src/core/locale-setup.c @@ -74,9 +74,9 @@ int locale_setup(char ***environment) { } if (strv_isempty(add)) { - /* If no locale is configured then default to C.UTF-8. */ + /* If no locale is configured then default to compile-time default. */ - add = strv_new("LANG=C.UTF-8"); + add = strv_new("LANG=" SYSTEMD_DEFAULT_LOCALE); if (!add) return -ENOMEM; } diff --git a/src/core/macros.systemd.in b/src/core/macros.systemd.in index 9ccad5ebfe..d9e7f573ba 100644 --- a/src/core/macros.systemd.in +++ b/src/core/macros.systemd.in @@ -43,7 +43,7 @@ OrderWithRequires(postun): systemd \ %systemd_post() \ if [ $1 -eq 1 ] ; then \ # Initial installation \ - systemctl --no-reload preset %{?*} &>/dev/null || : \ + systemctl --no-reload preset %{?*} >/dev/null 2>&1 || : \ fi \ %{nil} @@ -52,14 +52,14 @@ fi \ %systemd_preun() \ if [ $1 -eq 0 ] ; then \ # Package removal, not upgrade \ - systemctl --no-reload disable --now %{?*} &>/dev/null || : \ + systemctl --no-reload disable --now %{?*} >/dev/null 2>&1 || : \ fi \ %{nil} %systemd_user_preun() \ if [ $1 -eq 0 ] ; then \ # Package removal, not upgrade \ - systemctl --global disable %{?*} &>/dev/null || : \ + systemctl --global disable %{?*} >/dev/null 2>&1 || : \ fi \ %{nil} @@ -70,7 +70,7 @@ fi \ %systemd_postun_with_restart() \ if [ $1 -ge 1 ] ; then \ # Package upgrade, not uninstall \ - systemctl try-restart %{?*} &>/dev/null || : \ + systemctl try-restart %{?*} >/dev/null 2>&1 || : \ fi \ %{nil} @@ -84,16 +84,16 @@ fi \ # Deprecated. Use %tmpfiles_create_package instead %tmpfiles_create() \ -systemd-tmpfiles --create %{?*} &>/dev/null || : \ +systemd-tmpfiles --create %{?*} >/dev/null 2>&1 || : \ %{nil} # Deprecated. Use %sysusers_create_package instead %sysusers_create() \ -systemd-sysusers %{?*} &>/dev/null || : \ +systemd-sysusers %{?*} >/dev/null 2>&1 || : \ %{nil} %sysusers_create_inline() \ -systemd-sysusers - <<SYSTEMD_INLINE_EOF &>/dev/null || : \ +systemd-sysusers - <<SYSTEMD_INLINE_EOF >/dev/null 2>&1 || : \ %{?*} \ SYSTEMD_INLINE_EOF \ %{nil} @@ -112,7 +112,7 @@ SYSTEMD_INLINE_EOF \ # %files # %{_sysusersdir}/%{name}.conf %sysusers_create_package() \ -systemd-sysusers --replace=%_sysusersdir/%1.conf - <<SYSTEMD_INLINE_EOF &>/dev/null || : \ +systemd-sysusers --replace=%_sysusersdir/%1.conf - <<SYSTEMD_INLINE_EOF >/dev/null 2>&1 || : \ %(cat %2) \ SYSTEMD_INLINE_EOF \ %{nil} @@ -131,15 +131,15 @@ SYSTEMD_INLINE_EOF \ # %files # %{_tmpfilesdir}/%{name}.conf %tmpfiles_create_package() \ -systemd-tmpfiles --replace=%_tmpfilesdir/%1.conf --create - <<SYSTEMD_INLINE_EOF &>/dev/null || : \ +systemd-tmpfiles --replace=%_tmpfilesdir/%1.conf --create - <<SYSTEMD_INLINE_EOF >/dev/null 2>&1 || : \ %(cat %2) \ SYSTEMD_INLINE_EOF \ %{nil} %sysctl_apply() \ -@rootlibexecdir@/systemd-sysctl %{?*} &>/dev/null || : \ +@rootlibexecdir@/systemd-sysctl %{?*} >/dev/null 2>&1 || : \ %{nil} %binfmt_apply() \ -@rootlibexecdir@/systemd-binfmt %{?*} &>/dev/null || : \ +@rootlibexecdir@/systemd-binfmt %{?*} >/dev/null 2>&1 || : \ %{nil} diff --git a/src/core/main.c b/src/core/main.c index 839dc062ff..561f956f0a 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -83,6 +83,10 @@ #include "virt.h" #include "watchdog.h" +#if HAS_FEATURE_ADDRESS_SANITIZER +#include <sanitizer/lsan_interface.h> +#endif + static enum { ACTION_RUN, ACTION_HELP, @@ -1265,6 +1269,7 @@ static void bump_file_max_and_nr_open(void) { } static int bump_rlimit_nofile(struct rlimit *saved_rlimit) { + struct rlimit new_rlimit; int r, nr; assert(saved_rlimit); @@ -1299,12 +1304,30 @@ static int bump_rlimit_nofile(struct rlimit *saved_rlimit) { if (arg_system) rl->rlim_max = MIN((rlim_t) nr, MAX(rl->rlim_max, (rlim_t) HIGH_RLIMIT_NOFILE)); + /* If for some reason we were invoked with a soft limit above 1024 (which should never + * happen!, but who knows what we get passed in from pam_limit when invoked as --user + * instance), then lower what we pass on to not confuse our children */ + rl->rlim_cur = MIN(rl->rlim_cur, (rlim_t) FD_SETSIZE); + arg_default_rlimit[RLIMIT_NOFILE] = rl; } + /* Calculate the new limits to use for us. Never lower from what we inherited. */ + new_rlimit = (struct rlimit) { + .rlim_cur = MAX((rlim_t) nr, saved_rlimit->rlim_cur), + .rlim_max = MAX((rlim_t) nr, saved_rlimit->rlim_max), + }; + + /* Shortcut if nothing changes. */ + if (saved_rlimit->rlim_max >= new_rlimit.rlim_max && + saved_rlimit->rlim_cur >= new_rlimit.rlim_cur) { + log_debug("RLIMIT_NOFILE is already as high or higher than we need it, not bumping."); + return 0; + } + /* Bump up the resource limit for ourselves substantially, all the way to the maximum the kernel allows, for * both hard and soft. */ - r = setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(nr)); + r = setrlimit_closest(RLIMIT_NOFILE, &new_rlimit); if (r < 0) return log_warning_errno(r, "Setting RLIMIT_NOFILE failed, ignoring: %m"); @@ -1312,6 +1335,7 @@ static int bump_rlimit_nofile(struct rlimit *saved_rlimit) { } static int bump_rlimit_memlock(struct rlimit *saved_rlimit) { + struct rlimit new_rlimit; int r; assert(saved_rlimit); @@ -1323,7 +1347,33 @@ static int bump_rlimit_memlock(struct rlimit *saved_rlimit) { if (getrlimit(RLIMIT_MEMLOCK, saved_rlimit) < 0) return log_warning_errno(errno, "Reading RLIMIT_MEMLOCK failed, ignoring: %m"); - r = setrlimit_closest(RLIMIT_MEMLOCK, &RLIMIT_MAKE_CONST(HIGH_RLIMIT_MEMLOCK)); + /* Pass the original value down to invoked processes */ + if (!arg_default_rlimit[RLIMIT_MEMLOCK]) { + struct rlimit *rl; + + rl = newdup(struct rlimit, saved_rlimit, 1); + if (!rl) + return log_oom(); + + arg_default_rlimit[RLIMIT_MEMLOCK] = rl; + } + + /* Using MAX() on resource limits only is safe if RLIM_INFINITY is > 0. POSIX declares that rlim_t + * must be unsigned, hence this is a given, but let's make this clear here. */ + assert_cc(RLIM_INFINITY > 0); + + new_rlimit = (struct rlimit) { + .rlim_cur = MAX(HIGH_RLIMIT_MEMLOCK, saved_rlimit->rlim_cur), + .rlim_max = MAX(HIGH_RLIMIT_MEMLOCK, saved_rlimit->rlim_max), + }; + + if (saved_rlimit->rlim_max >= new_rlimit.rlim_cur && + saved_rlimit->rlim_cur >= new_rlimit.rlim_max) { + log_debug("RLIMIT_MEMLOCK is already as high or higher than we need it, not bumping."); + return 0; + } + + r = setrlimit_closest(RLIMIT_MEMLOCK, &new_rlimit); if (r < 0) return log_warning_errno(r, "Setting RLIMIT_MEMLOCK failed, ignoring: %m"); @@ -1660,12 +1710,11 @@ static void do_reexecute( * we do that */ watchdog_close(true); - /* Reset the RLIMIT_NOFILE to the kernel default, so that the new systemd can pass the kernel default to its - * child processes */ - - if (saved_rlimit_nofile->rlim_cur > 0) + /* Reset RLIMIT_NOFILE + RLIMIT_MEMLOCK back to the kernel defaults, so that the new systemd can pass + * the kernel default to its child processes */ + if (saved_rlimit_nofile->rlim_cur != 0) (void) setrlimit(RLIMIT_NOFILE, saved_rlimit_nofile); - if (saved_rlimit_memlock->rlim_cur != (rlim_t) -1) + if (saved_rlimit_memlock->rlim_cur != RLIM_INFINITY) (void) setrlimit(RLIMIT_MEMLOCK, saved_rlimit_memlock); if (switch_root_dir) { @@ -1914,7 +1963,7 @@ static void log_execution_mode(bool *ret_first_boot) { if (arg_system) { int v; - log_info(PACKAGE_STRING " running in %ssystem mode. (" SYSTEMD_FEATURES ")", + log_info("systemd " GIT_VERSION " running in %ssystem mode. (" SYSTEMD_FEATURES ")", arg_action == ACTION_TEST ? "test " : "" ); v = detect_virtualization(); @@ -1942,7 +1991,7 @@ static void log_execution_mode(bool *ret_first_boot) { _cleanup_free_ char *t; t = uid_to_name(getuid()); - log_debug(PACKAGE_STRING " running in %suser mode for user " UID_FMT "/%s. (" SYSTEMD_FEATURES ")", + log_debug("systemd " GIT_VERSION " running in %suser mode for user " UID_FMT "/%s. (" SYSTEMD_FEATURES ")", arg_action == ACTION_TEST ? " test" : "", getuid(), strna(t)); } @@ -2298,7 +2347,11 @@ int main(int argc, char *argv[]) { dual_timestamp initrd_timestamp = DUAL_TIMESTAMP_NULL, userspace_timestamp = DUAL_TIMESTAMP_NULL, kernel_timestamp = DUAL_TIMESTAMP_NULL, security_start_timestamp = DUAL_TIMESTAMP_NULL, security_finish_timestamp = DUAL_TIMESTAMP_NULL; - struct rlimit saved_rlimit_nofile = RLIMIT_MAKE_CONST(0), saved_rlimit_memlock = RLIMIT_MAKE_CONST((rlim_t) -1); + struct rlimit saved_rlimit_nofile = RLIMIT_MAKE_CONST(0), + saved_rlimit_memlock = RLIMIT_MAKE_CONST(RLIM_INFINITY); /* The original rlimits we passed + * in. Note we use different values + * for the two that indicate whether + * these fields are initialized! */ bool skip_setup, loaded_policy = false, queue_default_job = false, first_boot = false, reexecute = false; char *switch_root_dir = NULL, *switch_root_init = NULL; usec_t before_startup, after_startup; @@ -2612,6 +2665,10 @@ finish: } #endif +#if HAS_FEATURE_ADDRESS_SANITIZER + __lsan_do_leak_check(); +#endif + if (shutdown_verb) { r = become_shutdown(shutdown_verb, retval); log_error_errno(r, "Failed to execute shutdown binary, %s: %m", getpid_cached() == 1 ? "freezing" : "quitting"); diff --git a/src/core/manager.c b/src/core/manager.c index 35d9753b12..6086531bab 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -3243,11 +3243,11 @@ static int manager_deserialize_one_unit(Manager *m, const char *name, FILE *f, F } static int manager_deserialize_units(Manager *m, FILE *f, FDSet *fds) { - _cleanup_free_ char *line = NULL; const char *unit_name; int r; for (;;) { + _cleanup_free_ char *line = NULL; /* Start marker */ r = read_line(f, LONG_LINE_MAX, &line); if (r < 0) diff --git a/src/core/meson.build b/src/core/meson.build index 450d6f72a9..85021bdc01 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -173,26 +173,19 @@ systemd_shutdown_sources = files(''' '''.split()) in_files = [['macros.systemd', rpmmacrosdir], - ['triggers.systemd', ''], + ['system.conf', pkgsysconfdir], ['systemd.pc', pkgconfigdatadir], - ['system.conf', pkgsysconfdir]] + ['triggers.systemd', '']] foreach item : in_files file = item[0] dir = item[1] - # If 'no', disable generation completely. - # If '', generate, but do not install. - if dir != 'no' - gen = configure_file( - input : file + '.in', - output : file, - configuration : substs) - if dir != '' - install_data(gen, - install_dir : dir) - endif - endif + configure_file( + input : file + '.in', + output : file, + configuration : substs, + install_dir : dir == 'no' ? '' : dir) endforeach install_data('org.freedesktop.systemd1.conf', diff --git a/src/core/mount.c b/src/core/mount.c index ead9bc1f44..c31cad6b52 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -251,6 +251,32 @@ _pure_ static MountParameters* get_mount_parameters(Mount *m) { return get_mount_parameters_fragment(m); } +static int update_parameters_proc_self_mount_info( + Mount *m, + const char *what, + const char *options, + const char *fstype) { + + MountParameters *p; + int r, q, w; + + p = &m->parameters_proc_self_mountinfo; + + r = free_and_strdup(&p->what, what); + if (r < 0) + return r; + + q = free_and_strdup(&p->options, options); + if (q < 0) + return q; + + w = free_and_strdup(&p->fstype, fstype); + if (w < 0) + return w; + + return r > 0 || q > 0 || w > 0; +} + static int mount_add_mount_dependencies(Mount *m) { MountParameters *pm; Unit *other; @@ -352,7 +378,8 @@ static int mount_add_device_dependencies(Mount *m) { * automatically stopped when the device disappears suddenly. */ dep = mount_is_bound_to_device(m) ? UNIT_BINDS_TO : UNIT_REQUIRES; - mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT; + /* We always use 'what' from /proc/self/mountinfo if mounted */ + mask = m->from_proc_self_mountinfo ? UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT : UNIT_DEPENDENCY_FILE; r = unit_add_node_dependency(UNIT(m), p->what, device_wants_mount, dep, mask); if (r < 0) @@ -426,6 +453,7 @@ static int mount_add_default_dependencies(Mount *m) { const char *after, *before; UnitDependencyMask mask; MountParameters *p; + bool nofail; int r; assert(m); @@ -444,6 +472,7 @@ static int mount_add_default_dependencies(Mount *m) { return 0; mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_DEFAULT; + nofail = m->from_fragment ? fstab_test_yes_no_option(m->parameters_fragment.options, "nofail\0" "fail\0") : false; if (mount_is_network(p)) { /* We order ourselves after network.target. This is @@ -474,9 +503,11 @@ static int mount_add_default_dependencies(Mount *m) { before = SPECIAL_LOCAL_FS_TARGET; } - r = unit_add_dependency_by_name(UNIT(m), UNIT_BEFORE, before, true, mask); - if (r < 0) - return r; + if (!nofail) { + r = unit_add_dependency_by_name(UNIT(m), UNIT_BEFORE, before, true, mask); + if (r < 0) + return r; + } r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, true, mask); if (r < 0) @@ -733,7 +764,7 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) { "%sSloppyOptions: %s\n" "%sLazyUnmount: %s\n" "%sForceUnmount: %s\n" - "%sTimoutSec: %s\n", + "%sTimeoutSec: %s\n", prefix, mount_state_to_string(m->state), prefix, mount_result_to_string(m->result), prefix, m->where, @@ -823,6 +854,9 @@ static void mount_enter_dead(Mount *m, MountResult f) { unit_unref_uid_gid(UNIT(m), true); dynamic_creds_destroy(&m->dynamic_creds); + + /* Any dependencies based on /proc/self/mountinfo are now stale */ + unit_remove_dependencies(UNIT(m), UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT); } static void mount_enter_mounted(Mount *m, MountResult f) { @@ -1428,32 +1462,6 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user return 0; } -static int update_parameters_proc_self_mount_info( - Mount *m, - const char *what, - const char *options, - const char *fstype) { - - MountParameters *p; - int r, q, w; - - p = &m->parameters_proc_self_mountinfo; - - r = free_and_strdup(&p->what, what); - if (r < 0) - return r; - - q = free_and_strdup(&p->options, options); - if (q < 0) - return q; - - w = free_and_strdup(&p->fstype, fstype); - if (w < 0) - return w; - - return r > 0 || q > 0 || w > 0; -} - static int mount_setup_new_unit( Manager *m, const char *name, @@ -1528,10 +1536,10 @@ static int mount_setup_existing_unit( if (r > 0) flags |= MOUNT_PROC_JUST_CHANGED; - if (!MOUNT(u)->from_proc_self_mountinfo) { + if (!MOUNT(u)->from_proc_self_mountinfo || FLAGS_SET(MOUNT(u)->proc_flags, MOUNT_PROC_JUST_MOUNTED)) flags |= MOUNT_PROC_JUST_MOUNTED; - MOUNT(u)->from_proc_self_mountinfo = true; - } + + MOUNT(u)->from_proc_self_mountinfo = true; if (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_BAD_SETTING, UNIT_ERROR)) { /* The unit was previously not found or otherwise not loaded. Now that the unit shows up in @@ -1844,6 +1852,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, } mount->from_proc_self_mountinfo = false; + assert_se(update_parameters_proc_self_mount_info(mount, NULL, NULL, NULL) >= 0); switch (mount->state) { diff --git a/src/core/namespace.c b/src/core/namespace.c index c2ca3e0334..7f553a42c2 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -1628,7 +1628,7 @@ int setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) { return 0; } -int setup_netns(int netns_storage_socket[2]) { +int setup_netns(int netns_storage_socket[static 2]) { _cleanup_close_ int netns = -1; int r, q; diff --git a/src/core/namespace.h b/src/core/namespace.h index 1188c6d595..5e0ec97969 100644 --- a/src/core/namespace.h +++ b/src/core/namespace.h @@ -91,7 +91,7 @@ int setup_tmp_dirs( char **tmp_dir, char **var_tmp_dir); -int setup_netns(int netns_storage_socket[2]); +int setup_netns(int netns_storage_socket[static 2]); const char* protect_home_to_string(ProtectHome p) _const_; ProtectHome protect_home_from_string(const char *s) _pure_; diff --git a/src/core/service.c b/src/core/service.c index cfa3271232..324dcf2311 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -2154,7 +2154,7 @@ static void service_enter_restart(Service *s) { * restarted. We use JOB_RESTART (instead of the more obvious * JOB_START) here so that those dependency jobs will be added * as well. */ - r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_FAIL, &error, NULL); + r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_REPLACE, &error, NULL); if (r < 0) goto fail; diff --git a/src/core/socket.c b/src/core/socket.c index dd126a7f21..af95e9027e 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -561,7 +561,7 @@ int socket_acquire_peer(Socket *s, int fd, SocketPeer **p) { r = getpeername(fd, &sa.peer.sa, &salen); if (r < 0) - return log_error_errno(errno, "getpeername failed: %m"); + return log_unit_error_errno(UNIT(s), errno, "getpeername failed: %m"); if (!IN_SET(sa.peer.sa.sa_family, AF_INET, AF_INET6, AF_VSOCK)) { *p = NULL; @@ -1465,6 +1465,14 @@ static int socket_address_listen_do( label); } +#define log_address_error_errno(u, address, error, fmt) \ + ({ \ + _cleanup_free_ char *_t = NULL; \ + \ + (void) socket_address_print(address, &_t); \ + log_unit_error_errno(u, error, fmt, strna(_t)); \ + }) + static int socket_address_listen_in_cgroup( Socket *s, const SocketAddress *address, @@ -1503,13 +1511,13 @@ static int socket_address_listen_in_cgroup( fd = socket_address_listen_do(s, address, label); if (fd < 0) { - log_unit_error_errno(UNIT(s), fd, "Failed to create listening socket: %m"); + log_address_error_errno(UNIT(s), address, fd, "Failed to create listening socket (%s): %m"); _exit(EXIT_FAILURE); } r = send_one_fd(pair[1], fd, 0); if (r < 0) { - log_unit_error_errno(UNIT(s), r, "Failed to send listening socket to parent: %m"); + log_address_error_errno(UNIT(s), address, r, "Failed to send listening socket (%s) to parent: %m"); _exit(EXIT_FAILURE); } @@ -1527,19 +1535,22 @@ static int socket_address_listen_in_cgroup( } if (fd < 0) - return log_unit_error_errno(UNIT(s), fd, "Failed to receive listening socket: %m"); + return log_address_error_errno(UNIT(s), address, fd, "Failed to receive listening socket (%s): %m"); return fd; shortcut: fd = socket_address_listen_do(s, address, label); if (fd < 0) - return log_error_errno(fd, "Failed to create listening socket: %m"); + return log_address_error_errno(UNIT(s), address, fd, "Failed to create listening socket (%s): %m"); return fd; } -static int socket_open_fds(Socket *s) { +DEFINE_TRIVIAL_CLEANUP_FUNC(Socket *, socket_close_fds); + +static int socket_open_fds(Socket *_s) { + _cleanup_(socket_close_fdsp) Socket *s = _s; _cleanup_(mac_selinux_freep) char *label = NULL; bool know_label = false; SocketPort *p; @@ -1562,7 +1573,7 @@ static int socket_open_fds(Socket *s) { r = socket_determine_selinux_label(s, &label); if (r < 0) - goto rollback; + return log_unit_error_errno(UNIT(s), r, "Failed to determine SELinux label: %m"); know_label = true; } @@ -1582,11 +1593,10 @@ static int socket_open_fds(Socket *s) { break; } - r = socket_address_listen_in_cgroup(s, &p->address, label); - if (r < 0) - goto rollback; + p->fd = socket_address_listen_in_cgroup(s, &p->address, label); + if (p->fd < 0) + return p->fd; - p->fd = r; socket_apply_socket_options(s, p->fd); socket_symlink(s); break; @@ -1594,10 +1604,8 @@ static int socket_open_fds(Socket *s) { case SOCKET_SPECIAL: p->fd = special_address_create(p->path, s->writable); - if (p->fd < 0) { - r = p->fd; - goto rollback; - } + if (p->fd < 0) + return log_unit_error_errno(UNIT(s), p->fd, "Failed to open special file %s: %m", p->path); break; case SOCKET_FIFO: @@ -1606,10 +1614,8 @@ static int socket_open_fds(Socket *s) { p->path, s->directory_mode, s->socket_mode); - if (p->fd < 0) { - r = p->fd; - goto rollback; - } + if (p->fd < 0) + return log_unit_error_errno(UNIT(s), p->fd, "Failed to open FIFO %s: %m", p->path); socket_apply_fifo_options(s, p->fd); socket_symlink(s); @@ -1622,10 +1628,8 @@ static int socket_open_fds(Socket *s) { s->socket_mode, s->mq_maxmsg, s->mq_msgsize); - if (p->fd < 0) { - r = p->fd; - goto rollback; - } + if (p->fd < 0) + return log_unit_error_errno(UNIT(s), p->fd, "Failed to open message queue %s: %m", p->path); break; case SOCKET_USB_FUNCTION: { @@ -1634,18 +1638,16 @@ static int socket_open_fds(Socket *s) { ep = path_make_absolute("ep0", p->path); p->fd = usbffs_address_create(ep); - if (p->fd < 0) { - r = p->fd; - goto rollback; - } + if (p->fd < 0) + return p->fd; r = usbffs_write_descs(p->fd, SERVICE(UNIT_DEREF(s->service))); if (r < 0) - goto rollback; + return r; r = usbffs_dispatch_eps(p); if (r < 0) - goto rollback; + return r; break; } @@ -1654,11 +1656,8 @@ static int socket_open_fds(Socket *s) { } } + s = NULL; return 0; - -rollback: - socket_close_fds(s); - return r; } static void socket_unwatch_fds(Socket *s) { @@ -2521,14 +2520,14 @@ static int socket_serialize(Unit *u, FILE *f, FDSet *fds) { copy = fdset_put_dup(fds, p->fd); if (copy < 0) - return log_warning_errno(copy, "Failed to serialize socket fd: %m"); + return log_unit_warning_errno(u, copy, "Failed to serialize socket fd: %m"); if (p->type == SOCKET_SOCKET) { _cleanup_free_ char *t = NULL; r = socket_address_print(&p->address, &t); if (r < 0) - return log_error_errno(r, "Failed to format socket address: %m"); + return log_unit_error_errno(u, r, "Failed to format socket address: %m"); if (socket_address_family(&p->address) == AF_NETLINK) (void) serialize_item_format(f, "netlink", "%i %s", copy, t); diff --git a/src/core/systemd.pc.in b/src/core/systemd.pc.in index 655773ea8a..0dae950473 100644 --- a/src/core/systemd.pc.in +++ b/src/core/systemd.pc.in @@ -36,5 +36,5 @@ containeruidbasemax=@containeruidbasemax@ Name: systemd Description: systemd System and Service Manager -URL: @PACKAGE_URL@ -Version: @PACKAGE_VERSION@ +URL: @PROJECT_URL@ +Version: @PROJECT_VERSION@ diff --git a/src/core/transaction.c b/src/core/transaction.c index 486c6a4a05..2418332b9a 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -300,7 +300,7 @@ rescan: goto next_unit; } - /* log_debug("Found redundant job %s/%s, dropping.", j->unit->id, job_type_to_string(j->type)); */ + log_trace("Found redundant job %s/%s, dropping from transaction.", j->unit->id, job_type_to_string(j->type)); transaction_delete_job(tr, j, false); goto rescan; next_unit:; @@ -494,15 +494,17 @@ static void transaction_collect_garbage(Transaction *tr) { rescan: HASHMAP_FOREACH(j, tr->jobs, i) { - if (tr->anchor_job == j || j->object_list) { - /* log_debug("Keeping job %s/%s because of %s/%s", */ - /* j->unit->id, job_type_to_string(j->type), */ - /* j->object_list->subject ? j->object_list->subject->unit->id : "root", */ - /* j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */ + if (tr->anchor_job == j) + continue; + if (j->object_list) { + log_trace("Keeping job %s/%s because of %s/%s", + j->unit->id, job_type_to_string(j->type), + j->object_list->subject ? j->object_list->subject->unit->id : "root", + j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); continue; } - /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */ + log_trace("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); transaction_delete_job(tr, j, true); goto rescan; } @@ -798,7 +800,7 @@ static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, b if (is_new) *is_new = true; - /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */ + log_trace("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); return j; } @@ -892,10 +894,8 @@ int transaction_add_job_and_dependencies( if (MANAGER_IS_RELOADING(unit->manager)) unit_coldplug(unit); - /* log_debug("Pulling in %s/%s from %s/%s", */ - /* unit->id, job_type_to_string(type), */ - /* by ? by->unit->id : "NA", */ - /* by ? job_type_to_string(by->type) : "NA"); */ + if (by) + log_trace("Pulling in %s/%s from %s/%s", unit->id, job_type_to_string(type), by->unit->id, job_type_to_string(by->type)); /* Safety check that the unit is a valid state, i.e. not in UNIT_STUB or UNIT_MERGED which should only be set * temporarily. */ @@ -1053,7 +1053,7 @@ int transaction_add_job_and_dependencies( if (type == JOB_RELOAD) transaction_add_propagate_reload_jobs(tr, ret->unit, ret, ignore_order, e); - /* JOB_VERIFY_STARTED require no dependency handling */ + /* JOB_VERIFY_ACTIVE requires no dependency handling */ } return 0; diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c index a8e84ebe80..72391ace3a 100644 --- a/src/core/unit-printf.c +++ b/src/core/unit-printf.c @@ -195,6 +195,7 @@ int unit_name_printf(Unit *u, const char* format, char **ret) { { 'N', specifier_prefix_and_instance, NULL }, { 'p', specifier_prefix, NULL }, { 'i', specifier_string, u->instance }, + { 'j', specifier_last_component, NULL }, { 'g', specifier_group_name, NULL }, { 'G', specifier_group_id, NULL }, diff --git a/src/core/unit.h b/src/core/unit.h index 6fd39eaca3..43cf15715a 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -248,8 +248,8 @@ typedef struct Unit { /* Counterparts in the cgroup filesystem */ char *cgroup_path; - CGroupMask cgroup_realized_mask; /* In which hierarchies does this unit's cgroup exist? (only relevant on cgroupsv1) */ - CGroupMask cgroup_enabled_mask; /* Which controllers are enabled (or more correctly: enabled for the children) for this unit's cgroup? (only relevant on cgroupsv2) */ + CGroupMask cgroup_realized_mask; /* In which hierarchies does this unit's cgroup exist? (only relevant on cgroup v1) */ + CGroupMask cgroup_enabled_mask; /* Which controllers are enabled (or more correctly: enabled for the children) for this unit's cgroup? (only relevant on cgroup v2) */ CGroupMask cgroup_invalidated_mask; /* A mask specifiying controllers which shall be considered invalidated, and require re-realization */ CGroupMask cgroup_members_mask; /* A cache for the controllers required by all children of this cgroup (only relevant for slice units) */ int cgroup_inotify_wd; diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 0c888b26f9..ecbb4bffc9 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -142,7 +142,7 @@ static int parse_config(void) { CONFIG_PARSE_WARN, NULL); } -static inline uint64_t storage_size_max(void) { +static uint64_t storage_size_max(void) { if (arg_storage == COREDUMP_STORAGE_EXTERNAL) return arg_external_size_max; if (arg_storage == COREDUMP_STORAGE_JOURNAL) @@ -229,7 +229,7 @@ static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) { #define filename_escape(s) xescape((s), "./ ") -static inline const char *coredump_tmpfile_name(const char *s) { +static const char *coredump_tmpfile_name(const char *s) { return s ? s : "(unnamed temporary file)"; } @@ -794,15 +794,16 @@ log: core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID], " (", context[CONTEXT_COMM], ") of user ", context[CONTEXT_UID], " dumped core.", - journald_crash ? "\nCoredump diverted to " : NULL, - journald_crash ? filename : NULL); + journald_crash && filename ? "\nCoredump diverted to " : NULL, + journald_crash && filename ? filename : NULL); if (!core_message) return log_oom(); if (journald_crash) { - /* We cannot log to the journal, so just print the MESSAGE. + /* We cannot log to the journal, so just print the message. * The target was set previously to something safe. */ - log_dispatch(LOG_ERR, 0, core_message); + assert(startswith(core_message, "MESSAGE=")); + log_dispatch(LOG_ERR, 0, core_message + strlen("MESSAGE=")); return 0; } @@ -1062,19 +1063,10 @@ static int send_iovec(const struct iovec iovec[], size_t n_iovec, int input_fd) return 0; } -static char* set_iovec_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value) { - char *x; - - x = strappend(field, value); - if (x) - iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(x); - return x; -} - static char* set_iovec_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value) { char *x; - x = set_iovec_field(iovec, n_iovec, field, value); + x = set_iovec_string_field(iovec, n_iovec, field, value); free(value); return x; } @@ -1124,36 +1116,36 @@ static int gather_pid_metadata( disable_coredumps(); } - set_iovec_field(iovec, n_iovec, "COREDUMP_UNIT=", context[CONTEXT_UNIT]); + set_iovec_string_field(iovec, n_iovec, "COREDUMP_UNIT=", context[CONTEXT_UNIT]); } if (cg_pid_get_user_unit(pid, &t) >= 0) set_iovec_field_free(iovec, n_iovec, "COREDUMP_USER_UNIT=", t); /* The next few are mandatory */ - if (!set_iovec_field(iovec, n_iovec, "COREDUMP_PID=", context[CONTEXT_PID])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_PID=", context[CONTEXT_PID])) return log_oom(); - if (!set_iovec_field(iovec, n_iovec, "COREDUMP_UID=", context[CONTEXT_UID])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_UID=", context[CONTEXT_UID])) return log_oom(); - if (!set_iovec_field(iovec, n_iovec, "COREDUMP_GID=", context[CONTEXT_GID])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_GID=", context[CONTEXT_GID])) return log_oom(); - if (!set_iovec_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL])) return log_oom(); - if (!set_iovec_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT])) return log_oom(); - if (!set_iovec_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context[CONTEXT_HOSTNAME])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_HOSTNAME=", context[CONTEXT_HOSTNAME])) return log_oom(); - if (!set_iovec_field(iovec, n_iovec, "COREDUMP_COMM=", context[CONTEXT_COMM])) + if (!set_iovec_string_field(iovec, n_iovec, "COREDUMP_COMM=", context[CONTEXT_COMM])) return log_oom(); if (context[CONTEXT_EXE] && - !set_iovec_field(iovec, n_iovec, "COREDUMP_EXE=", context[CONTEXT_EXE])) + !set_iovec_string_field(iovec, n_iovec, "COREDUMP_EXE=", context[CONTEXT_EXE])) return log_oom(); if (sd_pid_get_session(pid, &t) >= 0) @@ -1221,7 +1213,7 @@ static int gather_pid_metadata( iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(t); if (safe_atoi(context[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo)) - set_iovec_field(iovec, n_iovec, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(signo)); + set_iovec_string_field(iovec, n_iovec, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(signo)); return 0; /* we successfully acquired all metadata */ } diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index daf26aad70..9cb52ddf26 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -408,8 +408,7 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc return log_oom(); strncpy(c, *p, arg_key_size); - free(*p); - *p = c; + free_and_replace(*p, c); } *ret = TAKE_PTR(passwords); @@ -451,7 +450,7 @@ static int attach_tcrypt( r = read_one_line_file(key_file, &passphrase); if (r < 0) { log_error_errno(r, "Failed to read password file '%s': %m", key_file); - return -EAGAIN; + return -EAGAIN; /* log with the actual error, but return EAGAIN */ } params.passphrase = passphrase; @@ -461,14 +460,19 @@ static int attach_tcrypt( r = crypt_load(cd, CRYPT_TCRYPT, ¶ms); if (r < 0) { - if (key_file && r == -EPERM) - return log_error_errno(SYNTHETIC_ERRNO(EAGAIN), - "Failed to activate using password file '%s'.", - key_file); - return r; + if (key_file && r == -EPERM) { + log_error_errno(r, "Failed to activate using password file '%s'. (Key data not correct?)", key_file); + return -EAGAIN; /* log the actual error, but return EAGAIN */ + } + + return log_error_errno(r, "Failed to load tcrypt superblock on device %s: %m", crypt_get_device_name(cd)); } - return crypt_activate_by_volume_key(cd, name, NULL, 0, flags); + r = crypt_activate_by_volume_key(cd, name, NULL, 0, flags); + if (r < 0) + return log_error_errno(r, "Failed to activate tcrypt device %s: %m", crypt_get_device_name(cd)); + + return 0; } static int attach_luks_or_plain(struct crypt_device *cd, @@ -486,10 +490,8 @@ static int attach_luks_or_plain(struct crypt_device *cd, if (!arg_type || STR_IN_SET(arg_type, ANY_LUKS, CRYPT_LUKS1)) { r = crypt_load(cd, CRYPT_LUKS, NULL); - if (r < 0) { - log_error("crypt_load() failed on device %s.\n", crypt_get_device_name(cd)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to load LUKS superblock on device %s: %m", crypt_get_device_name(cd)); if (data_device) r = crypt_set_data_device(cd, data_device); @@ -530,23 +532,16 @@ static int attach_luks_or_plain(struct crypt_device *cd, cipher_mode = "cbc-essiv:sha256"; } - /* for CRYPT_PLAIN limit reads - * from keyfile to key length, and - * ignore keyfile-size */ + /* for CRYPT_PLAIN limit reads from keyfile to key length, and ignore keyfile-size */ arg_keyfile_size = arg_key_size; - /* In contrast to what the name - * crypt_setup() might suggest this - * doesn't actually format anything, - * it just configures encryption - * parameters when used for plain - * mode. */ + /* In contrast to what the name crypt_setup() might suggest this doesn't actually format + * anything, it just configures encryption parameters when used for plain mode. */ r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, arg_keyfile_size, ¶ms); /* hash == NULL implies the user passed "plain" */ pass_volume_key = (params.hash == NULL); } - if (r < 0) return log_error_errno(r, "Loading of cryptographic parameters failed: %m"); @@ -558,22 +553,30 @@ static int attach_luks_or_plain(struct crypt_device *cd, if (key_file) { r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags); - if (r < 0) { - log_error_errno(r, "Failed to activate with key file '%s': %m", key_file); - return -EAGAIN; + if (r == -EPERM) { + log_error_errno(r, "Failed to activate with key file '%s'. (Key data incorrect?)", key_file); + return -EAGAIN; /* Log actual error, but return EAGAIN */ } + if (r < 0) + return log_error_errno(r, "Failed to activate with key file '%s': %m", key_file); } else { char **p; + r = -EINVAL; STRV_FOREACH(p, passwords) { if (pass_volume_key) r = crypt_activate_by_volume_key(cd, name, *p, arg_key_size, flags); else r = crypt_activate_by_passphrase(cd, name, arg_key_slot, *p, strlen(*p), flags); - if (r >= 0) break; } + if (r == -EPERM) { + log_error_errno(r, "Failed to activate with specified passphrase. (Passphrase incorrect?)"); + return -EAGAIN; /* log actual error, but return EAGAIN */ + } + if (r < 0) + return log_error_errno(r, "Failed to activate with specified passphrase: %m"); } return r; @@ -624,10 +627,8 @@ static int run(int argc, char *argv[]) { /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */ - if (argc < 4) { - log_error("attach requires at least two arguments."); - return -EINVAL; - } + if (argc < 4) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "attach requires at least two arguments."); if (argc >= 5 && argv[4][0] && @@ -635,7 +636,7 @@ static int run(int argc, char *argv[]) { !streq(argv[4], "none")) { if (!path_is_absolute(argv[4])) - log_error("Password file path '%s' is not absolute. Ignoring.", argv[4]); + log_warning("Password file path '%s' is not absolute. Ignoring.", argv[4]); else key_file = argv[4]; } @@ -709,20 +710,15 @@ static int run(int argc, char *argv[]) { flags); if (r >= 0) break; - if (r == -EAGAIN) { - key_file = NULL; - continue; - } - if (r != -EPERM) - return log_error_errno(r, "Failed to activate: %m"); + if (r != -EAGAIN) + return r; - log_warning("Invalid passphrase."); + /* Passphrase not correct? Let's try again! */ + key_file = NULL; } - if (arg_tries != 0 && tries >= arg_tries) { - log_error("Too many attempts; giving up."); - return -EPERM; - } + if (arg_tries != 0 && tries >= arg_tries) + return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Too many attempts to activate; giving up."); } else if (streq(argv[1], "detach")) { @@ -740,10 +736,8 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Failed to deactivate: %m"); - } else { - log_error("Unknown verb %s.", argv[1]); - return -EINVAL; - } + } else + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown verb %s.", argv[1]); return 0; } diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c index ba39f596fc..524327c4da 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c @@ -414,7 +414,7 @@ static int run(int argc, char *argv[]) { exit_status = wait_for_terminate_and_check("fsck", pid, WAIT_LOG_ABNORMAL); if (exit_status < 0) return exit_status; - if (exit_status & ~1) { + if ((exit_status & ~FSCK_ERROR_CORRECTED) != FSCK_SUCCESS) { log_error("fsck failed with exit status %i.", exit_status); if ((exit_status & FSCK_SYSTEM_SHOULD_REBOOT) && root_directory) { diff --git a/src/import/curl-util.c b/src/import/curl-util.c index 05b17c3c78..7db03b2919 100644 --- a/src/import/curl-util.c +++ b/src/import/curl-util.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #include "alloc-util.h" +#include "build.h" #include "curl-util.h" #include "fd-util.h" #include "locale-util.h" @@ -283,14 +284,14 @@ int curl_glue_make(CURL **ret, const char *url, void *userdata) { if (curl_easy_setopt(c, CURLOPT_PRIVATE, userdata) != CURLE_OK) return -EIO; - useragent = strjoina(program_invocation_short_name, "/" PACKAGE_VERSION); + useragent = strjoina(program_invocation_short_name, "/" GIT_VERSION); if (curl_easy_setopt(c, CURLOPT_USERAGENT, useragent) != CURLE_OK) return -EIO; if (curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK) return -EIO; - *ret = c; + *ret = TAKE_PTR(c); return 0; } diff --git a/src/import/pull-job.c b/src/import/pull-job.c index a44e0a7eda..6881bd627f 100644 --- a/src/import/pull-job.c +++ b/src/import/pull-job.c @@ -537,7 +537,7 @@ int pull_job_new(PullJob **ret, const char *url, CurlGlue *glue, void *userdata) assert(ret); u = strdup(url); - if (u) + if (!u) return -ENOMEM; j = new(PullJob, 1); diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c index c60d4bd740..260dc2eb61 100644 --- a/src/initctl/initctl.c +++ b/src/initctl/initctl.c @@ -233,12 +233,8 @@ static void server_done(Server *s) { while (s->fifos) fifo_free(s->fifos); - safe_close(s->epoll_fd); - - if (s->bus) { - sd_bus_flush(s->bus); - sd_bus_unref(s->bus); - } + s->epoll_fd = safe_close(s->epoll_fd); + s->bus = sd_bus_flush_close_unref(s->bus); } static int server_init(Server *s, unsigned n_sockets) { diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index 4185af63e1..af45fa549a 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -461,7 +461,7 @@ static int request_handler_entries( struct MHD_Connection *connection, void *connection_cls) { - struct MHD_Response *response; + _cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL; RequestMeta *m = connection_cls; int r; @@ -503,11 +503,7 @@ static int request_handler_entries( return respond_oom(connection); MHD_add_response_header(response, "Content-Type", mime_types[m->mode]); - - r = MHD_queue_response(connection, MHD_HTTP_OK, response); - MHD_destroy_response(response); - - return r; + return MHD_queue_response(connection, MHD_HTTP_OK, response); } static int output_field(FILE *f, OutputMode m, const char *d, size_t l) { @@ -619,7 +615,7 @@ static int request_handler_fields( const char *field, void *connection_cls) { - struct MHD_Response *response; + _cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL; RequestMeta *m = connection_cls; int r; @@ -642,11 +638,7 @@ static int request_handler_fields( return respond_oom(connection); MHD_add_response_header(response, "Content-Type", mime_types[m->mode == OUTPUT_JSON ? OUTPUT_JSON : OUTPUT_SHORT]); - - r = MHD_queue_response(connection, MHD_HTTP_OK, response); - MHD_destroy_response(response); - - return r; + return MHD_queue_response(connection, MHD_HTTP_OK, response); } static int request_handler_redirect( @@ -654,8 +646,7 @@ static int request_handler_redirect( const char *target) { char *page; - struct MHD_Response *response; - int ret; + _cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL; assert(connection); assert(target); @@ -671,11 +662,7 @@ static int request_handler_redirect( MHD_add_response_header(response, "Content-Type", "text/html"); MHD_add_response_header(response, "Location", target); - - ret = MHD_queue_response(connection, MHD_HTTP_MOVED_PERMANENTLY, response); - MHD_destroy_response(response); - - return ret; + return MHD_queue_response(connection, MHD_HTTP_MOVED_PERMANENTLY, response); } static int request_handler_file( @@ -683,8 +670,7 @@ static int request_handler_file( const char *path, const char *mime_type) { - struct MHD_Response *response; - int ret; + _cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL; _cleanup_close_ int fd = -1; struct stat st; @@ -702,15 +688,10 @@ static int request_handler_file( response = MHD_create_response_from_fd_at_offset64(st.st_size, fd, 0); if (!response) return respond_oom(connection); - - fd = -1; + TAKE_FD(fd); MHD_add_response_header(response, "Content-Type", mime_type); - - ret = MHD_queue_response(connection, MHD_HTTP_OK, response); - MHD_destroy_response(response); - - return ret; + return MHD_queue_response(connection, MHD_HTTP_OK, response); } static int get_virtualization(char **v) { @@ -747,14 +728,13 @@ static int request_handler_machine( struct MHD_Connection *connection, void *connection_cls) { - struct MHD_Response *response; + _cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL; RequestMeta *m = connection_cls; int r; _cleanup_free_ char* hostname = NULL, *os_name = NULL; uint64_t cutoff_from = 0, cutoff_to = 0, usage = 0; - char *json; sd_id128_t mid, bid; - _cleanup_free_ char *v = NULL; + _cleanup_free_ char *v = NULL, *json = NULL; assert(connection); assert(m); @@ -803,21 +783,16 @@ static int request_handler_machine( usage, cutoff_from, cutoff_to); - if (r < 0) return respond_oom(connection); response = MHD_create_response_from_buffer(strlen(json), json, MHD_RESPMEM_MUST_FREE); - if (!response) { - free(json); + if (!response) return respond_oom(connection); - } + TAKE_PTR(json); MHD_add_response_header(response, "Content-Type", "application/json"); - r = MHD_queue_response(connection, MHD_HTTP_OK, response); - MHD_destroy_response(response); - - return r; + return MHD_queue_response(connection, MHD_HTTP_OK, response); } static int request_handler( diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c index e1748cb46b..802c3ea608 100644 --- a/src/journal-remote/journal-remote-main.c +++ b/src/journal-remote/journal-remote-main.c @@ -221,16 +221,17 @@ static int process_http_upload( journal_remote_server_global->seal); if (r == -EAGAIN) break; - else if (r < 0) { - log_warning("Failed to process data for connection %p", connection); - if (r == -E2BIG) - return mhd_respondf(connection, - r, MHD_HTTP_PAYLOAD_TOO_LARGE, - "Entry is too large, maximum is " STRINGIFY(DATA_SIZE_MAX) " bytes."); + if (r < 0) { + if (r == -ENOBUFS) + log_warning_errno(r, "Entry is above the maximum of %u, aborting connection %p.", + DATA_SIZE_MAX, connection); + else if (r == -E2BIG) + log_warning_errno(r, "Entry with more fields than the maximum of %u, aborting connection %p.", + ENTRY_FIELD_COUNT_MAX, connection); else - return mhd_respondf(connection, - r, MHD_HTTP_UNPROCESSABLE_ENTITY, - "Processing failed: %m."); + log_warning_errno(r, "Failed to process data, aborting connection %p: %m", + connection); + return MHD_NO; } } @@ -264,6 +265,7 @@ static int request_handler( const char *header; int r, code, fd; _cleanup_free_ char *hostname = NULL; + size_t len; assert(connection); assert(connection_cls); @@ -283,12 +285,27 @@ static int request_handler( if (!streq(url, "/upload")) return mhd_respond(connection, MHD_HTTP_NOT_FOUND, "Not found."); - header = MHD_lookup_connection_value(connection, - MHD_HEADER_KIND, "Content-Type"); + header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Type"); if (!header || !streq(header, "application/vnd.fdo.journal")) return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE, "Content-Type: application/vnd.fdo.journal is required."); + header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Length"); + if (!header) + return mhd_respond(connection, MHD_HTTP_LENGTH_REQUIRED, + "Content-Length header is required."); + r = safe_atozu(header, &len); + if (r < 0) + return mhd_respondf(connection, r, MHD_HTTP_LENGTH_REQUIRED, + "Content-Length: %s cannot be parsed: %m", header); + + if (len > ENTRY_SIZE_MAX) + /* When serialized, an entry of maximum size might be slightly larger, + * so this does not correspond exactly to the limit in journald. Oh well. + */ + return mhd_respondf(connection, 0, MHD_HTTP_PAYLOAD_TOO_LARGE, + "Payload larger than maximum size of %u bytes", ENTRY_SIZE_MAX); + { const union MHD_ConnectionInfo *ci; diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c index 3c0916c438..1da32c5f85 100644 --- a/src/journal-remote/journal-remote.c +++ b/src/journal-remote/journal-remote.c @@ -407,6 +407,9 @@ int journal_remote_handle_raw_source( log_debug("%zu active sources remaining", s->active); return 0; } else if (r == -E2BIG) { + log_notice("Entry with too many fields, skipped"); + return 1; + } else if (r == -ENOBUFS) { log_notice("Entry too big, skipped"); return 1; } else if (r == -EAGAIN) { diff --git a/src/journal-remote/journal-upload-journal.c b/src/journal-remote/journal-upload-journal.c index be39f7c047..7d7e7384bf 100644 --- a/src/journal-remote/journal-upload-journal.c +++ b/src/journal-remote/journal-upload-journal.c @@ -235,7 +235,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { assert_not_reached("WTF?"); } -static inline void check_update_watchdog(Uploader *u) { +static void check_update_watchdog(Uploader *u) { usec_t after; usec_t elapsed_time; diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c index 1e08fcc554..ef3556f825 100644 --- a/src/journal-remote/journal-upload.c +++ b/src/journal-remote/journal-upload.c @@ -9,6 +9,7 @@ #include "sd-daemon.h" #include "alloc-util.h" +#include "build.h" #include "conf-parser.h" #include "daemon-util.h" #include "def.h" @@ -236,7 +237,7 @@ int start_upload(Uploader *u, easy_setopt(curl, CURLOPT_VERBOSE, 1L, LOG_WARNING, ); easy_setopt(curl, CURLOPT_USERAGENT, - "systemd-journal-upload " PACKAGE_STRING, + "systemd-journal-upload " GIT_VERSION, LOG_WARNING, ); if (arg_key || startswith(u->url, "https://")) { diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c index adf40b5abd..5f5691995d 100644 --- a/src/journal-remote/microhttpd-util.c +++ b/src/journal-remote/microhttpd-util.c @@ -32,21 +32,16 @@ static int mhd_respond_internal(struct MHD_Connection *connection, const char *buffer, size_t size, enum MHD_ResponseMemoryMode mode) { - struct MHD_Response *response; - int r; - assert(connection); - response = MHD_create_response_from_buffer(size, (char*) buffer, mode); + _cleanup_(MHD_destroy_responsep) struct MHD_Response *response + = MHD_create_response_from_buffer(size, (char*) buffer, mode); if (!response) return MHD_NO; log_debug("Queueing response %u: %s", code, buffer); MHD_add_response_header(response, "Content-Type", "text/plain"); - r = MHD_queue_response(connection, code, response); - MHD_destroy_response(response); - - return r; + return MHD_queue_response(connection, code, response); } int mhd_respond(struct MHD_Connection *connection, @@ -249,7 +244,7 @@ static int get_auth_dn(gnutls_x509_crt_t client_cert, char **buf) { return 0; } -static inline void gnutls_x509_crt_deinitp(gnutls_x509_crt_t *p) { +static void gnutls_x509_crt_deinitp(gnutls_x509_crt_t *p) { gnutls_x509_crt_deinit(*p); } diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h index 364cd0f7cf..ba51d847e4 100644 --- a/src/journal-remote/microhttpd-util.h +++ b/src/journal-remote/microhttpd-util.h @@ -75,3 +75,4 @@ int check_permissions(struct MHD_Connection *connection, int *code, char **hostn int setup_gnutls_logger(char **categories); DEFINE_TRIVIAL_CLEANUP_FUNC(struct MHD_Daemon*, MHD_stop_daemon); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct MHD_Response*, MHD_destroy_response); diff --git a/src/journal/audit-type.h b/src/journal/audit-type.h index 069a883490..98e5c39420 100644 --- a/src/journal/audit-type.h +++ b/src/journal/audit-type.h @@ -4,6 +4,7 @@ #include <alloca.h> #include <stdio.h> +#include "alloc-util.h" #include "macro.h" const char *audit_type_to_string(int type); @@ -15,7 +16,7 @@ int audit_type_from_string(const char *s); const char *_s_; \ _s_ = audit_type_to_string(type); \ if (!_s_) { \ - _s_ = alloca(STRLEN("AUDIT") + DECIMAL_STR_MAX(int)); \ + _s_ = newa(char, STRLEN("AUDIT") + DECIMAL_STR_MAX(int)); \ sprintf((char*) _s_, "AUDIT%04i", type); \ } \ _s_; \ diff --git a/src/journal/cat.c b/src/journal/cat.c index a84350fbc9..9900bd2e86 100644 --- a/src/journal/cat.c +++ b/src/journal/cat.c @@ -20,6 +20,7 @@ static const char *arg_identifier = NULL; static int arg_priority = LOG_INFO; +static int arg_stderr_priority = -1; static bool arg_level_prefix = true; static int help(void) { @@ -32,11 +33,12 @@ static int help(void) { printf("%s [OPTIONS...] {COMMAND} ...\n\n" "Execute process with stdout/stderr connected to the journal.\n\n" - " -h --help Show this help\n" - " --version Show package version\n" - " -t --identifier=STRING Set syslog identifier\n" - " -p --priority=PRIORITY Set priority value (0..7)\n" - " --level-prefix=BOOL Control whether level prefix shall be parsed\n" + " -h --help Show this help\n" + " --version Show package version\n" + " -t --identifier=STRING Set syslog identifier\n" + " -p --priority=PRIORITY Set priority value (0..7)\n" + " --stderr-priority=PRIORITY Set priority value (0..7) used for stderr\n" + " --level-prefix=BOOL Control whether level prefix shall be parsed\n" "\nSee the %s for details.\n" , program_invocation_short_name , link @@ -49,15 +51,17 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, + ARG_STDERR_PRIORITY, ARG_LEVEL_PREFIX }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "identifier", required_argument, NULL, 't' }, - { "priority", required_argument, NULL, 'p' }, - { "level-prefix", required_argument, NULL, ARG_LEVEL_PREFIX }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "identifier", required_argument, NULL, 't' }, + { "priority", required_argument, NULL, 'p' }, + { "stderr-priority", required_argument, NULL, ARG_STDERR_PRIORITY }, + { "level-prefix", required_argument, NULL, ARG_LEVEL_PREFIX }, {} }; @@ -91,6 +95,13 @@ static int parse_argv(int argc, char *argv[]) { "Failed to parse priority value."); break; + case ARG_STDERR_PRIORITY: + arg_stderr_priority = log_level_from_string(optarg); + if (arg_stderr_priority < 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Failed to parse stderr priority value."); + break; + case ARG_LEVEL_PREFIX: { int k; @@ -113,7 +124,7 @@ static int parse_argv(int argc, char *argv[]) { } static int run(int argc, char *argv[]) { - _cleanup_close_ int fd = -1, saved_stderr = -1; + _cleanup_close_ int outfd = -1, errfd = -1, saved_stderr = -1; int r; log_parse_environment(); @@ -123,14 +134,21 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - fd = sd_journal_stream_fd(arg_identifier, arg_priority, arg_level_prefix); - if (fd < 0) - return log_error_errno(fd, "Failed to create stream fd: %m"); + outfd = sd_journal_stream_fd(arg_identifier, arg_priority, arg_level_prefix); + if (outfd < 0) + return log_error_errno(outfd, "Failed to create stream fd: %m"); + + if (arg_stderr_priority >= 0 && arg_stderr_priority != arg_priority) { + errfd = sd_journal_stream_fd(arg_identifier, arg_stderr_priority, arg_level_prefix); + if (errfd < 0) + return log_error_errno(errfd, "Failed to create stream fd: %m"); + } saved_stderr = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 3); - r = rearrange_stdio(STDIN_FILENO, fd, fd); /* Invalidates fd on succcess + error! */ - TAKE_FD(fd); + r = rearrange_stdio(STDIN_FILENO, outfd, errfd < 0 ? outfd : errfd); /* Invalidates fd on succcess + error! */ + TAKE_FD(outfd); + TAKE_FD(errfd); if (r < 0) return log_error_errno(r, "Failed to rearrange stdout/stderr: %m"); diff --git a/src/journal/catalog.c b/src/journal/catalog.c index 3556a101bf..4062f12c2d 100644 --- a/src/journal/catalog.c +++ b/src/journal/catalog.c @@ -46,7 +46,8 @@ typedef struct CatalogHeader { typedef struct CatalogItem { sd_id128_t id; - char language[32]; + char language[32]; /* One byte is used for termination, so the maximum allowed + * length of the string is actually 31 bytes. */ le64_t offset; } CatalogItem; @@ -556,25 +557,44 @@ static const char *find_id(void *p, sd_id128_t id) { const char *loc; loc = setlocale(LC_MESSAGES, NULL); - if (loc && loc[0] && !streq(loc, "C") && !streq(loc, "POSIX")) { - strncpy(key.language, loc, sizeof(key.language)); - key.language[strcspn(key.language, ".@")] = 0; - - f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), (comparison_fn_t) catalog_compare_func); - if (!f) { - char *e; - - e = strchr(key.language, '_'); - if (e) { - *e = 0; - f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), (comparison_fn_t) catalog_compare_func); + if (!isempty(loc) && !STR_IN_SET(loc, "C", "POSIX")) { + size_t len; + + len = strcspn(loc, ".@"); + if (len > sizeof(key.language) - 1) + log_debug("LC_MESSAGES value too long, ignoring: \"%.*s\"", (int) len, loc); + else { + strncpy(key.language, loc, len); + key.language[len] = '\0'; + + f = bsearch(&key, + (const uint8_t*) p + le64toh(h->header_size), + le64toh(h->n_items), + le64toh(h->catalog_item_size), + (comparison_fn_t) catalog_compare_func); + if (!f) { + char *e; + + e = strchr(key.language, '_'); + if (e) { + *e = 0; + f = bsearch(&key, + (const uint8_t*) p + le64toh(h->header_size), + le64toh(h->n_items), + le64toh(h->catalog_item_size), + (comparison_fn_t) catalog_compare_func); + } } } } if (!f) { zero(key.language); - f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), (comparison_fn_t) catalog_compare_func); + f = bsearch(&key, + (const uint8_t*) p + le64toh(h->header_size), + le64toh(h->n_items), + le64toh(h->catalog_item_size), + (comparison_fn_t) catalog_compare_func); } if (!f) diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h index e48260206f..d68ce3894b 100644 --- a/src/journal/journal-def.h +++ b/src/journal/journal-def.h @@ -59,16 +59,20 @@ struct ObjectHeader { uint8_t payload[]; } _packed_; -struct DataObject { - ObjectHeader object; - le64_t hash; - le64_t next_hash_offset; - le64_t next_field_offset; - le64_t entry_offset; /* the first array entry we store inline */ - le64_t entry_array_offset; - le64_t n_entries; - uint8_t payload[]; -} _packed_; +#define DataObject__contents { \ + ObjectHeader object; \ + le64_t hash; \ + le64_t next_hash_offset; \ + le64_t next_field_offset; \ + le64_t entry_offset; /* the first array entry we store inline */ \ + le64_t entry_array_offset; \ + le64_t n_entries; \ + uint8_t payload[]; \ + } + +struct DataObject DataObject__contents; +struct DataObject__packed DataObject__contents _packed_; +assert_cc(sizeof(struct DataObject) == sizeof(struct DataObject__packed)); struct FieldObject { ObjectHeader object; @@ -83,15 +87,20 @@ struct EntryItem { le64_t hash; } _packed_; -struct EntryObject { - ObjectHeader object; - le64_t seqnum; - le64_t realtime; - le64_t monotonic; - sd_id128_t boot_id; - le64_t xor_hash; - EntryItem items[]; -} _packed_; +#define EntryObject__contents { \ + ObjectHeader object; \ + le64_t seqnum; \ + le64_t realtime; \ + le64_t monotonic; \ + sd_id128_t boot_id; \ + le64_t xor_hash; \ + EntryItem items[]; \ + } + +struct EntryObject EntryObject__contents; +struct EntryObject__packed EntryObject__contents _packed_; +assert_cc(sizeof(struct EntryObject) == sizeof(struct EntryObject__packed)); + struct HashItem { le64_t head_hash_offset; @@ -166,40 +175,43 @@ enum { #define HEADER_SIGNATURE ((char[]) { 'L', 'P', 'K', 'S', 'H', 'H', 'R', 'H' }) -struct Header { - uint8_t signature[8]; /* "LPKSHHRH" */ - le32_t compatible_flags; - le32_t incompatible_flags; - uint8_t state; - uint8_t reserved[7]; - sd_id128_t file_id; - sd_id128_t machine_id; - sd_id128_t boot_id; /* last writer */ - sd_id128_t seqnum_id; - le64_t header_size; - le64_t arena_size; - le64_t data_hash_table_offset; - le64_t data_hash_table_size; - le64_t field_hash_table_offset; - le64_t field_hash_table_size; - le64_t tail_object_offset; - le64_t n_objects; - le64_t n_entries; - le64_t tail_entry_seqnum; - le64_t head_entry_seqnum; - le64_t entry_array_offset; - le64_t head_entry_realtime; - le64_t tail_entry_realtime; - le64_t tail_entry_monotonic; - /* Added in 187 */ - le64_t n_data; - le64_t n_fields; - /* Added in 189 */ - le64_t n_tags; - le64_t n_entry_arrays; - - /* Size: 240 */ -} _packed_; +#define struct_Header__contents { \ + uint8_t signature[8]; /* "LPKSHHRH" */ \ + le32_t compatible_flags; \ + le32_t incompatible_flags; \ + uint8_t state; \ + uint8_t reserved[7]; \ + sd_id128_t file_id; \ + sd_id128_t machine_id; \ + sd_id128_t boot_id; /* last writer */ \ + sd_id128_t seqnum_id; \ + le64_t header_size; \ + le64_t arena_size; \ + le64_t data_hash_table_offset; \ + le64_t data_hash_table_size; \ + le64_t field_hash_table_offset; \ + le64_t field_hash_table_size; \ + le64_t tail_object_offset; \ + le64_t n_objects; \ + le64_t n_entries; \ + le64_t tail_entry_seqnum; \ + le64_t head_entry_seqnum; \ + le64_t entry_array_offset; \ + le64_t head_entry_realtime; \ + le64_t tail_entry_realtime; \ + le64_t tail_entry_monotonic; \ + /* Added in 187 */ \ + le64_t n_data; \ + le64_t n_fields; \ + /* Added in 189 */ \ + le64_t n_tags; \ + le64_t n_entry_arrays; \ + } + +struct Header struct_Header__contents; +struct Header__packed struct_Header__contents _packed_; +assert_cc(sizeof(struct Header) == sizeof(struct Header__packed)); +assert_cc(sizeof(struct Header) == 240); #define FSS_HEADER_SIGNATURE ((char[]) { 'K', 'S', 'H', 'H', 'R', 'H', 'L', 'P' }) diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c index 87056435fc..8618454131 100644 --- a/src/journal/journal-send.c +++ b/src/journal/journal-send.c @@ -30,7 +30,7 @@ const char *_func = (func); \ char **_f = &(f); \ _fl = strlen(_func) + 1; \ - *_f = alloca(_fl + 10); \ + *_f = newa(char, _fl + 10); \ memcpy(*_f, "CODE_FUNC=", 10); \ memcpy(*_f + 10, _func, _fl); \ } while (false) @@ -403,7 +403,7 @@ _public_ int sd_journal_stream_fd(const char *identifier, int priority, int leve identifier = strempty(identifier); l = strlen(identifier); - header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2); + header = newa(char, l + 1 + 1 + 2 + 2 + 2 + 2 + 2); memcpy(header, identifier, l); header[l++] = '\n'; diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c index 345e43ef44..accbad4180 100644 --- a/src/journal/journald-audit.c +++ b/src/journal/journald-audit.c @@ -162,7 +162,7 @@ static int map_generic_field(const char *prefix, const char **p, struct iovec ** if (e <= *p || e >= *p + 16) return 0; - c = alloca(strlen(prefix) + (e - *p) + 2); + c = newa(char, strlen(prefix) + (e - *p) + 2); t = stpcpy(c, prefix); for (f = *p; f < e; f++) { diff --git a/src/journal/journald-context.c b/src/journal/journald-context.c index 8253a45128..7c51f2f633 100644 --- a/src/journal/journald-context.c +++ b/src/journal/journald-context.c @@ -16,6 +16,7 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "procfs-util.h" #include "string-util.h" #include "syslog-util.h" #include "unaligned.h" @@ -60,7 +61,37 @@ /* Keep at most 16K entries in the cache. (Note though that this limit may be violated if enough streams pin entries in * the cache, in which case we *do* permit this limit to be breached. That's safe however, as the number of stream * clients itself is limited.) */ -#define CACHE_MAX (16*1024) +#define CACHE_MAX_FALLBACK 128U +#define CACHE_MAX_MAX (16*1024U) +#define CACHE_MAX_MIN 64U + +static size_t cache_max(void) { + static size_t cached = -1; + + if (cached == (size_t) -1) { + uint64_t mem_total; + int r; + + r = procfs_memory_get(&mem_total, NULL); + if (r < 0) { + log_warning_errno(r, "Cannot query /proc/meminfo for MemTotal: %m"); + cached = CACHE_MAX_FALLBACK; + } else { + /* Cache entries are usually a few kB, but the process cmdline is controlled by the + * user and can be up to _SC_ARG_MAX, usually 2MB. Let's say that approximately up to + * 1/8th of memory may be used by the cache. + * + * In the common case, this formula gives 64 cache entries for each GB of RAM. + */ + long l = sysconf(_SC_ARG_MAX); + assert(l > 0); + + cached = CLAMP(mem_total / 8 / (uint64_t) l, CACHE_MAX_MIN, CACHE_MAX_MAX); + } + } + + return cached; +} static int client_context_compare(const void *a, const void *b) { const ClientContext *x = a, *y = b; @@ -246,7 +277,7 @@ static int client_context_read_label( } static int client_context_read_cgroup(Server *s, ClientContext *c, const char *unit_id) { - char *t = NULL; + _cleanup_free_ char *t = NULL; int r; assert(c); @@ -254,10 +285,9 @@ static int client_context_read_cgroup(Server *s, ClientContext *c, const char *u /* Try to acquire the current cgroup path */ r = cg_pid_get_path_shifted(c->pid, s->cgroup_root, &t); if (r < 0 || empty_or_root(t)) { - /* We use the unit ID passed in as fallback if we have nothing cached yet and cg_pid_get_path_shifted() * failed or process is running in a root cgroup. Zombie processes are automatically migrated to root cgroup - * on cgroupsv1 and we want to be able to map log messages from them too. */ + * on cgroup v1 and we want to be able to map log messages from them too. */ if (unit_id && !c->unit) { c->unit = strdup(unit_id); if (c->unit) @@ -268,10 +298,8 @@ static int client_context_read_cgroup(Server *s, ClientContext *c, const char *u } /* Let's shortcut this if the cgroup path didn't change */ - if (streq_ptr(c->cgroup, t)) { - free(t); + if (streq_ptr(c->cgroup, t)) return 0; - } free_and_replace(c->cgroup, t); @@ -553,15 +581,39 @@ refresh: } static void client_context_try_shrink_to(Server *s, size_t limit) { + ClientContext *c; + usec_t t; + assert(s); + /* Flush any cache entries for PIDs that have already moved on. Don't do this + * too often, since it's a slow process. */ + t = now(CLOCK_MONOTONIC); + if (s->last_cache_pid_flush + MAX_USEC < t) { + unsigned n = prioq_size(s->client_contexts_lru), idx = 0; + + /* We do a number of iterations based on the initial size of the prioq. When we remove an + * item, a new item is moved into its places, and items to the right might be reshuffled. + */ + for (unsigned i = 0; i < n; i++) { + c = prioq_peek_by_index(s->client_contexts_lru, idx); + + assert(c->n_ref == 0); + + if (!pid_is_unwaited(c->pid)) + client_context_free(s, c); + else + idx ++; + } + + s->last_cache_pid_flush = t; + } + /* Bring the number of cache entries below the indicated limit, so that we can create a new entry without * breaching the limit. Note that we only flush out entries that aren't pinned here. This means the number of * cache entries may very well grow beyond the limit, if all entries stored remain pinned. */ while (hashmap_size(s->client_contexts) > limit) { - ClientContext *c; - c = prioq_pop(s->client_contexts_lru); if (!c) break; /* All remaining entries are pinned, give up */ @@ -630,7 +682,7 @@ static int client_context_get_internal( return 0; } - client_context_try_shrink_to(s, CACHE_MAX-1); + client_context_try_shrink_to(s, cache_max()-1); r = client_context_new(s, pid, &c); if (r < 0) diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index e86178ed77..221188db16 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -110,7 +110,7 @@ static int server_process_entry( int priority = LOG_INFO; pid_t object_pid = 0; const char *p; - int r = 0; + int r = 1; p = buffer; @@ -122,8 +122,7 @@ static int server_process_entry( if (!e) { /* Trailing noise, let's ignore it, and flush what we collected */ log_debug("Received message with trailing noise, ignoring."); - r = 1; /* finish processing of the message */ - break; + break; /* finish processing of the message */ } if (e == p) { @@ -133,14 +132,17 @@ static int server_process_entry( } if (IN_SET(*p, '.', '#')) { - /* Ignore control commands for now, and - * comments too. */ + /* Ignore control commands for now, and comments too. */ *remaining -= (e - p) + 1; p = e + 1; continue; } /* A property follows */ + if (n > ENTRY_FIELD_COUNT_MAX) { + log_debug("Received an entry that has more than " STRINGIFY(ENTRY_FIELD_COUNT_MAX) " fields, ignoring entry."); + goto finish; + } /* n existing properties, 1 new, +1 for _TRANSPORT */ if (!GREEDY_REALLOC(iovec, m, @@ -148,7 +150,7 @@ static int server_process_entry( N_IOVEC_META_FIELDS + N_IOVEC_OBJECT_FIELDS + client_context_extra_fields_n_iovec(context))) { r = log_oom(); - break; + goto finish; } q = memchr(p, '=', e - p); @@ -157,6 +159,16 @@ static int server_process_entry( size_t l; l = e - p; + if (l > DATA_SIZE_MAX) { + log_debug("Received text block of %zu bytes is too large, ignoring entry.", l); + goto finish; + } + + if (entry_size + l + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */ + log_debug("Entry is too big (%zu bytes after processing %zu entries), ignoring entry.", + entry_size + l, n + 1); + goto finish; + } /* If the field name starts with an underscore, skip the variable, since that indicates * a trusted field */ @@ -174,7 +186,7 @@ static int server_process_entry( p = e + 1; continue; } else { - uint64_t l; + uint64_t l, total; char *k; if (*remaining < e - p + 1 + sizeof(uint64_t) + 1) { @@ -183,10 +195,16 @@ static int server_process_entry( } l = unaligned_read_le64(e + 1); - if (l > DATA_SIZE_MAX) { - log_debug("Received binary data block of %"PRIu64" bytes is too large, ignoring.", l); - break; + log_debug("Received binary data block of %"PRIu64" bytes is too large, ignoring entry.", l); + goto finish; + } + + total = (e - p) + 1 + l; + if (entry_size + total + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */ + log_debug("Entry is too big (%"PRIu64"bytes after processing %zu fields), ignoring.", + entry_size + total, n + 1); + goto finish; } if ((uint64_t) *remaining < e - p + 1 + sizeof(uint64_t) + l + 1 || @@ -195,7 +213,7 @@ static int server_process_entry( break; } - k = malloc((e - p) + 1 + l); + k = malloc(total); if (!k) { log_oom(); break; @@ -223,15 +241,8 @@ static int server_process_entry( } } - if (n <= 0) { - r = 1; + if (n <= 0) goto finish; - } - - if (!client_context_test_priority(context, priority)) { - r = 0; - goto finish; - } tn = n++; iovec[tn] = IOVEC_MAKE_STRING("_TRANSPORT=journal"); @@ -242,6 +253,11 @@ static int server_process_entry( goto finish; } + r = 0; /* Success, we read the message. */ + + if (!client_context_test_priority(context, priority)) + goto finish; + if (message) { if (s->forward_to_syslog) server_forward_syslog(s, syslog_fixup_facility(priority), identifier, message, ucred, tv); @@ -313,15 +329,13 @@ void server_process_native_file( bool sealed; int r; - /* Data is in the passed fd, since it didn't fit in a - * datagram. */ + /* Data is in the passed fd, probably it didn't fit in a datagram. */ assert(s); assert(fd >= 0); /* If it's a memfd, check if it is sealed. If so, we can just - * use map it and use it, and do not need to copy the data - * out. */ + * mmap it and use it, and do not need to copy the data out. */ sealed = memfd_get_sealed(fd) > 0; if (!sealed && (!ucred || ucred->uid != 0)) { @@ -362,8 +376,10 @@ void server_process_native_file( if (st.st_size <= 0) return; - if (st.st_size > ENTRY_SIZE_MAX) { - log_error("File passed too large. Ignoring."); + /* When !sealed, set a lower memory limit. We have to read the file, + * effectively doubling memory use. */ + if (st.st_size > ENTRY_SIZE_MAX / (sealed ? 1 : 2)) { + log_error("File passed too large (%"PRIu64" bytes). Ignoring.", (uint64_t) st.st_size); return; } @@ -388,7 +404,7 @@ void server_process_native_file( ssize_t n; if (fstatvfs(fd, &vfs) < 0) { - log_error_errno(errno, "Failed to stat file system of passed file, ignoring: %m"); + log_error_errno(errno, "Failed to stat file system of passed file, not processing it: %m"); return; } @@ -398,7 +414,7 @@ void server_process_native_file( * https://github.com/systemd/systemd/issues/1822 */ if (vfs.f_flag & ST_MANDLOCK) { - log_error("Received file descriptor from file system with mandatory locking enabled, refusing."); + log_error("Received file descriptor from file system with mandatory locking enabled, not processing it."); return; } @@ -411,13 +427,13 @@ void server_process_native_file( * and so is SMB. */ r = fd_nonblock(fd, true); if (r < 0) { - log_error_errno(r, "Failed to make fd non-blocking, ignoring: %m"); + log_error_errno(r, "Failed to make fd non-blocking, not processing it: %m"); return; } /* The file is not sealed, we can't map the file here, since * clients might then truncate it and trigger a SIGBUS for - * us. So let's stupidly read it */ + * us. So let's stupidly read it. */ p = malloc(st.st_size); if (!p) { diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 434325c179..2a960ebb3e 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -905,6 +905,7 @@ static void dispatch_message_real( pid_t object_pid) { char source_time[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)]; + _cleanup_free_ char *cmdline1 = NULL, *cmdline2 = NULL; uid_t journal_uid; ClientContext *o; @@ -921,20 +922,23 @@ static void dispatch_message_real( IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->uid, uid_t, uid_is_valid, UID_FMT, "_UID"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->gid, gid_t, gid_is_valid, GID_FMT, "_GID"); - IOVEC_ADD_STRING_FIELD(iovec, n, c->comm, "_COMM"); - IOVEC_ADD_STRING_FIELD(iovec, n, c->exe, "_EXE"); - IOVEC_ADD_STRING_FIELD(iovec, n, c->cmdline, "_CMDLINE"); - IOVEC_ADD_STRING_FIELD(iovec, n, c->capeff, "_CAP_EFFECTIVE"); + IOVEC_ADD_STRING_FIELD(iovec, n, c->comm, "_COMM"); /* At most TASK_COMM_LENGTH (16 bytes) */ + IOVEC_ADD_STRING_FIELD(iovec, n, c->exe, "_EXE"); /* A path, so at most PATH_MAX (4096 bytes) */ - IOVEC_ADD_SIZED_FIELD(iovec, n, c->label, c->label_size, "_SELINUX_CONTEXT"); + if (c->cmdline) + /* At most _SC_ARG_MAX (2MB usually), which is too much to put on stack. + * Let's use a heap allocation for this one. */ + cmdline1 = set_iovec_string_field(iovec, &n, "_CMDLINE=", c->cmdline); + IOVEC_ADD_STRING_FIELD(iovec, n, c->capeff, "_CAP_EFFECTIVE"); /* Read from /proc/.../status */ + IOVEC_ADD_SIZED_FIELD(iovec, n, c->label, c->label_size, "_SELINUX_CONTEXT"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->auditid, uint32_t, audit_session_is_valid, "%" PRIu32, "_AUDIT_SESSION"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->loginuid, uid_t, uid_is_valid, UID_FMT, "_AUDIT_LOGINUID"); - IOVEC_ADD_STRING_FIELD(iovec, n, c->cgroup, "_SYSTEMD_CGROUP"); + IOVEC_ADD_STRING_FIELD(iovec, n, c->cgroup, "_SYSTEMD_CGROUP"); /* A path */ IOVEC_ADD_STRING_FIELD(iovec, n, c->session, "_SYSTEMD_SESSION"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->owner_uid, uid_t, uid_is_valid, UID_FMT, "_SYSTEMD_OWNER_UID"); - IOVEC_ADD_STRING_FIELD(iovec, n, c->unit, "_SYSTEMD_UNIT"); + IOVEC_ADD_STRING_FIELD(iovec, n, c->unit, "_SYSTEMD_UNIT"); /* Unit names are bounded by UNIT_NAME_MAX */ IOVEC_ADD_STRING_FIELD(iovec, n, c->user_unit, "_SYSTEMD_USER_UNIT"); IOVEC_ADD_STRING_FIELD(iovec, n, c->slice, "_SYSTEMD_SLICE"); IOVEC_ADD_STRING_FIELD(iovec, n, c->user_slice, "_SYSTEMD_USER_SLICE"); @@ -955,13 +959,14 @@ static void dispatch_message_real( IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->uid, uid_t, uid_is_valid, UID_FMT, "OBJECT_UID"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->gid, gid_t, gid_is_valid, GID_FMT, "OBJECT_GID"); + /* See above for size limits, only ->cmdline may be large, so use a heap allocation for it. */ IOVEC_ADD_STRING_FIELD(iovec, n, o->comm, "OBJECT_COMM"); IOVEC_ADD_STRING_FIELD(iovec, n, o->exe, "OBJECT_EXE"); - IOVEC_ADD_STRING_FIELD(iovec, n, o->cmdline, "OBJECT_CMDLINE"); - IOVEC_ADD_STRING_FIELD(iovec, n, o->capeff, "OBJECT_CAP_EFFECTIVE"); + if (o->cmdline) + cmdline2 = set_iovec_string_field(iovec, &n, "OBJECT_CMDLINE=", o->cmdline); + IOVEC_ADD_STRING_FIELD(iovec, n, o->capeff, "OBJECT_CAP_EFFECTIVE"); IOVEC_ADD_SIZED_FIELD(iovec, n, o->label, o->label_size, "OBJECT_SELINUX_CONTEXT"); - IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->auditid, uint32_t, audit_session_is_valid, "%" PRIu32, "OBJECT_AUDIT_SESSION"); IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->loginuid, uid_t, uid_is_valid, UID_FMT, "OBJECT_AUDIT_LOGINUID"); @@ -1276,8 +1281,7 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void return log_error_errno(errno, "recvmsg() failed: %m"); } - CMSG_FOREACH(cmsg, &msghdr) { - + CMSG_FOREACH(cmsg, &msghdr) if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) @@ -1295,7 +1299,6 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void fds = (int*) CMSG_DATA(cmsg); n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); } - } /* And a trailing NUL, just in case */ s->buffer[n] = 0; diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h index 6d4847b0cd..3f6b42ddd5 100644 --- a/src/journal/journald-server.h +++ b/src/journal/journald-server.h @@ -161,6 +161,8 @@ struct Server { Hashmap *client_contexts; Prioq *client_contexts_lru; + usec_t last_cache_pid_flush; + ClientContext *my_context; /* the context of journald itself */ ClientContext *pid1_context; /* the context of PID 1 */ }; diff --git a/src/journal/journald-wall.h b/src/journal/journald-wall.h index d081c8254c..b73059af46 100644 --- a/src/journal/journald-wall.h +++ b/src/journal/journald-wall.h @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once - #include "journald-server.h" void server_forward_wall(Server *s, int priority, const char *identifier, const char *message, const struct ucred *ucred); diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c index 90549f1c9f..0dc453e709 100644 --- a/src/journal/mmap-cache.c +++ b/src/journal/mmap-cache.c @@ -132,7 +132,7 @@ static void window_free(Window *w) { free(w); } -_pure_ static inline bool window_matches(Window *w, int prot, uint64_t offset, size_t size) { +_pure_ static bool window_matches(Window *w, int prot, uint64_t offset, size_t size) { assert(w); assert(size > 0); diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index b5ff5b64f3..0f996283cd 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -36,7 +36,6 @@ #include "process-util.h" #include "replace-var.h" #include "stat-util.h" -#include "stat-util.h" #include "stdio-util.h" #include "string-util.h" #include "strv.h" diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install index 39ec8a69c6..75dd5a1b7d 100644 --- a/src/kernel-install/90-loaderentry.install +++ b/src/kernel-install/90-loaderentry.install @@ -6,6 +6,7 @@ COMMAND="$1" KERNEL_VERSION="$2" BOOT_DIR_ABS="$3" KERNEL_IMAGE="$4" +INITRD_OPTIONS_START="5" if ! [[ $KERNEL_INSTALL_MACHINE_ID ]]; then exit 0 @@ -82,6 +83,24 @@ cp "$KERNEL_IMAGE" "$BOOT_DIR_ABS/linux" && exit 1 } +INITRD_OPTIONS=( "${@:${INITRD_OPTIONS_START}}" ) + +for initrd in "${INITRD_OPTIONS[@]}"; do + if [[ -f "${initrd}" ]]; then + initrd_basename="$(basename ${initrd})" + cp "${initrd}" "$BOOT_DIR_ABS/${initrd_basename}" && + chown root:root "$BOOT_DIR_ABS/${initrd_basename}" && + chmod 0644 "$BOOT_DIR_ABS/${initrd_basename}" || { + echo "Could not copy '${initrd}' to '$BOOT_DIR_ABS/${initrd_basename}'." >&2 + exit 1 + } + fi +done + +# If no initrd option is supplied, fallback to "initrd" which is +# the name used by dracut when generating it in its kernel-install hook +[[ ${#INITRD_OPTIONS[@]} == 0 ]] && INITRD_OPTIONS=( initrd ) + mkdir -p "${LOADER_ENTRY%/*}" || { echo "Could not create loader entry directory '${LOADER_ENTRY%/*}'." >&2 exit 1 @@ -93,8 +112,10 @@ mkdir -p "${LOADER_ENTRY%/*}" || { echo "machine-id $MACHINE_ID" echo "options ${BOOT_OPTIONS[*]}" echo "linux $BOOT_DIR/linux" - [[ -f $BOOT_DIR_ABS/initrd ]] && \ - echo "initrd $BOOT_DIR/initrd" + for initrd in "${INITRD_OPTIONS[@]}"; do + [[ -f $BOOT_DIR_ABS/$(basename ${initrd}) ]] && \ + echo "initrd $BOOT_DIR/$(basename ${initrd})" + done : } > "$LOADER_ENTRY" || { echo "Could not create loader entry '$LOADER_ENTRY'." >&2 diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install index 732d584bbe..b85c7c557e 100644 --- a/src/kernel-install/kernel-install +++ b/src/kernel-install/kernel-install @@ -24,7 +24,7 @@ SKIP_REMAINING=77 usage() { echo "Usage:" - echo " $0 add KERNEL-VERSION KERNEL-IMAGE" + echo " $0 add KERNEL-VERSION KERNEL-IMAGE [INITRD-FILE ...]" echo " $0 remove KERNEL-VERSION" } @@ -65,9 +65,12 @@ done if [[ "${0##*/}" == 'installkernel' ]]; then COMMAND='add' + # make install doesn't pass any parameter wrt initrd handling + INITRD_OPTIONS=() else COMMAND="$1" shift + INITRD_OPTIONS=( "${@:3}" ) fi KERNEL_VERSION="$1" @@ -123,7 +126,7 @@ case $COMMAND in for f in "${PLUGINS[@]}"; do if [[ -x $f ]]; then - "$f" add "$KERNEL_VERSION" "$BOOT_DIR_ABS" "$KERNEL_IMAGE" + "$f" add "$KERNEL_VERSION" "$BOOT_DIR_ABS" "$KERNEL_IMAGE" "${INITRD_OPTIONS[@]}" x=$? if [[ $x == $SKIP_REMAINING ]]; then ret=0 diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 07496adaa3..04bf64cce5 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -11,6 +11,7 @@ #include "network-internal.h" #include "siphash24.h" #include "sparse-endian.h" +#include "stdio-util.h" #include "virt.h" #define SYSTEMD_PEN 43793 @@ -169,10 +170,10 @@ int dhcp_identifier_set_iaid( if (detect_container() <= 0) { /* not in a container, udev will be around */ - char ifindex_str[2 + DECIMAL_STR_MAX(int)]; + char ifindex_str[1 + DECIMAL_STR_MAX(int)]; int r; - sprintf(ifindex_str, "n%d", ifindex); + xsprintf(ifindex_str, "n%d", ifindex); if (sd_device_new_from_device_id(&device, ifindex_str) >= 0) { r = sd_device_get_is_initialized(device); if (r < 0) @@ -195,7 +196,7 @@ int dhcp_identifier_set_iaid( if (legacy_unstable_byteorder) /* for historical reasons (a bug), the bits were swapped and thus - * the result was endianness dependant. Preserve that behavior. */ + * the result was endianness dependent. Preserve that behavior. */ id32 = __bswap_32(id32); else /* the fixed behavior returns a stable byte order. Since LE is expected diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c index 43fc8e03c0..f6db62594d 100644 --- a/src/libsystemd-network/lldp-neighbor.c +++ b/src/libsystemd-network/lldp-neighbor.c @@ -691,7 +691,7 @@ _public_ int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type) { return type == k; } -_public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[3], uint8_t *subtype) { +_public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t *subtype) { const uint8_t *d; size_t length; int r; @@ -720,7 +720,7 @@ _public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[3], u return 0; } -_public_ int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[3], uint8_t subtype) { +_public_ int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t subtype) { uint8_t k[3], st; int r; diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index b3b134d650..0348e7fa9d 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -52,7 +52,7 @@ int net_get_unique_predictable_data(sd_device *device, uint64_t *result) { l = strlen(name); sz = sizeof(sd_id128_t) + l; - v = alloca(sz); + v = newa(uint8_t, sz); /* fetch some persistent data unique to this machine */ r = sd_id128_get_machine((sd_id128_t*) v); diff --git a/src/libsystemd-network/radv-internal.h b/src/libsystemd-network/radv-internal.h index cd44352307..66f49ed44e 100644 --- a/src/libsystemd-network/radv-internal.h +++ b/src/libsystemd-network/radv-internal.h @@ -63,19 +63,34 @@ struct sd_radv { struct sd_radv_opt_dns *dnssl; }; +#define radv_prefix_opt__contents { \ + uint8_t type; \ + uint8_t length; \ + uint8_t prefixlen; \ + uint8_t flags; \ + be32_t valid_lifetime; \ + be32_t preferred_lifetime; \ + uint32_t reserved; \ + struct in6_addr in6_addr; \ +} + +struct radv_prefix_opt radv_prefix_opt__contents; + +/* We need the opt substructure to be packed, because we use it in send(). But + * if we use _packed_, this means that the structure cannot be used directly in + * normal code in general, because the fields might not be properly aligned. + * But in this particular case, the structure is defined in a way that gives + * proper alignment, even without the explicit _packed_ attribute. To appease + * the compiler we use the "unpacked" structure, but we also verify that + * structure contains no holes, so offsets are the same when _packed_ is used. + */ +struct radv_prefix_opt__packed radv_prefix_opt__contents _packed_; +assert_cc(sizeof(struct radv_prefix_opt) == sizeof(struct radv_prefix_opt__packed)); + struct sd_radv_prefix { unsigned n_ref; - struct { - uint8_t type; - uint8_t length; - uint8_t prefixlen; - uint8_t flags; - be32_t valid_lifetime; - be32_t preferred_lifetime; - uint32_t reserved; - struct in6_addr in6_addr; - } _packed_ opt; + struct radv_prefix_opt opt; LIST_FIELDS(struct sd_radv_prefix, prefix); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 2d7ffd22ca..35fc88ef91 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -118,19 +118,19 @@ static const uint8_t default_req_opts[] = { */ /* NOTE: using PRL options that Windows 10 RFC7844 implementation uses */ static const uint8_t default_req_opts_anonymize[] = { - SD_DHCP_OPTION_SUBNET_MASK, /* 1 */ - SD_DHCP_OPTION_ROUTER, /* 3 */ - SD_DHCP_OPTION_DOMAIN_NAME_SERVER, /* 6 */ - SD_DHCP_OPTION_DOMAIN_NAME, /* 15 */ - SD_DHCP_OPTION_ROUTER_DISCOVER, /* 31 */ - SD_DHCP_OPTION_STATIC_ROUTE, /* 33 */ - SD_DHCP_OPTION_VENDOR_SPECIFIC, /* 43 */ - SD_DHCP_OPTION_NETBIOS_NAMESERVER, /* 44 */ - SD_DHCP_OPTION_NETBIOS_NODETYPE, /* 46 */ - SD_DHCP_OPTION_NETBIOS_SCOPE, /* 47 */ - SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, /* 121 */ - SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE, /* 249 */ - SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY, /* 252 */ + SD_DHCP_OPTION_SUBNET_MASK, /* 1 */ + SD_DHCP_OPTION_ROUTER, /* 3 */ + SD_DHCP_OPTION_DOMAIN_NAME_SERVER, /* 6 */ + SD_DHCP_OPTION_DOMAIN_NAME, /* 15 */ + SD_DHCP_OPTION_ROUTER_DISCOVER, /* 31 */ + SD_DHCP_OPTION_STATIC_ROUTE, /* 33 */ + SD_DHCP_OPTION_VENDOR_SPECIFIC, /* 43 */ + SD_DHCP_OPTION_NETBIOS_NAMESERVER, /* 44 */ + SD_DHCP_OPTION_NETBIOS_NODETYPE, /* 46 */ + SD_DHCP_OPTION_NETBIOS_SCOPE, /* 47 */ + SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, /* 121 */ + SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE, /* 249 */ + SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY, /* 252 */ }; static int client_receive_message_raw( @@ -353,9 +353,9 @@ static int dhcp_client_set_iaid_duid_internal( size_t len; assert_return(client, -EINVAL); - assert_return(duid_len == 0 || duid != NULL, -EINVAL); + assert_return(duid_len == 0 || duid, -EINVAL); - if (duid != NULL) { + if (duid) { r = dhcp_validate_duid_len(duid_type, duid_len, true); if (r < 0) return r; @@ -377,7 +377,7 @@ static int dhcp_client_set_iaid_duid_internal( } } - if (duid != NULL) { + if (duid) { client->client_id.ns.duid.type = htobe16(duid_type); memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len); len = sizeof(client->client_id.ns.duid.type) + duid_len; @@ -1795,7 +1795,7 @@ static int client_receive_message_raw( } else if ((size_t)len < sizeof(DHCPPacket)) return 0; - CMSG_FOREACH(cmsg, &msg) { + CMSG_FOREACH(cmsg, &msg) if (cmsg->cmsg_level == SOL_PACKET && cmsg->cmsg_type == PACKET_AUXDATA && cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) { @@ -1804,7 +1804,6 @@ static int client_receive_message_raw( checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY); break; } - } r = dhcp_packet_verify_headers(packet, len, checksum, client->port); if (r < 0) diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index 79b2ea8bf2..32c20b1e4a 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -34,7 +34,6 @@ static void ndisc_callback(sd_ndisc *ndisc, sd_ndisc_event event, sd_ndisc_route assert(ndisc); assert(event >= 0 && event < _SD_NDISC_EVENT_MAX); - if (!ndisc->callback) { log_ndisc("Received '%s' event.", ndisc_event_to_string(event)); return; diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c index cb4545d901..b6c896f0a1 100644 --- a/src/libsystemd-network/test-lldp.c +++ b/src/libsystemd-network/test-lldp.c @@ -192,6 +192,8 @@ static void test_receive_oui_packet(sd_event *e) { 0x01, 0x02, 0xfe, 0x09, 0x00, 0x80, 0xc2, 0x07, /* Link aggregation: status 1, ID 0x00140012 */ 0x01, 0x00, 0x14, 0x00, 0x12, + 0xfe, 0x07, 0x00, 0x12, 0x0f, 0x02, /* 802.3 Power via MDI: PSE, MDI enabled */ + 0x07, 0x01, 0x00, 0x00, 0x00 /* End of LLDPDU */ }; @@ -220,6 +222,8 @@ static void test_receive_oui_packet(sd_event *e) { assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION) > 0); assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_3, SD_LLDP_OUI_802_3_SUBTYPE_POWER_VIA_MDI) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_END) > 0); assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) == 0); diff --git a/src/libsystemd/libsystemd.pc.in b/src/libsystemd/libsystemd.pc.in index c861905b67..a010dea2e9 100644 --- a/src/libsystemd/libsystemd.pc.in +++ b/src/libsystemd/libsystemd.pc.in @@ -14,7 +14,7 @@ includedir=@includedir@ Name: systemd Description: systemd Library -URL: @PACKAGE_URL@ -Version: @PACKAGE_VERSION@ +URL: @PROJECT_URL@ +Version: @PROJECT_VERSION@ Libs: -L${libdir} -lsystemd Cflags: -I${includedir} diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 96e6347795..a6748ceb20 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -671,3 +671,8 @@ global: sd_event_source_get_floating; sd_event_source_set_floating; } LIBSYSTEMD_239; + +LIBSYSTEMD_241 { +global: + sd_bus_close_unref; +} LIBSYSTEMD_240; diff --git a/src/libsystemd/meson.build b/src/libsystemd/meson.build index 05d4ea0e7f..67add387e6 100644 --- a/src/libsystemd/meson.build +++ b/src/libsystemd/meson.build @@ -109,9 +109,8 @@ libsystemd_static = static_library( libsystemd_sym = 'src/libsystemd/libsystemd.sym' -libsystemd_pc = configure_file( +configure_file( input : 'libsystemd.pc.in', output : 'libsystemd.pc', - configuration : substs) -install_data(libsystemd_pc, - install_dir : pkgconfiglibdir) + configuration : substs, + install_dir : pkgconfiglibdir == 'no' ? '' : pkgconfiglibdir) diff --git a/src/libsystemd/sd-bus/bus-dump.h b/src/libsystemd/sd-bus/bus-dump.h index 373a86dd4f..a1b67c6b14 100644 --- a/src/libsystemd/sd-bus/bus-dump.h +++ b/src/libsystemd/sd-bus/bus-dump.h @@ -7,8 +7,8 @@ #include "sd-bus.h" enum { - BUS_MESSAGE_DUMP_WITH_HEADER = 1, - BUS_MESSAGE_DUMP_SUBTREE_ONLY = 2, + BUS_MESSAGE_DUMP_WITH_HEADER = 1 << 0, + BUS_MESSAGE_DUMP_SUBTREE_ONLY = 1 << 1, }; int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags); diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c index ad135406f6..9642de10c3 100644 --- a/src/libsystemd/sd-bus/bus-match.c +++ b/src/libsystemd/sd-bus/bus-match.c @@ -49,11 +49,11 @@ * ` BUS_MATCH_LEAF: E */ -static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) { +static bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) { return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_HAS_LAST; } -static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) { +static bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) { return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) || (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST) || (t >= BUS_MATCH_ARG_HAS && t <= BUS_MATCH_ARG_HAS_LAST); diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index d0538104ae..58329f3fe7 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -1149,7 +1149,7 @@ static int object_manager_serialize_path_and_fallbacks( return 0; /* Second, add fallback vtables registered for any of the prefixes */ - prefix = alloca(strlen(path) + 1); + prefix = newa(char, strlen(path) + 1); OBJECT_PATH_FOREACH_PREFIX(prefix, path) { r = object_manager_serialize_path(bus, reply, prefix, path, true, error); if (r < 0) @@ -1500,7 +1500,7 @@ static int bus_find_parent_object_manager(sd_bus *bus, struct node **out, const if (!n) { char *prefix; - prefix = alloca(strlen(path) + 1); + prefix = newa(char, strlen(path) + 1); OBJECT_PATH_FOREACH_PREFIX(prefix, path) { n = hashmap_get(bus->nodes, prefix); if (n) @@ -2114,7 +2114,7 @@ _public_ int sd_bus_emit_properties_changed_strv( if (bus->nodes_modified) continue; - prefix = alloca(strlen(path) + 1); + prefix = newa(char, strlen(path) + 1); OBJECT_PATH_FOREACH_PREFIX(prefix, path) { r = emit_properties_changed_on_interface(bus, prefix, path, interface, true, &found_interface, names); if (r != 0) @@ -2291,7 +2291,7 @@ static int object_added_append_all(sd_bus *bus, sd_bus_message *m, const char *p if (bus->nodes_modified) return 0; - prefix = alloca(strlen(path) + 1); + prefix = newa(char, strlen(path) + 1); OBJECT_PATH_FOREACH_PREFIX(prefix, path) { r = object_added_append_all_prefix(bus, m, s, prefix, path, true); if (r < 0) @@ -2462,7 +2462,7 @@ static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char if (bus->nodes_modified) return 0; - prefix = alloca(strlen(path) + 1); + prefix = newa(char, strlen(path) + 1); OBJECT_PATH_FOREACH_PREFIX(prefix, path) { r = object_removed_append_all_prefix(bus, m, s, prefix, path, true); if (r < 0) @@ -2626,7 +2626,7 @@ static int interfaces_added_append_one( if (bus->nodes_modified) return 0; - prefix = alloca(strlen(path) + 1); + prefix = newa(char, strlen(path) + 1); OBJECT_PATH_FOREACH_PREFIX(prefix, path) { r = interfaces_added_append_one_prefix(bus, m, prefix, path, interface, true); if (r != 0) diff --git a/src/libsystemd/sd-bus/bus-protocol.h b/src/libsystemd/sd-bus/bus-protocol.h index a5f4724aa9..d01fd8e6a3 100644 --- a/src/libsystemd/sd-bus/bus-protocol.h +++ b/src/libsystemd/sd-bus/bus-protocol.h @@ -54,9 +54,9 @@ enum { /* Flags */ enum { - BUS_MESSAGE_NO_REPLY_EXPECTED = 1, - BUS_MESSAGE_NO_AUTO_START = 2, - BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION = 4, + BUS_MESSAGE_NO_REPLY_EXPECTED = 1 << 0, + BUS_MESSAGE_NO_AUTO_START = 1 << 1, + BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION = 1 << 2, }; /* Header fields */ @@ -78,9 +78,9 @@ enum { /* RequestName parameters */ enum { - BUS_NAME_ALLOW_REPLACEMENT = 1, - BUS_NAME_REPLACE_EXISTING = 2, - BUS_NAME_DO_NOT_QUEUE = 4 + BUS_NAME_ALLOW_REPLACEMENT = 1 << 0, + BUS_NAME_REPLACE_EXISTING = 1 << 1, + BUS_NAME_DO_NOT_QUEUE = 1 << 2, }; /* RequestName returns */ diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index ed185131b8..441b4a816f 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -981,7 +981,7 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) { return r; n = m->n_iovec * sizeof(struct iovec); - iov = alloca(n); + iov = newa(struct iovec, n); memcpy_safe(iov, m->iovec, n); j = 0; @@ -1072,7 +1072,7 @@ static int bus_socket_read_message_need(sd_bus *bus, size_t *need) { } static int bus_socket_make_message(sd_bus *bus, size_t size) { - sd_bus_message *t; + sd_bus_message *t = NULL; void *b; int r; @@ -1097,7 +1097,9 @@ static int bus_socket_make_message(sd_bus *bus, size_t size) { bus->fds, bus->n_fds, NULL, &t); - if (r < 0) { + if (r == -EBADMSG) + log_debug_errno(r, "Received invalid message from connection %s, dropping.", strna(bus->description)); + else if (r < 0) { free(b); return r; } @@ -1108,7 +1110,8 @@ static int bus_socket_make_message(sd_bus *bus, size_t size) { bus->fds = NULL; bus->n_fds = 0; - bus->rqueue[bus->rqueue_size++] = t; + if (t) + bus->rqueue[bus->rqueue_size++] = t; return 1; } diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index 3b00bc8157..1ff858f32d 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -1556,17 +1556,24 @@ _public_ void sd_bus_close(sd_bus *bus) { bus_close_inotify_fd(bus); } +_public_ sd_bus *sd_bus_close_unref(sd_bus *bus) { + if (!bus) + return NULL; + + sd_bus_close(bus); + + return sd_bus_unref(bus); +} + _public_ sd_bus* sd_bus_flush_close_unref(sd_bus *bus) { if (!bus) return NULL; /* Have to do this before flush() to prevent hang */ bus_kill_exec(bus); - sd_bus_flush(bus); - sd_bus_close(bus); - return sd_bus_unref(bus); + return sd_bus_close_unref(bus); } void bus_enter_closing(sd_bus *bus) { diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c index 218210f234..9e8f0a73f5 100644 --- a/src/libsystemd/sd-daemon/sd-daemon.c +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -604,7 +604,13 @@ _public_ int sd_booted(void) { * created. This takes place in mount-setup.c, so is * guaranteed to happen very early during boot. */ - return laccess("/run/systemd/system/", F_OK) >= 0; + if (laccess("/run/systemd/system/", F_OK) >= 0) + return true; + + if (errno == ENOENT) + return false; + + return -errno; } _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) { diff --git a/src/libsystemd/sd-device/device-monitor.c b/src/libsystemd/sd-device/device-monitor.c index b86932663e..27d0af5918 100644 --- a/src/libsystemd/sd-device/device-monitor.c +++ b/src/libsystemd/sd-device/device-monitor.c @@ -93,14 +93,8 @@ _public_ int sd_device_monitor_set_receive_buffer_size(sd_device_monitor *m, siz assert_return(m, -EINVAL); assert_return((size_t) n == size, -EINVAL); - if (m->bound) - return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), - "sd-device-monitor: Socket fd is already bound. " - "It may be dangerous to change buffer size. " - "Refusing to change buffer size."); - - if (setsockopt_int(m->sock, SOL_SOCKET, SO_RCVBUF, n) < 0) { - r = setsockopt_int(m->sock, SOL_SOCKET, SO_RCVBUFFORCE, n); + if (setsockopt_int(m->sock, SOL_SOCKET, SO_RCVBUFFORCE, n) < 0) { + r = setsockopt_int(m->sock, SOL_SOCKET, SO_RCVBUF, n); if (r < 0) return r; } @@ -754,7 +748,7 @@ _public_ int sd_device_monitor_filter_remove(sd_device_monitor *m) { m->subsystem_filter = hashmap_free_free_free(m->subsystem_filter); m->tag_filter = set_free_free(m->tag_filter); - if (setsockopt(m->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) < 0) + if (setsockopt(m->sock, SOL_SOCKET, SO_DETACH_FILTER, &filter, sizeof(filter)) < 0) return -errno; m->filter_uptodate = true; diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c index 01a5aa3d3f..76267a1e74 100644 --- a/src/libsystemd/sd-device/device-private.c +++ b/src/libsystemd/sd-device/device-private.c @@ -326,15 +326,6 @@ static int device_append(sd_device *device, char *key, const char **_major, cons action = device_action_from_string(value); if (action == _DEVICE_ACTION_INVALID) return -EINVAL; - /* FIXME: remove once we no longer flush previuos state for each action */ - if (action == DEVICE_ACTION_BIND || action == DEVICE_ACTION_UNBIND) { - static bool warned; - if (!warned) { - log_device_debug(device, "sd-device: ignoring actions 'bind' and 'unbind'"); - warned = true; - } - return -EINVAL; - } } else if (streq(key, "SEQNUM")) { r = safe_atou64(value, &seqnum); if (r < 0) @@ -711,13 +702,24 @@ int device_new_from_stat_rdev(sd_device **ret, const struct stat *st) { int device_copy_properties(sd_device *device_dst, sd_device *device_src) { const char *property, *value; + Iterator i; int r; assert(device_dst); assert(device_src); - FOREACH_DEVICE_PROPERTY(device_src, property, value) { - r = device_add_property(device_dst, property, value); + r = device_properties_prepare(device_src); + if (r < 0) + return r; + + ORDERED_HASHMAP_FOREACH_KEY(value, property, device_src->properties_db, i) { + r = device_add_property_aux(device_dst, property, value, true); + if (r < 0) + return r; + } + + ORDERED_HASHMAP_FOREACH_KEY(value, property, device_src->properties, i) { + r = device_add_property_aux(device_dst, property, value, false); if (r < 0) return r; } diff --git a/src/libsystemd/sd-device/device-private.h b/src/libsystemd/sd-device/device-private.h index 56558b38c6..062bfd651c 100644 --- a/src/libsystemd/sd-device/device-private.h +++ b/src/libsystemd/sd-device/device-private.h @@ -37,6 +37,7 @@ uint64_t device_get_properties_generation(sd_device *device); uint64_t device_get_tags_generation(sd_device *device); uint64_t device_get_devlinks_generation(sd_device *device); +int device_properties_prepare(sd_device *device); int device_get_properties_nulstr(sd_device *device, const uint8_t **nulstr, size_t *len); int device_get_properties_strv(sd_device *device, char ***strv); diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index db58615df5..2a69f2e94b 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -29,7 +29,7 @@ #include "util.h" int device_new_aux(sd_device **ret) { - sd_device *device = NULL; + sd_device *device; assert(ret); @@ -205,9 +205,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) { return r; free_and_replace(device->syspath, syspath); - device->devpath = devpath; - return 0; } @@ -227,7 +225,6 @@ _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) { return r; *ret = TAKE_PTR(device); - return 0; } @@ -610,8 +607,8 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) { return sd_device_new_from_devnum(ret, id[0], devt); } - case 'n': - { + + case 'n': { _cleanup_(sd_device_unrefp) sd_device *device = NULL; _cleanup_close_ int sk = -1; struct ifreq ifr = {}; @@ -642,11 +639,10 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) { return -ENODEV; *ret = TAKE_PTR(device); - return 0; } - case '+': - { + + case '+': { char subsys[PATH_MAX]; char *sysname; @@ -660,6 +656,7 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) { return sd_device_new_from_subsystem_sysname(ret, subsys, sysname); } + default: return -EINVAL; } @@ -727,7 +724,6 @@ _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) { return -ENOENT; *ret = child->parent; - return 0; } @@ -746,11 +742,8 @@ int device_set_subsystem(sd_device *device, const char *_subsystem) { if (r < 0) return r; - free_and_replace(device->subsystem, subsystem); - device->subsystem_set = true; - - return 0; + return free_and_replace(device->subsystem, subsystem); } static int device_set_drivers_subsystem(sd_device *device, const char *_subsystem) { @@ -769,9 +762,7 @@ static int device_set_drivers_subsystem(sd_device *device, const char *_subsyste if (r < 0) return r; - free_and_replace(device->driver_subsystem, subsystem); - - return 0; + return free_and_replace(device->driver_subsystem, subsystem); } _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) { @@ -836,7 +827,6 @@ _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) { return -ENOENT; *ret = device->subsystem; - return 0; } @@ -886,7 +876,6 @@ _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const return r; *ret = parent; - return 0; } @@ -923,11 +912,8 @@ int device_set_driver(sd_device *device, const char *_driver) { if (r < 0) return r; - free_and_replace(device->driver, driver); - device->driver_set = true; - - return 0; + return free_and_replace(device->driver, driver); } _public_ int sd_device_get_driver(sd_device *device, const char **ret) { @@ -960,7 +946,6 @@ _public_ int sd_device_get_driver(sd_device *device, const char **ret) { return -ENOENT; *ret = device->driver; - return 0; } @@ -972,7 +957,6 @@ _public_ int sd_device_get_devpath(sd_device *device, const char **devpath) { assert(device->devpath[0] == '/'); *devpath = device->devpath; - return 0; } @@ -992,7 +976,6 @@ _public_ int sd_device_get_devname(sd_device *device, const char **devname) { assert(path_startswith(device->devname, "/dev/")); *devname = device->devname; - return 0; } @@ -1002,6 +985,9 @@ static int device_set_sysname(sd_device *device) { const char *pos; size_t len = 0; + if (!device->devpath) + return -EINVAL; + pos = strrchr(device->devpath, '/'); if (!pos) return -EINVAL; @@ -1030,13 +1016,9 @@ static int device_set_sysname(sd_device *device) { if (len == 0) sysnum = NULL; - free_and_replace(device->sysname, sysname); - - device->sysnum = sysnum; - device->sysname_set = true; - - return 0; + device->sysnum = sysnum; + return free_and_replace(device->sysname, sysname); } _public_ int sd_device_get_sysname(sd_device *device, const char **ret) { @@ -1054,7 +1036,6 @@ _public_ int sd_device_get_sysname(sd_device *device, const char **ret) { assert_return(device->sysname, -ENOENT); *ret = device->sysname; - return 0; } @@ -1074,7 +1055,6 @@ _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) { return -ENOENT; *ret = device->sysnum; - return 0; } @@ -1283,7 +1263,6 @@ int device_get_id_filename(sd_device *device, const char **ret) { } *ret = device->id_filename; - return 0; } @@ -1415,7 +1394,6 @@ _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *u return -EIO; *usec = now_ts - device->usec_initialized; - return 0; } @@ -1475,7 +1453,7 @@ _public_ const char *sd_device_get_devlink_next(sd_device *device) { return v; } -static int device_properties_prepare(sd_device *device) { +int device_properties_prepare(sd_device *device) { int r; assert(device); @@ -1558,7 +1536,6 @@ _public_ const char *sd_device_get_property_first(sd_device *device, const char if (_value) *_value = value; - return key; } @@ -1580,7 +1557,6 @@ _public_ const char *sd_device_get_property_next(sd_device *device, const char * if (_value) *_value = value; - return key; } @@ -1691,7 +1667,6 @@ _public_ int sd_device_get_property_value(sd_device *device, const char *key, co if (_value) *_value = value; - return 0; } @@ -1718,8 +1693,7 @@ static int device_add_sysattr_value(sd_device *device, const char *_key, char *v r = hashmap_put(device->sysattr_values, key, value); if (r < 0) return r; - - key = NULL; + TAKE_PTR(key); return 0; } @@ -1736,7 +1710,6 @@ static int device_get_sysattr_value(sd_device *device, const char *_key, const c if (_value) *_value = value; - return 0; } @@ -1820,14 +1793,11 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, static void device_remove_sysattr_value(sd_device *device, const char *_key) { _cleanup_free_ char *key = NULL; - _cleanup_free_ char *value = NULL; assert(device); assert(_key); - value = hashmap_remove2(device->sysattr_values, _key, (void **) &key); - - return; + free(hashmap_remove2(device->sysattr_values, _key, (void **) &key)); } /* set the attribute and save it in the cache. If a NULL value is passed the @@ -1843,7 +1813,6 @@ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, if (!_value) { device_remove_sysattr_value(device, sysattr); - return 0; } @@ -1874,23 +1843,22 @@ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, if (r == -EISDIR) return r; - free(value); - value = strdup(""); - if (!value) - return -ENOMEM; + r = free_and_strdup(&value, ""); + if (r < 0) + return r; r = device_add_sysattr_value(device, sysattr, value); if (r < 0) return r; + TAKE_PTR(value); - value = NULL; return -ENXIO; } r = device_add_sysattr_value(device, sysattr, value); if (r < 0) return r; + TAKE_PTR(value); - value = NULL; return 0; } diff --git a/src/libsystemd/sd-device/test-sd-device-monitor.c b/src/libsystemd/sd-device/test-sd-device-monitor.c index 9e5ca11fe9..aa1edaaf3c 100644 --- a/src/libsystemd/sd-device/test-sd-device-monitor.c +++ b/src/libsystemd/sd-device/test-sd-device-monitor.c @@ -21,14 +21,46 @@ static int monitor_handler(sd_device_monitor *m, sd_device *d, void *userdata) { assert_se(sd_device_get_syspath(d, &s) >= 0); assert_se(streq(s, syspath)); - return sd_event_exit(sd_device_monitor_get_event(m), 0); + return sd_event_exit(sd_device_monitor_get_event(m), 100); } -static int test_send_receive_one(sd_device *device, bool subsystem_filter, bool tag_filter, bool use_bpf) { +static int test_receive_device_fail(void) { _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL; - const char *syspath, *subsystem, *tag, *devtype = NULL; + _cleanup_(sd_device_unrefp) sd_device *loopback = NULL; + const char *syspath; int r; + log_info("/* %s */", __func__); + + /* Try to send device with invalid action and without seqnum. */ + assert_se(sd_device_new_from_syspath(&loopback, "/sys/class/net/lo") >= 0); + assert_se(device_add_property(loopback, "ACTION", "hoge") >= 0); + + assert_se(sd_device_get_syspath(loopback, &syspath) >= 0); + + assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0); + assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0); + assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0); + + assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0); + assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0); + assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0); + assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0); + + /* Do not use assert_se() here. */ + r = device_monitor_send_device(monitor_server, monitor_client, loopback); + if (r < 0) + return log_error_errno(r, "Failed to send loopback device: %m"); + + assert_se(sd_event_run(sd_device_monitor_get_event(monitor_client), 0) >= 0); + + return 0; +} + +static void test_send_receive_one(sd_device *device, bool subsystem_filter, bool tag_filter, bool use_bpf) { + _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL; + const char *syspath, *subsystem, *tag, *devtype = NULL; + log_device_info(device, "/* %s(subsystem_filter=%s, tag_filter=%s, use_bpf=%s) */", __func__, true_false(subsystem_filter), true_false(tag_filter), true_false(use_bpf)); @@ -56,14 +88,8 @@ static int test_send_receive_one(sd_device *device, bool subsystem_filter, bool if ((subsystem_filter || tag_filter) && use_bpf) assert_se(sd_device_monitor_filter_update(monitor_client) >= 0); - /* Do not use assert_se() here. */ - r = device_monitor_send_device(monitor_server, monitor_client, device); - if (r < 0) - return log_error_errno(r, "Failed to send loopback device: %m"); - - assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 0); - - return 0; + assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0); + assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100); } static void test_subsystem_filter(sd_device *device) { @@ -99,7 +125,45 @@ static void test_subsystem_filter(sd_device *device) { log_info("Sending device subsystem:%s syspath:%s", subsystem, syspath); assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0); - assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 0); + assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100); +} + +static void test_sd_device_monitor_filter_remove(sd_device *device) { + _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL; + const char *syspath; + + log_device_info(device, "/* %s */", __func__); + + assert_se(sd_device_get_syspath(device, &syspath) >= 0); + + assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0); + assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0); + assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0); + + assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0); + assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0); + assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0); + assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0); + + assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, "hoge", NULL) >= 0); + assert_se(sd_device_monitor_filter_update(monitor_client) >= 0); + + assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0); + assert_se(sd_event_run(sd_device_monitor_get_event(monitor_client), 0) >= 0); + + assert_se(sd_device_monitor_filter_remove(monitor_client) >= 0); + + assert_se(device_monitor_send_device(monitor_server, monitor_client, device) >= 0); + assert_se(sd_event_loop(sd_device_monitor_get_event(monitor_client)) == 100); +} + +static void test_device_copy_properties(sd_device *device) { + _cleanup_(sd_device_unrefp) sd_device *copy = NULL; + + assert_se(device_shallow_clone(device, ©) >= 0); + assert_se(device_copy_properties(copy, device) >= 0); + + test_send_receive_one(copy, false, false, false); } int main(int argc, char *argv[]) { @@ -111,24 +175,27 @@ int main(int argc, char *argv[]) { if (getuid() != 0) return log_tests_skipped("not root"); - assert_se(sd_device_new_from_syspath(&loopback, "/sys/class/net/lo") >= 0); - assert_se(device_add_property(loopback, "ACTION", "add") >= 0); - assert_se(device_add_property(loopback, "SEQNUM", "10") >= 0); - - r = test_send_receive_one(loopback, false, false, false); + r = test_receive_device_fail(); if (r < 0) { assert_se(r == -EPERM && detect_container() > 0); return log_tests_skipped("Running in container? Skipping remaining tests"); } - assert_se(test_send_receive_one(loopback, true, false, false) >= 0); - assert_se(test_send_receive_one(loopback, false, true, false) >= 0); - assert_se(test_send_receive_one(loopback, true, true, false) >= 0); - assert_se(test_send_receive_one(loopback, true, false, true) >= 0); - assert_se(test_send_receive_one(loopback, false, true, true) >= 0); - assert_se(test_send_receive_one(loopback, true, true, true) >= 0); + assert_se(sd_device_new_from_syspath(&loopback, "/sys/class/net/lo") >= 0); + assert_se(device_add_property(loopback, "ACTION", "add") >= 0); + assert_se(device_add_property(loopback, "SEQNUM", "10") >= 0); + + test_send_receive_one(loopback, false, false, false); + test_send_receive_one(loopback, true, false, false); + test_send_receive_one(loopback, false, true, false); + test_send_receive_one(loopback, true, true, false); + test_send_receive_one(loopback, true, false, true); + test_send_receive_one(loopback, false, true, true); + test_send_receive_one(loopback, true, true, true); test_subsystem_filter(loopback); + test_sd_device_monitor_filter_remove(loopback); + test_device_copy_properties(loopback); r = sd_device_new_from_subsystem_sysname(&sda, "block", "sda"); if (r < 0) { @@ -139,13 +206,13 @@ int main(int argc, char *argv[]) { assert_se(device_add_property(sda, "ACTION", "change") >= 0); assert_se(device_add_property(sda, "SEQNUM", "11") >= 0); - assert_se(test_send_receive_one(sda, false, false, false) >= 0); - assert_se(test_send_receive_one(sda, true, false, false) >= 0); - assert_se(test_send_receive_one(sda, false, true, false) >= 0); - assert_se(test_send_receive_one(sda, true, true, false) >= 0); - assert_se(test_send_receive_one(sda, true, false, true) >= 0); - assert_se(test_send_receive_one(sda, false, true, true) >= 0); - assert_se(test_send_receive_one(sda, true, true, true) >= 0); + test_send_receive_one(sda, false, false, false); + test_send_receive_one(sda, true, false, false); + test_send_receive_one(sda, false, true, false); + test_send_receive_one(sda, true, true, false); + test_send_receive_one(sda, true, false, true); + test_send_receive_one(sda, false, true, true); + test_send_receive_one(sda, true, true, true); return 0; } diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index 0030ea5dbe..04ba7e2574 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -470,6 +470,17 @@ static struct clock_data* event_get_clock_data(sd_event *e, EventSourceType t) { } } +static void event_free_signal_data(sd_event *e, struct signal_data *d) { + assert(e); + + if (!d) + return; + + hashmap_remove(e->signal_data, &d->priority); + safe_close(d->fd); + free(d); +} + static int event_make_signal_data( sd_event *e, int sig, @@ -559,11 +570,8 @@ static int event_make_signal_data( return 0; fail: - if (added) { - d->fd = safe_close(d->fd); - hashmap_remove(e->signal_data, &d->priority); - free(d); - } + if (added) + event_free_signal_data(e, d); return r; } @@ -582,11 +590,8 @@ static void event_unmask_signal_data(sd_event *e, struct signal_data *d, int sig assert_se(sigdelset(&d->sigset, sig) >= 0); if (sigisemptyset(&d->sigset)) { - /* If all the mask is all-zero we can get rid of the structure */ - hashmap_remove(e->signal_data, &d->priority); - safe_close(d->fd); - free(d); + event_free_signal_data(e, d); return; } diff --git a/src/libsystemd/sd-hwdb/hwdb-util.c b/src/libsystemd/sd-hwdb/hwdb-util.c index c5c329f2ac..f8529670b3 100644 --- a/src/libsystemd/sd-hwdb/hwdb-util.c +++ b/src/libsystemd/sd-hwdb/hwdb-util.c @@ -367,7 +367,7 @@ static int trie_store(struct trie *trie, const char *filename, bool compat) { int64_t size; struct trie_header_f h = { .signature = HWDB_SIG, - .tool_version = htole64(atoi(PACKAGE_VERSION)), + .tool_version = htole64(PROJECT_VERSION), .header_size = htole64(sizeof(struct trie_header_f)), .node_size = htole64(sizeof(struct trie_node_f)), .child_entry_size = htole64(sizeof(struct trie_child_entry_f)), diff --git a/src/libsystemd/sd-hwdb/sd-hwdb.c b/src/libsystemd/sd-hwdb/sd-hwdb.c index b81786a64d..233944c078 100644 --- a/src/libsystemd/sd-hwdb/sd-hwdb.c +++ b/src/libsystemd/sd-hwdb/sd-hwdb.c @@ -240,7 +240,7 @@ static int trie_search_f(sd_hwdb *hwdb, const char *search) { size_t p = 0; if (node->prefix_off) { - uint8_t c; + char c; for (; (c = trie_string(hwdb, node->prefix_off)[p]); p++) { if (IN_SET(c, '*', '?', '[')) diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c index 3593a71c02..e72af1593c 100644 --- a/src/libsystemd/sd-id128/sd-id128.c +++ b/src/libsystemd/sd-id128/sd-id128.c @@ -18,7 +18,7 @@ #include "user-util.h" #include "util.h" -_public_ char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]) { +_public_ char *sd_id128_to_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD_ID128_STRING_MAX]) { unsigned n; assert_return(s, NULL); diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c index a904c6b544..07f21e84de 100644 --- a/src/libsystemd/sd-login/sd-login.c +++ b/src/libsystemd/sd-login/sd-login.c @@ -945,11 +945,11 @@ _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) { return nr; } -static inline int MONITOR_TO_FD(sd_login_monitor *m) { +static int MONITOR_TO_FD(sd_login_monitor *m) { return (int) (unsigned long) m - 1; } -static inline sd_login_monitor* FD_TO_MONITOR(int fd) { +static sd_login_monitor* FD_TO_MONITOR(int fd) { return (sd_login_monitor*) (unsigned long) (fd + 1); } diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index b0b25639f4..5e9bc45139 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -370,6 +370,42 @@ int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short typ return 0; } +int sd_netlink_message_append_sockaddr_in(sd_netlink_message *m, unsigned short type, const struct sockaddr_in *data) { + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(data, -EINVAL); + + r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_SOCKADDR); + if (r < 0) + return r; + + r = add_rtattr(m, type, data, sizeof(struct sockaddr_in)); + if (r < 0) + return r; + + return 0; +} + +int sd_netlink_message_append_sockaddr_in6(sd_netlink_message *m, unsigned short type, const struct sockaddr_in6 *data) { + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(data, -EINVAL); + + r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_SOCKADDR); + if (r < 0) + return r; + + r = add_rtattr(m, type, data, sizeof(struct sockaddr_in6)); + if (r < 0) + return r; + + return 0; +} + int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data) { int r; diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index cd5cdcc6e5..9dcd3f2ac8 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -721,7 +721,7 @@ static const NLType genl_wireguard_peer_types[] = { [WGPEER_A_FLAGS] = { .type = NETLINK_TYPE_U32 }, [WGPEER_A_PRESHARED_KEY] = { .size = WG_KEY_LEN }, [WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL] = { .type = NETLINK_TYPE_U16 }, - [WGPEER_A_ENDPOINT] = { /* either size of sockaddr_in or sockaddr_in6 depending on address family */ }, + [WGPEER_A_ENDPOINT] = { .type = NETLINK_TYPE_SOCKADDR }, [WGPEER_A_ALLOWEDIPS] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_allowedip_type_system }, }; @@ -732,7 +732,7 @@ static const NLTypeSystem genl_wireguard_peer_type_system = { static const NLType genl_wireguard_set_device_types[] = { [WGDEVICE_A_IFINDEX] = { .type = NETLINK_TYPE_U32 }, - [WGDEVICE_A_IFNAME] = { .type = NETLINK_TYPE_STRING }, + [WGDEVICE_A_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ-1 }, [WGDEVICE_A_FLAGS] = { .type = NETLINK_TYPE_U32 }, [WGDEVICE_A_PRIVATE_KEY] = { .size = WG_KEY_LEN }, [WGDEVICE_A_LISTEN_PORT] = { .type = NETLINK_TYPE_U16 }, diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h index 3133e4863d..b84fa4762b 100644 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ b/src/libsystemd/sd-netlink/netlink-types.h @@ -16,6 +16,7 @@ enum { NETLINK_TYPE_CACHE_INFO, NETLINK_TYPE_NESTED, /* NLA_NESTED */ NETLINK_TYPE_UNION, + NETLINK_TYPE_SOCKADDR, }; typedef enum NLMatchType { diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index d4b5e248cc..812826fe3d 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -276,11 +276,11 @@ _public_ int sd_network_link_get_carrier_bound_by(int ifindex, int **ret) { return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_BY", ret); } -static inline int MONITOR_TO_FD(sd_network_monitor *m) { +static int MONITOR_TO_FD(sd_network_monitor *m) { return (int) (unsigned long) m - 1; } -static inline sd_network_monitor* FD_TO_MONITOR(int fd) { +static sd_network_monitor* FD_TO_MONITOR(int fd) { return (sd_network_monitor*) (unsigned long) (fd + 1); } diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index 21d783b8f0..36b9c8d019 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -912,7 +912,6 @@ static int alloc_query(sd_resolve *resolve, bool floating, sd_resolve_query **_q return 0; } - int resolve_getaddrinfo_with_destroy_callback( sd_resolve *resolve, sd_resolve_query **ret_query, diff --git a/src/libudev/libudev-list.c b/src/libudev/libudev-list.c index 5f6726c2d8..2737326187 100644 --- a/src/libudev/libudev-list.c +++ b/src/libudev/libudev-list.c @@ -61,7 +61,7 @@ static void udev_list_node_remove(struct udev_list_node *entry) { } /* return list entry which embeds this node */ -static inline struct udev_list_entry *list_node_to_entry(struct udev_list_node *node) { +static struct udev_list_entry *list_node_to_entry(struct udev_list_node *node) { return container_of(node, struct udev_list_entry, node); } diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c index f67ab40354..7e21719fbf 100644 --- a/src/libudev/libudev-util.c +++ b/src/libudev/libudev-util.c @@ -122,19 +122,20 @@ size_t util_path_encode(const char *src, char *dest, size_t size) { * * Note this may be called with 'str' == 'to', i.e. to replace whitespace * in-place in a buffer. This function can handle that situation. + * + * Note that only 'len' characters are read from 'str'. */ size_t util_replace_whitespace(const char *str, char *to, size_t len) { bool is_space = false; - const char *p = str; - size_t j; + size_t i, j; assert(str); assert(to); - p += strspn(p, WHITESPACE); + i = strspn(str, WHITESPACE); - for (j = 0; j < len && *p != '\0'; p++) { - if (isspace(*p)) { + for (j = 0; j < len && i < len && str[i] != '\0'; i++) { + if (isspace(str[i])) { is_space = true; continue; } @@ -146,7 +147,7 @@ size_t util_replace_whitespace(const char *str, char *to, size_t len) { to[j++] = '_'; is_space = false; } - to[j++] = *p; + to[j++] = str[i]; } to[j] = '\0'; diff --git a/src/libudev/libudev.pc.in b/src/libudev/libudev.pc.in index 69f5c6463e..40b340362e 100644 --- a/src/libudev/libudev.pc.in +++ b/src/libudev/libudev.pc.in @@ -14,6 +14,6 @@ includedir=@includedir@ Name: libudev Description: Library to access udev device information -Version: @PACKAGE_VERSION@ +Version: @PROJECT_VERSION@ Libs: -L${libdir} -ludev Cflags: -I${includedir} diff --git a/src/libudev/meson.build b/src/libudev/meson.build index 8d86c34189..88189748d3 100644 --- a/src/libudev/meson.build +++ b/src/libudev/meson.build @@ -22,9 +22,8 @@ libudev_sym_path = meson.current_source_dir() + '/libudev.sym' install_headers('libudev.h') libudev_h_path = '@0@/libudev.h'.format(meson.current_source_dir()) -libudev_pc = configure_file( +configure_file( input : 'libudev.pc.in', output : 'libudev.pc', - configuration : substs) -install_data(libudev_pc, - install_dir : pkgconfiglibdir) + configuration : substs, + install_dir : pkgconfiglibdir == 'no' ? '' : pkgconfiglibdir) diff --git a/src/login/logind-action.c b/src/login/logind-action.c index e4e6c90191..6c9366761d 100644 --- a/src/login/logind-action.c +++ b/src/login/logind-action.c @@ -121,7 +121,7 @@ int manager_handle_action( return -EOPNOTSUPP; } - if (m->action_what) { + if (m->action_what > 0) { log_debug("Action already in progress, ignoring."); return -EALREADY; } diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index bd9f5ac4d6..8ab498fdc2 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1474,23 +1474,15 @@ int manager_set_lid_switch_ignore(Manager *m, usec_t until) { } static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) { - - static const char * const signal_name[_INHIBIT_WHAT_MAX] = { - [INHIBIT_SHUTDOWN] = "PrepareForShutdown", - [INHIBIT_SLEEP] = "PrepareForSleep" - }; - int active = _active; assert(m); - assert(w >= 0); - assert(w < _INHIBIT_WHAT_MAX); - assert(signal_name[w]); + assert(IN_SET(w, INHIBIT_SHUTDOWN, INHIBIT_SLEEP)); return sd_bus_emit_signal(m->bus, "/org/freedesktop/login1", "org.freedesktop.login1.Manager", - signal_name[w], + w == INHIBIT_SHUTDOWN ? "PrepareForShutdown" : "PrepareForSleep", "b", active); } @@ -1502,7 +1494,6 @@ static int execute_shutdown_or_sleep( sd_bus_error *error) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - char *c = NULL; const char *p; int r; @@ -1530,15 +1521,11 @@ static int execute_shutdown_or_sleep( if (r < 0) goto error; - c = strdup(p); - if (!c) { - r = -ENOMEM; + r = free_and_strdup(&m->action_job, p); + if (r < 0) goto error; - } m->action_unit = unit_name; - free(m->action_job); - m->action_job = c; m->action_what = w; /* Make sure the lid switch is ignored for a while */ @@ -1656,7 +1643,7 @@ int bus_manager_shutdown_or_sleep_now_or_later( assert(m); assert(unit_name); assert(w > 0); - assert(w <= _INHIBIT_WHAT_MAX); + assert(w < _INHIBIT_WHAT_MAX); assert(!m->action_job); r = unit_load_state(m->bus, unit_name, &load_state); @@ -1773,7 +1760,7 @@ static int method_do_shutdown_or_sleep( return r; /* Don't allow multiple jobs being executed at the same time */ - if (m->action_what) + if (m->action_what > 0) return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "There's already a shutdown or sleep operation in progress"); if (sleep_verb) { @@ -2012,7 +1999,7 @@ static int manager_scheduled_shutdown_handler( assert_not_reached("unexpected shutdown type"); /* Don't allow multiple jobs being executed at the same time */ - if (m->action_what) { + if (m->action_what > 0) { r = -EALREADY; log_error("Scheduled shutdown to %s failed: shutdown or sleep operation already in progress", target); goto error; diff --git a/src/login/logind-inhibit.h b/src/login/logind-inhibit.h index d358a48559..650587106d 100644 --- a/src/login/logind-inhibit.h +++ b/src/login/logind-inhibit.h @@ -4,15 +4,15 @@ typedef struct Inhibitor Inhibitor; typedef enum InhibitWhat { - INHIBIT_SHUTDOWN = 1, - INHIBIT_SLEEP = 2, - INHIBIT_IDLE = 4, - INHIBIT_HANDLE_POWER_KEY = 8, - INHIBIT_HANDLE_SUSPEND_KEY = 16, - INHIBIT_HANDLE_HIBERNATE_KEY = 32, - INHIBIT_HANDLE_LID_SWITCH = 64, - _INHIBIT_WHAT_MAX = 128, - _INHIBIT_WHAT_INVALID = -1 + INHIBIT_SHUTDOWN = 1 << 0, + INHIBIT_SLEEP = 1 << 1, + INHIBIT_IDLE = 1 << 2, + INHIBIT_HANDLE_POWER_KEY = 1 << 3, + INHIBIT_HANDLE_SUSPEND_KEY = 1 << 4, + INHIBIT_HANDLE_HIBERNATE_KEY = 1 << 5, + INHIBIT_HANDLE_LID_SWITCH = 1 << 6, + _INHIBIT_WHAT_MAX = 1 << 7, + _INHIBIT_WHAT_INVALID = -1 } InhibitWhat; typedef enum InhibitMode { diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c index c758ffd5fa..a6d88f8e7b 100644 --- a/src/login/logind-seat.c +++ b/src/login/logind-seat.c @@ -376,7 +376,7 @@ int seat_read_active_vt(Seat *s) { k = read(s->manager->console_active_fd, t, sizeof(t)-1); if (k <= 0) { - log_error("Failed to read current console: %s", k < 0 ? strerror(-errno) : "EOF"); + log_error("Failed to read current console: %s", k < 0 ? strerror(errno) : "EOF"); return k < 0 ? -errno : -EIO; } diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 4b4dd4c060..90a9108566 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -1227,54 +1227,26 @@ error: } static void session_restore_vt(Session *s) { - pid_t pid; - int r; - - if (s->vtnr < 1) - return; + int r, vt, old_fd; - if (s->vtfd < 0) - return; - - /* The virtual terminal can potentially be entering in hung-up state at any time - * depending on when the controlling process exits. - * - * If the controlling process exits while we're restoring the virtual terminal, - * the VT will enter in hung-up state and we'll fail at restoring it. To prevent - * this case, we kick off the current controlling process (if any) in a child - * process so logind doesn't play around with tty ownership. - * - * If the controlling process already exited, getting a fresh handle to the - * virtual terminal reset the hung-up state. */ - r = safe_fork("(logind)", FORK_REOPEN_LOG|FORK_CLOSE_ALL_FDS|FORK_RESET_SIGNALS|FORK_WAIT|FORK_LOG, &pid); - if (r == 0) { - char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)]; - int vt; - - /* We must be a session leader in order to become the controlling process. */ - pid = setsid(); - if (pid < 0) { - log_error_errno(errno, "Failed to become session leader: %m"); - _exit(EXIT_FAILURE); - } + /* We need to get a fresh handle to the virtual terminal, + * since the old file-descriptor is potentially in a hung-up + * state after the controlling process exited; we do a + * little dance to avoid having the terminal be available + * for reuse before we've cleaned it up. + */ + old_fd = TAKE_FD(s->vtfd); - sprintf(path, "/dev/tty%u", s->vtnr); - vt = acquire_terminal(path, ACQUIRE_TERMINAL_FORCE, USEC_INFINITY); - if (vt < 0) { - log_error_errno(vt, "Cannot acquire VT %s of session %s: %m", path, s->id); - _exit(EXIT_FAILURE); - } + vt = session_open_vt(s); + safe_close(old_fd); - r = vt_restore(vt); - if (r < 0) - log_warning_errno(r, "Failed to restore VT, ignoring: %m"); + if (vt < 0) + return; - /* Give up and release the controlling terminal. */ - safe_close(vt); - _exit(EXIT_SUCCESS); - } + r = vt_restore(vt); + if (r < 0) + log_warning_errno(r, "Failed to restore VT, ignoring: %m"); - /* Close the fd in any cases. */ s->vtfd = safe_close(s->vtfd); } diff --git a/src/login/logind.c b/src/login/logind.c index 8d85de9b43..95ec0a57c6 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -146,7 +146,7 @@ static Manager* manager_unref(Manager *m) { bus_verify_polkit_async_registry_free(m->polkit_registry); - sd_bus_unref(m->bus); + sd_bus_flush_close_unref(m->bus); sd_event_unref(m->event); safe_close(m->reserve_vt_fd); diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index c7d9dcf4e2..997b74eb88 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -28,6 +28,7 @@ #include "path-util.h" #include "process-util.h" #include "socket-util.h" +#include "stdio-util.h" #include "strv.h" #include "terminal-util.h" #include "util.h" @@ -190,6 +191,45 @@ static int get_seat_from_display(const char *display, const char **seat, uint32_ return 0; } +static int export_legacy_dbus_address( + pam_handle_t *handle, + uid_t uid, + const char *runtime) { + + const char *s; + _cleanup_free_ char *t = NULL; + int r = PAM_BUF_ERR; + + /* We need to export $DBUS_SESSION_BUS_ADDRESS because various applications will not connect + * correctly to the bus without it. This setting matches what dbus.socket does for the user + * session using 'systemctl --user set-environment'. We want to have the same configuration + * in processes started from the PAM session. + * + * The setting of the address is guarded by the access() check because it is also possible to compile + * dbus without --enable-user-session, in which case this socket is not used, and + * $DBUS_SESSION_BUS_ADDRESS should not be set. An alternative approach would to not do the access() + * check here, and let applications try on their own, by using "unix:path=%s/bus;autolaunch:". But we + * expect the socket to be present by the time we do this check, so we can just as well check once + * here. */ + + s = strjoina(runtime, "/bus"); + if (access(s, F_OK) < 0) + return PAM_SUCCESS; + + if (asprintf(&t, DEFAULT_USER_BUS_ADDRESS_FMT, runtime) < 0) + goto error; + + r = pam_misc_setenv(handle, "DBUS_SESSION_BUS_ADDRESS", t, 0); + if (r != PAM_SUCCESS) + goto error; + + return PAM_SUCCESS; + +error: + pam_syslog(handle, LOG_ERR, "Failed to set bus variable."); + return r; +} + static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, const char *limit) { uint64_t val; int r; @@ -392,11 +432,9 @@ _public_ PAM_EXTERN int pam_sm_open_session( pam_get_item(handle, PAM_SERVICE, (const void**) &service); if (streq_ptr(service, "systemd-user")) { - _cleanup_free_ char *rt = NULL; - - if (asprintf(&rt, "/run/user/"UID_FMT, pw->pw_uid) < 0) - return PAM_BUF_ERR; + char rt[STRLEN("/run/user/") + DECIMAL_STR_MAX(uid_t)]; + xsprintf(rt, "/run/user/"UID_FMT, pw->pw_uid); if (validate_runtime_directory(handle, rt, pw->pw_uid)) { r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", rt, 0); if (r != PAM_SUCCESS) { @@ -405,6 +443,10 @@ _public_ PAM_EXTERN int pam_sm_open_session( } } + r = export_legacy_dbus_address(handle, pw->pw_uid, rt); + if (r != PAM_SUCCESS) + return r; + return PAM_SUCCESS; } @@ -569,7 +611,7 @@ _public_ PAM_EXTERN int pam_sm_open_session( if (r < 0) { if (sd_bus_error_has_name(&error, BUS_ERROR_SESSION_BUSY)) { if (debug) - pam_syslog(handle, LOG_DEBUG, "Cannot create session: %s", bus_error_message(&error, r)); + pam_syslog(handle, LOG_DEBUG, "Not creating session: %s", bus_error_message(&error, r)); return PAM_SUCCESS; } else { pam_syslog(handle, LOG_ERR, "Failed to create session: %s", bus_error_message(&error, r)); @@ -613,6 +655,10 @@ _public_ PAM_EXTERN int pam_sm_open_session( if (r != PAM_SUCCESS) return r; } + + r = export_legacy_dbus_address(handle, pw->pw_uid, runtime_path); + if (r != PAM_SUCCESS) + return r; } /* Most likely we got the session/type/class from environment variables, but might have gotten the data diff --git a/src/login/user-runtime-dir.c b/src/login/user-runtime-dir.c index 5e58e4baad..eb66e18de1 100644 --- a/src/login/user-runtime-dir.c +++ b/src/login/user-runtime-dir.c @@ -22,7 +22,7 @@ static int acquire_runtime_dir_size(uint64_t *ret) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; r = sd_bus_default_system(&bus); diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 48270b3709..7a558df898 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -454,7 +454,7 @@ static int container_bus_new(Machine *m, sd_bus_error *error, sd_bus **ret) { break; case MACHINE_CONTAINER: { - _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL; char *address; r = sd_bus_new(&bus); diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 44e6c76035..30f2e26a1e 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -1309,7 +1309,7 @@ static int on_machine_removed(sd_bus_message *m, void *userdata, sd_bus_error *r static int process_forward(sd_event *event, PTYForward **forward, int master, PTYForwardFlags flags, const char *name) { char last_char = 0; bool machine_died; - int ret = 0, r; + int r; assert(event); assert(master >= 0); @@ -1355,8 +1355,7 @@ static int process_forward(sd_event *event, PTYForward **forward, int master, PT log_info("Connection to machine %s terminated.", name); } - sd_event_get_exit_code(event, &ret); - return ret; + return 0; } static int parse_machine_uid(const char *spec, const char **machine, char **uid) { @@ -1740,7 +1739,7 @@ static int start_machine(int argc, char *argv[], void *userdata) { if (r < 0) return r; if (r == 0) { - log_error("Machine image '%s' does not exist.", argv[1]); + log_error("Machine image '%s' does not exist.", argv[i]); return -ENXIO; } @@ -1812,7 +1811,7 @@ static int enable_machine(int argc, char *argv[], void *userdata) { if (r < 0) return r; if (r == 0) { - log_error("Machine image '%s' does not exist.", argv[1]); + log_error("Machine image '%s' does not exist.", argv[i]); return -ENXIO; } diff --git a/src/machine/machined.c b/src/machine/machined.c index 9f23e369a4..0b92b1c6ee 100644 --- a/src/machine/machined.c +++ b/src/machine/machined.c @@ -81,7 +81,7 @@ static Manager* manager_unref(Manager *m) { bus_verify_polkit_async_registry_free(m->polkit_registry); - sd_bus_unref(m->bus); + sd_bus_flush_close_unref(m->bus); sd_event_unref(m->event); return mfree(m); diff --git a/src/network/netdev/bridge.c b/src/network/netdev/bridge.c index 0c804adb2e..aadb3ab905 100644 --- a/src/network/netdev/bridge.c +++ b/src/network/netdev/bridge.c @@ -47,7 +47,7 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess r = sd_netlink_message_open_container(req, IFLA_LINKINFO); if (r < 0) - return log_netdev_error_errno(netdev, r, "Could not append IFLA_PROTINFO attribute: %m"); + return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m"); r = sd_netlink_message_open_container_union(req, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind)); if (r < 0) diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index f0e9d00246..0263917468 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -148,11 +148,16 @@ static void netdev_callbacks_clear(NetDev *netdev) { } } +bool netdev_is_managed(NetDev *netdev) { + if (!netdev || !netdev->manager || !netdev->ifname) + return false; + + return hashmap_get(netdev->manager->netdevs, netdev->ifname) == netdev; +} + static void netdev_detach_from_manager(NetDev *netdev) { if (netdev->ifname && netdev->manager) hashmap_remove(netdev->manager->netdevs, netdev->ifname); - - netdev->manager = NULL; } static NetDev *netdev_free(NetDev *netdev) { @@ -476,7 +481,7 @@ int netdev_get_mac(const char *ifname, struct ether_addr **ret) { l = strlen(ifname); sz = sizeof(sd_id128_t) + l; - v = alloca(sz); + v = newa(uint8_t, sz); /* fetch some persistent data unique to the machine */ r = sd_id128_get_machine((sd_id128_t*) v); diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h index bfe1094181..d6524da0f3 100644 --- a/src/network/netdev/netdev.h +++ b/src/network/netdev/netdev.h @@ -156,6 +156,7 @@ NetDev *netdev_ref(NetDev *netdev); DEFINE_TRIVIAL_DESTRUCTOR(netdev_destroy_callback, NetDev, netdev_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(NetDev*, netdev_unref); +bool netdev_is_managed(NetDev *netdev); int netdev_get(Manager *manager, const char *name, NetDev **ret); int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *newlink); int netdev_get_mac(const char *ifname, struct ether_addr **ret); diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c index 167cf65046..0c0b16d1da 100644 --- a/src/network/netdev/wireguard.c +++ b/src/network/netdev/wireguard.c @@ -45,22 +45,137 @@ static WireguardPeer *wireguard_peer_new(Wireguard *w, unsigned section) { return peer; } -static int set_wireguard_interface(NetDev *netdev) { +static int wireguard_set_ipmask_one(NetDev *netdev, sd_netlink_message *message, const WireguardIPmask *mask, uint16_t index) { int r; - unsigned i, j; - WireguardPeer *peer, *peer_start; - WireguardIPmask *mask, *mask_start = NULL; + + assert(message); + assert(mask); + assert(index > 0); + + /* This returns 1 on success, 0 on recoverable error, and negative errno on failure. */ + + r = sd_netlink_message_open_array(message, index); + if (r < 0) + return 0; + + r = sd_netlink_message_append_u16(message, WGALLOWEDIP_A_FAMILY, mask->family); + if (r < 0) + goto cancel; + + if (mask->family == AF_INET) + r = sd_netlink_message_append_in_addr(message, WGALLOWEDIP_A_IPADDR, &mask->ip.in); + else if (mask->family == AF_INET6) + r = sd_netlink_message_append_in6_addr(message, WGALLOWEDIP_A_IPADDR, &mask->ip.in6); + if (r < 0) + goto cancel; + + r = sd_netlink_message_append_u8(message, WGALLOWEDIP_A_CIDR_MASK, mask->cidr); + if (r < 0) + goto cancel; + + r = sd_netlink_message_close_container(message); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not add wireguard allowed ip: %m"); + + return 1; + +cancel: + r = sd_netlink_message_cancel_array(message); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not cancel wireguard allowed ip message attribute: %m"); + + return 0; +} + +static int wireguard_set_peer_one(NetDev *netdev, sd_netlink_message *message, const WireguardPeer *peer, uint16_t index, WireguardIPmask **mask_start) { + WireguardIPmask *mask, *start; + uint16_t j = 0; + int r; + + assert(message); + assert(peer); + assert(index > 0); + assert(mask_start); + + /* This returns 1 on success, 0 on recoverable error, and negative errno on failure. */ + + start = *mask_start ?: peer->ipmasks; + + r = sd_netlink_message_open_array(message, index); + if (r < 0) + return 0; + + r = sd_netlink_message_append_data(message, WGPEER_A_PUBLIC_KEY, &peer->public_key, sizeof(peer->public_key)); + if (r < 0) + goto cancel; + + if (!*mask_start) { + r = sd_netlink_message_append_data(message, WGPEER_A_PRESHARED_KEY, &peer->preshared_key, WG_KEY_LEN); + if (r < 0) + goto cancel; + + r = sd_netlink_message_append_u32(message, WGPEER_A_FLAGS, peer->flags); + if (r < 0) + goto cancel; + + r = sd_netlink_message_append_u16(message, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, peer->persistent_keepalive_interval); + if (r < 0) + goto cancel; + + if (peer->endpoint.sa.sa_family == AF_INET) + r = sd_netlink_message_append_sockaddr_in(message, WGPEER_A_ENDPOINT, &peer->endpoint.in); + else if (peer->endpoint.sa.sa_family == AF_INET6) + r = sd_netlink_message_append_sockaddr_in6(message, WGPEER_A_ENDPOINT, &peer->endpoint.in6); + if (r < 0) + goto cancel; + } + + r = sd_netlink_message_open_container(message, WGPEER_A_ALLOWEDIPS); + if (r < 0) + goto cancel; + + LIST_FOREACH(ipmasks, mask, start) { + r = wireguard_set_ipmask_one(netdev, message, mask, ++j); + if (r < 0) + return r; + if (r == 0) + break; + } + + r = sd_netlink_message_close_container(message); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not add wireguard allowed ip: %m"); + + r = sd_netlink_message_close_container(message); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not add wireguard peer: %m"); + + *mask_start = mask; /* Start next cycle from this mask. */ + return !mask; + +cancel: + r = sd_netlink_message_cancel_array(message); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not cancel wireguard peers: %m"); + + return 0; +} + +static int wireguard_set_interface(NetDev *netdev) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL; - Wireguard *w; + WireguardIPmask *mask_start = NULL; + WireguardPeer *peer, *peer_start; uint32_t serial; + Wireguard *w; + int r; assert(netdev); w = WIREGUARD(netdev); assert(w); - peer_start = w->peers; + for (peer_start = w->peers; peer_start; ) { + uint16_t i = 0; - do { message = sd_netlink_message_unref(message); r = sd_genl_message_new(netdev->manager->genl, SD_GENL_WIREGUARD, WG_CMD_SET_DEVICE, &message); @@ -93,97 +208,14 @@ static int set_wireguard_interface(NetDev *netdev) { if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append wireguard peer attributes: %m"); - i = 0; - LIST_FOREACH(peers, peer, peer_start) { - r = sd_netlink_message_open_array(message, ++i); - if (r < 0) - break; - - r = sd_netlink_message_append_data(message, WGPEER_A_PUBLIC_KEY, &peer->public_key, sizeof(peer->public_key)); + r = wireguard_set_peer_one(netdev, message, peer, ++i, &mask_start); if (r < 0) + return r; + if (r == 0) break; - - if (!mask_start) { - r = sd_netlink_message_append_data(message, WGPEER_A_PRESHARED_KEY, &peer->preshared_key, WG_KEY_LEN); - if (r < 0) - break; - - r = sd_netlink_message_append_u32(message, WGPEER_A_FLAGS, peer->flags); - if (r < 0) - break; - - r = sd_netlink_message_append_u16(message, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, peer->persistent_keepalive_interval); - if (r < 0) - break; - - if (peer->endpoint.sa.sa_family == AF_INET) { - r = sd_netlink_message_append_data(message, WGPEER_A_ENDPOINT, &peer->endpoint.in, sizeof(peer->endpoint.in)); - if (r < 0) - break; - } else if (peer->endpoint.sa.sa_family == AF_INET6) { - r = sd_netlink_message_append_data(message, WGPEER_A_ENDPOINT, &peer->endpoint.in6, sizeof(peer->endpoint.in6)); - if (r < 0) - break; - } - - mask_start = peer->ipmasks; - } - - r = sd_netlink_message_open_container(message, WGPEER_A_ALLOWEDIPS); - if (r < 0) { - mask_start = NULL; - break; - } - j = 0; - LIST_FOREACH(ipmasks, mask, mask_start) { - r = sd_netlink_message_open_array(message, ++j); - if (r < 0) - break; - - r = sd_netlink_message_append_u16(message, WGALLOWEDIP_A_FAMILY, mask->family); - if (r < 0) - break; - - if (mask->family == AF_INET) { - r = sd_netlink_message_append_in_addr(message, WGALLOWEDIP_A_IPADDR, &mask->ip.in); - if (r < 0) - break; - } else if (mask->family == AF_INET6) { - r = sd_netlink_message_append_in6_addr(message, WGALLOWEDIP_A_IPADDR, &mask->ip.in6); - if (r < 0) - break; - } - - r = sd_netlink_message_append_u8(message, WGALLOWEDIP_A_CIDR_MASK, mask->cidr); - if (r < 0) - break; - - r = sd_netlink_message_close_container(message); - if (r < 0) - return log_netdev_error_errno(netdev, r, "Could not add wireguard allowed ip: %m"); - } - mask_start = mask; - if (mask_start) { - r = sd_netlink_message_cancel_array(message); - if (r < 0) - return log_netdev_error_errno(netdev, r, "Could not cancel wireguard allowed ip message attribute: %m"); - } - r = sd_netlink_message_close_container(message); - if (r < 0) - return log_netdev_error_errno(netdev, r, "Could not add wireguard allowed ip: %m"); - - r = sd_netlink_message_close_container(message); - if (r < 0) - return log_netdev_error_errno(netdev, r, "Could not add wireguard peer: %m"); - } - - peer_start = peer; - if (peer_start && !mask_start) { - r = sd_netlink_message_cancel_array(message); - if (r < 0) - return log_netdev_error_errno(netdev, r, "Could not cancel wireguard peers: %m"); } + peer_start = peer; /* Start next cycle from this peer. */ r = sd_netlink_message_close_container(message); if (r < 0) @@ -192,8 +224,7 @@ static int set_wireguard_interface(NetDev *netdev) { r = sd_netlink_send(netdev->manager->genl, message, &serial); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not set wireguard device: %m"); - - } while (peer || mask_start); + } return 0; } @@ -224,8 +255,7 @@ static int on_resolve_retry(sd_event_source *s, usec_t usec, void *userdata) { w = WIREGUARD(netdev); assert(w); - if (!netdev->manager) - /* The netdev is detached. */ + if (!netdev_is_managed(netdev)) return 0; assert(!w->unresolved_endpoints); @@ -260,8 +290,7 @@ static int wireguard_resolve_handler(sd_resolve_query *q, w = WIREGUARD(netdev); assert(w); - if (!netdev->manager) - /* The netdev is detached. */ + if (!netdev_is_managed(netdev)) return 0; if (ret != 0) { @@ -280,7 +309,7 @@ static int wireguard_resolve_handler(sd_resolve_query *q, return 0; } - set_wireguard_interface(netdev); + (void) wireguard_set_interface(netdev); if (w->failed_endpoints) { _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; @@ -355,7 +384,7 @@ static int netdev_wireguard_post_create(NetDev *netdev, Link *link, sd_netlink_m w = WIREGUARD(netdev); assert(w); - set_wireguard_interface(netdev); + (void) wireguard_set_interface(netdev); resolve_endpoints(netdev); return 0; } diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 9f0a22b827..3cdbd9e37e 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -5,6 +5,7 @@ #include "alloc-util.h" #include "conf-parser.h" #include "firewall-util.h" +#include "missing_network.h" #include "netlink-util.h" #include "networkd-address.h" #include "networkd-manager.h" @@ -351,18 +352,17 @@ int address_update( address->cinfo = *cinfo; link_update_operstate(address->link); + link_check_ready(address->link); - if (!ready && address_is_ready(address)) { - link_check_ready(address->link); + if (!ready && + address_is_ready(address) && + address->family == AF_INET6 && + in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 && + in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) { - if (address->family == AF_INET6 && - in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 && - in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) { - - r = link_ipv6ll_gained(address->link, &address->in_addr.in6); - if (r < 0) - return r; - } + r = link_ipv6ll_gained(address->link, &address->in_addr.in6); + if (r < 0) + return r; } return 0; @@ -632,14 +632,10 @@ int address_configure( r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6); if (r < 0) return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m"); - } else { - if (address->family == AF_INET) { - if (address->prefixlen <= 30) { - r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast); - if (r < 0) - return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m"); - } - } + } else if (address->family == AF_INET && address->prefixlen <= 30) { + r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast); + if (r < 0) + return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m"); } if (address->label) { @@ -648,8 +644,7 @@ int address_configure( return log_error_errno(r, "Could not append IFA_LABEL attribute: %m"); } - r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO, - &address->cinfo); + r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo); if (r < 0) return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m"); @@ -657,8 +652,7 @@ int address_configure( if (r < 0) return r; - r = netlink_call_async(link->manager->rtnl, NULL, req, callback, - link_netlink_destroy_callback, link); + r = netlink_call_async(link->manager->rtnl, NULL, req, callback, link_netlink_destroy_callback, link); if (r < 0) { address_release(address); return log_error_errno(r, "Could not send rtnetlink message: %m"); @@ -666,7 +660,10 @@ int address_configure( link_ref(link); - r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL); + if (address->family == AF_INET6 && !in_addr_is_null(address->family, &address->in_addr_peer)) + r = address_add(link, address->family, &address->in_addr_peer, address->prefixlen, NULL); + else + r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL); if (r < 0) { address_release(address); return log_error_errno(r, "Could not add address: %m"); @@ -752,7 +749,15 @@ int config_parse_address(const char *unit, return r; /* Address=address/prefixlen */ - r = in_addr_default_prefix_from_string_auto(rvalue, &f, &buffer, &prefixlen); + r = in_addr_prefix_from_string_auto_internal(rvalue, PREFIXLEN_REFUSE, &f, &buffer, &prefixlen); + if (r == -ENOANO) { + log_syntax(unit, LOG_ERR, filename, line, r, + "An address '%s' is specified without prefix length. " + "The behavior of parsing addresses without prefix length will be changed in the future release. " + "Please specify prefix length explicitly.", rvalue); + + r = in_addr_prefix_from_string_auto_internal(rvalue, PREFIXLEN_LEGACY, &f, &buffer, &prefixlen); + } if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Invalid address '%s', ignoring assignment: %m", rvalue); return 0; diff --git a/src/network/networkd-brvlan.c b/src/network/networkd-brvlan.c index 1d18e29b7c..8377623da4 100644 --- a/src/network/networkd-brvlan.c +++ b/src/network/networkd-brvlan.c @@ -9,6 +9,7 @@ #include "alloc-util.h" #include "conf-parser.h" +#include "missing_if_bridge.h" #include "netlink-util.h" #include "networkd-brvlan.h" #include "networkd-link.h" @@ -22,7 +23,7 @@ static bool is_bit_set(unsigned bit, uint32_t scope) { return scope & (1 << bit); } -static inline void set_bit(unsigned nr, uint32_t *addr) { +static void set_bit(unsigned nr, uint32_t *addr) { if (nr < BRIDGE_VLAN_BITMAP_MAX) addr[nr / 32] |= (((uint32_t) 1) << (nr % 32)); } diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 980d49e4ff..d8ac4552f4 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -690,7 +690,7 @@ int dhcp4_set_client_identifier(Link *link) { if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0) r = sd_dhcp_client_set_duid_llt(link->dhcp_client, - duid->llt_time); + duid->llt_time); else r = sd_dhcp_client_set_duid(link->dhcp_client, duid->type, diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index ed6b9df72b..c1fba03f9f 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -11,6 +11,7 @@ #include "hashmap.h" #include "hostname-util.h" +#include "missing_network.h" #include "network-internal.h" #include "networkd-link.h" #include "networkd-manager.h" @@ -254,7 +255,6 @@ static int dhcp6_route_handler(sd_netlink *nl, sd_netlink_message *m, Link *link return 1; } - static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) { int r; sd_dhcp6_lease *lease; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index e2851df31a..22392d70bc 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -517,8 +517,6 @@ static void link_detach_from_manager(Link *link) { hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex)); set_remove(link->manager->links_requesting_uuid, link); link_clean(link); - - link->manager = NULL; } static Link *link_free(Link *link) { @@ -730,70 +728,16 @@ static void link_enter_configured(Link *link) { link_dirty(link); } -void link_check_ready(Link *link) { - Address *a; - Iterator i; - - assert(link); - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return; - - if (!link->network) - return; - - if (!link->addresses_configured) - return; - - if (!link->neighbors_configured) - return; - - if (!link->static_routes_configured) - return; - - if (!link->routing_policy_rules_configured) - return; - - if (link_ipv4ll_enabled(link)) - if (!link->ipv4ll_address || - !link->ipv4ll_route) - return; - - if (!link->network->bridge) { - - if (link_ipv6ll_enabled(link)) - if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) > 0) - return; - - if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) && - !link->dhcp4_configured) || - (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) && - !link->dhcp6_configured) || - (link_dhcp4_enabled(link) && link_dhcp6_enabled(link) && - !link->dhcp4_configured && !link->dhcp6_configured)) - return; - - if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured) - return; - } - - SET_FOREACH(a, link->addresses, i) - if (!address_is_ready(a)) - return; - - if (link->state != LINK_STATE_CONFIGURED) - link_enter_configured(link); - - return; -} - -static int link_set_routing_policy_rule(Link *link) { +static int link_request_set_routing_policy_rule(Link *link) { RoutingPolicyRule *rule, *rrule = NULL; int r; assert(link); assert(link->network); + link_set_state(link, LINK_STATE_CONFIGURING); + link->routing_policy_rules_configured = false; + LIST_FOREACH(rules, rule, link->network->rules) { r = routing_policy_rule_get(link->manager, rule->family, &rule->from, rule->from_prefixlen, &rule->to, rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, rule->iif, rule->oif, @@ -865,8 +809,11 @@ static int link_request_set_routes(Link *link) { assert(link->state != _LINK_STATE_INVALID); link_set_state(link, LINK_STATE_CONFIGURING); + link->static_routes_configured = false; - (void) link_set_routing_policy_rule(link); + r = link_request_set_routing_policy_rule(link); + if (r < 0) + return r; /* First add the routes that enable us to talk to gateways, then add in the others that need a gateway. */ for (phase = 0; phase < _PHASE_MAX; phase++) @@ -894,6 +841,68 @@ static int link_request_set_routes(Link *link) { return 0; } +void link_check_ready(Link *link) { + Address *a; + Iterator i; + + assert(link); + + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return; + + if (!link->network) + return; + + if (!link->addresses_configured) + return; + + if (!link->neighbors_configured) + return; + + SET_FOREACH(a, link->addresses, i) + if (!address_is_ready(a)) + return; + + if (!link->addresses_ready) { + link->addresses_ready = true; + link_request_set_routes(link); + } + + if (!link->static_routes_configured) + return; + + if (!link->routing_policy_rules_configured) + return; + + if (link_ipv4ll_enabled(link)) + if (!link->ipv4ll_address || + !link->ipv4ll_route) + return; + + if (!link->network->bridge) { + + if (link_ipv6ll_enabled(link)) + if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) > 0) + return; + + if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) && + !link->dhcp4_configured) || + (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) && + !link->dhcp6_configured) || + (link_dhcp4_enabled(link) && link_dhcp6_enabled(link) && + !link->dhcp4_configured && !link->dhcp6_configured)) + return; + + if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured) + return; + } + + if (link->state != LINK_STATE_CONFIGURED) + link_enter_configured(link); + + return; +} + static int link_request_set_neighbors(Link *link) { Neighbor *neighbor; int r; @@ -903,6 +912,7 @@ static int link_request_set_neighbors(Link *link) { assert(link->state != _LINK_STATE_INVALID); link_set_state(link, LINK_STATE_CONFIGURING); + link->neighbors_configured = false; LIST_FOREACH(neighbors, neighbor, link->network->neighbors) { r = neighbor_configure(neighbor, link, NULL); @@ -947,7 +957,7 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) if (link->address_messages == 0) { log_link_debug(link, "Addresses set"); link->addresses_configured = true; - link_request_set_routes(link); + link_check_ready(link); } return 1; @@ -1073,16 +1083,29 @@ static int link_request_set_addresses(Link *link) { assert(link->network); assert(link->state != _LINK_STATE_INVALID); + link_set_state(link, LINK_STATE_CONFIGURING); + + /* Reset all *_configured flags we are configuring. */ + link->addresses_configured = false; + link->addresses_ready = false; + link->neighbors_configured = false; + link->static_routes_configured = false; + link->routing_policy_rules_configured = false; + r = link_set_bridge_fdb(link); if (r < 0) return r; - link_set_state(link, LINK_STATE_CONFIGURING); - - link_request_set_neighbors(link); + r = link_request_set_neighbors(link); + if (r < 0) + return r; LIST_FOREACH(addresses, ad, link->network->static_addresses) { - r = address_configure(ad, link, address_handler, false); + bool update; + + update = address_get(link, ad->family, &ad->in_addr, ad->prefixlen, NULL) > 0; + + r = address_configure(ad, link, address_handler, update); if (r < 0) { log_link_warning_errno(link, r, "Could not set addresses: %m"); link_enter_failed(link); @@ -1207,14 +1230,15 @@ static int link_request_set_addresses(Link *link) { return r; } } + if (!sd_dhcp_server_is_running(link->dhcp_server)) { + r = sd_dhcp_server_start(link->dhcp_server); + if (r < 0) { + log_link_warning_errno(link, r, "Could not start DHCPv4 server instance: %m"); - r = sd_dhcp_server_start(link->dhcp_server); - if (r < 0) { - log_link_warning_errno(link, r, "Could not start DHCPv4 server instance: %m"); - - link_enter_failed(link); + link_enter_failed(link); - return 0; + return 0; + } } log_link_debug(link, "Offering DHCPv4 leases"); @@ -1222,7 +1246,7 @@ static int link_request_set_addresses(Link *link) { if (link->address_messages == 0) { link->addresses_configured = true; - link_request_set_routes(link); + link_check_ready(link); } else log_link_debug(link, "Setting addresses"); @@ -1739,6 +1763,84 @@ bool link_has_carrier(Link *link) { return false; } +static int link_address_genmode_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { + int r; + + assert(link); + + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return 1; + + r = sd_netlink_message_get_errno(m); + if (r < 0) + log_link_warning_errno(link, r, "Could not set address genmode for interface: %m"); + + return 1; +} + +static int link_configure_addrgen_mode(Link *link) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; + uint8_t ipv6ll_mode; + int r; + + assert(link); + assert(link->network); + assert(link->manager); + assert(link->manager->rtnl); + + log_link_debug(link, "Setting address genmode for link"); + + r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex); + if (r < 0) + return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m"); + + r = sd_netlink_message_open_container(req, IFLA_AF_SPEC); + if (r < 0) + return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m"); + + r = sd_netlink_message_open_container(req, AF_INET6); + if (r < 0) + return log_link_error_errno(link, r, "Could not open AF_INET6 container: %m"); + + if (!link_ipv6ll_enabled(link)) + ipv6ll_mode = IN6_ADDR_GEN_MODE_NONE; + else { + const char *p = NULL; + _cleanup_free_ char *stable_secret = NULL; + + p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/stable_secret"); + + /* The file may not exist. And event if it exists, when stable_secret is unset, + * then reading the file fails and EIO is returned. */ + r = read_one_line_file(p, &stable_secret); + if (r < 0) + ipv6ll_mode = IN6_ADDR_GEN_MODE_EUI64; + else + ipv6ll_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY; + } + + r = sd_netlink_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, ipv6ll_mode); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_INET6_ADDR_GEN_MODE: %m"); + + r = sd_netlink_message_close_container(req); + if (r < 0) + return log_link_error_errno(link, r, "Could not close AF_INET6 container: %m"); + + r = sd_netlink_message_close_container(req); + if (r < 0) + return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m"); + + r = netlink_call_async(link->manager->rtnl, NULL, req, link_address_genmode_handler, + link_netlink_destroy_callback, link); + if (r < 0) + return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); + + link_ref(link); + + return 0; +} + static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { int r; @@ -1755,9 +1857,8 @@ static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) return 1; } -int link_up(Link *link) { +static int link_up(Link *link) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; - uint8_t ipv6ll_mode; int r; assert(link); @@ -1788,34 +1889,16 @@ int link_up(Link *link) { return log_link_error_errno(link, r, "Could not set MAC address: %m"); } - r = sd_netlink_message_open_container(req, IFLA_AF_SPEC); - if (r < 0) - return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m"); - if (link_ipv6_enabled(link)) { + r = sd_netlink_message_open_container(req, IFLA_AF_SPEC); + if (r < 0) + return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m"); + /* if the kernel lacks ipv6 support setting IFF_UP fails if any ipv6 options are passed */ r = sd_netlink_message_open_container(req, AF_INET6); if (r < 0) return log_link_error_errno(link, r, "Could not open AF_INET6 container: %m"); - if (!link_ipv6ll_enabled(link)) - ipv6ll_mode = IN6_ADDR_GEN_MODE_NONE; - else { - const char *p = NULL; - _cleanup_free_ char *stable_secret = NULL; - - p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/stable_secret"); - r = read_one_line_file(p, &stable_secret); - - if (r < 0) - ipv6ll_mode = IN6_ADDR_GEN_MODE_EUI64; - else - ipv6ll_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY; - } - r = sd_netlink_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, ipv6ll_mode); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_INET6_ADDR_GEN_MODE: %m"); - if (!in_addr_is_null(AF_INET6, &link->network->ipv6_token)) { r = sd_netlink_message_append_in6_addr(req, IFLA_INET6_TOKEN, &link->network->ipv6_token.in6); if (r < 0) @@ -1825,11 +1908,11 @@ int link_up(Link *link) { r = sd_netlink_message_close_container(req); if (r < 0) return log_link_error_errno(link, r, "Could not close AF_INET6 container: %m"); - } - r = sd_netlink_message_close_container(req); - if (r < 0) - return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m"); + r = sd_netlink_message_close_container(req); + if (r < 0) + return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m"); + } r = netlink_call_async(link->manager->rtnl, NULL, req, link_up_handler, link_netlink_destroy_callback, link); @@ -2918,6 +3001,12 @@ static int link_configure(Link *link) { return r; } + if (socket_ipv6_is_supported()) { + r = link_configure_addrgen_mode(link); + if (r < 0) + return r; + } + return link_configure_after_setting_mtu(link); } diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 00e68fdfaa..dcb1ea68dd 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -82,6 +82,7 @@ typedef struct Link { Set *routes_foreign; bool addresses_configured; + bool addresses_ready; sd_dhcp_client *dhcp_client; sd_dhcp_lease *dhcp_lease; @@ -142,7 +143,6 @@ int link_get(Manager *m, int ifindex, Link **ret); int link_add(Manager *manager, sd_netlink_message *message, Link **ret); void link_drop(Link *link); -int link_up(Link *link); int link_down(Link *link); void link_enter_failed(Link *link); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 81c81f18af..c8d369e2a0 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1456,7 +1456,7 @@ void manager_free(Manager *m) { sd_device_monitor_unref(m->device_monitor); - sd_bus_unref(m->bus); + sd_bus_flush_close_unref(m->bus); free(m->dynamic_timezone); free(m->dynamic_hostname); diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 80bfd2cba1..e5b8d11555 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -8,6 +8,7 @@ #include "sd-ndisc.h" +#include "missing_network.h" #include "networkd-ndisc.h" #include "networkd-route.h" #include "strv.h" diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index ccc1c3ce89..12344ec695 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -98,12 +98,13 @@ void network_apply_anonymize_if_set(Network *network) { } int network_load_one(Manager *manager, const char *filename) { + _cleanup_free_ char *fname = NULL, *name = NULL; _cleanup_(network_freep) Network *network = NULL; _cleanup_fclose_ FILE *file = NULL; - char *d; const char *dropin_dirname; - Route *route; Address *address; + Route *route; + char *d; int r; assert(manager); @@ -122,12 +123,30 @@ int network_load_one(Manager *manager, const char *filename) { return 0; } + fname = strdup(filename); + if (!fname) + return log_oom(); + + name = strdup(basename(filename)); + if (!name) + return log_oom(); + + d = strrchr(name, '.'); + if (!d) + return -EINVAL; + + *d = '\0'; + + dropin_dirname = strjoina(name, ".network.d"); + network = new(Network, 1); if (!network) return log_oom(); *network = (Network) { .manager = manager, + .filename = TAKE_PTR(fname), + .name = TAKE_PTR(name), .required_for_online = true, .dhcp = ADDRESS_FAMILY_NO, @@ -190,22 +209,6 @@ int network_load_one(Manager *manager, const char *filename) { .ipv6_accept_ra_route_table = RT_TABLE_MAIN, }; - network->filename = strdup(filename); - if (!network->filename) - return log_oom(); - - network->name = strdup(basename(filename)); - if (!network->name) - return log_oom(); - - d = strrchr(network->name, '.'); - if (!d) - return -EINVAL; - - *d = '\0'; - - dropin_dirname = strjoina(network->name, ".network.d"); - r = config_parse_many(filename, network_dirs, dropin_dirname, "Match\0" "Link\0" @@ -228,8 +231,11 @@ int network_load_one(Manager *manager, const char *filename) { "CAN\0", config_item_perf_lookup, network_network_gperf_lookup, CONFIG_PARSE_WARN, network); - if (r < 0) + if (r < 0) { + /* Unset manager here. Otherwise, LIST_REMOVE() in network_free() fails. */ + network->manager = NULL; return r; + } network_apply_anonymize_if_set(network); @@ -253,21 +259,19 @@ int network_load_one(Manager *manager, const char *filename) { if (r < 0) return r; - LIST_FOREACH(routes, route, network->static_routes) { + LIST_FOREACH(routes, route, network->static_routes) if (!route->family) { log_warning("Route section without Gateway field configured in %s. " "Ignoring", filename); return 0; } - } - LIST_FOREACH(addresses, address, network->static_addresses) { + LIST_FOREACH(addresses, address, network->static_addresses) if (!address->family) { log_warning("Address section without Address field configured in %s. " "Ignoring", filename); return 0; } - } network = NULL; diff --git a/src/network/wait-online/manager.c b/src/network/wait-online/manager.c index e1ccc9ff67..67218b6db3 100644 --- a/src/network/wait-online/manager.c +++ b/src/network/wait-online/manager.c @@ -89,16 +89,25 @@ static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void * assert(mm); r = sd_netlink_message_get_type(mm, &type); - if (r < 0) - goto fail; + if (r < 0) { + log_warning_errno(r, "rtnl: Could not get message type, ignoring: %m"); + return 0; + } r = sd_rtnl_message_link_get_ifindex(mm, &ifindex); - if (r < 0) - goto fail; + if (r < 0) { + log_warning_errno(r, "rtnl: Could not get ifindex from link, ignoring: %m"); + return 0; + } else if (ifindex <= 0) { + log_warning("rtnl: received link message with invalid ifindex %d, ignoring", ifindex); + return 0; + } r = sd_netlink_message_read_string(mm, IFLA_IFNAME, &ifname); - if (r < 0) - goto fail; + if (r < 0) { + log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m"); + return 0; + } l = hashmap_get(m->links, INT_TO_PTR(ifindex)); @@ -110,16 +119,16 @@ static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void * r = link_new(m, &l, ifindex, ifname); if (r < 0) - goto fail; + return log_error_errno(r, "Failed to create link object: %m"); r = link_update_monitor(l); if (r < 0) - goto fail; + return log_error_errno(r, "Failed to initialize link object: %m"); } r = link_update_rtnl(l, mm); if (r < 0) - goto fail; + return log_warning_errno(r, "Failed to process RTNL link message: %m");; break; @@ -133,10 +142,6 @@ static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void * } return 0; - -fail: - log_warning_errno(r, "Failed to process RTNL link message: %m"); - return 0; } static int on_rtnl_event(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) { diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index 9d0f8a9956..c028b5755a 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -67,7 +67,7 @@ static int generate_mac( if (idx > 0) sz += sizeof(idx); - v = alloca(sz); + v = newa(uint8_t, sz); /* fetch some persistent data unique to the host */ r = sd_id128_get_machine((sd_id128_t*) v); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 91c97b60a7..e0c2d711e6 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -1964,11 +1964,11 @@ static int setup_hostname(void) { } static int setup_journal(const char *directory) { - sd_id128_t this_id; _cleanup_free_ char *d = NULL; - const char *p, *q; + const char *dirname, *p, *q; + sd_id128_t this_id; + char id[33]; bool try; - char id[33], *dirname; int r; /* Don't link journals in ephemeral mode */ @@ -4230,6 +4230,11 @@ int main(int argc, char *argv[]) { if (r < 0) goto finish; + /* Ignore SIGPIPE here, because we use splice() on the ptyfwd stuff and that will generate SIGPIPE if + * the result is closed. Note that the container payload child will reset signal mask+handler anyway, + * so just turning this off here means we only turn it off in nspawn itself, not any children. */ + (void) ignore_signals(SIGPIPE, -1); + n_fd_passed = sd_listen_fds(false); if (n_fd_passed > 0) { r = fdset_new_listen_fds(&fds, false); diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c index 5abc0c91bf..e491351dee 100644 --- a/src/nss-myhostname/nss-myhostname.c +++ b/src/nss-myhostname/nss-myhostname.c @@ -74,6 +74,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r( } else { hn = gethostname_malloc(); if (!hn) { + UNPROTECT_ERRNO; *errnop = ENOMEM; *h_errnop = NO_RECOVERY; return NSS_STATUS_TRYAGAIN; @@ -96,6 +97,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r( l = strlen(canonical); ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * (n_addresses > 0 ? n_addresses : 2); if (buflen < ms) { + UNPROTECT_ERRNO; *errnop = ERANGE; *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; @@ -186,6 +188,8 @@ static enum nss_status fill_in_hostent( assert(errnop); assert(h_errnop); + PROTECT_ERRNO; + alen = FAMILY_ADDRESS_SIZE(af); for (a = addresses, n = 0, c = 0; n < n_addresses; a++, n++) @@ -202,6 +206,7 @@ static enum nss_status fill_in_hostent( (c > 0 ? c+1 : 2) * sizeof(char*); if (buflen < ms) { + UNPROTECT_ERRNO; *errnop = ERANGE; *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; @@ -321,6 +326,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r( af = AF_INET; if (!IN_SET(af, AF_INET, AF_INET6)) { + UNPROTECT_ERRNO; *errnop = EAFNOSUPPORT; *h_errnop = NO_DATA; return NSS_STATUS_UNAVAIL; @@ -343,6 +349,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r( } else { hn = gethostname_malloc(); if (!hn) { + UNPROTECT_ERRNO; *errnop = ENOMEM; *h_errnop = NO_RECOVERY; return NSS_STATUS_TRYAGAIN; @@ -362,6 +369,8 @@ enum nss_status _nss_myhostname_gethostbyname3_r( local_address_ipv4 = LOCALADDRESS_IPV4; } + UNPROTECT_ERRNO; + return fill_in_hostent( canonical, additional, af, @@ -401,12 +410,14 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r( assert(h_errnop); if (!IN_SET(af, AF_INET, AF_INET6)) { + UNPROTECT_ERRNO; *errnop = EAFNOSUPPORT; *h_errnop = NO_DATA; return NSS_STATUS_UNAVAIL; } if (len != FAMILY_ADDRESS_SIZE(af)) { + UNPROTECT_ERRNO; *errnop = EINVAL; *h_errnop = NO_RECOVERY; return NSS_STATUS_UNAVAIL; @@ -461,6 +472,7 @@ found: if (!canonical || additional_from_hostname) { hn = gethostname_malloc(); if (!hn) { + UNPROTECT_ERRNO; *errnop = ENOMEM; *h_errnop = NO_RECOVERY; return NSS_STATUS_TRYAGAIN; @@ -472,6 +484,7 @@ found: additional = hn; } + UNPROTECT_ERRNO; return fill_in_hostent( canonical, additional, af, diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c index 3d1fc28353..486a658958 100644 --- a/src/nss-mymachines/nss-mymachines.c +++ b/src/nss-mymachines/nss-mymachines.c @@ -153,6 +153,7 @@ enum nss_status _nss_mymachines_gethostbyname4_r( l = strlen(name); ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c; if (buflen < ms) { + UNPROTECT_ERRNO; *errnop = ERANGE; *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; @@ -227,6 +228,7 @@ enum nss_status _nss_mymachines_gethostbyname4_r( return NSS_STATUS_SUCCESS; fail: + UNPROTECT_ERRNO; *errnop = -r; *h_errnop = NO_DATA; return NSS_STATUS_UNAVAIL; @@ -313,6 +315,7 @@ enum nss_status _nss_mymachines_gethostbyname3_r( ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*); if (buflen < ms) { + UNPROTECT_ERRNO; *errnop = ERANGE; *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; @@ -396,6 +399,7 @@ enum nss_status _nss_mymachines_gethostbyname3_r( return NSS_STATUS_SUCCESS; fail: + UNPROTECT_ERRNO; *errnop = -r; *h_errnop = NO_DATA; return NSS_STATUS_UNAVAIL; @@ -484,6 +488,7 @@ enum nss_status _nss_mymachines_getpwnam_r( l = strlen(name); if (buflen < l+1) { + UNPROTECT_ERRNO; *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } @@ -501,6 +506,7 @@ enum nss_status _nss_mymachines_getpwnam_r( return NSS_STATUS_SUCCESS; fail: + UNPROTECT_ERRNO; *errnop = -r; return NSS_STATUS_UNAVAIL; } @@ -564,6 +570,7 @@ enum nss_status _nss_mymachines_getpwuid_r( return NSS_STATUS_NOTFOUND; if (snprintf(buffer, buflen, "vu-%s-" UID_FMT, machine, (uid_t) mapped) >= (int) buflen) { + UNPROTECT_ERRNO; *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } @@ -579,6 +586,7 @@ enum nss_status _nss_mymachines_getpwuid_r( return NSS_STATUS_SUCCESS; fail: + UNPROTECT_ERRNO; *errnop = -r; return NSS_STATUS_UNAVAIL; } @@ -662,6 +670,7 @@ enum nss_status _nss_mymachines_getgrnam_r( l = sizeof(char*) + strlen(name) + 1; if (buflen < l) { + UNPROTECT_ERRNO; *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } @@ -677,6 +686,7 @@ enum nss_status _nss_mymachines_getgrnam_r( return NSS_STATUS_SUCCESS; fail: + UNPROTECT_ERRNO; *errnop = -r; return NSS_STATUS_UNAVAIL; } @@ -740,12 +750,14 @@ enum nss_status _nss_mymachines_getgrgid_r( return NSS_STATUS_NOTFOUND; if (buflen < sizeof(char*) + 1) { + UNPROTECT_ERRNO; *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } memzero(buffer, sizeof(char*)); if (snprintf(buffer + sizeof(char*), buflen - sizeof(char*), "vg-%s-" GID_FMT, machine, (gid_t) mapped) >= (int) buflen) { + UNPROTECT_ERRNO; *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } @@ -758,6 +770,7 @@ enum nss_status _nss_mymachines_getgrgid_r( return NSS_STATUS_SUCCESS; fail: + UNPROTECT_ERRNO; *errnop = -r; return NSS_STATUS_UNAVAIL; } diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c index a28b5d8ba8..8370fed076 100644 --- a/src/nss-resolve/nss-resolve.c +++ b/src/nss-resolve/nss-resolve.c @@ -186,6 +186,7 @@ enum nss_status _nss_resolve_gethostbyname4_r( l = strlen(canonical); ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c; if (buflen < ms) { + UNPROTECT_ERRNO; *errnop = ERANGE; *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; @@ -267,6 +268,7 @@ enum nss_status _nss_resolve_gethostbyname4_r( return NSS_STATUS_SUCCESS; fail: + UNPROTECT_ERRNO; *errnop = -r; *h_errnop = NO_RECOVERY; return ret; @@ -364,6 +366,7 @@ enum nss_status _nss_resolve_gethostbyname3_r( ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*); if (buflen < ms) { + UNPROTECT_ERRNO; *errnop = ERANGE; *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; @@ -455,6 +458,7 @@ enum nss_status _nss_resolve_gethostbyname3_r( return NSS_STATUS_SUCCESS; fail: + UNPROTECT_ERRNO; *errnop = -r; *h_errnop = NO_RECOVERY; return ret; @@ -492,12 +496,14 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( assert(h_errnop); if (!IN_SET(af, AF_INET, AF_INET6)) { + UNPROTECT_ERRNO; *errnop = EAFNOSUPPORT; *h_errnop = NO_DATA; return NSS_STATUS_UNAVAIL; } if (len != FAMILY_ADDRESS_SIZE(af)) { + UNPROTECT_ERRNO; *errnop = EINVAL; *h_errnop = NO_RECOVERY; return NSS_STATUS_UNAVAIL; @@ -576,6 +582,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( c * sizeof(char*); /* pointers to aliases, plus trailing NULL */ if (buflen < ms) { + UNPROTECT_ERRNO; *errnop = ERANGE; *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; @@ -636,6 +643,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( return NSS_STATUS_SUCCESS; fail: + UNPROTECT_ERRNO; *errnop = -r; *h_errnop = NO_RECOVERY; return ret; diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c index f554828d49..f8db27ae27 100644 --- a/src/nss-systemd/nss-systemd.c +++ b/src/nss-systemd/nss-systemd.c @@ -210,6 +210,7 @@ enum nss_status _nss_systemd_getpwnam_r( l = strlen(name); if (buflen < l+1) { + UNPROTECT_ERRNO; *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } @@ -227,6 +228,7 @@ enum nss_status _nss_systemd_getpwnam_r( return NSS_STATUS_SUCCESS; fail: + UNPROTECT_ERRNO; *errnop = -r; return NSS_STATUS_UNAVAIL; } @@ -310,6 +312,7 @@ enum nss_status _nss_systemd_getpwuid_r( l = strlen(translated) + 1; if (buflen < l) { + UNPROTECT_ERRNO; *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } @@ -327,6 +330,7 @@ enum nss_status _nss_systemd_getpwuid_r( return NSS_STATUS_SUCCESS; fail: + UNPROTECT_ERRNO; *errnop = -r; return NSS_STATUS_UNAVAIL; } @@ -408,6 +412,7 @@ enum nss_status _nss_systemd_getgrnam_r( l = sizeof(char*) + strlen(name) + 1; if (buflen < l) { + UNPROTECT_ERRNO; *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } @@ -423,6 +428,7 @@ enum nss_status _nss_systemd_getgrnam_r( return NSS_STATUS_SUCCESS; fail: + UNPROTECT_ERRNO; *errnop = -r; return NSS_STATUS_UNAVAIL; } @@ -506,6 +512,7 @@ enum nss_status _nss_systemd_getgrgid_r( l = sizeof(char*) + strlen(translated) + 1; if (buflen < l) { + UNPROTECT_ERRNO; *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } @@ -521,6 +528,7 @@ enum nss_status _nss_systemd_getgrgid_r( return NSS_STATUS_SUCCESS; fail: + UNPROTECT_ERRNO; *errnop = -r; return NSS_STATUS_UNAVAIL; } @@ -740,6 +748,7 @@ enum nss_status _nss_systemd_getpwent_r(struct passwd *result, char *buffer, siz LIST_FOREACH(entries, p, getpwent_data.position) { len = strlen(p->name) + 1; if (buflen < len) { + UNPROTECT_ERRNO; *errnop = ERANGE; ret = NSS_STATUS_TRYAGAIN; goto finalize; @@ -791,6 +800,7 @@ enum nss_status _nss_systemd_getgrent_r(struct group *result, char *buffer, size LIST_FOREACH(entries, p, getgrent_data.position) { len = sizeof(char*) + strlen(p->name) + 1; if (buflen < len) { + UNPROTECT_ERRNO; *errnop = ERANGE; ret = NSS_STATUS_TRYAGAIN; goto finalize; diff --git a/src/portable/portabled.c b/src/portable/portabled.c index 63fc340469..49a359fd31 100644 --- a/src/portable/portabled.c +++ b/src/portable/portabled.c @@ -53,7 +53,7 @@ static Manager* manager_unref(Manager *m) { bus_verify_polkit_async_registry_free(m->polkit_registry); - sd_bus_unref(m->bus); + sd_bus_flush_close_unref(m->bus); sd_event_unref(m->event); return mfree(m); diff --git a/src/resolve/resolved-dns-answer.h b/src/resolve/resolved-dns-answer.h index 97514c3408..47fc80e2b0 100644 --- a/src/resolve/resolved-dns-answer.h +++ b/src/resolve/resolved-dns-answer.h @@ -15,11 +15,11 @@ typedef struct DnsAnswerItem DnsAnswerItem; * Note that we usually encode the empty DnsAnswer object as a simple NULL. */ typedef enum DnsAnswerFlags { - DNS_ANSWER_AUTHENTICATED = 1, /* Item has been authenticated */ - DNS_ANSWER_CACHEABLE = 2, /* Item is subject to caching */ - DNS_ANSWER_SHARED_OWNER = 4, /* For mDNS: RRset may be owner by multiple peers */ - DNS_ANSWER_CACHE_FLUSH = 8, /* For mDNS: sets cache-flush bit in the rrclass of response records */ - DNS_ANSWER_GOODBYE = 16, /* For mDNS: item is subject to disappear */ + DNS_ANSWER_AUTHENTICATED = 1 << 0, /* Item has been authenticated */ + DNS_ANSWER_CACHEABLE = 1 << 1, /* Item is subject to caching */ + DNS_ANSWER_SHARED_OWNER = 1 << 2, /* For mDNS: RRset may be owner by multiple peers */ + DNS_ANSWER_CACHE_FLUSH = 1 << 3, /* For mDNS: sets cache-flush bit in the rrclass of response records */ + DNS_ANSWER_GOODBYE = 1 << 4, /* For mDNS: item is subject to disappear */ } DnsAnswerFlags; struct DnsAnswerItem { diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index 335fd47780..14acc4e77d 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -402,7 +402,7 @@ static int dnssec_ecdsa_verify( if (rrsig->rrsig.signature_size != key_size * 2) return -EINVAL; - q = alloca(key_size*2 + 1); + q = newa(uint8_t, key_size*2 + 1); q[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */ memcpy(q+1, dnskey->dnskey.key, key_size*2); diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index 7a4f97754b..535ef4e776 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -719,7 +719,7 @@ int dns_query_go(DnsQuery *q) { match = dns_scope_good_domain(s, q->ifindex, q->flags, name); if (match < 0) { - log_debug("Couldn't check if '%s' matches agains scope, ignoring.", name); + log_debug("Couldn't check if '%s' matches against scope, ignoring.", name); continue; } diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 972e661d72..66dd2b1b5a 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -527,6 +527,7 @@ DnsScopeMatch dns_scope_good_domain( switch (s->protocol) { case DNS_PROTOCOL_DNS: { + bool has_search_domains = false; int n_best = -1; /* Never route things to scopes that lack DNS servers */ @@ -536,7 +537,11 @@ DnsScopeMatch dns_scope_good_domain( /* Always honour search domains for routing queries, except if this scope lacks DNS servers. Note that * we return DNS_SCOPE_YES here, rather than just DNS_SCOPE_MAYBE, which means other wildcard scopes * won't be considered anymore. */ - LIST_FOREACH(domains, d, dns_scope_get_search_domains(s)) + LIST_FOREACH(domains, d, dns_scope_get_search_domains(s)) { + + if (!d->route_only && !dns_name_is_root(d->name)) + has_search_domains = true; + if (dns_name_endswith(domain, d->name) > 0) { int c; @@ -547,6 +552,13 @@ DnsScopeMatch dns_scope_good_domain( if (c > n_best) n_best = c; } + } + + /* If there's a true search domain defined for this scope, and the query is single-label, + * then let's resolve things here, prefereably. Note that LLMNR considers itself + * authoritative for single-label names too, at the same preference, see below. */ + if (has_search_domains && dns_name_is_single_label(domain)) + return DNS_SCOPE_YES_BASE + 1; /* Let's return the number of labels in the best matching result */ if (n_best >= 0) { @@ -606,12 +618,16 @@ DnsScopeMatch dns_scope_good_domain( if ((dns_name_is_single_label(domain) && /* only resolve single label names via LLMNR */ !is_gateway_hostname(domain) && /* don't resolve "gateway" with LLMNR, let nss-myhostname handle this */ manager_is_own_hostname(s->manager, domain) <= 0)) /* never resolve the local hostname via LLMNR */ - return DNS_SCOPE_YES_BASE + 1; /* Return +1, as we consider ourselves authoritative for - * single-label names, i.e. one label. This is particular - * relevant as it means a "." route on some other scope won't - * pull all traffic away from us. (If people actually want to - * pull traffic away from us they should turn off LLMNR on the - * link) */ + return DNS_SCOPE_YES_BASE + 1; /* Return +1, as we consider ourselves authoritative + * for single-label names, i.e. one label. This is + * particular relevant as it means a "." route on some + * other scope won't pull all traffic away from + * us. (If people actually want to pull traffic away + * from us they should turn off LLMNR on the + * link). Note that unicast DNS scopes with search + * domains also consider themselves authoritative for + * single-label domains, at the same preference (see + * above). */ return DNS_SCOPE_NO; } diff --git a/src/resolve/resolved-etc-hosts.c b/src/resolve/resolved-etc-hosts.c index 01cde4acf7..ee21222e50 100644 --- a/src/resolve/resolved-etc-hosts.c +++ b/src/resolve/resolved-etc-hosts.c @@ -12,12 +12,12 @@ /* Recheck /etc/hosts at most once every 2s */ #define ETC_HOSTS_RECHECK_USEC (2*USEC_PER_SEC) -static inline void etc_hosts_item_free(EtcHostsItem *item) { +static void etc_hosts_item_free(EtcHostsItem *item) { strv_free(item->names); free(item); } -static inline void etc_hosts_item_by_name_free(EtcHostsItemByName *item) { +static void etc_hosts_item_by_name_free(EtcHostsItemByName *item) { free(item->name); free(item->addresses); free(item); diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index b7dc09ae37..b3d35c8341 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -689,7 +689,7 @@ Manager *manager_free(Manager *m) { manager_mdns_stop(m); manager_dns_stub_stop(m); - sd_bus_unref(m->bus); + sd_bus_flush_close_unref(m->bus); sd_event_source_unref(m->sigusr1_event_source); sd_event_source_unref(m->sigusr2_event_source); diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c index f4efddf8e5..0845b2c1ae 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -81,9 +81,7 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Event loop failed: %m"); - (void) sd_event_get_exit_code(m->event, &r); - - return r; + return 0; } DEFINE_MAIN_FUNCTION(run); diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c index 6f0657174c..9633514513 100644 --- a/src/shared/acl-util.c +++ b/src/shared/acl-util.c @@ -220,10 +220,10 @@ int parse_acl(const char *text, acl_t *acl_access, acl_t *acl_default, bool want char *p; p = STARTSWITH_SET(*entry, "default:", "d:"); - if (!p) - p = *entry; - - r = strv_push(&d, p); + if (p) + r = strv_push(&d, p); + else + r = strv_push(&a, *entry); if (r < 0) return r; } diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index 246e27a135..072bf72c56 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -156,7 +156,7 @@ static int add_to_keyring_and_log(const char *keyname, AskPasswordFlags flags, c return 0; } -int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret) { +static int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret) { key_serial_t serial; int r; @@ -341,7 +341,7 @@ int ask_password_tty( goto finish; } - if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0) { + if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0 && keyname) { (void) flush_fd(notify); r = ask_password_keyring(keyname, flags, ret); diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h index 2d84ba6b04..15762b9cde 100644 --- a/src/shared/ask-password-api.h +++ b/src/shared/ask-password-api.h @@ -17,5 +17,4 @@ typedef enum AskPasswordFlags { int ask_password_tty(int tty_fd, const char *message, const char *keyname, usec_t until, AskPasswordFlags flags, const char *flag_file, char ***ret); int ask_password_agent(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret); -int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret); int ask_password_auto(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret); diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index dce8646f37..9a8051d063 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -118,7 +118,7 @@ DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t, parse_mode); DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou); DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64); -static inline int bus_append_string(sd_bus_message *m, const char *field, const char *eq) { +static int bus_append_string(sd_bus_message *m, const char *field, const char *eq) { int r; r = sd_bus_message_append(m, "(sv)", field, "s", eq); diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 976643e4ce..cbcf698e96 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -559,7 +559,7 @@ int bus_check_peercred(sd_bus *c) { } int bus_connect_system_systemd(sd_bus **_bus) { - _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL; int r; assert(_bus); @@ -592,7 +592,7 @@ int bus_connect_system_systemd(sd_bus **_bus) { } int bus_connect_user_systemd(sd_bus **_bus) { - _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL; _cleanup_free_ char *ee = NULL; const char *e; int r; @@ -1279,7 +1279,7 @@ int bus_map_all_properties( } int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) { - _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL; int r; assert(transport >= 0); @@ -1666,7 +1666,7 @@ int bus_track_add_name_many(sd_bus_track *t, char **l) { } int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *description) { - _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL; const char *e; int r; diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 8fe177990a..b80c147807 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -137,7 +137,7 @@ static int next_assignment( /* Warn about unknown non-extension fields. */ if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-")) - log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section); + log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s', ignoring", lvalue, section); return 0; } @@ -321,7 +321,7 @@ int config_parse(const char *unit, return r; } - if (strchr(COMMENTS, *buf)) + if (strchr(COMMENTS, *skip_leading_chars(buf, WHITESPACE))) continue; l = buf; diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 3a46faf769..d340487025 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -1178,7 +1178,6 @@ int dissected_image_decrypt_interactively( #if HAVE_LIBCRYPTSETUP static int deferred_remove(DecryptedPartition *p) { - struct dm_ioctl dm = { .version = { DM_VERSION_MAJOR, @@ -1199,6 +1198,9 @@ static int deferred_remove(DecryptedPartition *p) { if (fd < 0) return -errno; + if (strlen(p->name) > sizeof(dm.name)) + return -ENAMETOOLONG; + strncpy(dm.name, p->name, sizeof(dm.name)); if (ioctl(fd, DM_DEV_REMOVE, &dm)) diff --git a/src/shared/efivars.c b/src/shared/efivars.c index cb9e13c15f..26f905bfaa 100644 --- a/src/shared/efivars.c +++ b/src/shared/efivars.c @@ -40,11 +40,17 @@ #define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001 -struct boot_option { - uint32_t attr; - uint16_t path_len; - uint16_t title[]; -} _packed_; +#define boot_option__contents { \ + uint32_t attr; \ + uint16_t path_len; \ + uint16_t title[]; \ + } + +struct boot_option boot_option__contents; +struct boot_option__packed boot_option__contents _packed_; +assert_cc(offsetof(struct boot_option, title) == offsetof(struct boot_option__packed, title)); +/* sizeof(struct boot_option) != sizeof(struct boot_option__packed), so + * the *size* of the structure should not be used anywhere below. */ struct drive_path { uint32_t part_nr; @@ -55,15 +61,19 @@ struct drive_path { uint8_t signature_type; } _packed_; -struct device_path { - uint8_t type; - uint8_t sub_type; - uint16_t length; - union { - uint16_t path[0]; - struct drive_path drive; - }; -} _packed_; +#define device_path__contents { \ + uint8_t type; \ + uint8_t sub_type; \ + uint16_t length; \ + union { \ + uint16_t path[0]; \ + struct drive_path drive; \ + }; \ + } + +struct device_path device_path__contents; +struct device_path__packed device_path__contents _packed_; +assert_cc(sizeof(struct device_path) == sizeof(struct device_path__packed)); bool is_efi_boot(void) { if (detect_container() > 0) @@ -354,32 +364,46 @@ int efi_set_variable_string(sd_id128_t vendor, const char *name, const char *v) return efi_set_variable(vendor, name, u16, (char16_strlen(u16) + 1) * sizeof(char16_t)); } -static size_t utf16_size(const uint16_t *s) { +static ssize_t utf16_size(const uint16_t *s, size_t buf_len_bytes) { size_t l = 0; - while (s[l] > 0) + /* Returns the size of the string in bytes without the terminating two zero bytes */ + + if (buf_len_bytes % sizeof(uint16_t) != 0) + return -EINVAL; + + while (l < buf_len_bytes / sizeof(uint16_t)) { + if (s[l] == 0) + return (l + 1) * sizeof(uint16_t); l++; + } - return (l+1) * sizeof(uint16_t); + return -EINVAL; /* The terminator was not found */ } +struct guid { + uint32_t u1; + uint16_t u2; + uint16_t u3; + uint8_t u4[8]; +} _packed_; + static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) { - struct uuid { - uint32_t u1; - uint16_t u2; - uint16_t u3; - uint8_t u4[8]; - } _packed_; - const struct uuid *uuid = guid; - - id128->bytes[0] = (uuid->u1 >> 24) & 0xff; - id128->bytes[1] = (uuid->u1 >> 16) & 0xff; - id128->bytes[2] = (uuid->u1 >> 8) & 0xff; - id128->bytes[3] = (uuid->u1) & 0xff; - id128->bytes[4] = (uuid->u2 >> 8) & 0xff; - id128->bytes[5] = (uuid->u2) & 0xff; - id128->bytes[6] = (uuid->u3 >> 8) & 0xff; - id128->bytes[7] = (uuid->u3) & 0xff; + uint32_t u1; + uint16_t u2, u3; + const struct guid *uuid = guid; + + memcpy(&u1, &uuid->u1, sizeof(uint32_t)); + id128->bytes[0] = (u1 >> 24) & 0xff; + id128->bytes[1] = (u1 >> 16) & 0xff; + id128->bytes[2] = (u1 >> 8) & 0xff; + id128->bytes[3] = u1 & 0xff; + memcpy(&u2, &uuid->u2, sizeof(uint16_t)); + id128->bytes[4] = (u2 >> 8) & 0xff; + id128->bytes[5] = u2 & 0xff; + memcpy(&u3, &uuid->u3, sizeof(uint16_t)); + id128->bytes[6] = (u3 >> 8) & 0xff; + id128->bytes[7] = u3 & 0xff; memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4)); } @@ -394,7 +418,7 @@ int efi_get_boot_option( _cleanup_free_ uint8_t *buf = NULL; size_t l; struct boot_option *header; - size_t title_size; + ssize_t title_size; _cleanup_free_ char *s = NULL, *p = NULL; sd_id128_t p_uuid = SD_ID128_NULL; int r; @@ -406,13 +430,13 @@ int efi_get_boot_option( r = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l); if (r < 0) return r; - if (l < sizeof(struct boot_option)) + if (l < offsetof(struct boot_option, title)) return -ENOENT; header = (struct boot_option *)buf; - title_size = utf16_size(header->title); - if (title_size > l - offsetof(struct boot_option, title)) - return -EINVAL; + title_size = utf16_size(header->title, l - offsetof(struct boot_option, title)); + if (title_size < 0) + return title_size; if (title) { s = utf16_to_utf8(header->title, title_size); @@ -494,20 +518,14 @@ static void to_utf16(uint16_t *dest, const char *src) { dest[i] = '\0'; } -struct guid { - uint32_t u1; - uint16_t u2; - uint16_t u3; - uint8_t u4[8]; -} _packed_; - static void id128_to_efi_guid(sd_id128_t id, void *guid) { - struct guid *uuid = guid; - - uuid->u1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3]; - uuid->u2 = id.bytes[4] << 8 | id.bytes[5]; - uuid->u3 = id.bytes[6] << 8 | id.bytes[7]; - memcpy(uuid->u4, id.bytes+8, sizeof(uuid->u4)); + struct guid uuid = { + .u1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3], + .u2 = id.bytes[4] << 8 | id.bytes[5], + .u3 = id.bytes[6] << 8 | id.bytes[7], + }; + memcpy(uuid.u4, id.bytes+8, sizeof(uuid.u4)); + memcpy(guid, &uuid, sizeof(uuid)); } static uint16_t *tilt_slashes(uint16_t *s) { @@ -541,7 +559,7 @@ int efi_add_boot_option( title_len = (strlen(title)+1) * 2; path_len = (strlen(path)+1) * 2; - buf = malloc0(sizeof(struct boot_option) + title_len + + buf = malloc0(offsetof(struct boot_option, title) + title_len + sizeof(struct drive_path) + sizeof(struct device_path) + path_len); if (!buf) @@ -561,12 +579,12 @@ int efi_add_boot_option( devicep->type = MEDIA_DEVICE_PATH; devicep->sub_type = MEDIA_HARDDRIVE_DP; devicep->length = offsetof(struct device_path, drive) + sizeof(struct drive_path); - devicep->drive.part_nr = part; - devicep->drive.part_start = pstart; - devicep->drive.part_size = psize; - devicep->drive.signature_type = SIGNATURE_TYPE_GUID; - devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER; + memcpy(&devicep->drive.part_nr, &part, sizeof(uint32_t)); + memcpy(&devicep->drive.part_start, &pstart, sizeof(uint64_t)); + memcpy(&devicep->drive.part_size, &psize, sizeof(uint64_t)); id128_to_efi_guid(part_uuid, devicep->drive.signature); + devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER; + devicep->drive.signature_type = SIGNATURE_TYPE_GUID; size += devicep->length; /* path to loader */ @@ -630,7 +648,7 @@ int efi_set_boot_order(uint16_t *order, size_t n) { return efi_set_variable(EFI_VENDOR_GLOBAL, "BootOrder", order, n * sizeof(uint16_t)); } -static int boot_id_hex(const char s[4]) { +static int boot_id_hex(const char s[static 4]) { int id = 0, i; for (i = 0; i < 4; i++) diff --git a/src/shared/install.c b/src/shared/install.c index 3104043af6..8629304cef 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -68,7 +68,7 @@ typedef struct { size_t n_rules; } Presets; -static inline bool unit_file_install_info_has_rules(const UnitFileInstallInfo *i) { +static bool unit_file_install_info_has_rules(const UnitFileInstallInfo *i) { assert(i); return !strv_isempty(i->aliases) || @@ -76,13 +76,13 @@ static inline bool unit_file_install_info_has_rules(const UnitFileInstallInfo *i !strv_isempty(i->required_by); } -static inline bool unit_file_install_info_has_also(const UnitFileInstallInfo *i) { +static bool unit_file_install_info_has_also(const UnitFileInstallInfo *i) { assert(i); return !strv_isempty(i->also); } -static inline void presets_freep(Presets *p) { +static void presets_freep(Presets *p) { size_t i; if (!p) diff --git a/src/shared/journal-importer.c b/src/shared/journal-importer.c index b0e619205d..8638cd3cc9 100644 --- a/src/shared/journal-importer.c +++ b/src/shared/journal-importer.c @@ -23,6 +23,9 @@ enum { }; static int iovw_put(struct iovec_wrapper *iovw, void* data, size_t len) { + if (iovw->count >= ENTRY_FIELD_COUNT_MAX) + return -E2BIG; + if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1)) return log_oom(); @@ -97,7 +100,7 @@ static int get_line(JournalImporter *imp, char **line, size_t *size) { imp->scanned = imp->filled; if (imp->scanned >= DATA_SIZE_MAX) - return log_error_errno(SYNTHETIC_ERRNO(E2BIG), + return log_error_errno(SYNTHETIC_ERRNO(ENOBUFS), "Entry is bigger than %u bytes.", DATA_SIZE_MAX); diff --git a/src/shared/journal-importer.h b/src/shared/journal-importer.h index 53354b7c78..7914c0cf5f 100644 --- a/src/shared/journal-importer.h +++ b/src/shared/journal-importer.h @@ -21,6 +21,9 @@ #endif #define LINE_CHUNK 8*1024u +/* The maximum number of fields in an entry */ +#define ENTRY_FIELD_COUNT_MAX 1024 + struct iovec_wrapper { struct iovec *iovec; size_t size_bytes; diff --git a/src/shared/json.c b/src/shared/json.c index 59c4617592..3786ff12b8 100644 --- a/src/shared/json.c +++ b/src/shared/json.c @@ -979,6 +979,8 @@ bool json_variant_has_type(JsonVariant *v, JsonVariantType type) { JsonVariantType rt; v = json_variant_dereference(v); + if (!v) + return false; rt = json_variant_type(v); if (rt == type) @@ -3140,10 +3142,7 @@ int json_log_internal( va_list ap; int r; - if (error < 0) - error = -error; - - errno = error; + errno = ERRNO_VALUE(error); va_start(ap, format); (void) vsnprintf(buffer, sizeof buffer, format, ap); diff --git a/src/shared/json.h b/src/shared/json.h index 4eba91c272..f8e035cda1 100644 --- a/src/shared/json.h +++ b/src/shared/json.h @@ -1,5 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ - #pragma once #include <stdbool.h> @@ -154,7 +153,7 @@ typedef enum JsonFormatFlags { JSON_FORMAT_NEWLINE = 1 << 0, /* suffix with newline */ JSON_FORMAT_PRETTY = 1 << 1, /* add internal whitespace to appeal to human readers */ JSON_FORMAT_COLOR = 1 << 2, /* insert ANSI color sequences */ - JSON_FORMAT_COLOR_AUTO = 1 << 3, /* insetr ANSI color sequences if colors_enabled() says so */ + JSON_FORMAT_COLOR_AUTO = 1 << 3, /* insert ANSI color sequences if colors_enabled() says so */ JSON_FORMAT_SOURCE = 1 << 4, /* prefix with source filename/line/column */ JSON_FORMAT_SSE = 1 << 5, /* prefix/suffix with W3C server-sent events */ JSON_FORMAT_SEQ = 1 << 6, /* prefix/suffix with RFC 7464 application/json-seq */ diff --git a/src/shared/lockfile-util.c b/src/shared/lockfile-util.c index 4bae23b243..260c2088d5 100644 --- a/src/shared/lockfile-util.c +++ b/src/shared/lockfile-util.c @@ -12,6 +12,7 @@ #include "fs-util.h" #include "lockfile-util.h" #include "macro.h" +#include "missing_fcntl.h" #include "path-util.h" int make_lock_file(const char *p, int operation, LockFile *ret) { diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index 525a948f36..15ef0f19ff 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -724,7 +724,7 @@ void json_escape( fputs(" ]", f); } else { - fputc('\"', f); + fputc('"', f); while (l > 0) { if (IN_SET(*p, '"', '\\')) { @@ -741,7 +741,7 @@ void json_escape( l--; } - fputc('\"', f); + fputc('"', f); } } diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c index 872c25c3dc..bf426eb8bc 100644 --- a/src/shared/loop-util.c +++ b/src/shared/loop-util.c @@ -45,11 +45,11 @@ int loop_device_make(int fd, int open_flags, LoopDevice **ret) { *d = (LoopDevice) { .fd = copy, .nr = -1, + .relinquished = true, /* It's not allocated by us, don't destroy it when this object is freed */ }; *ret = d; - - return 0; + return d->fd; } r = stat_verify_regular(&st); @@ -88,8 +88,7 @@ int loop_device_make(int fd, int open_flags, LoopDevice **ret) { }; *ret = d; - - return (*ret)->fd; + return d->fd; } int loop_device_make_by_path(const char *path, int open_flags, LoopDevice **ret) { diff --git a/src/shared/pager.c b/src/shared/pager.c index ce4ca9bdb2..bf2597e65a 100644 --- a/src/shared/pager.c +++ b/src/shared/pager.c @@ -173,7 +173,7 @@ int pager_open(PagerFlags flags) { execvp(pager_args[0], pager_args); log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno, - "Failed execute %s, using fallback pagers: %m", pager_args[0]); + "Failed to execute '%s', using fallback pagers: %m", pager_args[0]); } /* Debian's alternatives command for pagers is @@ -190,7 +190,7 @@ int pager_open(PagerFlags flags) { } execlp(exe, exe, NULL); log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno, - "Failed execute %s, using next fallback pager: %m", exe); + "Failed to execute '%s', using next fallback pager: %m", exe); } r = loop_write(exe_name_pipe[1], "(built-in)", strlen("(built-in") + 1, false); diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index 42d6dd2a94..cc58b3c078 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -793,7 +793,6 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = { "ioprio_get\0" "kcmp\0" "madvise\0" - "mincore\0" "mprotect\0" "mremap\0" "name_to_handle_at\0" diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c index ee31c448fc..dbb4622312 100644 --- a/src/shared/switch-root.c +++ b/src/shared/switch-root.c @@ -83,7 +83,7 @@ int switch_root(const char *new_root, (void) mkdir_p_label(chased, 0755); if (mount(i, chased, NULL, mount_flags, NULL) < 0) - return log_error_errno(r, "Failed to mount %s to %s: %m", i, chased); + return log_error_errno(errno, "Failed to mount %s to %s: %m", i, chased); } /* Do not fail if base_filesystem_create() fails. Not all switch roots are like base_filesystem_create() wants diff --git a/src/shared/xml.c b/src/shared/xml.c index cb34d870c1..2709076264 100644 --- a/src/shared/xml.c +++ b/src/shared/xml.c @@ -191,7 +191,7 @@ int xml_tokenize(const char **p, char **name, void **state, unsigned *line) { if (*c == '=') { c++; - if (IN_SET(*c, '\'', '\"')) { + if (IN_SET(*c, '\'', '"')) { /* Tag with a quoted value */ e = strchr(c+1, *c); diff --git a/src/sleep/sleep.conf b/src/sleep/sleep.conf new file mode 100644 index 0000000000..dc2ed37f70 --- /dev/null +++ b/src/sleep/sleep.conf @@ -0,0 +1,25 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# Entries in this file show the compile time defaults. +# You can change settings by editing this file. +# Defaults can be restored by simply deleting this file. +# +# See systemd-sleep.conf(5) for details + +[Sleep] +#AllowSuspend=yes +#AllowHibernation=yes +#AllowSuspendThenHibernate=yes +#AllowHybridSleep=yes +#SuspendMode= +#SuspendState=mem standby freeze +#HibernateMode=platform shutdown +#HibernateState=disk +#HybridSleepMode=suspend platform shutdown +#HybridSleepState=disk +#HibernateDelaySec=180min diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c index f882a665a8..bac5c164d4 100644 --- a/src/socket-proxy/socket-proxyd.c +++ b/src/socket-proxy/socket-proxyd.c @@ -86,7 +86,7 @@ static void context_clear(Context *context) { sd_resolve_unref(context->resolve); } -static int connection_create_pipes(Connection *c, int buffer[2], size_t *sz) { +static int connection_create_pipes(Connection *c, int buffer[static 2], size_t *sz) { int r; assert(c); diff --git a/src/stdio-bridge/stdio-bridge.c b/src/stdio-bridge/stdio-bridge.c index 3a21aa4aed..7060897ab7 100644 --- a/src/stdio-bridge/stdio-bridge.c +++ b/src/stdio-bridge/stdio-bridge.c @@ -91,7 +91,7 @@ static int parse_argv(int argc, char *argv[]) { } static int run(int argc, char *argv[]) { - _cleanup_(sd_bus_unrefp) sd_bus *a = NULL, *b = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *a = NULL, *b = NULL; sd_id128_t server_id; bool is_unix; int r, in_fd, out_fd; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 629f9cb505..63dae2c872 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -6933,9 +6933,9 @@ static int run_editor(char **paths) { if (r < 0) return r; if (r == 0) { - char **editor_args = NULL, **tmp_path, **original_path, *p; + char **editor_args = NULL, **tmp_path, **original_path; size_t n_editor_args = 0, i = 1, argc; - const char **args, *editor; + const char **args, *editor, *p; argc = strv_length(paths)/2 + 1; diff --git a/src/systemd/_sd-common.h b/src/systemd/_sd-common.h index 05c38008cf..b3ee7bbc24 100644 --- a/src/systemd/_sd-common.h +++ b/src/systemd/_sd-common.h @@ -72,6 +72,14 @@ typedef void (*_sd_destroy_t)(void *userdata); # endif #endif +#ifndef _SD_ARRAY_STATIC +# if __STDC_VERSION__ >= 199901L +# define _SD_ARRAY_STATIC static +# else +# define _SD_ARRAY_STATIC +# endif +#endif + #define _SD_DEFINE_POINTER_CLEANUP_FUNC(type, func) \ static __inline__ void func##p(type **p) { \ if (*p) \ diff --git a/src/systemd/meson.build b/src/systemd/meson.build index e0c967efc5..75c48b07a5 100644 --- a/src/systemd/meson.build +++ b/src/systemd/meson.build @@ -52,8 +52,7 @@ if cc.has_argument('-std=iso9899:2017') opts += [['c', '-std=iso9899:2017']] endif -cxx = find_program('c++', required : false) -if cxx.found() +if add_languages('cpp', required : false) opts += [['c++'], ['c++', '-std=c++98'], ['c++', '-std=c++11']] diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index 4c1acab9f3..129cc93328 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -170,6 +170,7 @@ void sd_bus_close(sd_bus *bus); sd_bus *sd_bus_ref(sd_bus *bus); sd_bus *sd_bus_unref(sd_bus *bus); +sd_bus *sd_bus_close_unref(sd_bus *bus); sd_bus *sd_bus_flush_close_unref(sd_bus *bus); void sd_bus_default_flush_close(void); @@ -493,6 +494,7 @@ int sd_bus_track_get_destroy_callback(sd_bus_track *s, sd_bus_destroy_t *ret); /* Define helpers so that __attribute__((cleanup(sd_bus_unrefp))) and similar may be used. */ _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_bus, sd_bus_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_bus, sd_bus_close_unref); _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_bus, sd_bus_flush_close_unref); _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_bus_slot, sd_bus_slot_unref); _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_bus_message, sd_bus_message_unref); diff --git a/src/systemd/sd-id128.h b/src/systemd/sd-id128.h index f4c05a3683..bdf88ed53f 100644 --- a/src/systemd/sd-id128.h +++ b/src/systemd/sd-id128.h @@ -35,7 +35,7 @@ union sd_id128 { #define SD_ID128_STRING_MAX 33 -char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]); +char *sd_id128_to_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD_ID128_STRING_MAX]); int sd_id128_from_string(const char *s, sd_id128_t *ret); int sd_id128_randomize(sd_id128_t *ret); diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index a3e5cd6be6..bf3afadcec 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -27,7 +27,7 @@ _SD_BEGIN_DECLARATIONS; -/* IEEE 802.3AB Clause 9: TLV Types */ +/* IEEE 802.1AB-2009 Clause 8: TLV Types */ enum { SD_LLDP_TYPE_END = 0, SD_LLDP_TYPE_CHASSIS_ID = 1, @@ -41,7 +41,7 @@ enum { SD_LLDP_TYPE_PRIVATE = 127, }; -/* IEEE 802.3AB Clause 9.5.2: Chassis subtypes */ +/* IEEE 802.1AB-2009 Clause 8.5.2: Chassis subtypes */ enum { SD_LLDP_CHASSIS_SUBTYPE_RESERVED = 0, SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT = 1, @@ -53,7 +53,7 @@ enum { SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7, }; -/* IEEE 802.3AB Clause 9.5.3: Port subtype */ +/* IEEE 802.1AB-2009 Clause 8.5.3: Port subtype */ enum { SD_LLDP_PORT_SUBTYPE_RESERVED = 0, SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1, @@ -65,6 +65,7 @@ enum { SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7, }; +/* IEEE 802.1AB-2009 Clause 8.5.8: System capabilities */ enum { SD_LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0, SD_LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1, @@ -95,6 +96,7 @@ enum { #define SD_LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 } #define SD_LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f } +/* IEEE 802.1AB-2009 Annex E */ enum { SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID = 1, SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID = 2, @@ -105,6 +107,14 @@ enum { SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7, }; +/* IEEE 802.1AB-2009 Annex F */ +enum { + SD_LLDP_OUI_802_3_SUBTYPE_MAC_PHY_CONFIG_STATUS = 1, + SD_LLDP_OUI_802_3_SUBTYPE_POWER_VIA_MDI = 2, + SD_LLDP_OUI_802_3_SUBTYPE_LINK_AGGREGATION = 3, + SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE = 4, +}; + typedef struct sd_lldp sd_lldp; typedef struct sd_lldp_neighbor sd_lldp_neighbor; @@ -168,8 +178,8 @@ int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n); int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n); int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type); int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type); -int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[3], uint8_t *subtype); -int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[3], uint8_t subtype); +int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t *subtype); +int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t subtype); int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size); _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp, sd_lldp_unref); diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index 30be5b113c..9e6e437bab 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -78,6 +78,8 @@ int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, ui int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, const void *data, size_t len); int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data); int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data); +int sd_netlink_message_append_sockaddr_in(sd_netlink_message *m, unsigned short type, const struct sockaddr_in *data); +int sd_netlink_message_append_sockaddr_in6(sd_netlink_message *m, unsigned short type, const struct sockaddr_in6 *data); int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data); int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info); @@ -200,7 +202,6 @@ int sd_netlink_slot_set_floating(sd_netlink_slot *slot, int b); int sd_netlink_slot_get_description(sd_netlink_slot *slot, const char **description); int sd_netlink_slot_set_description(sd_netlink_slot *slot, const char *description); - _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink, sd_netlink_unref); _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink_message, sd_netlink_message_unref); _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink_slot, sd_netlink_slot_unref); diff --git a/src/test/meson.build b/src/test/meson.build index ea049a6fba..08026ea8c4 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -929,7 +929,8 @@ tests += [ [['src/libsystemd/sd-resolve/test-resolve.c'], [], - [threads]], + [threads], + '', 'timeout=120'], [['src/libsystemd/sd-login/test-login.c'], [], @@ -957,7 +958,7 @@ tests += [ ] -if cxx.found() +if cxx_cmd != '' tests += [ [['src/libsystemd/sd-bus/test-bus-vtable-cc.cc'], [], diff --git a/src/test/test-barrier.c b/src/test/test-barrier.c index 6ae84cd6fc..6469129fa4 100644 --- a/src/test/test-barrier.c +++ b/src/test/test-barrier.c @@ -17,6 +17,7 @@ #include "barrier.h" #include "util.h" #include "tests.h" +#include "virt.h" /* 20ms to test deadlocks; All timings use multiples of this constant as * alarm/sleep timers. If this timeout is too small for slow machines to perform @@ -420,11 +421,27 @@ TEST_BARRIER(test_barrier_pending_exit, TEST_BARRIER_WAIT_SUCCESS(pid2)); int main(int argc, char *argv[]) { + int v; test_setup_logging(LOG_INFO); if (!slow_tests_enabled()) return log_tests_skipped("slow tests are disabled"); + /* + * 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. Given the recent + * issues when running the test in a virtualized environments, limit it + * to bare metal machines only, to minimize false-positives in CIs. + */ + v = detect_virtualization(); + if (IN_SET(v, -EPERM, -EACCES)) + return log_tests_skipped("Cannot detect virtualization"); + + if (v != VIRTUALIZATION_NONE) + return log_tests_skipped("This test requires a baremetal machine"); + test_barrier_sync(); test_barrier_wait_next(); test_barrier_wait_next_twice(); diff --git a/src/test/test-bpf.c b/src/test/test-bpf.c index ea5f0f5bc6..cd8d68f215 100644 --- a/src/test/test-bpf.c +++ b/src/test/test-bpf.c @@ -2,6 +2,7 @@ #include <linux/libbpf.h> #include <string.h> +#include <sys/mman.h> #include <unistd.h> #include "bpf-firewall.h" @@ -14,6 +15,30 @@ #include "tests.h" #include "unit.h" +/* We use the same limit here that PID 1 bumps RLIMIT_MEMLOCK to if it can */ +#define CAN_MEMLOCK_SIZE (64U*1024U*1024U) + +static bool can_memlock(void) { + void *p; + bool b; + + /* Let's see if we can mlock() a larger blob of memory. BPF programs are charged against + * RLIMIT_MEMLOCK, hence let's first make sure we can lock memory at all, and skip the test if we + * cannot. Why not check RLIMIT_MEMLOCK explicitly? Because in container environments the + * RLIMIT_MEMLOCK value we see might not match the RLIMIT_MEMLOCK value actually in effect. */ + + p = mmap(NULL, CAN_MEMLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, -1, 0); + if (p == MAP_FAILED) + return false; + + b = mlock(p, CAN_MEMLOCK_SIZE) >= 0; + if (b) + assert_se(munlock(p, CAN_MEMLOCK_SIZE) >= 0); + + assert_se(munmap(p, CAN_MEMLOCK_SIZE) >= 0); + return b; +} + int main(int argc, char *argv[]) { struct bpf_insn exit_insn[] = { BPF_MOV64_IMM(BPF_REG_0, 1), @@ -26,10 +51,21 @@ int main(int argc, char *argv[]) { _cleanup_(manager_freep) Manager *m = NULL; Unit *u; char log_buf[65535]; + struct rlimit rl; int r; test_setup_logging(LOG_DEBUG); + if (is_run_on_travis_ci()) + return log_tests_skipped("test-bpf fails on Travis CI: https://github.com/systemd/systemd/issues/9666"); + + assert_se(getrlimit(RLIMIT_MEMLOCK, &rl) >= 0); + rl.rlim_cur = rl.rlim_max = MAX3(rl.rlim_cur, rl.rlim_max, CAN_MEMLOCK_SIZE); + (void) setrlimit(RLIMIT_MEMLOCK, &rl); + + if (!can_memlock()) + return log_tests_skipped("Can't use mlock(), skipping."); + r = enter_cgroup_subroot(); if (r == -ENOMEDIUM) return log_tests_skipped("cgroupfs not available"); diff --git a/src/test/test-capability.c b/src/test/test-capability.c index dae85f2f91..325d7c8cc2 100644 --- a/src/test/test-capability.c +++ b/src/test/test-capability.c @@ -13,6 +13,7 @@ #include "fd-util.h" #include "fileio.h" #include "macro.h" +#include "missing_prctl.h" #include "parse-util.h" #include "tests.h" #include "util.h" diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c index 2921338f62..1738938fce 100644 --- a/src/test/test-conf-parser.c +++ b/src/test/test-conf-parser.c @@ -248,6 +248,18 @@ static const char* const config_file[] = { "3\n", "[Section]\n" + " #hogehoge\\\n" /* whitespaces before comments */ + " setting1=1\\\n" /* whitespaces before key */ + "2\\\n" + "3\n", + + "[Section]\n" + " setting1=1\\\n" /* whitespaces before key */ + " #hogehoge\\\n" /* commented out line prefixed with whitespaces in continuation */ + "2\\\n" + "3\n", + + "[Section]\n" "setting1=1\\\n" /* continuation with extra trailing backslash at the end */ "2\\\n" "3\\\n", @@ -323,27 +335,27 @@ static void test_config_parse(unsigned i, const char *s) { assert_se(streq(setting1, "1")); break; - case 4 ... 7: + case 4 ... 9: assert_se(r == 0); assert_se(streq(setting1, "1 2 3")); break; - case 8: + case 10: assert_se(r == 0); assert_se(streq(setting1, "1\\\\ \\\\2")); break; - case 9: + case 11: assert_se(r == 0); assert_se(streq(setting1, x1000("ABCD"))); break; - case 10 ... 11: + case 12 ... 13: assert_se(r == 0); assert_se(streq(setting1, x1000("ABCD") " foobar")); break; - case 12 ... 13: + case 14 ... 15: assert_se(r == -ENOBUFS); assert_se(setting1 == NULL); break; diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 2115061add..eb8f7c4eff 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -13,6 +13,7 @@ #include "fs-util.h" #include "macro.h" #include "manager.h" +#include "missing_prctl.h" #include "mkdir.h" #include "path-util.h" #include "rm-rf.h" @@ -130,7 +131,7 @@ static bool check_user_has_group_with_same_name(const char *name) { } static bool is_inaccessible_available(void) { - char *p; + const char *p; FOREACH_STRING(p, "/run/systemd/inaccessible/reg", @@ -769,6 +770,7 @@ int main(int argc, char *argv[]) { (void) unsetenv("USER"); (void) unsetenv("LOGNAME"); (void) unsetenv("SHELL"); + (void) unsetenv("HOME"); can_unshare = have_namespaces(); diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index bf918c1d1e..2ddaabe7f8 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -26,7 +26,8 @@ static void test_parse_env_file(void) { p[] = "/tmp/test-fileio-out-XXXXXX"; FILE *f; _cleanup_free_ char *one = NULL, *two = NULL, *three = NULL, *four = NULL, *five = NULL, - *six = NULL, *seven = NULL, *eight = NULL, *nine = NULL, *ten = NULL; + *six = NULL, *seven = NULL, *eight = NULL, *nine = NULL, *ten = NULL, + *eleven = NULL, *twelve = NULL, *thirteen = NULL; _cleanup_strv_free_ char **a = NULL, **b = NULL; char **i; unsigned k; @@ -43,7 +44,7 @@ static void test_parse_env_file(void) { "three = \"333\n" "xxxx\"\n" "four = \'44\\\"44\'\n" - "five = \'55\\\'55\' \"FIVE\" cinco \n" + "five = \"55\\\"55\" \"FIVE\" cinco \n" "six = seis sechs\\\n" " sis\n" "seven=\"sevenval\" #nocomment\n" @@ -51,7 +52,10 @@ static void test_parse_env_file(void) { "export nine=nineval\n" "ten=ignored\n" "ten=ignored\n" - "ten=", f); + "ten=\n" + "eleven=\\value\n" + "twelve=\"\\value\"\n" + "thirteen='\\value'", f); fflush(f); fclose(f); @@ -65,14 +69,17 @@ static void test_parse_env_file(void) { assert_se(streq_ptr(a[0], "one=BAR")); assert_se(streq_ptr(a[1], "two=bar")); assert_se(streq_ptr(a[2], "three=333\nxxxx")); - assert_se(streq_ptr(a[3], "four=44\"44")); - assert_se(streq_ptr(a[4], "five=55\'55FIVEcinco")); + assert_se(streq_ptr(a[3], "four=44\\\"44")); + assert_se(streq_ptr(a[4], "five=55\"55FIVEcinco")); assert_se(streq_ptr(a[5], "six=seis sechs sis")); assert_se(streq_ptr(a[6], "seven=sevenval#nocomment")); assert_se(streq_ptr(a[7], "eight=eightval #nocomment")); assert_se(streq_ptr(a[8], "export nine=nineval")); assert_se(streq_ptr(a[9], "ten=")); - assert_se(a[10] == NULL); + assert_se(streq_ptr(a[10], "eleven=value")); + assert_se(streq_ptr(a[11], "twelve=\\value")); + assert_se(streq_ptr(a[12], "thirteen=\\value")); + assert_se(a[13] == NULL); strv_env_clean(a); @@ -93,7 +100,10 @@ static void test_parse_env_file(void) { "seven", &seven, "eight", &eight, "export nine", &nine, - "ten", &ten); + "ten", &ten, + "eleven", &eleven, + "twelve", &twelve, + "thirteen", &thirteen); assert_se(r >= 0); @@ -107,17 +117,23 @@ static void test_parse_env_file(void) { log_info("eight=[%s]", strna(eight)); log_info("export nine=[%s]", strna(nine)); log_info("ten=[%s]", strna(nine)); + log_info("eleven=[%s]", strna(eleven)); + log_info("twelve=[%s]", strna(twelve)); + log_info("thirteen=[%s]", strna(thirteen)); assert_se(streq(one, "BAR")); assert_se(streq(two, "bar")); assert_se(streq(three, "333\nxxxx")); - assert_se(streq(four, "44\"44")); - assert_se(streq(five, "55\'55FIVEcinco")); + assert_se(streq(four, "44\\\"44")); + assert_se(streq(five, "55\"55FIVEcinco")); assert_se(streq(six, "seis sechs sis")); assert_se(streq(seven, "sevenval#nocomment")); assert_se(streq(eight, "eightval #nocomment")); assert_se(streq(nine, "nineval")); assert_se(ten == NULL); + assert_se(streq(eleven, "value")); + assert_se(streq(twelve, "\\value")); + assert_se(streq(thirteen, "\\value")); { /* prepare a temporary file to write the environment to */ diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c index b3a4b1749c..e049abc4a4 100644 --- a/src/test/test-fs-util.c +++ b/src/test/test-fs-util.c @@ -361,11 +361,11 @@ static void test_unlink_noerrno(void) { { PROTECT_ERRNO; - errno = -42; + errno = 42; assert_se(unlink_noerrno(name) >= 0); - assert_se(errno == -42); + assert_se(errno == 42); assert_se(unlink_noerrno(name) < 0); - assert_se(errno == -42); + assert_se(errno == 42); } } diff --git a/src/test/test-hexdecoct.c b/src/test/test-hexdecoct.c index 6e9b94b933..52217429b1 100644 --- a/src/test/test-hexdecoct.c +++ b/src/test/test-hexdecoct.c @@ -234,7 +234,6 @@ static void test_unbase32hexmem(void) { test_unbase32hexmem_one("CPNMUOJ1E8======", false, -EINVAL, NULL); test_unbase32hexmem_one("A", false, -EINVAL, NULL); - test_unbase32hexmem_one("A", false, -EINVAL, NULL); test_unbase32hexmem_one("AAA", false, -EINVAL, NULL); test_unbase32hexmem_one("AAAAAA", false, -EINVAL, NULL); test_unbase32hexmem_one("AB", false, -EINVAL, NULL); diff --git a/src/test/test-in-addr-util.c b/src/test/test-in-addr-util.c index 75c3e305c3..16844e9565 100644 --- a/src/test/test-in-addr-util.c +++ b/src/test/test-in-addr-util.c @@ -2,83 +2,85 @@ #include <netinet/in.h> +#include "log.h" #include "in-addr-util.h" -static void test_in_addr_prefix_from_string(const char *p, int family, int ret, const union in_addr_union *u, unsigned char prefixlen, bool use_default) { +static void test_in_addr_prefix_from_string( + const char *p, + int family, + int ret, + const union in_addr_union *u, + unsigned char prefixlen, + int ret_refuse, + unsigned char prefixlen_refuse, + int ret_legacy, + unsigned char prefixlen_legacy) { + union in_addr_union q; unsigned char l; - int r; + int f, r; - r = in_addr_prefix_from_string_internal(p, use_default, family, &q, &l); + r = in_addr_prefix_from_string(p, family, &q, &l); assert_se(r == ret); - if (r >= 0) { - int f; + if (r < 0) + return; + + assert_se(in_addr_equal(family, &q, u)); + assert_se(l == prefixlen); + + r = in_addr_prefix_from_string_auto(p, &f, &q, &l); + assert_se(r >= 0); + + assert_se(f == family); + assert_se(in_addr_equal(family, &q, u)); + assert_se(l == prefixlen); + + r = in_addr_prefix_from_string_auto_internal(p, PREFIXLEN_REFUSE, &f, &q, &l); + assert_se(r == ret_refuse); + if (r >= 0) { + assert_se(f == family); assert_se(in_addr_equal(family, &q, u)); - assert_se(l == prefixlen); + assert_se(l == prefixlen_refuse); + } - r = in_addr_prefix_from_string_auto_internal(p, use_default, &f, &q, &l); - assert_se(r >= 0); + r = in_addr_prefix_from_string_auto_internal(p, PREFIXLEN_LEGACY, &f, &q, &l); + assert_se(r == ret_legacy); + if (r >= 0) { assert_se(f == family); assert_se(in_addr_equal(family, &q, u)); - assert_se(l == prefixlen); + assert_se(l == prefixlen_legacy); } } int main(int argc, char *argv[]) { - test_in_addr_prefix_from_string("", AF_INET, -EINVAL, NULL, 0, false); - test_in_addr_prefix_from_string("/", AF_INET, -EINVAL, NULL, 0, false); - test_in_addr_prefix_from_string("/8", AF_INET, -EINVAL, NULL, 0, false); - test_in_addr_prefix_from_string("1.2.3.4", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32, false); - test_in_addr_prefix_from_string("1.2.3.4/0", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 0, false); - test_in_addr_prefix_from_string("1.2.3.4/1", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 1, false); - test_in_addr_prefix_from_string("1.2.3.4/2", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 2, false); - test_in_addr_prefix_from_string("1.2.3.4/32", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32, false); - test_in_addr_prefix_from_string("1.2.3.4/33", AF_INET, -ERANGE, NULL, 0, false); - test_in_addr_prefix_from_string("1.2.3.4/-1", AF_INET, -ERANGE, NULL, 0, false); - test_in_addr_prefix_from_string("::1", AF_INET, -EINVAL, NULL, 0, false); - - test_in_addr_prefix_from_string("", AF_INET6, -EINVAL, NULL, 0, false); - test_in_addr_prefix_from_string("/", AF_INET6, -EINVAL, NULL, 0, false); - test_in_addr_prefix_from_string("/8", AF_INET6, -EINVAL, NULL, 0, false); - test_in_addr_prefix_from_string("::1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128, false); - test_in_addr_prefix_from_string("::1/0", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0, false); - test_in_addr_prefix_from_string("::1/1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 1, false); - test_in_addr_prefix_from_string("::1/2", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 2, false); - test_in_addr_prefix_from_string("::1/32", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 32, false); - test_in_addr_prefix_from_string("::1/33", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 33, false); - test_in_addr_prefix_from_string("::1/64", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 64, false); - test_in_addr_prefix_from_string("::1/128", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128, false); - test_in_addr_prefix_from_string("::1/129", AF_INET6, -ERANGE, NULL, 0, false); - test_in_addr_prefix_from_string("::1/-1", AF_INET6, -ERANGE, NULL, 0, false); - - test_in_addr_prefix_from_string("", AF_INET, -EINVAL, NULL, 0, true); - test_in_addr_prefix_from_string("/", AF_INET, -EINVAL, NULL, 0, true); - test_in_addr_prefix_from_string("/8", AF_INET, -EINVAL, NULL, 0, true); - test_in_addr_prefix_from_string("1.2.3.4", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 8, true); - test_in_addr_prefix_from_string("1.2.3.4/0", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 0, true); - test_in_addr_prefix_from_string("1.2.3.4/1", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 1, true); - test_in_addr_prefix_from_string("1.2.3.4/2", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 2, true); - test_in_addr_prefix_from_string("1.2.3.4/32", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32, true); - test_in_addr_prefix_from_string("1.2.3.4/33", AF_INET, -ERANGE, NULL, 0, true); - test_in_addr_prefix_from_string("1.2.3.4/-1", AF_INET, -ERANGE, NULL, 0, true); - test_in_addr_prefix_from_string("::1", AF_INET, -EINVAL, NULL, 0, true); - - test_in_addr_prefix_from_string("", AF_INET6, -EINVAL, NULL, 0, true); - test_in_addr_prefix_from_string("/", AF_INET6, -EINVAL, NULL, 0, true); - test_in_addr_prefix_from_string("/8", AF_INET6, -EINVAL, NULL, 0, true); - test_in_addr_prefix_from_string("::1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0, true); - test_in_addr_prefix_from_string("::1/0", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0, true); - test_in_addr_prefix_from_string("::1/1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 1, true); - test_in_addr_prefix_from_string("::1/2", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 2, true); - test_in_addr_prefix_from_string("::1/32", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 32, true); - test_in_addr_prefix_from_string("::1/33", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 33, true); - test_in_addr_prefix_from_string("::1/64", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 64, true); - test_in_addr_prefix_from_string("::1/128", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128, true); - test_in_addr_prefix_from_string("::1/129", AF_INET6, -ERANGE, NULL, 0, true); - test_in_addr_prefix_from_string("::1/-1", AF_INET6, -ERANGE, NULL, 0, true); + test_in_addr_prefix_from_string("", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0); + test_in_addr_prefix_from_string("/", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0); + test_in_addr_prefix_from_string("/8", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0); + test_in_addr_prefix_from_string("1.2.3.4", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32, -ENOANO, 0, 0, 8); + test_in_addr_prefix_from_string("1.2.3.4/0", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 0, 0, 0, 0, 0); + test_in_addr_prefix_from_string("1.2.3.4/1", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 1, 0, 1, 0, 1); + test_in_addr_prefix_from_string("1.2.3.4/2", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 2, 0, 2, 0, 2); + test_in_addr_prefix_from_string("1.2.3.4/32", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32, 0, 32, 0, 32); + test_in_addr_prefix_from_string("1.2.3.4/33", AF_INET, -ERANGE, NULL, 0, -ERANGE, 0, -ERANGE, 0); + test_in_addr_prefix_from_string("1.2.3.4/-1", AF_INET, -ERANGE, NULL, 0, -ERANGE, 0, -ERANGE, 0); + test_in_addr_prefix_from_string("::1", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0); + + test_in_addr_prefix_from_string("", AF_INET6, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0); + test_in_addr_prefix_from_string("/", AF_INET6, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0); + test_in_addr_prefix_from_string("/8", AF_INET6, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0); + test_in_addr_prefix_from_string("::1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128, -ENOANO, 0, 0, 0); + test_in_addr_prefix_from_string("::1/0", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0, 0, 0, 0, 0); + test_in_addr_prefix_from_string("::1/1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 1, 0, 1, 0, 1); + test_in_addr_prefix_from_string("::1/2", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 2, 0, 2, 0, 2); + test_in_addr_prefix_from_string("::1/32", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 32, 0, 32, 0, 32); + test_in_addr_prefix_from_string("::1/33", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 33, 0, 33, 0, 33); + test_in_addr_prefix_from_string("::1/64", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 64, 0, 64, 0, 64); + test_in_addr_prefix_from_string("::1/128", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128, 0, 128, 0, 128); + test_in_addr_prefix_from_string("::1/129", AF_INET6, -ERANGE, NULL, 0, -ERANGE, 0, -ERANGE, 0); + test_in_addr_prefix_from_string("::1/-1", AF_INET6, -ERANGE, NULL, 0, -ERANGE, 0, -ERANGE, 0); return 0; } diff --git a/src/test/test-json.c b/src/test/test-json.c index 5aa4d19dbe..fdf1b4f40c 100644 --- a/src/test/test-json.c +++ b/src/test/test-json.c @@ -1,9 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #include <math.h> -#if HAVE_VALGRIND_VALGRIND_H -#include <valgrind/valgrind.h> -#endif #include "alloc-util.h" #include "fd-util.h" @@ -45,12 +42,13 @@ static void test_tokenizer(const char *data, ...) { d = va_arg(ap, long double); -#if HAVE_VALGRIND_VALGRIND_H - if (!RUNNING_ON_VALGRIND) -#endif - /* Valgrind doesn't support long double calculations and automatically downgrades to 80bit: - * http://www.valgrind.org/docs/manual/manual-core.html#manual-core.limits */ - assert_se(fabsl(d - v.real) < 0.001L); + /* Valgrind doesn't support long double calculations and automatically downgrades to 80bit: + * http://www.valgrind.org/docs/manual/manual-core.html#manual-core.limits. + * Some architectures might not support long double either. + */ + + assert_se(fabsl(d - v.real) < 1e-10 || + fabsl((d - v.real) / v.real) < 1e-10); } else if (t == JSON_TOKEN_INTEGER) { intmax_t i; @@ -211,7 +209,6 @@ static void test_2(JsonVariant *v) { assert_se(p && json_variant_type(p) == JSON_VARIANT_REAL && fabsl(json_variant_real(p) - 1.27) < 0.001); } - static void test_zeroes(JsonVariant *v) { size_t i; @@ -285,6 +282,7 @@ static void test_build(void) { a = json_variant_unref(a); b = json_variant_unref(b); + const char* arr_1234[] = {"one", "two", "three", "four", NULL}; assert_se(json_build(&a, JSON_BUILD_ARRAY(JSON_BUILD_OBJECT(JSON_BUILD_PAIR("x", JSON_BUILD_BOOLEAN(true)), JSON_BUILD_PAIR("y", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("this", JSON_BUILD_NULL)))), JSON_BUILD_VARIANT(NULL), @@ -292,8 +290,9 @@ static void test_build(void) { JSON_BUILD_STRING(NULL), JSON_BUILD_NULL, JSON_BUILD_INTEGER(77), - JSON_BUILD_ARRAY(JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("foobar")), JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("zzz"))), - JSON_BUILD_STRV(STRV_MAKE("one", "two", "three", "four")))) >= 0); + JSON_BUILD_ARRAY(JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("foobar")), + JSON_BUILD_VARIANT(JSON_VARIANT_STRING_CONST("zzz"))), + JSON_BUILD_STRV((char**) arr_1234))) >= 0); assert_se(json_variant_format(a, 0, &s) >= 0); log_info("GOT: %s\n", s); diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c index 10bf365035..15c0f8853d 100644 --- a/src/test/test-libudev.c +++ b/src/test/test-libudev.c @@ -7,6 +7,7 @@ #include <unistd.h> #include "alloc-util.h" +#include "build.h" #include "fd-util.h" #include "libudev-list-internal.h" #include "libudev-util.h" @@ -364,16 +365,23 @@ static void test_util_replace_whitespace(void) { test_util_replace_whitespace_one_len("hoge hoge ", 1, "h"); test_util_replace_whitespace_one_len("hoge hoge ", 0, ""); - test_util_replace_whitespace_one_len(" hoge hoge ", 9, "hoge_hoge"); - test_util_replace_whitespace_one_len(" hoge hoge ", 8, "hoge_hog"); - test_util_replace_whitespace_one_len(" hoge hoge ", 7, "hoge_ho"); - test_util_replace_whitespace_one_len(" hoge hoge ", 6, "hoge_h"); - test_util_replace_whitespace_one_len(" hoge hoge ", 5, "hoge"); - test_util_replace_whitespace_one_len(" hoge hoge ", 4, "hoge"); - test_util_replace_whitespace_one_len(" hoge hoge ", 3, "hog"); - test_util_replace_whitespace_one_len(" hoge hoge ", 2, "ho"); - test_util_replace_whitespace_one_len(" hoge hoge ", 1, "h"); - test_util_replace_whitespace_one_len(" hoge hoge ", 0, ""); + test_util_replace_whitespace_one_len(" hoge hoge ", 16, "hoge_hoge"); + test_util_replace_whitespace_one_len(" hoge hoge ", 15, "hoge_hoge"); + test_util_replace_whitespace_one_len(" hoge hoge ", 14, "hoge_hog"); + test_util_replace_whitespace_one_len(" hoge hoge ", 13, "hoge_ho"); + test_util_replace_whitespace_one_len(" hoge hoge ", 12, "hoge_h"); + test_util_replace_whitespace_one_len(" hoge hoge ", 11, "hoge"); + test_util_replace_whitespace_one_len(" hoge hoge ", 10, "hoge"); + test_util_replace_whitespace_one_len(" hoge hoge ", 9, "hoge"); + test_util_replace_whitespace_one_len(" hoge hoge ", 8, "hoge"); + test_util_replace_whitespace_one_len(" hoge hoge ", 7, "hog"); + test_util_replace_whitespace_one_len(" hoge hoge ", 6, "ho"); + test_util_replace_whitespace_one_len(" hoge hoge ", 5, "h"); + test_util_replace_whitespace_one_len(" hoge hoge ", 4, ""); + test_util_replace_whitespace_one_len(" hoge hoge ", 3, ""); + test_util_replace_whitespace_one_len(" hoge hoge ", 2, ""); + test_util_replace_whitespace_one_len(" hoge hoge ", 1, ""); + test_util_replace_whitespace_one_len(" hoge hoge ", 0, ""); } static void test_util_resolve_subsys_kernel_one(const char *str, bool read_value, int retval, const char *expected) { @@ -507,7 +515,7 @@ int main(int argc, char *argv[]) { return EXIT_SUCCESS; case 'V': - printf("%s\n", PACKAGE_VERSION); + printf("%s\n", GIT_VERSION); return EXIT_SUCCESS; case 'm': diff --git a/src/test/test-mountpoint-util.c b/src/test/test-mountpoint-util.c index 6d8bee0d63..8e45c0b1a7 100644 --- a/src/test/test-mountpoint-util.c +++ b/src/test/test-mountpoint-util.c @@ -8,7 +8,6 @@ #include "fileio.h" #include "hashmap.h" #include "log.h" -#include "log.h" #include "mountpoint-util.h" #include "path-util.h" #include "rm-rf.h" diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index 8854a94f6c..c64ca7b016 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -531,7 +531,7 @@ static void test_hidden_or_backup_file(void) { static void test_systemd_installation_has_version(const char *path) { int r; - const unsigned versions[] = {0, 231, atoi(PACKAGE_VERSION), 999}; + const unsigned versions[] = {0, 231, PROJECT_VERSION, 999}; unsigned i; for (i = 0; i < ELEMENTSOF(versions); i++) { diff --git a/src/test/test-prioq.c b/src/test/test-prioq.c index bc5fdd15b2..53c9e090a7 100644 --- a/src/test/test-prioq.c +++ b/src/test/test-prioq.c @@ -69,6 +69,11 @@ static void test_struct(void) { assert_se(q = prioq_new((compare_func_t) test_compare)); assert_se(s = set_new(&test_hash_ops)); + assert_se(prioq_peek(q) == NULL); + assert_se(prioq_peek_by_index(q, 0) == NULL); + assert_se(prioq_peek_by_index(q, 1) == NULL); + assert_se(prioq_peek_by_index(q, (unsigned) -1) == NULL); + for (i = 0; i < SET_SIZE; i++) { assert_se(t = new0(struct test, 1)); t->value = (unsigned) rand(); @@ -79,6 +84,17 @@ static void test_struct(void) { assert_se(set_consume(s, t) >= 0); } + for (i = 0; i < SET_SIZE; i++) + assert_se(prioq_peek_by_index(q, i)); + assert_se(prioq_peek_by_index(q, SET_SIZE) == NULL); + + unsigned count = 0; + PRIOQ_FOREACH_ITEM(q, t) { + assert_se(t); + count++; + } + assert_se(count == SET_SIZE); + while ((t = set_steal_first(s))) { assert_se(prioq_remove(q, t, &t->idx) == 1); assert_se(prioq_remove(q, t, &t->idx) == 0); diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index 5c87db08f5..b5ba651d89 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -70,11 +70,9 @@ static void test_get_process_comm(pid_t pid) { assert_se(get_process_uid(pid, &u) == 0); log_info("PID"PID_FMT" UID: "UID_FMT, pid, u); - assert_se(u == 0 || pid != 1); assert_se(get_process_gid(pid, &g) == 0); log_info("PID"PID_FMT" GID: "GID_FMT, pid, g); - assert_se(g == 0 || pid != 1); r = get_process_environ(pid, &env); assert_se(r >= 0 || r == -EACCES); diff --git a/src/test/test-procfs-util.c b/src/test/test-procfs-util.c index 08af380cc7..1d0612985b 100644 --- a/src/test/test-procfs-util.c +++ b/src/test/test-procfs-util.c @@ -18,7 +18,7 @@ int main(int argc, char *argv[]) { assert_se(procfs_cpu_get_usage(&nsec) >= 0); log_info("Current system CPU time: %s", format_timespan(buf, sizeof(buf), nsec/NSEC_PER_USEC, 1)); - assert_se(procfs_memory_get_current(&v) >= 0); + assert_se(procfs_memory_get_used(&v) >= 0); log_info("Current memory usage: %s", format_bytes(buf, sizeof(buf), v)); assert_se(procfs_tasks_get_current(&v) >= 0); diff --git a/src/test/test-sizeof.c b/src/test/test-sizeof.c index 7a1e496ed2..35b087653e 100644 --- a/src/test/test-sizeof.c +++ b/src/test/test-sizeof.c @@ -13,11 +13,12 @@ #pragma GCC diagnostic ignored "-Wtype-limits" -#define info(t) \ - printf("%s → %zu bits%s\n", STRINGIFY(t), \ - sizeof(t)*CHAR_BIT, \ - strstr(STRINGIFY(t), "signed") ? "" : \ - ((t)-1 < (t)0 ? ", signed" : ", unsigned")); +#define info(t) \ + printf("%s → %zu bits%s, %zu byte alignment\n", STRINGIFY(t), \ + sizeof(t)*CHAR_BIT, \ + strstr(STRINGIFY(t), "signed") ? "" : \ + (t)-1 < (t)0 ? ", signed" : ", unsigned", \ + __alignof__(t)) enum Enum { enum_value, diff --git a/src/test/test-stat-util.c b/src/test/test-stat-util.c index d16fdd90d1..0e2155e911 100644 --- a/src/test/test-stat-util.c +++ b/src/test/test-stat-util.c @@ -56,7 +56,6 @@ static void test_path_is_fs_type(void) { } assert_se(path_is_fs_type("/proc", PROC_SUPER_MAGIC) > 0); assert_se(path_is_fs_type("/proc", BTRFS_SUPER_MAGIC) == 0); - assert_se(path_is_fs_type("/proc", BTRFS_SUPER_MAGIC) == 0); assert_se(path_is_fs_type("/i-dont-exist", BTRFS_SUPER_MAGIC) == -ENOENT); } diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c index 2ec2ade3f1..eb6041c152 100644 --- a/src/test/test-time-util.c +++ b/src/test/test-time-util.c @@ -212,7 +212,6 @@ static void test_format_timespan(usec_t accuracy) { test_format_timespan_one(12345678, accuracy); test_format_timespan_one(1200000, accuracy); test_format_timespan_one(1230000, accuracy); - test_format_timespan_one(1230000, accuracy); test_format_timespan_one(1234000, accuracy); test_format_timespan_one(1234500, accuracy); test_format_timespan_one(1234560, accuracy); @@ -289,7 +288,6 @@ static void test_usec_sub_signed(void) { assert_se(usec_sub_signed(4, 4) == 0); assert_se(usec_sub_signed(4, 5) == 0); assert_se(usec_sub_signed(USEC_INFINITY-3, -3) == USEC_INFINITY); - assert_se(usec_sub_signed(USEC_INFINITY-3, -3) == USEC_INFINITY); assert_se(usec_sub_signed(USEC_INFINITY-3, -4) == USEC_INFINITY); assert_se(usec_sub_signed(USEC_INFINITY-3, -5) == USEC_INFINITY); assert_se(usec_sub_signed(USEC_INFINITY, 5) == USEC_INFINITY); diff --git a/src/test/test-udev.c b/src/test/test-udev.c index 7a4622b875..ab31f5a2f1 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -11,6 +11,7 @@ #include <sys/signalfd.h> #include <unistd.h> +#include "build.h" #include "device-private.h" #include "fs-util.h" #include "log.h" @@ -81,7 +82,7 @@ static int run(int argc, char *argv[]) { return 0; } - log_debug("version %s", PACKAGE_VERSION); + log_debug("version %s", GIT_VERSION); mac_selinux_init(); action = argv[1]; diff --git a/src/test/test-util.c b/src/test/test-util.c index 3c1b5f9b41..ffacd65669 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -139,11 +139,11 @@ static void test_container_of(void) { uint64_t v1; uint8_t pad2[2]; uint32_t v2; - } _packed_ myval = { }; + } myval = { }; log_info("/* %s */", __func__); - assert_cc(sizeof(myval) == 17); + assert_cc(sizeof(myval) >= 17); assert_se(container_of(&myval.v1, struct mytype, v1) == &myval); assert_se(container_of(&myval.v2, struct mytype, v2) == &myval); assert_se(container_of(&container_of(&myval.v2, @@ -213,6 +213,30 @@ static void test_protect_errno(void) { assert_se(errno == 12); } +static void test_unprotect_errno_inner_function(void) { + PROTECT_ERRNO; + + errno = 2222; +} + +static void test_unprotect_errno(void) { + log_info("/* %s */", __func__); + + errno = 4711; + + PROTECT_ERRNO; + + errno = 815; + + UNPROTECT_ERRNO; + + assert_se(errno == 4711); + + test_unprotect_errno_inner_function(); + + assert_se(errno == 4711); +} + static void test_in_set(void) { log_info("/* %s */", __func__); @@ -383,6 +407,7 @@ int main(int argc, char *argv[]) { test_div_round_up(); test_u64log2(); test_protect_errno(); + test_unprotect_errno(); test_in_set(); test_log2i(); test_eqzero(); diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index e16888945c..eeb17b613e 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -160,7 +160,7 @@ static int context_ntp_service_is_active(Context *c) { /* Call context_update_ntp_status() to update UnitStatusInfo before calling this. */ LIST_FOREACH(units, info, c->units) - count += streq_ptr(info->active_state, "active"); + count += !STRPTR_IN_SET(info->active_state, "inactive", "failed"); return count; } @@ -174,7 +174,7 @@ static int context_ntp_service_is_enabled(Context *c) { /* Call context_update_ntp_status() to update UnitStatusInfo before calling this. */ LIST_FOREACH(units, info, c->units) - count += STRPTR_IN_SET(info->unit_file_state, "enabled", "enabled-runtime"); + count += !STRPTR_IN_SET(info->unit_file_state, "masked", "masked-runtime", "disabled", "bad"); return count; } @@ -523,6 +523,10 @@ static int property_get_can_ntp( assert(reply); assert(error); + if (c->slot_job_removed) + /* When the previous request is not finished, then assume NTP is enabled. */ + return sd_bus_message_append(reply, "b", true); + r = context_update_ntp_status(c, bus, reply); if (r < 0) return r; @@ -548,6 +552,10 @@ static int property_get_ntp( assert(reply); assert(error); + if (c->slot_job_removed) + /* When the previous request is not finished, then assume NTP is active. */ + return sd_bus_message_append(reply, "b", true); + r = context_update_ntp_status(c, bus, reply); if (r < 0) return r; @@ -735,6 +743,9 @@ static int method_set_time(sd_bus_message *m, void *userdata, sd_bus_error *erro assert(m); assert(c); + if (c->slot_job_removed) + return sd_bus_error_set(error, BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED, "Previous request is not finished, refusing."); + r = context_update_ntp_status(c, bus, m); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to update context: %m"); diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c index 4b0696f3a3..6fde4a316b 100644 --- a/src/timesync/timesyncd-manager.c +++ b/src/timesync/timesyncd-manager.c @@ -616,8 +616,9 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re m->good = true; server_address_pretty(m->current_server_address, &pretty); - log_info("Synchronized to time server %s (%s).", strna(pretty), m->current_server_name->string); - sd_notifyf(false, "STATUS=Synchronized to time server %s (%s).", strna(pretty), m->current_server_name->string); + /* "for the first time", as further successful syncs will not be logged. */ + log_info("Synchronized to time server for the first time %s (%s).", strna(pretty), m->current_server_name->string); + sd_notifyf(false, "STATUS=Synchronized to time server for the first time %s (%s).", strna(pretty), m->current_server_name->string); } r = manager_arm_timer(m, m->poll_interval_usec); @@ -937,7 +938,7 @@ void manager_free(Manager *m) { sd_resolve_unref(m->resolve); sd_event_unref(m->event); - sd_bus_unref(m->bus); + sd_bus_flush_close_unref(m->bus); free(m); } diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c index 70774d757b..b4f70c0007 100644 --- a/src/timesync/timesyncd.c +++ b/src/timesync/timesyncd.c @@ -169,9 +169,7 @@ static int run(int argc, char *argv[]) { log_debug_errno(r, "Failed to touch %s, ignoring: %m", CLOCK_FILE); } - (void) sd_event_get_exit_code(m->event, &r); - - return r; + return 0; } DEFINE_MAIN_FUNCTION(run); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 19225f8cfd..b66765b407 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -1463,7 +1463,7 @@ static int copy_files(Item *i) { dfd, bn, i->uid_set ? i->uid : UID_INVALID, i->gid_set ? i->gid : GID_INVALID, - COPY_REFLINK); + COPY_REFLINK | COPY_MERGE_EMPTY); if (r < 0) { struct stat a, b; @@ -3130,7 +3130,7 @@ static int link_parent(ItemArray *a) { return 0; path = a->items[0].path; - prefix = alloca(strlen(path) + 1); + prefix = newa(char, strlen(path) + 1); PATH_FOREACH_PREFIX(prefix, path) { ItemArray *j; diff --git a/src/udev/meson.build b/src/udev/meson.build index e378d9190c..9d3f6d1c56 100644 --- a/src/udev/meson.build +++ b/src/udev/meson.build @@ -41,6 +41,8 @@ libudev_core_sources = ''' net/link-config.h net/ethtool-util.c net/ethtool-util.h + net/naming-scheme.c + net/naming-scheme.h '''.split() if conf.get('HAVE_KMOD') == 1 @@ -187,12 +189,11 @@ endforeach install_data('udev.conf', install_dir : join_paths(sysconfdir, 'udev')) -udev_pc = configure_file( +configure_file( input : 'udev.pc.in', output : 'udev.pc', - configuration : substs) -install_data(udev_pc, - install_dir : pkgconfigdatadir) + configuration : substs, + install_dir : pkgconfigdatadir == 'no' ? '' : pkgconfigdatadir) meson.add_install_script('sh', '-c', mkdir_p.format(join_paths(sysconfdir, 'udev/rules.d'))) diff --git a/src/udev/net/ethtool-util.c b/src/udev/net/ethtool-util.c index bc0deaf347..0dcec03f67 100644 --- a/src/udev/net/ethtool-util.c +++ b/src/udev/net/ethtool-util.c @@ -31,18 +31,18 @@ static const char* const wol_table[_WOL_MAX] = { [WOL_ARP] = "arp", [WOL_MAGIC] = "magic", [WOL_MAGICSECURE] = "secureon", - [WOL_OFF] = "off" + [WOL_OFF] = "off", }; DEFINE_STRING_TABLE_LOOKUP(wol, WakeOnLan); DEFINE_CONFIG_PARSE_ENUM(config_parse_wol, wol, WakeOnLan, "Failed to parse WakeOnLan setting"); -static const char* const port_table[_NET_DEV_PORT_MAX] = { +static const char* const port_table[] = { [NET_DEV_PORT_TP] = "tp", [NET_DEV_PORT_AUI] = "aui", [NET_DEV_PORT_MII] = "mii", [NET_DEV_PORT_FIBRE] = "fibre", - [NET_DEV_PORT_BNC] = "bnc" + [NET_DEV_PORT_BNC] = "bnc", }; DEFINE_STRING_TABLE_LOOKUP(port, NetDevPort); @@ -583,7 +583,7 @@ int ethtool_set_glinksettings(int *fd, const char *ifname, struct link_config *l struct ifreq ifr = {}; int r; - if (link->autonegotiation != 0) { + if (link->autonegotiation != AUTONEG_DISABLE && eqzero(link->advertise)) { log_info("link_config: autonegotiation is unset or enabled, the speed and duplex are not writable."); return 0; } @@ -612,9 +612,11 @@ int ethtool_set_glinksettings(int *fd, const char *ifname, struct link_config *l if (link->port != _NET_DEV_PORT_INVALID) u->base.port = link->port; - u->base.autoneg = link->autonegotiation; + if (link->autonegotiation >= 0) + u->base.autoneg = link->autonegotiation; if (!eqzero(link->advertise)) { + u->base.autoneg = AUTONEG_ENABLE; memcpy(&u->link_modes.advertising, link->advertise, sizeof(link->advertise)); memzero((uint8_t*) &u->link_modes.advertising + sizeof(link->advertise), ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES - sizeof(link->advertise)); diff --git a/src/udev/net/ethtool-util.h b/src/udev/net/ethtool-util.h index e4bc5161d5..618b26bf59 100644 --- a/src/udev/net/ethtool-util.h +++ b/src/udev/net/ethtool-util.h @@ -42,14 +42,14 @@ typedef enum NetDevFeature { } NetDevFeature; typedef enum NetDevPort { - NET_DEV_PORT_TP = 0x00, - NET_DEV_PORT_AUI = 0x01, - NET_DEV_PORT_MII = 0x02, - NET_DEV_PORT_FIBRE = 0x03, - NET_DEV_PORT_BNC = 0x04, - NET_DEV_PORT_DA = 0x05, - NET_DEV_PORT_NONE = 0xef, - NET_DEV_PORT_OTHER = 0xff, + NET_DEV_PORT_TP = PORT_TP, + NET_DEV_PORT_AUI = PORT_AUI, + NET_DEV_PORT_MII = PORT_MII, + NET_DEV_PORT_FIBRE = PORT_FIBRE, + NET_DEV_PORT_BNC = PORT_BNC, + NET_DEV_PORT_DA = PORT_DA, + NET_DEV_PORT_NONE = PORT_NONE, + NET_DEV_PORT_OTHER = PORT_OTHER, _NET_DEV_PORT_MAX, _NET_DEV_PORT_INVALID = -1 } NetDevPort; diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index ac66ffd047..eb2477cea4 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -14,6 +14,7 @@ #include "link-config.h" #include "log.h" #include "missing_network.h" +#include "naming-scheme.h" #include "netlink-util.h" #include "network-internal.h" #include "parse-util.h" @@ -186,6 +187,22 @@ static bool enable_name_policy(void) { return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b; } +static int link_name_type(sd_device *device, unsigned *type) { + const char *s; + int r; + + r = sd_device_get_sysattr_value(device, "name_assign_type", &s); + if (r < 0) + return log_device_debug_errno(device, r, "Failed to query name_assign_type: %m"); + + r = safe_atou(s, type); + if (r < 0) + return log_device_warning_errno(device, r, "Failed to parse name_assign_type \"%s\": %m", s); + + log_device_debug(device, "Device has name_assign_type=%d", *type); + return 0; +} + int link_config_load(link_config_ctx *ctx) { _cleanup_strv_free_ char **files; char **f; @@ -256,13 +273,13 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) if (name_assign_type == NET_NAME_ENUM) { log_warning("Config file %s applies to device based on potentially unpredictable interface name '%s'", - link->filename, sysname); + link->filename, sysname); *ret = link; return 0; } else if (name_assign_type == NET_NAME_RENAMED) { log_warning("Config file %s matches device based on renamed interface name '%s', ignoring", - link->filename, sysname); + link->filename, sysname); continue; } @@ -272,13 +289,11 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) link->filename, sysname); *ret = link; - return 0; } } *ret = NULL; - return -ENOENT; } @@ -298,31 +313,6 @@ static bool mac_is_random(sd_device *device) { return type == NET_ADDR_RANDOM; } -static bool should_rename(sd_device *device, bool respect_predictable) { - const char *s; - unsigned type; - int r; - - /* if we can't get the assgin type, assume we should rename */ - if (sd_device_get_sysattr_value(device, "name_assign_type", &s) < 0) - return true; - - r = safe_atou(s, &type); - if (r < 0) - return true; - - switch (type) { - case NET_NAME_PREDICTABLE: - /* the kernel claims to have given a predictable name */ - if (respect_predictable) - return false; - _fallthrough_; - default: - /* the name is known to be bad, or of an unknown type */ - return true; - } -} - static int get_mac(sd_device *device, bool want_random, struct ether_addr *mac) { int r; @@ -349,12 +339,12 @@ static int get_mac(sd_device *device, bool want_random, int link_config_apply(link_config_ctx *ctx, link_config *config, sd_device *device, const char **name) { - bool respect_predictable = false; struct ether_addr generated_mac; struct ether_addr *mac = NULL; const char *new_name = NULL; const char *old_name; - unsigned speed; + unsigned speed, name_type = NET_NAME_UNKNOWN; + NamePolicy policy; int r, ifindex; assert(ctx); @@ -407,38 +397,63 @@ int link_config_apply(link_config_ctx *ctx, link_config *config, if (r < 0) return log_device_warning_errno(device, r, "Could not find ifindex: %m"); - if (ctx->enable_name_policy && config->name_policy) { - NamePolicy *policy; - for (policy = config->name_policy; - !new_name && *policy != _NAMEPOLICY_INVALID; policy++) { - switch (*policy) { - case NAMEPOLICY_KERNEL: - respect_predictable = true; - break; - case NAMEPOLICY_DATABASE: - (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &new_name); - break; - case NAMEPOLICY_ONBOARD: - (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &new_name); - break; - case NAMEPOLICY_SLOT: - (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &new_name); - break; - case NAMEPOLICY_PATH: - (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &new_name); - break; - case NAMEPOLICY_MAC: - (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &new_name); - break; - default: - break; + (void) link_name_type(device, &name_type); + + if (IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED) + && !naming_scheme_has(NAMING_ALLOW_RERENAMES)) { + log_device_debug(device, "Device already has a name given by userspace, not renaming."); + goto no_rename; + } + + if (ctx->enable_name_policy && config->name_policy) + for (NamePolicy *p = config->name_policy; !new_name && *p != _NAMEPOLICY_INVALID; p++) { + policy = *p; + + switch (policy) { + case NAMEPOLICY_KERNEL: + if (name_type != NET_NAME_PREDICTABLE) + continue; + + /* The kernel claims to have given a predictable name, keep it. */ + log_device_debug(device, "Policy *%s*: keeping predictable kernel name", + name_policy_to_string(policy)); + goto no_rename; + case NAMEPOLICY_KEEP: + if (!IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED)) + continue; + + log_device_debug(device, "Policy *%s*: keeping existing userspace name", + name_policy_to_string(policy)); + goto no_rename; + case NAMEPOLICY_DATABASE: + (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &new_name); + break; + case NAMEPOLICY_ONBOARD: + (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &new_name); + break; + case NAMEPOLICY_SLOT: + (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &new_name); + break; + case NAMEPOLICY_PATH: + (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &new_name); + break; + case NAMEPOLICY_MAC: + (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &new_name); + break; + default: + assert_not_reached("invalid policy"); } } - } - if (!new_name && should_rename(device, respect_predictable)) + if (new_name) + log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name); + else if (config->name) { new_name = config->name; + log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", new_name); + } else + log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming."); + no_rename: switch (config->mac_policy) { case MACPOLICY_PERSISTENT: @@ -497,7 +512,7 @@ int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret) { static const char* const mac_policy_table[_MACPOLICY_MAX] = { [MACPOLICY_PERSISTENT] = "persistent", [MACPOLICY_RANDOM] = "random", - [MACPOLICY_NONE] = "none" + [MACPOLICY_NONE] = "none", }; DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy); @@ -506,11 +521,12 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy, static const char* const name_policy_table[_NAMEPOLICY_MAX] = { [NAMEPOLICY_KERNEL] = "kernel", + [NAMEPOLICY_KEEP] = "keep", [NAMEPOLICY_DATABASE] = "database", [NAMEPOLICY_ONBOARD] = "onboard", [NAMEPOLICY_SLOT] = "slot", [NAMEPOLICY_PATH] = "path", - [NAMEPOLICY_MAC] = "mac" + [NAMEPOLICY_MAC] = "mac", }; DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy); diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index 8204959034..1113b1052e 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -22,6 +22,7 @@ typedef enum MACPolicy { typedef enum NamePolicy { NAMEPOLICY_KERNEL, + NAMEPOLICY_KEEP, NAMEPOLICY_DATABASE, NAMEPOLICY_ONBOARD, NAMEPOLICY_SLOT, diff --git a/src/udev/net/naming-scheme.c b/src/udev/net/naming-scheme.c new file mode 100644 index 0000000000..27cede5e2e --- /dev/null +++ b/src/udev/net/naming-scheme.c @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#include "alloc-util.h" +#include "naming-scheme.h" +#include "proc-cmdline.h" +#include "string-util.h" + +static const NamingScheme naming_schemes[] = { + { "v238", NAMING_V238 }, + { "v239", NAMING_V239 }, + { "v240", NAMING_V240 }, + /* … add more schemes here, as the logic to name devices is updated … */ +}; + +static const NamingScheme* naming_scheme_from_name(const char *name) { + size_t i; + + if (streq(name, "latest")) + return naming_schemes + ELEMENTSOF(naming_schemes) - 1; + + for (i = 0; i < ELEMENTSOF(naming_schemes); i++) + if (streq(naming_schemes[i].name, name)) + return naming_schemes + i; + + return NULL; +} + +const NamingScheme* naming_scheme(void) { + static const NamingScheme *cache = NULL; + _cleanup_free_ char *buffer = NULL; + const char *e, *k; + + if (cache) + return cache; + + /* Acquire setting from the kernel command line */ + (void) proc_cmdline_get_key("net.naming-scheme", 0, &buffer); + + /* Also acquire it from an env var */ + e = getenv("NET_NAMING_SCHEME"); + if (e) { + if (*e == ':') { + /* If prefixed with ':' the kernel cmdline takes precedence */ + k = buffer ?: e + 1; + } else + k = e; /* Otherwise the env var takes precedence */ + } else + k = buffer; + + if (k) { + cache = naming_scheme_from_name(k); + if (cache) { + log_info("Using interface naming scheme '%s'.", cache->name); + return cache; + } + + log_warning("Unknown interface naming scheme '%s' requested, ignoring.", k); + } + + cache = naming_scheme_from_name(DEFAULT_NET_NAMING_SCHEME); + assert(cache); + log_info("Using default interface naming scheme '%s'.", cache->name); + + return cache; +} diff --git a/src/udev/net/naming-scheme.h b/src/udev/net/naming-scheme.h new file mode 100644 index 0000000000..0b3d9bff1d --- /dev/null +++ b/src/udev/net/naming-scheme.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include <stdbool.h> + +#include "macro.h" + +/* So here's the deal: net_id is supposed to be an excercise in providing stable names for network devices. However, we + * also want to keep updating the naming scheme used in future versions of net_id. These two goals of course are + * contradictory: on one hand we want things to not change and on the other hand we want them to improve. Our way out + * of this dilemma is to introduce the "naming scheme" concept: each time we improve the naming logic we define a new + * flag for it. Then, we keep a list of schemes, each identified by a name associated with the flags it implements. Via + * a kernel command line and environment variable we then allow the user to pick the scheme they want us to follow: + * installers could "freeze" the used scheme at the moment of installation this way. + * + * Developers: each time you tweak the naming logic here, define a new flag below, and condition the tweak with + * it. Each time we do a release we'll then add a new scheme entry and include all newly defined flags. + * + * Note that this is only half a solution to the problem though: not only udev/net_id gets updated all the time, the + * kernel gets too. And thus a kernel that previously didn't expose some sysfs attribute we look for might eventually + * do, and thus affect our naming scheme too. Thus, enforcing a naming scheme will make interfacing more stable across + * OS versions, but not fully stabilize them. */ +typedef enum NamingSchemeFlags { + /* First, the individual features */ + NAMING_SR_IOV_V = 1 << 0, /* Use "v" suffix for SR-IOV, see 609948c7043a40008b8299529c978ed8e11de8f6*/ + NAMING_NPAR_ARI = 1 << 1, /* Use NPAR "ARI", see 6bc04997b6eab35d1cb9fa73889892702c27be09 */ + NAMING_INFINIBAND = 1 << 2, /* Use "ib" prefix for infiniband, see 938d30aa98df887797c9e05074a562ddacdcdf5e */ + NAMING_ZERO_ACPI_INDEX = 1 << 3, /* Allow zero acpi_index field, see d81186ef4f6a888a70f20a1e73a812d6acb9e22f */ + NAMING_ALLOW_RERENAMES = 1 << 4, /* Allow re-renaming of devices, see #9006 */ + + /* And now the masks that combine the features above */ + NAMING_V238 = 0, + NAMING_V239 = NAMING_V238 | NAMING_SR_IOV_V | NAMING_NPAR_ARI, + NAMING_V240 = NAMING_V239 | NAMING_INFINIBAND | NAMING_ZERO_ACPI_INDEX | NAMING_ALLOW_RERENAMES, + + _NAMING_SCHEME_FLAGS_INVALID = -1, +} NamingSchemeFlags; + +typedef struct NamingScheme { + const char *name; + NamingSchemeFlags flags; +} NamingScheme; + +const NamingScheme* naming_scheme(void); + +static inline bool naming_scheme_has(NamingSchemeFlags flags) { + return FLAGS_SET(naming_scheme()->flags, flags); +} diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c index e94f2946f9..2698cdd82f 100644 --- a/src/udev/scsi_id/scsi_id.c +++ b/src/udev/scsi_id/scsi_id.c @@ -18,6 +18,7 @@ #include <unistd.h> #include "alloc-util.h" +#include "build.h" #include "fd-util.h" #include "libudev-util.h" #include "scsi_id.h" @@ -370,7 +371,7 @@ static int set_options(int argc, char **argv, break; case 'V': - printf("%s\n", PACKAGE_VERSION); + printf("%s\n", GIT_VERSION); exit(EXIT_SUCCESS); case 'x': diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c index df0f95461d..69d6c4bbee 100644 --- a/src/udev/udev-builtin-blkid.c +++ b/src/udev/udev-builtin-blkid.c @@ -240,7 +240,7 @@ static int builtin_blkid(sd_device *dev, int argc, char *argv[], bool test) { if (r < 0) return log_device_error_errno(dev, r, "Failed to parse '%s' as an integer: %m", optarg); if (offset < 0) - return log_device_error_errno(dev, -ERANGE, "Invalid offset %"PRIi64": %m", offset); + return log_device_error_errno(dev, SYNTHETIC_ERRNO(ERANGE), "Invalid offset %"PRIi64": %m", offset); break; case 'R': noraid = true; diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c index 85dba3d099..956be59afb 100644 --- a/src/udev/udev-builtin-btrfs.c +++ b/src/udev/udev-builtin-btrfs.c @@ -18,7 +18,7 @@ static int builtin_btrfs(sd_device *dev, int argc, char *argv[], bool test) { int r; if (argc != 3 || !streq(argv[1], "ready")) - return log_device_error_errno(dev, EINVAL, "Invalid arguments"); + return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid arguments"); fd = open("/dev/btrfs-control", O_RDWR|O_CLOEXEC); if (fd < 0) diff --git a/src/udev/udev-builtin-hwdb.c b/src/udev/udev-builtin-hwdb.c index ccad98e892..225e0265a4 100644 --- a/src/udev/udev-builtin-hwdb.c +++ b/src/udev/udev-builtin-hwdb.c @@ -165,7 +165,7 @@ static int builtin_hwdb(sd_device *dev, int argc, char *argv[], bool test) { if (r < 0) return log_device_debug_errno(dev, r, "Failed to lookup hwdb: %m"); if (r == 0) - return log_device_debug_errno(dev, ENOENT, "No entry found from hwdb: %m"); + return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ENODATA), "No entry found from hwdb."); return r; } @@ -180,7 +180,7 @@ static int builtin_hwdb(sd_device *dev, int argc, char *argv[], bool test) { if (r < 0) return log_device_debug_errno(dev, r, "Failed to lookup hwdb: %m"); if (r == 0) - return log_device_debug_errno(dev, ENOENT, "No entry found from hwdb: %m"); + return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ENODATA), "No entry found from hwdb."); return r; } diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c index 13e9f0108d..e3db55b1a9 100644 --- a/src/udev/udev-builtin-input_id.c +++ b/src/udev/udev-builtin-input_id.c @@ -42,7 +42,7 @@ static const struct range high_key_blocks[] = { { KEY_ALS_TOGGLE, BTN_TRIGGER_HAPPY } }; -static inline int abs_size_mm(const struct input_absinfo *absinfo) { +static int abs_size_mm(const struct input_absinfo *absinfo) { /* Resolution is defined to be in units/mm for ABS_X/Y */ return (absinfo->maximum - absinfo->minimum) / absinfo->resolution; } diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c index cb49a17c33..d80cdd26aa 100644 --- a/src/udev/udev-builtin-keyboard.c +++ b/src/udev/udev-builtin-keyboard.c @@ -74,7 +74,7 @@ static int map_keycode(sd_device *dev, int fd, int scancode, const char *keycode /* check if it's a numeric code already */ keycode_num = strtoul(keycode, &endptr, 0); if (endptr[0] !='\0') - return log_device_error_errno(dev, EINVAL, "Failed to parse key identifier '%s'", keycode); + return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Failed to parse key identifier '%s'", keycode); } map.scan = scancode; @@ -89,7 +89,7 @@ static int map_keycode(sd_device *dev, int fd, int scancode, const char *keycode return 0; } -static inline char* parse_token(const char *current, int32_t *val_out) { +static char* parse_token(const char *current, int32_t *val_out) { char *next; int32_t val; @@ -152,7 +152,7 @@ static int set_trackpoint_sensitivity(sd_device *dev, const char *value) { if (r < 0) return log_device_error_errno(dev, r, "Failed to parse POINTINGSTICK_SENSITIVITY '%s': %m", value); else if (val_i < 0 || val_i > 255) - return log_device_error_errno(dev, ERANGE, "POINTINGSTICK_SENSITIVITY %d outside range [0..255]", val_i); + return log_device_error_errno(dev, SYNTHETIC_ERRNO(ERANGE), "POINTINGSTICK_SENSITIVITY %d outside range [0..255]", val_i); xsprintf(val_s, "%d", val_i); diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index 0292c4973c..03b281a771 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -106,6 +106,7 @@ #include "fd-util.h" #include "fileio.h" #include "fs-util.h" +#include "naming-scheme.h" #include "parse-util.h" #include "proc-cmdline.h" #include "stdio-util.h" @@ -116,48 +117,6 @@ #define ONBOARD_INDEX_MAX (16*1024-1) -/* So here's the deal: net_id is supposed to be an excercise in providing stable names for network devices. However, we - * also want to keep updating the naming scheme used in future versions of net_id. These two goals of course are - * contradictory: on one hand we want things to not change and on the other hand we want them to improve. Our way out - * of this dilemma is to introduce the "naming scheme" concept: each time we improve the naming logic we define a new - * flag for it. Then, we keep a list of schemes, each identified by a name associated with the flags it implements. Via - * a kernel command line and environment variable we then allow the user to pick the scheme they want us to follow: - * installers could "freeze" the used scheme at the moment of installation this way. - * - * Developers: each time you tweak the naming logic here, define a new flag below, and condition the tweak with - * it. Each time we do a release we'll then add a new scheme entry and include all newly defined flags. - * - * Note that this is only half a solution to the problem though: not only udev/net_id gets updated all the time, the - * kernel gets too. And thus a kernel that previously didn't expose some sysfs attribute we look for might eventually - * do, and thus affect our naming scheme too. Thus, enforcing a naming scheme will make interfacing more stable across - * OS versions, but not fully stabilize them. */ -typedef enum NamingSchemeFlags { - /* First, the individual features */ - NAMING_SR_IOV_V = 1 << 0, /* Use "v" suffix for SR-IOV, see 609948c7043a40008b8299529c978ed8e11de8f6*/ - NAMING_NPAR_ARI = 1 << 1, /* Use NPAR "ARI", see 6bc04997b6eab35d1cb9fa73889892702c27be09 */ - NAMING_INFINIBAND = 1 << 2, /* Use "ib" prefix for infiniband, see 938d30aa98df887797c9e05074a562ddacdcdf5e */ - NAMING_ZERO_ACPI_INDEX = 1 << 3, /* Allow zero acpi_index field, see d81186ef4f6a888a70f20a1e73a812d6acb9e22f */ - - /* And now the masks that combine the features above */ - NAMING_V238 = 0, - NAMING_V239 = NAMING_V238|NAMING_SR_IOV_V|NAMING_NPAR_ARI, - NAMING_V240 = NAMING_V239|NAMING_INFINIBAND|NAMING_ZERO_ACPI_INDEX, - - _NAMING_SCHEME_FLAGS_INVALID = -1, -} NamingSchemeFlags; - -typedef struct NamingScheme { - const char *name; - NamingSchemeFlags flags; -} NamingScheme; - -static const NamingScheme naming_schemes[] = { - { "v238", NAMING_V238 }, - { "v239", NAMING_V239 }, - { "v240", NAMING_V240 }, - /* … add more schemes here, as the logic to name devices is updated … */ -}; - enum netname_type{ NET_UNDEF, NET_PCI, @@ -193,62 +152,6 @@ struct virtfn_info { char suffix[IFNAMSIZ]; }; -static const NamingScheme* naming_scheme_from_name(const char *name) { - size_t i; - - if (streq(name, "latest")) - return naming_schemes + ELEMENTSOF(naming_schemes) - 1; - - for (i = 0; i < ELEMENTSOF(naming_schemes); i++) - if (streq(naming_schemes[i].name, name)) - return naming_schemes + i; - - return NULL; -} - -static const NamingScheme* naming_scheme(void) { - static const NamingScheme *cache = NULL; - _cleanup_free_ char *buffer = NULL; - const char *e, *k; - - if (cache) - return cache; - - /* Acquire setting from the kernel command line */ - (void) proc_cmdline_get_key("net.naming-scheme", 0, &buffer); - - /* Also acquire it from an env var */ - e = getenv("NET_NAMING_SCHEME"); - if (e) { - if (*e == ':') { - /* If prefixed with ':' the kernel cmdline takes precedence */ - k = buffer ?: e + 1; - } else - k = e; /* Otherwise the env var takes precedence */ - } else - k = buffer; - - if (k) { - cache = naming_scheme_from_name(k); - if (cache) { - log_info("Using interface naming scheme '%s'.", cache->name); - return cache; - } - - log_warning("Unknown interface naming scheme '%s' requested, ignoring.", k); - } - - cache = naming_scheme_from_name(DEFAULT_NET_NAMING_SCHEME); - assert(cache); - log_info("Using default interface naming scheme '%s'.", cache->name); - - return cache; -} - -static bool naming_scheme_has(NamingSchemeFlags flags) { - return FLAGS_SET(naming_scheme()->flags, flags); -} - /* skip intermediate virtio devices */ static sd_device *skip_virtio(sd_device *dev) { sd_device *parent; @@ -460,7 +363,7 @@ static int dev_pci_slot(sd_device *dev, struct netnames *names) { } } - /* kernel provided front panel port name for multiple port PCI device */ + /* kernel provided front panel port name for multi-port PCI device */ (void) sd_device_get_sysattr_value(dev, "phys_port_name", &port_name); /* compose a name based on the raw kernel's PCI bus, slot numbers */ @@ -478,7 +381,7 @@ static int dev_pci_slot(sd_device *dev, struct netnames *names) { if (l == 0) names->pci_path[0] = '\0'; - /* ACPI _SUN — slot user number */ + /* ACPI _SUN — slot user number */ r = sd_device_new_from_subsystem_sysname(&pci, "subsystem", "pci"); if (r < 0) return r; diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c index c0d3d4aa01..a845dfa5c1 100644 --- a/src/udev/udev-builtin-net_setup_link.c +++ b/src/udev/udev-builtin-net_setup_link.c @@ -16,7 +16,7 @@ static int builtin_net_setup_link(sd_device *dev, int argc, char **argv, bool te int r; if (argc > 1) - return log_device_error_errno(dev, EINVAL, "This program takes no arguments."); + return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments."); r = link_get_driver(ctx, dev, &driver); if (r >= 0) diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c index 94f2740592..7ce1c5644f 100644 --- a/src/udev/udev-builtin-path_id.c +++ b/src/udev/udev-builtin-path_id.c @@ -110,7 +110,6 @@ static sd_device *handle_scsi_fibre_channel(sd_device *parent, char **path) { assert(parent); assert(path); - if (sd_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target", &targetdev) < 0) return NULL; if (sd_device_get_sysname(targetdev, &sysname) < 0) diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c index 3a61be10ca..48ce295a46 100644 --- a/src/udev/udev-builtin.c +++ b/src/udev/udev-builtin.c @@ -139,7 +139,7 @@ int udev_builtin_add_property(sd_device *dev, bool test, const char *key, const key, val ? "=" : "", strempty(val)); if (test) - printf("%s=%s\n", key, val); + printf("%s=%s\n", key, strempty(val)); return 0; } diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index d90ebb7259..c217815ac6 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -213,14 +213,12 @@ static struct udev_ctrl_connection *udev_ctrl_connection_free(struct udev_ctrl_c DEFINE_TRIVIAL_REF_UNREF_FUNC(struct udev_ctrl_connection, udev_ctrl_connection, udev_ctrl_connection_free); -static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, int timeout) { - struct udev_ctrl_msg_wire ctrl_msg_wire; - int err = 0; - - memzero(&ctrl_msg_wire, sizeof(struct udev_ctrl_msg_wire)); - strcpy(ctrl_msg_wire.version, "udev-" PACKAGE_VERSION); - ctrl_msg_wire.magic = UDEV_CTRL_MAGIC; - ctrl_msg_wire.type = type; +static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, usec_t timeout) { + struct udev_ctrl_msg_wire ctrl_msg_wire = { + .version = "udev-" STRINGIFY(PROJECT_VERSION), + .magic = UDEV_CTRL_MAGIC, + .type = type, + }; if (buf) strscpy(ctrl_msg_wire.buf, sizeof(ctrl_msg_wire.buf), buf); @@ -228,74 +226,64 @@ static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int ctrl_msg_wire.intval = intval; if (!uctrl->connected) { - if (connect(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen) < 0) { - err = -errno; - goto out; - } + if (connect(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen) < 0) + return -errno; uctrl->connected = true; } - if (send(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0) < 0) { - err = -errno; - goto out; - } + if (send(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0) < 0) + return -errno; /* wait for peer message handling or disconnect */ for (;;) { - struct pollfd pfd[1]; + struct pollfd pfd = { + .fd = uctrl->sock, + .events = POLLIN, + }; int r; - pfd[0].fd = uctrl->sock; - pfd[0].events = POLLIN; - r = poll(pfd, 1, timeout * MSEC_PER_SEC); + r = poll(&pfd, 1, DIV_ROUND_UP(timeout, USEC_PER_MSEC)); if (r < 0) { if (errno == EINTR) continue; - err = -errno; - break; - } - - if (r > 0 && pfd[0].revents & POLLERR) { - err = -EIO; - break; + return -errno; } - if (r == 0) - err = -ETIMEDOUT; - break; + return -ETIMEDOUT; + if (pfd.revents & POLLERR) + return -EIO; + return 0; } -out: - return err; } -int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout) { +int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, usec_t timeout) { return ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL, timeout); } -int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout) { +int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, usec_t timeout) { return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL, timeout); } -int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout) { +int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, usec_t timeout) { return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL, timeout); } -int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout) { +int udev_ctrl_send_reload(struct udev_ctrl *uctrl, usec_t timeout) { return ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL, timeout); } -int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout) { +int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, usec_t timeout) { return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key, timeout); } -int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout) { +int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, usec_t timeout) { return ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL, timeout); } -int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout) { +int udev_ctrl_send_ping(struct udev_ctrl *uctrl, usec_t timeout) { return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout); } -int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout) { +int udev_ctrl_send_exit(struct udev_ctrl *uctrl, usec_t timeout) { return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, timeout); } diff --git a/src/udev/udev-ctrl.h b/src/udev/udev-ctrl.h index 87021cb880..8e452a4249 100644 --- a/src/udev/udev-ctrl.h +++ b/src/udev/udev-ctrl.h @@ -2,6 +2,7 @@ #pragma once #include "macro.h" +#include "time-util.h" struct udev_ctrl; struct udev_ctrl *udev_ctrl_new(void); @@ -10,14 +11,14 @@ int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl); struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl); int udev_ctrl_cleanup(struct udev_ctrl *uctrl); int udev_ctrl_get_fd(struct udev_ctrl *uctrl); -int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout); -int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout); -int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout); -int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout); -int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout); -int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout); -int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout); -int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout); +int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, usec_t timeout); +int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, usec_t timeout); +int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, usec_t timeout); +int udev_ctrl_send_reload(struct udev_ctrl *uctrl, usec_t timeout); +int udev_ctrl_send_ping(struct udev_ctrl *uctrl, usec_t timeout); +int udev_ctrl_send_exit(struct udev_ctrl *uctrl, usec_t timeout); +int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, usec_t timeout); +int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, usec_t timeout); struct udev_ctrl_connection; struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl); diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index e28d6a5d08..07b7365e3a 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -504,38 +504,34 @@ static int on_spawn_timeout_warning(sd_event_source *s, uint64_t usec, void *use static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata) { Spawn *spawn = userdata; + int ret = -EIO; assert(spawn); switch (si->si_code) { case CLD_EXITED: - if (si->si_status == 0) { + if (si->si_status == 0) log_debug("Process '%s' succeeded.", spawn->cmd); - sd_event_exit(sd_event_source_get_event(s), 0); - - return 1; - } - - log_full(spawn->accept_failure ? LOG_DEBUG : LOG_WARNING, - "Process '%s' failed with exit code %i.", spawn->cmd, si->si_status); + else + log_full(spawn->accept_failure ? LOG_DEBUG : LOG_WARNING, + "Process '%s' failed with exit code %i.", spawn->cmd, si->si_status); + ret = si->si_status; break; case CLD_KILLED: case CLD_DUMPED: - log_warning("Process '%s' terminated by signal %s.", spawn->cmd, signal_to_string(si->si_status)); - + log_error("Process '%s' terminated by signal %s.", spawn->cmd, signal_to_string(si->si_status)); break; default: log_error("Process '%s' failed due to unknown reason.", spawn->cmd); } - sd_event_exit(sd_event_source_get_event(s), -EIO); - + sd_event_exit(sd_event_source_get_event(s), ret); return 1; } static int spawn_wait(Spawn *spawn) { _cleanup_(sd_event_unrefp) sd_event *e = NULL; - int r, ret; + int r; assert(spawn); @@ -570,27 +566,23 @@ static int spawn_wait(Spawn *spawn) { } } - r = sd_event_add_io(e, NULL, spawn->fd_stdout, EPOLLIN, on_spawn_io, spawn); - if (r < 0) - return r; + if (spawn->fd_stdout >= 0) { + r = sd_event_add_io(e, NULL, spawn->fd_stdout, EPOLLIN, on_spawn_io, spawn); + if (r < 0) + return r; + } - r = sd_event_add_io(e, NULL, spawn->fd_stderr, EPOLLIN, on_spawn_io, spawn); - if (r < 0) - return r; + if (spawn->fd_stderr >= 0) { + r = sd_event_add_io(e, NULL, spawn->fd_stderr, EPOLLIN, on_spawn_io, spawn); + if (r < 0) + return r; + } r = sd_event_add_child(e, NULL, spawn->pid, WEXITED, on_spawn_sigchld, spawn); if (r < 0) return r; - r = sd_event_loop(e); - if (r < 0) - return r; - - r = sd_event_get_exit_code(e, &ret); - if (r < 0) - return r; - - return ret; + return sd_event_loop(e); } int udev_event_spawn(UdevEvent *event, @@ -675,12 +667,12 @@ int udev_event_spawn(UdevEvent *event, }; r = spawn_wait(&spawn); if (r < 0) - return log_error_errno(r, "Failed to wait spawned command '%s': %m", cmd); + return log_error_errno(r, "Failed to wait for spawned command '%s': %m", cmd); if (result) result[spawn.result_len] = '\0'; - return r; + return r; /* 0 for success, and positive if the program failed */ } static int rename_netif(UdevEvent *event) { @@ -895,7 +887,7 @@ void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec) { (void) usleep(event->exec_delay_usec); } - udev_event_spawn(event, timeout_usec, false, command, NULL, 0); + (void) udev_event_spawn(event, timeout_usec, false, command, NULL, 0); } } } diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index c11eb8c1ac..1c00dd1e9e 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -181,6 +181,9 @@ static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir, priority = db_prio; } + if (!target) + return -ENOENT; + *ret = TAKE_PTR(target); return 0; } @@ -297,7 +300,7 @@ static int node_permissions_apply(sd_device *dev, bool apply, return log_device_debug_errno(dev, errno, "cannot stat() node '%s' (%m)", devnode); if (((stats.st_mode & S_IFMT) != (mode & S_IFMT)) || (stats.st_rdev != devnum)) - return log_device_debug_errno(dev, EEXIST, "Found node '%s' with non-matching devnum %s, skip handling", + return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EEXIST), "Found node '%s' with non-matching devnum %s, skip handling", devnode, id_filename); if (apply) { diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 53c68d254a..bc9c6c26c5 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -441,8 +441,8 @@ static void dump_rules(UdevRules *rules) { dump_token(rules, &rules->tokens[i]); } #else -static inline void dump_token(UdevRules *rules, struct token *token) {} -static inline void dump_rules(UdevRules *rules) {} +static void dump_token(UdevRules *rules, struct token *token) {} +static void dump_rules(UdevRules *rules) {} #endif /* ENABLE_DEBUG_UDEV */ static int add_token(UdevRules *rules, struct token *token) { @@ -645,11 +645,13 @@ static int import_program_into_properties(UdevEvent *event, const char *program) { char result[UTIL_LINE_SIZE]; char *line; - int err; + int r; - err = udev_event_spawn(event, timeout_usec, true, program, result, sizeof(result)); - if (err < 0) - return err; + r = udev_event_spawn(event, timeout_usec, false, program, result, sizeof result); + if (r < 0) + return r; + if (r > 0) + return -EIO; line = result; while (line) { @@ -831,13 +833,15 @@ static const char *get_key_attribute(char *str) { return NULL; } -static void rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, - enum operation_type op, - const char *value, const void *data) { +static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, + enum operation_type op, + const char *value, const void *data) { struct token *token = rule_tmp->token + rule_tmp->token_cur; const char *attr = NULL; - assert(rule_tmp->token_cur < ELEMENTSOF(rule_tmp->token)); + if (rule_tmp->token_cur >= ELEMENTSOF(rule_tmp->token)) + return -E2BIG; + memzero(token, sizeof(struct token)); switch (type) { @@ -968,6 +972,8 @@ static void rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, token->key.type = type; token->key.op = op; rule_tmp->token_cur++; + + return 0; } static int sort_token(UdevRules *rules, struct rule_tmp *rule_tmp) { @@ -1009,6 +1015,7 @@ static int sort_token(UdevRules *rules, struct rule_tmp *rule_tmp) { #define LOG_RULE_WARNING(fmt, ...) LOG_RULE_FULL(LOG_WARNING, fmt, ##__VA_ARGS__) #define LOG_RULE_DEBUG(fmt, ...) LOG_RULE_FULL(LOG_DEBUG, fmt, ##__VA_ARGS__) #define LOG_AND_RETURN(fmt, ...) { LOG_RULE_ERROR(fmt, __VA_ARGS__); return; } +#define LOG_AND_RETURN_ADD_KEY LOG_AND_RETURN("Temporary rule array too small, aborting event processing with %u items", rule_tmp.token_cur); static void add_rule(UdevRules *rules, char *line, const char *filename, unsigned filename_off, unsigned lineno) { @@ -1018,6 +1025,7 @@ static void add_rule(UdevRules *rules, char *line, .rules = rules, .rule.type = TK_RULE, }; + int r; /* the offset in the rule is limited to unsigned short */ if (filename_off < USHRT_MAX) @@ -1051,26 +1059,26 @@ static void add_rule(UdevRules *rules, char *line, break; } - if (rule_tmp.token_cur >= ELEMENTSOF(rule_tmp.token)) - LOG_AND_RETURN("Temporary rule array too small, aborting event processing with %u items", rule_tmp.token_cur); - if (streq(key, "ACTION")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_ACTION, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_ACTION, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "DEVPATH")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_DEVPATH, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_DEVPATH, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "KERNEL")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_KERNEL, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_KERNEL, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "SUBSYSTEM")) { if (op > OP_MATCH_MAX) @@ -1081,15 +1089,18 @@ static void add_rule(UdevRules *rules, char *line, if (!streq(value, "subsystem")) LOG_RULE_WARNING("'%s' must be specified as 'subsystem'; please fix", value); - rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, "subsystem|class|bus", NULL); + r = rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, "subsystem|class|bus", NULL); } else - rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, value, NULL); + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "DRIVER")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_DRIVER, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_DRIVER, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "ATTR{")) { attr = get_key_attribute(key + STRLEN("ATTR")); @@ -1100,9 +1111,11 @@ static void add_rule(UdevRules *rules, char *line, LOG_AND_RETURN("Invalid %s operation", "ATTR"); if (op < OP_MATCH_MAX) - rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr); + r = rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr); else - rule_add_key(&rule_tmp, TK_A_ATTR, op, value, attr); + r = rule_add_key(&rule_tmp, TK_A_ATTR, op, value, attr); + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "SYSCTL{")) { attr = get_key_attribute(key + STRLEN("SYSCTL")); @@ -1113,9 +1126,11 @@ static void add_rule(UdevRules *rules, char *line, LOG_AND_RETURN("Invalid %s operation", "ATTR"); if (op < OP_MATCH_MAX) - rule_add_key(&rule_tmp, TK_M_SYSCTL, op, value, attr); + r = rule_add_key(&rule_tmp, TK_M_SYSCTL, op, value, attr); else - rule_add_key(&rule_tmp, TK_A_SYSCTL, op, value, attr); + r = rule_add_key(&rule_tmp, TK_A_SYSCTL, op, value, attr); + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "SECLABEL{")) { attr = get_key_attribute(key + STRLEN("SECLABEL")); @@ -1125,25 +1140,29 @@ static void add_rule(UdevRules *rules, char *line, if (op == OP_REMOVE) LOG_AND_RETURN("Invalid %s operation", "SECLABEL"); - rule_add_key(&rule_tmp, TK_A_SECLABEL, op, value, attr); + if (rule_add_key(&rule_tmp, TK_A_SECLABEL, op, value, attr) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "KERNELS")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "SUBSYSTEMS")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "DRIVERS")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_DRIVERS, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_DRIVERS, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "ATTRS{")) { if (op > OP_MATCH_MAX) @@ -1157,13 +1176,15 @@ static void add_rule(UdevRules *rules, char *line, LOG_RULE_WARNING("'device' link may not be available in future kernels; please fix"); if (strstr(attr, "../")) LOG_RULE_WARNING("Direct reference to parent sysfs directory, may break in future kernels; please fix"); - rule_add_key(&rule_tmp, TK_M_ATTRS, op, value, attr); + if (rule_add_key(&rule_tmp, TK_M_ATTRS, op, value, attr) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "TAGS")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_TAGS, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_TAGS, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "ENV{")) { attr = get_key_attribute(key + STRLEN("ENV")); @@ -1174,7 +1195,7 @@ static void add_rule(UdevRules *rules, char *line, LOG_AND_RETURN("Invalid %s operation", "ENV"); if (op < OP_MATCH_MAX) - rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr); + r = rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr); else { if (STR_IN_SET(attr, "ACTION", @@ -1190,26 +1211,32 @@ static void add_rule(UdevRules *rules, char *line, "TAGS")) LOG_AND_RETURN("Invalid ENV attribute, '%s' cannot be set", attr); - rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr); + r = rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr); } + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "TAG")) { if (op < OP_MATCH_MAX) - rule_add_key(&rule_tmp, TK_M_TAG, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_TAG, op, value, NULL); else - rule_add_key(&rule_tmp, TK_A_TAG, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_A_TAG, op, value, NULL); + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "PROGRAM")) { if (op == OP_REMOVE) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "RESULT")) { if (op > OP_MATCH_MAX) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_M_RESULT, op, value, NULL); + if (rule_add_key(&rule_tmp, TK_M_RESULT, op, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "IMPORT")) { attr = get_key_attribute(key + STRLEN("IMPORT")); @@ -1227,28 +1254,34 @@ static void add_rule(UdevRules *rules, char *line, if (cmd >= 0) { LOG_RULE_DEBUG("IMPORT found builtin '%s', replacing", value); - rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd); + if (rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd) < 0) + LOG_AND_RETURN_ADD_KEY; continue; } } - rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL); } else if (streq(attr, "builtin")) { const enum udev_builtin_cmd cmd = udev_builtin_lookup(value); - if (cmd < 0) - LOG_RULE_WARNING("IMPORT{builtin} '%s' unknown", value); - else - rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd); + if (cmd < 0) { + LOG_RULE_WARNING("IMPORT{builtin} '%s' unknown, ignoring", value); + continue; + } else + r = rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd); } else if (streq(attr, "file")) - rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL); else if (streq(attr, "db")) - rule_add_key(&rule_tmp, TK_M_IMPORT_DB, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_IMPORT_DB, op, value, NULL); else if (streq(attr, "cmdline")) - rule_add_key(&rule_tmp, TK_M_IMPORT_CMDLINE, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_IMPORT_CMDLINE, op, value, NULL); else if (streq(attr, "parent")) - rule_add_key(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL); - else + r = rule_add_key(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL); + else { LOG_RULE_ERROR("Ignoring unknown %s{} type '%s'", "IMPORT", attr); + continue; + } + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "TEST")) { mode_t mode = 0; @@ -1259,9 +1292,11 @@ static void add_rule(UdevRules *rules, char *line, attr = get_key_attribute(key + STRLEN("TEST")); if (attr) { mode = strtol(attr, NULL, 8); - rule_add_key(&rule_tmp, TK_M_TEST, op, value, &mode); + r = rule_add_key(&rule_tmp, TK_M_TEST, op, value, &mode); } else - rule_add_key(&rule_tmp, TK_M_TEST, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_TEST, op, value, NULL); + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "RUN")) { attr = get_key_attribute(key + STRLEN("RUN")); @@ -1273,16 +1308,21 @@ static void add_rule(UdevRules *rules, char *line, if (streq(attr, "builtin")) { const enum udev_builtin_cmd cmd = udev_builtin_lookup(value); - if (cmd < 0) - LOG_RULE_ERROR("RUN{builtin}: '%s' unknown", value); - else - rule_add_key(&rule_tmp, TK_A_RUN_BUILTIN, op, value, &cmd); + if (cmd < 0) { + LOG_RULE_ERROR("RUN{builtin}: '%s' unknown, ignoring", value); + continue; + } else + r = rule_add_key(&rule_tmp, TK_A_RUN_BUILTIN, op, value, &cmd); } else if (streq(attr, "program")) { const enum udev_builtin_cmd cmd = _UDEV_BUILTIN_MAX; - rule_add_key(&rule_tmp, TK_A_RUN_PROGRAM, op, value, &cmd); - } else + r = rule_add_key(&rule_tmp, TK_A_RUN_PROGRAM, op, value, &cmd); + } else { LOG_RULE_ERROR("Ignoring unknown %s{} type '%s'", "RUN", attr); + continue; + } + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } else if (streq(key, "LABEL")) { if (op == OP_REMOVE) @@ -1294,14 +1334,15 @@ static void add_rule(UdevRules *rules, char *line, if (op == OP_REMOVE) LOG_AND_RETURN("Invalid %s operation", key); - rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL); + if (rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; } else if (startswith(key, "NAME")) { if (op == OP_REMOVE) LOG_AND_RETURN("Invalid %s operation", key); if (op < OP_MATCH_MAX) - rule_add_key(&rule_tmp, TK_M_NAME, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_NAME, op, value, NULL); else { if (streq(value, "%k")) { LOG_RULE_WARNING("NAME=\"%%k\" is ignored, because it breaks kernel supplied names; please remove"); @@ -1311,8 +1352,10 @@ static void add_rule(UdevRules *rules, char *line, LOG_RULE_DEBUG("NAME=\"\" is ignored, because udev will not delete any device nodes; please remove"); continue; } - rule_add_key(&rule_tmp, TK_A_NAME, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_A_NAME, op, value, NULL); } + if (r < 0) + LOG_AND_RETURN_ADD_KEY; rule_tmp.rule.rule.can_set_name = true; } else if (streq(key, "SYMLINK")) { @@ -1320,9 +1363,11 @@ static void add_rule(UdevRules *rules, char *line, LOG_AND_RETURN("Invalid %s operation", key); if (op < OP_MATCH_MAX) - rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL); else - rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, NULL); + if (r < 0) + LOG_AND_RETURN_ADD_KEY; rule_tmp.rule.rule.can_set_name = true; } else if (streq(key, "OWNER")) { @@ -1334,12 +1379,18 @@ static void add_rule(UdevRules *rules, char *line, uid = strtoul(value, &endptr, 10); if (endptr[0] == '\0') - rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); + r = rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); else if (rules->resolve_name_timing == RESOLVE_NAME_EARLY && !strchr("$%", value[0])) { uid = add_uid(rules, value); - rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); + r = rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); } else if (rules->resolve_name_timing != RESOLVE_NAME_NEVER) - rule_add_key(&rule_tmp, TK_A_OWNER, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_A_OWNER, op, value, NULL); + else { + LOG_RULE_ERROR("Invalid %s operation", key); + continue; + } + if (r < 0) + LOG_AND_RETURN_ADD_KEY; rule_tmp.rule.rule.can_set_name = true; @@ -1352,12 +1403,18 @@ static void add_rule(UdevRules *rules, char *line, gid = strtoul(value, &endptr, 10); if (endptr[0] == '\0') - rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); + r = rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); else if ((rules->resolve_name_timing == RESOLVE_NAME_EARLY) && !strchr("$%", value[0])) { gid = add_gid(rules, value); - rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); + r = rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); } else if (rules->resolve_name_timing != RESOLVE_NAME_NEVER) - rule_add_key(&rule_tmp, TK_A_GROUP, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_A_GROUP, op, value, NULL); + else { + LOG_RULE_ERROR("Invalid %s operation", key); + continue; + } + if (r < 0) + LOG_AND_RETURN_ADD_KEY; rule_tmp.rule.rule.can_set_name = true; @@ -1370,9 +1427,12 @@ static void add_rule(UdevRules *rules, char *line, mode = strtol(value, &endptr, 8); if (endptr[0] == '\0') - rule_add_key(&rule_tmp, TK_A_MODE_ID, op, NULL, &mode); + r = rule_add_key(&rule_tmp, TK_A_MODE_ID, op, NULL, &mode); else - rule_add_key(&rule_tmp, TK_A_MODE, op, value, NULL); + r = rule_add_key(&rule_tmp, TK_A_MODE, op, value, NULL); + if (r < 0) + LOG_AND_RETURN_ADD_KEY; + rule_tmp.rule.rule.can_set_name = true; } else if (streq(key, "OPTIONS")) { @@ -1385,37 +1445,48 @@ static void add_rule(UdevRules *rules, char *line, if (pos) { int prio = atoi(pos + STRLEN("link_priority=")); - rule_add_key(&rule_tmp, TK_A_DEVLINK_PRIO, op, NULL, &prio); + if (rule_add_key(&rule_tmp, TK_A_DEVLINK_PRIO, op, NULL, &prio) < 0) + LOG_AND_RETURN_ADD_KEY; } pos = strstr(value, "string_escape="); if (pos) { pos += STRLEN("string_escape="); if (startswith(pos, "none")) - rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_NONE, op, NULL, NULL); + r = rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_NONE, op, NULL, NULL); else if (startswith(pos, "replace")) - rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_REPLACE, op, NULL, NULL); + r = rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_REPLACE, op, NULL, NULL); + else { + LOG_RULE_ERROR("OPTIONS: unknown string_escape mode '%s', ignoring", pos); + r = 0; + } + if (r < 0) + LOG_AND_RETURN_ADD_KEY; } pos = strstr(value, "db_persist"); if (pos) - rule_add_key(&rule_tmp, TK_A_DB_PERSIST, op, NULL, NULL); + if (rule_add_key(&rule_tmp, TK_A_DB_PERSIST, op, NULL, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; pos = strstr(value, "nowatch"); if (pos) { static const int zero = 0; - rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &zero); + if (rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &zero) < 0) + LOG_AND_RETURN_ADD_KEY; } else { static const int one = 1; pos = strstr(value, "watch"); if (pos) - rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &one); + if (rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &one) < 0) + LOG_AND_RETURN_ADD_KEY; } pos = strstr(value, "static_node="); if (pos) { pos += STRLEN("static_node="); - rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, pos, NULL); + if (rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, pos, NULL) < 0) + LOG_AND_RETURN_ADD_KEY; rule_tmp.rule.rule.has_static_node = true; } @@ -1959,7 +2030,7 @@ int udev_rules_apply_to_event( rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); - if (udev_event_spawn(event, timeout_usec, true, program, result, sizeof(result)) < 0) { + if (udev_event_spawn(event, timeout_usec, true, program, result, sizeof(result)) != 0) { if (cur->key.op != OP_NOMATCH) goto nomatch; } else { @@ -2229,13 +2300,12 @@ int udev_rules_apply_to_event( r = hashmap_put(event->seclabel_list, name, label); if (r < 0) return log_oom(); - - name = label = NULL; - log_device_debug(dev, "SECLABEL{%s}='%s' %s:%u", name, label, rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); + name = label = NULL; + break; } case TK_A_ENV: { diff --git a/src/udev/udev.pc.in b/src/udev/udev.pc.in index e384a6f7c9..5acbb2d01a 100644 --- a/src/udev/udev.pc.in +++ b/src/udev/udev.pc.in @@ -1,5 +1,5 @@ Name: udev Description: udev -Version: @PACKAGE_VERSION@ +Version: @PROJECT_VERSION@ udevdir=@udevlibexecdir@ diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c index d9320418cf..7cfc4c929d 100644 --- a/src/udev/udevadm-control.c +++ b/src/udev/udevadm-control.c @@ -26,6 +26,7 @@ #include "udevadm.h" #include "udev-ctrl.h" #include "util.h" +#include "virt.h" static int help(void) { printf("%s control OPTION\n\n" @@ -39,6 +40,7 @@ static int help(void) { " -R --reload Reload rules and databases\n" " -p --property=KEY=VALUE Set a global property for all events\n" " -m --children-max=N Maximum number of children\n" + " --ping Wait for udev to respond to a ping message\n" " -t --timeout=SECONDS Maximum time to block for a reply\n" , program_invocation_short_name); @@ -47,22 +49,27 @@ static int help(void) { int control_main(int argc, char *argv[], void *userdata) { _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL; - int timeout = 60; + usec_t timeout = 60 * USEC_PER_SEC; int c, r; + enum { + ARG_PING = 0x100, + }; + static const struct option options[] = { - { "exit", no_argument, NULL, 'e' }, - { "log-priority", required_argument, NULL, 'l' }, - { "stop-exec-queue", no_argument, NULL, 's' }, - { "start-exec-queue", no_argument, NULL, 'S' }, - { "reload", no_argument, NULL, 'R' }, - { "reload-rules", no_argument, NULL, 'R' }, /* alias for -R */ - { "property", required_argument, NULL, 'p' }, - { "env", required_argument, NULL, 'p' }, /* alias for -p */ - { "children-max", required_argument, NULL, 'm' }, - { "timeout", required_argument, NULL, 't' }, - { "version", no_argument, NULL, 'V' }, - { "help", no_argument, NULL, 'h' }, + { "exit", no_argument, NULL, 'e' }, + { "log-priority", required_argument, NULL, 'l' }, + { "stop-exec-queue", no_argument, NULL, 's' }, + { "start-exec-queue", no_argument, NULL, 'S' }, + { "reload", no_argument, NULL, 'R' }, + { "reload-rules", no_argument, NULL, 'R' }, /* alias for -R */ + { "property", required_argument, NULL, 'p' }, + { "env", required_argument, NULL, 'p' }, /* alias for -p */ + { "children-max", required_argument, NULL, 'm' }, + { "ping", no_argument, NULL, ARG_PING }, + { "timeout", required_argument, NULL, 't' }, + { "version", no_argument, NULL, 'V' }, + { "help", no_argument, NULL, 'h' }, {} }; @@ -70,12 +77,18 @@ int control_main(int argc, char *argv[], void *userdata) { if (r < 0) return r; + if (running_in_chroot() > 0) { + log_info("Running in chroot, ignoring request."); + return 0; + } + if (argc <= 1) - log_error("Option missing"); + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "This command expects one or more options."); uctrl = udev_ctrl_new(); if (!uctrl) - return -ENOMEM; + return log_oom(); while ((c = getopt_long(argc, argv, "el:sSRp:m:t:Vh", options, NULL)) >= 0) switch (c) { @@ -109,10 +122,9 @@ int control_main(int argc, char *argv[], void *userdata) { return r; break; case 'p': - if (!strchr(optarg, '=')) { - log_error("expect <KEY>=<value> instead of '%s'", optarg); - return -EINVAL; - } + if (!strchr(optarg, '=')) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "expect <KEY>=<value> instead of '%s'", optarg); + r = udev_ctrl_send_set_env(uctrl, optarg, timeout); if (r < 0) return r; @@ -129,19 +141,16 @@ int control_main(int argc, char *argv[], void *userdata) { return r; break; } - case 't': { - usec_t s; - - r = parse_sec(optarg, &s); + case ARG_PING: + r = udev_ctrl_send_ping(uctrl, timeout); if (r < 0) - return log_error_errno(r, "Failed to parse timeout value '%s'.", optarg); - - if (DIV_ROUND_UP(s, USEC_PER_SEC) > INT_MAX) - log_error("Timeout value is out of range, ignoring."); - else - timeout = s != USEC_INFINITY ? (int) DIV_ROUND_UP(s, USEC_PER_SEC) : INT_MAX; + return log_error_errno(r, "Failed to connect to udev daemon: %m"); + break; + case 't': + r = parse_sec(optarg, &timeout); + if (r < 0) + return log_error_errno(r, "Failed to parse timeout value '%s': %m", optarg); break; - } case 'V': return print_version(); case 'h': @@ -152,13 +161,9 @@ int control_main(int argc, char *argv[], void *userdata) { assert_not_reached("Unknown option."); } - if (optind < argc) { - log_error("Extraneous argument: %s", argv[optind]); - return -EINVAL; - } else if (optind == 1) { - log_error("Option missing"); - return -EINVAL; - } + if (optind < argc) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Extraneous argument: %s", argv[optind]); return 0; } diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index d141bc74b2..ebd15d384a 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -61,12 +61,15 @@ static bool skip_attribute(const char *name) { static void print_all_attributes(sd_device *device, const char *key) { const char *name, *value; - FOREACH_DEVICE_PROPERTY(device, name, value) { + FOREACH_DEVICE_SYSATTR(device, name) { size_t len; if (skip_attribute(name)) continue; + if (sd_device_get_sysattr_value(device, name, &value) < 0) + continue; + /* skip any values that look like a path */ if (value[0] == '/') continue; @@ -387,10 +390,8 @@ int info_main(int argc, char *argv[], void *userdata) { query = QUERY_PATH; else if (streq(optarg, "all")) query = QUERY_ALL; - else { - log_error("unknown query type"); - return -EINVAL; - } + else + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "unknown query type"); break; case 'r': arg_root = true; @@ -413,6 +414,7 @@ int info_main(int argc, char *argv[], void *userdata) { arg_export = true; break; case 'P': + arg_export = true; arg_export_prefix = optarg; break; case 'V': @@ -425,7 +427,6 @@ int info_main(int argc, char *argv[], void *userdata) { assert_not_reached("Unknown option"); } - if (action == ACTION_DEVICE_ID_FILE) { if (argv[optind]) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c index f7737d0790..3dde3f338a 100644 --- a/src/udev/udevadm-monitor.c +++ b/src/udev/udevadm-monitor.c @@ -17,6 +17,7 @@ #include "signal-util.h" #include "string-util.h" #include "udevadm.h" +#include "virt.h" static bool arg_show_property = false; static bool arg_print_kernel = false; @@ -143,11 +144,11 @@ static int parse_argv(int argc, char *argv[]) { slash = strchr(optarg, '/'); if (slash) { - devtype = strdup(devtype + 1); + devtype = strdup(slash + 1); if (!devtype) return -ENOMEM; - subsystem = strndup(optarg, devtype - optarg); + subsystem = strndup(optarg, slash - optarg); } else subsystem = strdup(optarg); @@ -210,6 +211,11 @@ int monitor_main(int argc, char *argv[], void *userdata) { if (r <= 0) goto finalize; + if (running_in_chroot() > 0) { + log_info("Running in chroot, ignoring request."); + return 0; + } + /* Callers are expecting to see events as they happen: Line buffering */ setlinebuf(stdout); diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c index 4ae237d430..8d9c4509ff 100644 --- a/src/udev/udevadm-settle.c +++ b/src/udev/udevadm-settle.c @@ -18,6 +18,7 @@ #include "udevadm.h" #include "udev-ctrl.h" #include "util.h" +#include "virt.h" static usec_t arg_timeout = 120 * USEC_PER_SEC; static const char *arg_exists = NULL; @@ -88,6 +89,11 @@ int settle_main(int argc, char *argv[], void *userdata) { if (r <= 0) return r; + if (running_in_chroot() > 0) { + log_info("Running in chroot, ignoring request."); + return 0; + } + deadline = now(CLOCK_MONOTONIC) + arg_timeout; /* guarantee that the udev daemon isn't pre-processing */ @@ -96,9 +102,9 @@ int settle_main(int argc, char *argv[], void *userdata) { uctrl = udev_ctrl_new(); if (uctrl) { - r = udev_ctrl_send_ping(uctrl, MAX(5U, arg_timeout / USEC_PER_SEC)); + r = udev_ctrl_send_ping(uctrl, MAX(5 * USEC_PER_SEC, arg_timeout)); if (r < 0) { - log_debug_errno(r, "Failed to connect to udev daemon."); + log_debug_errno(r, "Failed to connect to udev daemon: %m"); return 0; } } diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index f13a08f3f9..95329469e3 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -10,11 +10,14 @@ #include "fd-util.h" #include "fileio.h" #include "path-util.h" +#include "process-util.h" #include "set.h" #include "string-util.h" #include "strv.h" #include "udevadm.h" #include "udevadm-util.h" +#include "udev-ctrl.h" +#include "virt.h" static bool arg_verbose = false; static bool arg_dry_run = false; @@ -117,6 +120,8 @@ static int help(void) { " --name-match=NAME Trigger devices with this /dev name\n" " -b --parent-match=NAME Trigger devices with that parent device\n" " -w --settle Wait for the triggered events to complete\n" + " --wait-daemon[=SECONDS] Wait for udevd daemon to be initialized\n" + " before triggering uevents\n" , program_invocation_short_name); return 0; @@ -125,6 +130,7 @@ static int help(void) { int trigger_main(int argc, char *argv[], void *userdata) { enum { ARG_NAME = 0x100, + ARG_PING, }; static const struct option options[] = { @@ -142,6 +148,7 @@ int trigger_main(int argc, char *argv[], void *userdata) { { "name-match", required_argument, NULL, ARG_NAME }, { "parent-match", required_argument, NULL, 'b' }, { "settle", no_argument, NULL, 'w' }, + { "wait-daemon", optional_argument, NULL, ARG_PING }, { "version", no_argument, NULL, 'V' }, { "help", no_argument, NULL, 'h' }, {} @@ -155,9 +162,15 @@ int trigger_main(int argc, char *argv[], void *userdata) { _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL; _cleanup_set_free_free_ Set *settle_set = NULL; - bool settle = false; + usec_t ping_timeout_usec = 5 * USEC_PER_SEC; + bool settle = false, ping = false; int c, r; + if (running_in_chroot() > 0) { + log_info("Running in chroot, ignoring request."); + return 0; + } + r = sd_device_enumerator_new(&e); if (r < 0) return r; @@ -182,18 +195,14 @@ int trigger_main(int argc, char *argv[], void *userdata) { device_type = TYPE_DEVICES; else if (streq(optarg, "subsystems")) device_type = TYPE_SUBSYSTEMS; - else { - log_error("Unknown type --type=%s", optarg); - return -EINVAL; - } + else + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown type --type=%s", optarg); break; case 'c': if (STR_IN_SET(optarg, "add", "remove", "change")) action = optarg; - else { - log_error("Unknown action '%s'", optarg); - return -EINVAL; - } + else + log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown action '%s'", optarg); break; case 's': @@ -269,6 +278,16 @@ int trigger_main(int argc, char *argv[], void *userdata) { break; } + case ARG_PING: { + ping = true; + if (optarg) { + r = parse_sec(optarg, &ping_timeout_usec); + if (r < 0) + log_error_errno(r, "Failed to parse timeout value '%s', ignoring: %m", optarg); + } + break; + } + case 'V': return print_version(); case 'h': @@ -280,6 +299,24 @@ int trigger_main(int argc, char *argv[], void *userdata) { } } + if (!arg_dry_run || ping) { + r = must_be_root(); + if (r < 0) + return r; + } + + if (ping) { + _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL; + + uctrl = udev_ctrl_new(); + if (!uctrl) + return log_oom(); + + r = udev_ctrl_send_ping(uctrl, ping_timeout_usec); + if (r < 0) + return log_error_errno(r, "Failed to connect to udev daemon: %m"); + } + for (; optind < argc; optind++) { _cleanup_(sd_device_unrefp) sd_device *dev = NULL; diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c index 1125c54b9f..28194314de 100644 --- a/src/udev/udevadm.c +++ b/src/udev/udevadm.c @@ -113,12 +113,13 @@ static int run(int argc, char *argv[]) { udev_parse_config(); log_parse_environment(); log_open(); - log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level()); r = parse_argv(argc, argv); if (r <= 0) return r; + log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level()); + mac_selinux_init(); return udevadm_main(argc, argv); } diff --git a/src/udev/udevadm.h b/src/udev/udevadm.h index 98f9019a48..86b24af086 100644 --- a/src/udev/udevadm.h +++ b/src/udev/udevadm.h @@ -3,6 +3,9 @@ #include <stdio.h> +#include "build.h" +#include "macro.h" + int info_main(int argc, char *argv[], void *userdata); int trigger_main(int argc, char *argv[], void *userdata); int settle_main(int argc, char *argv[], void *userdata); @@ -13,6 +16,7 @@ int test_main(int argc, char *argv[], void *userdata); int builtin_main(int argc, char *argv[], void *userdata); static inline int print_version(void) { - puts(PACKAGE_VERSION); + /* Dracut relies on the version being a single integer */ + puts(STRINGIFY(PROJECT_VERSION)); return 0; } diff --git a/src/udev/udevd.c b/src/udev/udevd.c index fb8724ea87..0303f36b4f 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -31,6 +31,7 @@ #include "sd-event.h" #include "alloc-util.h" +#include "build.h" #include "cgroup-util.h" #include "cpu-set-util.h" #include "dev-setup.h" @@ -185,20 +186,11 @@ static void worker_free(struct worker *worker) { free(worker); } -static void manager_workers_free(Manager *manager) { - struct worker *worker; - Iterator i; - - assert(manager); - - HASHMAP_FOREACH(worker, manager->workers, i) - worker_free(worker); - - manager->workers = hashmap_free(manager->workers); -} +DEFINE_TRIVIAL_CLEANUP_FUNC(struct worker *, worker_free); +DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(worker_hash_op, void, trivial_hash_func, trivial_compare_func, struct worker, worker_free); static int worker_new(struct worker **ret, Manager *manager, sd_device_monitor *worker_monitor, pid_t pid) { - _cleanup_free_ struct worker *worker = NULL; + _cleanup_(worker_freep) struct worker *worker = NULL; int r; assert(ret); @@ -206,17 +198,20 @@ static int worker_new(struct worker **ret, Manager *manager, sd_device_monitor * assert(worker_monitor); assert(pid > 1); - worker = new0(struct worker, 1); + /* close monitor, but keep address around */ + device_monitor_disconnect(worker_monitor); + + worker = new(struct worker, 1); if (!worker) return -ENOMEM; - worker->manager = manager; - /* close monitor, but keep address around */ - device_monitor_disconnect(worker_monitor); - worker->monitor = sd_device_monitor_ref(worker_monitor); - worker->pid = pid; + *worker = (struct worker) { + .manager = manager, + .monitor = sd_device_monitor_ref(worker_monitor), + .pid = pid, + }; - r = hashmap_ensure_allocated(&manager->workers, NULL); + r = hashmap_ensure_allocated(&manager->workers, &worker_hash_op); if (r < 0) return r; @@ -290,7 +285,7 @@ static void manager_clear_for_worker(Manager *manager) { manager->event = sd_event_unref(manager->event); - manager_workers_free(manager); + manager->workers = hashmap_free(manager->workers); event_queue_cleanup(manager, EVENT_UNDEF); manager->monitor = sd_device_monitor_unref(manager->monitor); @@ -396,7 +391,7 @@ static int worker_lock_block_device(sd_device *dev, int *ret_fd) { static int worker_process_device(Manager *manager, sd_device *dev) { _cleanup_(udev_event_freep) UdevEvent *udev_event = NULL; _cleanup_close_ int fd_lock = -1; - const char *seqnum; + const char *seqnum, *action; int r; assert(manager); @@ -404,9 +399,13 @@ static int worker_process_device(Manager *manager, sd_device *dev) { r = sd_device_get_property_value(dev, "SEQNUM", &seqnum); if (r < 0) - log_device_debug_errno(dev, r, "Failed to get SEQNUM: %m"); + return log_device_debug_errno(dev, r, "Failed to get SEQNUM: %m"); - log_device_debug(dev, "Processing device (SEQNUM=%s)", seqnum); + r = sd_device_get_property_value(dev, "ACTION", &action); + if (r < 0) + return log_device_debug_errno(dev, r, "Failed to get ACTION: %m"); + + log_device_debug(dev, "Processing device (SEQNUM=%s, ACTION=%s)", seqnum, action); udev_event = udev_event_new(dev, arg_exec_delay_usec, manager->rtnl); if (!udev_event) @@ -432,7 +431,7 @@ static int worker_process_device(Manager *manager, sd_device *dev) { return log_device_debug_errno(dev, r, "Failed to update database under /run/udev/data/: %m"); } - log_device_debug(dev, "Device (SEQNUM=%s) processed", seqnum); + log_device_debug(dev, "Device (SEQNUM=%s, ACTION=%s) processed", seqnum, action); return 0; } @@ -464,7 +463,7 @@ static int worker_device_monitor_handler(sd_device_monitor *monitor, sd_device * static int worker_main(Manager *_manager, sd_device_monitor *monitor, sd_device *first_device) { _cleanup_(sd_device_unrefp) sd_device *dev = first_device; _cleanup_(manager_freep) Manager *manager = _manager; - int r, ret; + int r; assert(manager); assert(monitor); @@ -507,11 +506,7 @@ static int worker_main(Manager *_manager, sd_device_monitor *monitor, sd_device if (r < 0) return log_error_errno(r, "Event loop failed: %m"); - r = sd_event_get_exit_code(manager->event, &ret); - if (r < 0) - return log_error_errno(r, "Failed to get exit code: %m"); - - return ret; + return 0; } static int worker_spawn(Manager *manager, struct event *event) { @@ -534,7 +529,7 @@ static int worker_spawn(Manager *manager, struct event *event) { if (r < 0) return log_error_errno(r, "Worker: Failed to enable receiving of device: %m"); - r = safe_fork("(worker)", FORK_DEATHSIG, &pid); + r = safe_fork(NULL, FORK_DEATHSIG, &pid); if (r < 0) { event->state = EVENT_QUEUED; return log_error_errno(r, "Failed to fork() worker: %m"); @@ -592,8 +587,8 @@ static void event_run(Manager *manager, struct event *event) { static int event_queue_insert(Manager *manager, sd_device *dev) { _cleanup_(sd_device_unrefp) sd_device *clone = NULL; + const char *val, *action; struct event *event; - const char *val; uint64_t seqnum; int r; @@ -618,6 +613,11 @@ static int event_queue_insert(Manager *manager, sd_device *dev) { if (seqnum == 0) return -EINVAL; + /* Refuse devices do not have ACTION property. */ + r = sd_device_get_property_value(dev, "ACTION", &action); + if (r < 0) + return r; + /* Save original device to restore the state on failures. */ r = device_shallow_clone(dev, &clone); if (r < 0) @@ -647,12 +647,7 @@ static int event_queue_insert(Manager *manager, sd_device *dev) { LIST_APPEND(event, manager->events, event); - if (DEBUG_LOGGING) { - if (sd_device_get_property_value(dev, "ACTION", &val) < 0) - val = NULL; - - log_device_debug(dev, "Device (SEQNUM=%"PRIu64", ACTION=%s) is queued", seqnum, strnull(val)); - } + log_device_debug(dev, "Device (SEQNUM=%"PRIu64", ACTION=%s) is queued", seqnum, action); return 0; } @@ -875,7 +870,7 @@ static void event_queue_start(Manager *manager) { assert_se(sd_event_now(manager->event, CLOCK_MONOTONIC, &usec) >= 0); /* check for changed config, every 3 seconds at most */ if (manager->last_usec == 0 || - (usec - manager->last_usec) > 3 * USEC_PER_SEC) { + usec - manager->last_usec > 3 * USEC_PER_SEC) { if (udev_rules_check_timestamp(manager->rules) || udev_builtin_validate()) manager_reload(manager); @@ -960,12 +955,11 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat continue; } - CMSG_FOREACH(cmsg, &msghdr) { + CMSG_FOREACH(cmsg, &msghdr) if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) ucred = (struct ucred*) CMSG_DATA(cmsg); - } if (!ucred || ucred->pid <= 0) { log_warning("Ignoring worker message without valid PID"); @@ -1033,7 +1027,8 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd i = udev_ctrl_get_set_log_level(ctrl_msg); if (i >= 0) { log_debug("Received udev control message (SET_LOG_LEVEL), setting log_priority=%i", i); - log_set_max_level(i); + log_set_max_level_realm(LOG_REALM_UDEV, i); + log_set_max_level_realm(LOG_REALM_SYSTEMD, i); manager_kill_workers(manager); } @@ -1118,7 +1113,7 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd } if (udev_ctrl_get_ping(ctrl_msg) > 0) - log_debug("Received udev control message (SYNC)"); + log_debug("Received udev control message (PING)"); if (udev_ctrl_get_exit(ctrl_msg) > 0) { log_debug("Received udev control message (EXIT)"); @@ -1338,9 +1333,9 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi log_debug("Worker ["PID_FMT"] exited", pid); else log_warning("Worker ["PID_FMT"] exited with return code %i", pid, WEXITSTATUS(status)); - } else if (WIFSIGNALED(status)) { + } else if (WIFSIGNALED(status)) log_warning("Worker ["PID_FMT"] terminated by signal %i (%s)", pid, WTERMSIG(status), signal_to_string(WTERMSIG(status))); - } else if (WIFSTOPPED(status)) { + else if (WIFSTOPPED(status)) { log_info("Worker ["PID_FMT"] stopped", pid); continue; } else if (WIFCONTINUED(status)) { @@ -1579,7 +1574,7 @@ static int parse_argv(int argc, char *argv[]) { case 'h': return help(); case 'V': - printf("%s\n", PACKAGE_VERSION); + printf("%s\n", GIT_VERSION); return 0; case '?': return -EINVAL; @@ -1594,7 +1589,7 @@ static int parse_argv(int argc, char *argv[]) { static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cgroup) { _cleanup_(manager_freep) Manager *manager = NULL; - int r, fd_worker; + int r; assert(ret); @@ -1608,25 +1603,13 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg .cgroup = cgroup, }; - udev_builtin_init(); - - r = udev_rules_new(&manager->rules, arg_resolve_name_timing); - if (!manager->rules) - return log_error_errno(r, "Failed to read udev rules: %m"); - manager->ctrl = udev_ctrl_new_from_fd(fd_ctrl); if (!manager->ctrl) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to initialize udev control socket"); - if (fd_ctrl < 0) { - r = udev_ctrl_enable_receiving(manager->ctrl); - if (r < 0) - return log_error_errno(r, "Failed to bind udev control socket: %m"); - } - - fd_ctrl = udev_ctrl_get_fd(manager->ctrl); - if (fd_ctrl < 0) - return log_error_errno(fd_ctrl, "Failed to get udev control socket fd: %m"); + r = udev_ctrl_enable_receiving(manager->ctrl); + if (r < 0) + return log_error_errno(r, "Failed to bind udev control socket: %m"); r = device_monitor_new_full(&manager->monitor, MONITOR_GROUP_KERNEL, fd_uevent); if (r < 0) @@ -1634,6 +1617,18 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg (void) sd_device_monitor_set_receive_buffer_size(manager->monitor, 128 * 1024 * 1024); + r = device_monitor_enable_receiving(manager->monitor); + if (r < 0) + return log_error_errno(r, "Failed to bind netlink socket: %m"); + + *ret = TAKE_PTR(manager); + + return 0; +} + +static int main_loop(Manager *manager) { + int fd_worker, fd_ctrl, r; + /* unnamed socket from workers to the main daemon */ r = socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, manager->worker_watch); if (r < 0) @@ -1679,6 +1674,10 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg if (r < 0) return log_error_errno(r, "Failed to create watchdog event source: %m"); + fd_ctrl = udev_ctrl_get_fd(manager->ctrl); + if (fd_ctrl < 0) + return log_error_errno(fd_ctrl, "Failed to get udev control socket fd: %m"); + r = sd_event_add_io(manager->event, &manager->ctrl_event, fd_ctrl, EPOLLIN, on_ctrl_msg, manager); if (r < 0) return log_error_errno(r, "Failed to create udev control event source: %m"); @@ -1713,20 +1712,11 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg if (r < 0) return log_error_errno(r, "Failed to create post event source: %m"); - *ret = TAKE_PTR(manager); - - return 0; -} - -static int main_loop(int fd_ctrl, int fd_uevent, const char *cgroup) { - _cleanup_(manager_freep) Manager *manager = NULL; - int r; + udev_builtin_init(); - r = manager_new(&manager, fd_ctrl, fd_uevent, cgroup); - if (r < 0) { - r = log_error_errno(r, "Failed to allocate manager object: %m"); - goto exit; - } + r = udev_rules_new(&manager->rules, arg_resolve_name_timing); + if (!manager->rules) + return log_error_errno(r, "Failed to read udev rules: %m"); r = udev_rules_apply_static_dev_perms(manager->rules); if (r < 0) @@ -1737,24 +1727,18 @@ static int main_loop(int fd_ctrl, int fd_uevent, const char *cgroup) { "STATUS=Processing with %u children at max", arg_children_max); r = sd_event_loop(manager->event); - if (r < 0) { + if (r < 0) log_error_errno(r, "Event loop failed: %m"); - goto exit; - } - sd_event_get_exit_code(manager->event, &r); - -exit: sd_notify(false, "STOPPING=1\n" "STATUS=Shutting down..."); - if (manager) - udev_ctrl_cleanup(manager->ctrl); return r; } static int run(int argc, char *argv[]) { _cleanup_free_ char *cgroup = NULL; + _cleanup_(manager_freep) Manager *manager = NULL; int fd_ctrl = -1, fd_uevent = -1; int r; @@ -1814,10 +1798,10 @@ static int run(int argc, char *argv[]) { dev_setup(NULL, UID_INVALID, GID_INVALID); - if (getppid() == 1) { - /* get our own cgroup, we regularly kill everything udev has left behind - we only do this on systemd systems, and only if we are directly spawned - by PID1. otherwise we are not guaranteed to have a dedicated cgroup */ + if (getppid() == 1 && sd_booted() > 0) { + /* Get our own cgroup, we regularly kill everything udev has left behind. + * We only do this on systemd systems, and only if we are directly spawned + * by PID1. Otherwise we are not guaranteed to have a dedicated cgroup. */ r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup); if (r < 0) { if (IN_SET(r, -ENOENT, -ENOMEDIUM)) @@ -1831,10 +1815,14 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Failed to listen on fds: %m"); + r = manager_new(&manager, fd_ctrl, fd_uevent, cgroup); + if (r < 0) + return log_error_errno(r, "Failed to create manager: %m"); + if (arg_daemonize) { pid_t pid; - log_info("starting version " PACKAGE_VERSION); + log_info("Starting version " GIT_VERSION); /* connect /dev/null to stdin, stdout, stderr */ if (log_get_max_level() < LOG_DEBUG) { @@ -1858,7 +1846,10 @@ static int run(int argc, char *argv[]) { log_debug_errno(r, "Failed to adjust OOM score, ignoring: %m"); } - return main_loop(fd_ctrl, fd_uevent, cgroup); + r = main_loop(manager); + /* FIXME: move this into manager_free() */ + udev_ctrl_cleanup(manager->ctrl); + return r; } DEFINE_MAIN_FUNCTION(run); diff --git a/src/version/version.h.in b/src/version/version.h.in new file mode 100644 index 0000000000..9f82d905a7 --- /dev/null +++ b/src/version/version.h.in @@ -0,0 +1 @@ +#define GIT_VERSION "@VCS_TAG@" |