diff options
Diffstat (limited to 'src')
91 files changed, 1644 insertions, 826 deletions
diff --git a/src/basic/fileio.c b/src/basic/fileio.c index f14afa5dce..fa6084e602 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -160,7 +160,7 @@ int write_string_file_ts( /* We manually build our own version of fopen(..., "we") that * works without O_CREAT */ - fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY); + fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY | ((flags & WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0)); if (fd < 0) { r = -errno; goto fail; diff --git a/src/basic/fileio.h b/src/basic/fileio.h index 102d33d75f..f809848408 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -17,6 +17,7 @@ typedef enum { WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1 << 3, WRITE_STRING_FILE_SYNC = 1 << 4, WRITE_STRING_FILE_DISABLE_BUFFER = 1 << 5, + WRITE_STRING_FILE_NOFOLLOW = 1 << 6, /* And before you wonder, why write_string_file_atomic_label_ts() is a separate function instead of just one more flag here: it's about linking: we don't want to pull -lselinux into all users of write_string_file() diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index d83658eaa7..6a00de2ef0 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -314,6 +314,7 @@ int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union } int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) { + _cleanup_free_ char *buf = NULL; const char *suffix; int r, ifi = 0; @@ -341,7 +342,11 @@ int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_u } } - s = strndupa(s, suffix - s); + buf = strndup(s, suffix - s); + if (!buf) + return -ENOMEM; + + s = buf; } r = in_addr_from_string_auto(s, family, ret); @@ -490,12 +495,14 @@ int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) { return 0; } -int in_addr_prefix_from_string( +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) { + _cleanup_free_ char *str = NULL; union in_addr_union buffer; const char *e, *l; unsigned char k; @@ -507,9 +514,13 @@ int in_addr_prefix_from_string( return -EAFNOSUPPORT; e = strchr(p, '/'); - if (e) - l = strndupa(p, e - p); - else + if (e) { + str = strndup(p, e - p); + if (!str) + return -ENOMEM; + + l = str; + } else l = p; r = in_addr_from_string(family, l, &buffer); @@ -520,6 +531,13 @@ int in_addr_prefix_from_string( 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; @@ -531,12 +549,14 @@ int in_addr_prefix_from_string( return 0; } -int in_addr_prefix_from_string_auto( +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) { + _cleanup_free_ char *str = NULL; union in_addr_union buffer; const char *e, *l; unsigned char k; @@ -545,9 +565,13 @@ int in_addr_prefix_from_string_auto( assert(p); e = strchr(p, '/'); - if (e) - l = strndupa(p, e - p); - else + if (e) { + str = strndup(p, e - p); + if (!str) + return -ENOMEM; + + l = str; + } else l = p; r = in_addr_from_string_auto(l, &family, &buffer); @@ -558,6 +582,13 @@ int in_addr_prefix_from_string_auto( 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; diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index e4be30dc0d..2dafa3c084 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -45,8 +45,20 @@ 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(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen); -int in_addr_prefix_from_string_auto(const char *p, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen); +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); +} +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); +} static inline size_t FAMILY_ADDRESS_SIZE(int family) { assert(IN_SET(family, AF_INET, AF_INET6)); diff --git a/src/basic/missing.h b/src/basic/missing.h index 648a2b92d9..d671202551 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -752,7 +752,7 @@ struct input_mask { #define IFLA_MAX (__IFLA_MAX - 1) #endif -#if !HAVE_IFLA_BOND_AD_INFO +#if !HAVE_IFLA_BOND_AD_ACTOR_SYSTEM #define IFLA_BOND_UNSPEC 0 #define IFLA_BOND_MODE 1 #define IFLA_BOND_ACTIVE_SLAVE 2 @@ -777,7 +777,10 @@ struct input_mask { #define IFLA_BOND_AD_LACP_RATE 21 #define IFLA_BOND_AD_SELECT 22 #define IFLA_BOND_AD_INFO 23 -#define __IFLA_BOND_MAX 24 +#define IFLA_BOND_AD_ACTOR_SYS_PRIO 24 +#define IFLA_BOND_AD_USER_PORT_KEY 25 +#define IFLA_BOND_AD_ACTOR_SYSTEM 26 +#define __IFLA_BOND_MAX 27 #define IFLA_BOND_MAX (__IFLA_BOND_MAX - 1) #endif diff --git a/src/basic/random-util.c b/src/basic/random-util.c index aa04cc2318..071a41f186 100644 --- a/src/basic/random-util.c +++ b/src/basic/random-util.c @@ -142,8 +142,9 @@ void initialize_srand(void) { static bool srand_called = false; unsigned x; #if HAVE_SYS_AUXV_H - void *auxv; + const void *auxv; #endif + uint64_t k; if (srand_called) return; @@ -153,7 +154,7 @@ void initialize_srand(void) { * try to make use of that to seed the pseudo-random generator. It's * better than nothing... */ - auxv = (void*) getauxval(AT_RANDOM); + auxv = (const void*) getauxval(AT_RANDOM); if (auxv) { assert_cc(sizeof(x) <= 16); memcpy(&x, auxv, sizeof(x)); @@ -164,6 +165,9 @@ void initialize_srand(void) { x ^= (unsigned) now(CLOCK_REALTIME); x ^= (unsigned) gettid(); + if (rdrand64(&k) >= 0) + x ^= (unsigned) k; + srand(x); srand_called = true; } diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c index e7ea78f349..123d00e13e 100644 --- a/src/basic/smack-util.c +++ b/src/basic/smack-util.c @@ -115,7 +115,7 @@ int mac_smack_apply_pid(pid_t pid, const char *label) { return 0; p = procfs_file_alloca(pid, "attr/current"); - r = write_string_file(p, label, 0); + r = write_string_file(p, label, WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) return r; diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index 4e8651f428..3bef0dfe44 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -213,15 +213,47 @@ int fd_is_network_fs(int fd) { } int fd_is_network_ns(int fd) { + struct statfs s; int r; - r = fd_is_fs_type(fd, NSFS_MAGIC); - if (r <= 0) - return r; + /* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice + * way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle + * this somewhat nicely. + * + * This function returns > 0 if the fd definitely refers to a network namespace, 0 if it definitely does not + * refer to a network namespace, -EUCLEAN if we can't determine, and other negative error codes on error. */ + + if (fstatfs(fd, &s) < 0) + return -errno; + + if (!is_fs_type(&s, NSFS_MAGIC)) { + /* On really old kernels, there was no "nsfs", and network namespace sockets belonged to procfs + * instead. Handle that in a somewhat smart way. */ + + if (is_fs_type(&s, PROC_SUPER_MAGIC)) { + struct statfs t; + + /* OK, so it is procfs. Let's see if our own network namespace is procfs, too. If so, then the + * passed fd might refer to a network namespace, but we can't know for sure. In that case, + * return a recognizable error. */ + + if (statfs("/proc/self/ns/net", &t) < 0) + return -errno; + + if (s.f_type == t.f_type) + return -EUCLEAN; /* It's possible, we simply don't know */ + } + + return 0; /* No! */ + } r = ioctl(fd, NS_GET_NSTYPE); - if (r < 0) + if (r < 0) { + if (errno == ENOTTY) /* Old kernels didn't know this ioctl, let's also return a recognizable error in that case */ + return -EUCLEAN; + return -errno; + } return r == CLONE_NEWNET; } diff --git a/src/basic/stdio-util.h b/src/basic/stdio-util.h index 73c03274c7..dc67b6e761 100644 --- a/src/basic/stdio-util.h +++ b/src/basic/stdio-util.h @@ -7,6 +7,7 @@ #include <sys/types.h> #include "macro.h" +#include "util.h" #define snprintf_ok(buf, len, fmt, ...) \ ((size_t) snprintf(buf, len, fmt, __VA_ARGS__) < (len)) @@ -18,6 +19,9 @@ do { \ int _argtypes[128]; \ size_t _i, _k; \ + /* See https://github.com/google/sanitizers/issues/992 */ \ + if (HAS_FEATURE_MEMORY_SANITIZER) \ + zero(_argtypes); \ _k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \ assert(_k < ELEMENTSOF(_argtypes)); \ for (_i = 0; _i < _k; _i++) { \ diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 141b91f637..151ac954ad 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -868,7 +868,7 @@ int parse_timestamp(const char *t, usec_t *usec) { return tmp.return_value; } -static char* extract_multiplier(char *p, usec_t *multiplier) { +static const char* extract_multiplier(const char *p, usec_t *multiplier) { static const struct { const char *suffix; usec_t usec; @@ -942,8 +942,7 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) { for (;;) { usec_t multiplier = default_unit, k; - long long l, z = 0; - unsigned n = 0; + long long l; char *e; p += strspn(p, WHITESPACE); @@ -966,46 +965,47 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) { return -ERANGE; if (*e == '.') { - char *b = e + 1; - - /* Don't allow "0.-0", "3.+1" or "3. 1" */ - if (IN_SET(*b, '-', '+') || isspace(*b)) - return -EINVAL; - - errno = 0; - z = strtoll(b, &e, 10); - if (errno > 0) - return -errno; - if (z < 0) - return -ERANGE; - if (e == b) - return -EINVAL; - - n = e - b; - + p = e + 1; + p += strspn(p, DIGITS); } else if (e == p) return -EINVAL; + else + p = e; - e += strspn(e, WHITESPACE); - p = extract_multiplier(e, &multiplier); + s = extract_multiplier(p + strspn(p, WHITESPACE), &multiplier); + if (s == p && *s != '\0') + /* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/ + return -EINVAL; - something = true; + p = s; + if ((usec_t) l >= USEC_INFINITY / multiplier) + return -ERANGE; - k = ((usec_t) -1) / multiplier; - if ((usec_t) l + 1 >= k || (usec_t) z >= k) + k = (usec_t) l * multiplier; + if (k >= USEC_INFINITY - r) return -ERANGE; - k = (usec_t) z * multiplier; + r += k; - for (; n > 0; n--) - k /= 10; + something = true; - k += (usec_t) l * multiplier; - if (k >= ((usec_t) -1) - r) - return -ERANGE; + if (*e == '.') { + usec_t m = multiplier / 10; + const char *b; - r += k; + for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) { + k = (usec_t) (*b - '0') * m; + if (k >= USEC_INFINITY - r) + return -ERANGE; + + r += k; + } + + /* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/ + if (b == e + 1) + return -EINVAL; + } } *usec = r; @@ -1032,44 +1032,60 @@ int parse_sec_fix_0(const char *t, usec_t *ret) { return r; } -int parse_nsec(const char *t, nsec_t *nsec) { +static const char* extract_nsec_multiplier(const char *p, nsec_t *multiplier) { static const struct { const char *suffix; nsec_t nsec; } table[] = { - { "seconds", NSEC_PER_SEC }, - { "second", NSEC_PER_SEC }, - { "sec", NSEC_PER_SEC }, - { "s", NSEC_PER_SEC }, + { "seconds", NSEC_PER_SEC }, + { "second", NSEC_PER_SEC }, + { "sec", NSEC_PER_SEC }, + { "s", NSEC_PER_SEC }, { "minutes", NSEC_PER_MINUTE }, - { "minute", NSEC_PER_MINUTE }, - { "min", NSEC_PER_MINUTE }, - { "months", NSEC_PER_MONTH }, - { "month", NSEC_PER_MONTH }, - { "msec", NSEC_PER_MSEC }, - { "ms", NSEC_PER_MSEC }, - { "m", NSEC_PER_MINUTE }, - { "hours", NSEC_PER_HOUR }, - { "hour", NSEC_PER_HOUR }, - { "hr", NSEC_PER_HOUR }, - { "h", NSEC_PER_HOUR }, - { "days", NSEC_PER_DAY }, - { "day", NSEC_PER_DAY }, - { "d", NSEC_PER_DAY }, - { "weeks", NSEC_PER_WEEK }, - { "week", NSEC_PER_WEEK }, - { "w", NSEC_PER_WEEK }, - { "years", NSEC_PER_YEAR }, - { "year", NSEC_PER_YEAR }, - { "y", NSEC_PER_YEAR }, - { "usec", NSEC_PER_USEC }, - { "us", NSEC_PER_USEC }, - { "µs", NSEC_PER_USEC }, - { "nsec", 1ULL }, - { "ns", 1ULL }, - { "", 1ULL }, /* default is nsec */ + { "minute", NSEC_PER_MINUTE }, + { "min", NSEC_PER_MINUTE }, + { "months", NSEC_PER_MONTH }, + { "month", NSEC_PER_MONTH }, + { "M", NSEC_PER_MONTH }, + { "msec", NSEC_PER_MSEC }, + { "ms", NSEC_PER_MSEC }, + { "m", NSEC_PER_MINUTE }, + { "hours", NSEC_PER_HOUR }, + { "hour", NSEC_PER_HOUR }, + { "hr", NSEC_PER_HOUR }, + { "h", NSEC_PER_HOUR }, + { "days", NSEC_PER_DAY }, + { "day", NSEC_PER_DAY }, + { "d", NSEC_PER_DAY }, + { "weeks", NSEC_PER_WEEK }, + { "week", NSEC_PER_WEEK }, + { "w", NSEC_PER_WEEK }, + { "years", NSEC_PER_YEAR }, + { "year", NSEC_PER_YEAR }, + { "y", NSEC_PER_YEAR }, + { "usec", NSEC_PER_USEC }, + { "us", NSEC_PER_USEC }, + { "µs", NSEC_PER_USEC }, + { "nsec", 1ULL }, + { "ns", 1ULL }, + { "", 1ULL }, /* default is nsec */ }; + size_t i; + + for (i = 0; i < ELEMENTSOF(table); i++) { + char *e; + + e = startswith(p, table[i].suffix); + if (e) { + *multiplier = table[i].nsec; + return e; + } + } + + return p; +} +int parse_nsec(const char *t, nsec_t *nsec) { const char *p, *s; nsec_t r = 0; bool something = false; @@ -1091,8 +1107,8 @@ int parse_nsec(const char *t, nsec_t *nsec) { } for (;;) { - long long l, z = 0; - size_t n = 0, i; + nsec_t multiplier = 1, k; + long long l; char *e; p += strspn(p, WHITESPACE); @@ -1104,7 +1120,7 @@ int parse_nsec(const char *t, nsec_t *nsec) { break; } - if (*p == '-') + if (*p == '-') /* Don't allow "-0" */ return -ERANGE; errno = 0; @@ -1115,54 +1131,47 @@ int parse_nsec(const char *t, nsec_t *nsec) { return -ERANGE; if (*e == '.') { - char *b = e + 1; - - if (IN_SET(*b, '-', '+') || isspace(*b)) - return -EINVAL; - - errno = 0; - z = strtoll(b, &e, 10); - if (errno > 0) - return -errno; - if (z < 0) - return -ERANGE; - if (e == b) - return -EINVAL; - - n = e - b; - + p = e + 1; + p += strspn(p, DIGITS); } else if (e == p) return -EINVAL; + else + p = e; - e += strspn(e, WHITESPACE); + s = extract_nsec_multiplier(p + strspn(p, WHITESPACE), &multiplier); + if (s == p && *s != '\0') + /* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/ + return -EINVAL; - for (i = 0; i < ELEMENTSOF(table); i++) - if (startswith(e, table[i].suffix)) { - nsec_t k; + p = s; - k = ((nsec_t) -1) / table[i].nsec; - if ((nsec_t) l + 1 >= k || (nsec_t) z >= k) - return -ERANGE; + if ((nsec_t) l >= NSEC_INFINITY / multiplier) + return -ERANGE; + + k = (nsec_t) l * multiplier; + if (k >= NSEC_INFINITY - r) + return -ERANGE; - k = (nsec_t) z * table[i].nsec; + r += k; + + something = true; - for (; n > 0; n--) - k /= 10; + if (*e == '.') { + nsec_t m = multiplier / 10; + const char *b; - k += (nsec_t) l * table[i].nsec; - if (k >= ((nsec_t) -1) - r) + for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) { + k = (nsec_t) (*b - '0') * m; + if (k >= NSEC_INFINITY - r) return -ERANGE; r += k; - p = e + strlen(table[i].suffix); - - something = true; - break; } - if (i >= ELEMENTSOF(table)) - return -EINVAL; - + /* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/ + if (b == e + 1) + return -EINVAL; + } } *nsec = r; diff --git a/src/basic/util.c b/src/basic/util.c index 0da963f4af..b6e874c3b8 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -606,7 +606,7 @@ void disable_coredumps(void) { if (detect_container() > 0) return; - r = write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0); + r = write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) log_debug_errno(r, "Failed to turn off coredumps, ignoring: %m"); } diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c index fb8cf13f23..0dd202d086 100644 --- a/src/binfmt/binfmt.c +++ b/src/binfmt/binfmt.c @@ -47,7 +47,7 @@ static int delete_rule(const char *rule) { if (!fn) return log_oom(); - return write_string_file(fn, "-1", 0); + return write_string_file(fn, "-1", WRITE_STRING_FILE_DISABLE_BUFFER); } static int apply_rule(const char *rule) { @@ -55,7 +55,7 @@ static int apply_rule(const char *rule) { (void) delete_rule(rule); - r = write_string_file("/proc/sys/fs/binfmt_misc/register", rule, 0); + r = write_string_file("/proc/sys/fs/binfmt_misc/register", rule, WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) return log_error_errno(r, "Failed to add binary format: %m"); @@ -219,7 +219,7 @@ int main(int argc, char *argv[]) { } /* Flush out all rules */ - write_string_file("/proc/sys/fs/binfmt_misc/status", "-1", 0); + write_string_file("/proc/sys/fs/binfmt_misc/status", "-1", WRITE_STRING_FILE_DISABLE_BUFFER); STRV_FOREACH(f, files) { k = apply_file(*f, true); diff --git a/src/core/main.c b/src/core/main.c index 8a09ab67b5..a866160d76 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1391,7 +1391,7 @@ static int bump_unix_max_dgram_qlen(void) { r = read_one_line_file("/proc/sys/net/unix/max_dgram_qlen", &qlen); if (r < 0) - return log_warning_errno(r, "Failed to read AF_UNIX datagram queue length, ignoring: %m"); + return log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to read AF_UNIX datagram queue length, ignoring: %m"); r = safe_atolu(qlen, &v); if (r < 0) @@ -1400,7 +1400,7 @@ static int bump_unix_max_dgram_qlen(void) { if (v >= DEFAULT_UNIX_MAX_DGRAM_QLEN) return 0; - r = write_string_filef("/proc/sys/net/unix/max_dgram_qlen", 0, "%lu", DEFAULT_UNIX_MAX_DGRAM_QLEN); + r = write_string_filef("/proc/sys/net/unix/max_dgram_qlen", WRITE_STRING_FILE_DISABLE_BUFFER, "%lu", DEFAULT_UNIX_MAX_DGRAM_QLEN); if (r < 0) return log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to bump AF_UNIX datagram queue length, ignoring: %m"); @@ -1615,7 +1615,7 @@ static void initialize_core_pattern(bool skip_setup) { if (getpid_cached() != 1) return; - r = write_string_file("/proc/sys/kernel/core_pattern", arg_early_core_pattern, 0); + r = write_string_file("/proc/sys/kernel/core_pattern", arg_early_core_pattern, WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) log_warning_errno(r, "Failed to write '%s' to /proc/sys/kernel/core_pattern, ignoring: %m", arg_early_core_pattern); } diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c index 47138b863a..4e9506f09c 100644 --- a/src/core/smack-setup.c +++ b/src/core/smack-setup.c @@ -351,17 +351,17 @@ int mac_smack_setup(bool *loaded_policy) { } #ifdef SMACK_RUN_LABEL - r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, 0); + r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) log_warning_errno(r, "Failed to set SMACK label \"" SMACK_RUN_LABEL "\" on self: %m"); - r = write_string_file("/sys/fs/smackfs/ambient", SMACK_RUN_LABEL, 0); + r = write_string_file("/sys/fs/smackfs/ambient", SMACK_RUN_LABEL, WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) log_warning_errno(r, "Failed to set SMACK ambient label \"" SMACK_RUN_LABEL "\": %m"); r = write_string_file("/sys/fs/smackfs/netlabel", - "0.0.0.0/0 " SMACK_RUN_LABEL, 0); + "0.0.0.0/0 " SMACK_RUN_LABEL, WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) log_warning_errno(r, "Failed to set SMACK netlabel rule \"0.0.0.0/0 " SMACK_RUN_LABEL "\": %m"); - r = write_string_file("/sys/fs/smackfs/netlabel", "127.0.0.1 -CIPSO", 0); + r = write_string_file("/sys/fs/smackfs/netlabel", "127.0.0.1 -CIPSO", WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) log_warning_errno(r, "Failed to set SMACK netlabel rule \"127.0.0.1 -CIPSO\": %m"); #endif diff --git a/src/coredump/meson.build b/src/coredump/meson.build index bfba7ef58c..7fa5942697 100644 --- a/src/coredump/meson.build +++ b/src/coredump/meson.build @@ -13,8 +13,10 @@ endif coredumpctl_sources = files('coredumpctl.c') -install_data('coredump.conf', - install_dir : pkgsysconfdir) +if conf.get('ENABLE_COREDUMP') == 1 + install_data('coredump.conf', + install_dir : pkgsysconfdir) +endif tests += [ [['src/coredump/test-coredump-vacuum.c', diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c index c3a4509030..45231bf527 100644 --- a/src/cryptsetup/cryptsetup-generator.c +++ b/src/cryptsetup/cryptsetup-generator.c @@ -6,11 +6,13 @@ #include "alloc-util.h" #include "def.h" #include "dropin.h" +#include "escape.h" #include "fd-util.h" #include "fileio.h" #include "fstab-util.h" #include "generator.h" #include "hashmap.h" +#include "id128-util.h" #include "log.h" #include "mkdir.h" #include "parse-util.h" @@ -40,7 +42,7 @@ static char *arg_default_options = NULL; static char *arg_default_keyfile = NULL; static int generate_keydev_mount(const char *name, const char *keydev, char **unit, char **mount) { - _cleanup_free_ char *u = NULL, *what = NULL, *where = NULL; + _cleanup_free_ char *u = NULL, *what = NULL, *where = NULL, *name_escaped = NULL; _cleanup_fclose_ FILE *f = NULL; int r; @@ -54,16 +56,20 @@ static int generate_keydev_mount(const char *name, const char *keydev, char **un return r; r = mkdir("/run/systemd/cryptsetup", 0700); - if (r < 0) - return r; + if (r < 0 && errno != EEXIST) + return -errno; - where = strjoin("/run/systemd/cryptsetup/keydev-", name); + name_escaped = cescape(name); + if (!name_escaped) + return -ENOMEM; + + where = strjoin("/run/systemd/cryptsetup/keydev-", name_escaped); if (!where) return -ENOMEM; r = mkdir(where, 0700); - if (r < 0) - return r; + if (r < 0 && errno != EEXIST) + return -errno; r = unit_name_from_path(where, ".mount", &u); if (r < 0) @@ -392,36 +398,52 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat return log_oom(); } else if (streq(key, "luks.key")) { + size_t n; + _cleanup_free_ char *keyfile = NULL, *keydev = NULL; + char *c; + const char *keyspec; if (proc_cmdline_value_missing(key, value)) return 0; - r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value); - if (r == 2) { - char *c; - _cleanup_free_ char *keyfile = NULL, *keydev = NULL; + n = strspn(value, LETTERS DIGITS "-"); + if (value[n] != '=') { + if (free_and_strdup(&arg_default_keyfile, value) < 0) + return log_oom(); + return 0; + } - d = get_crypto_device(uuid); - if (!d) - return log_oom(); + uuid = strndup(value, n); + if (!uuid) + return log_oom(); + + if (!id128_is_valid(uuid)) { + log_warning("Failed to parse luks.key= kernel command line switch. UUID is invalid, ignoring."); + return 0; + } - c = strrchr(uuid_value, ':'); - if (!c) - /* No keydev specified */ - return free_and_replace(d->keyfile, uuid_value); + d = get_crypto_device(uuid); + if (!d) + return log_oom(); - *c = '\0'; - keyfile = strdup(uuid_value); - keydev = strdup(++c); + keyspec = value + n + 1; + c = strrchr(keyspec, ':'); + if (c) { + *c = '\0'; + keyfile = strdup(keyspec); + keydev = strdup(c + 1); if (!keyfile || !keydev) return log_oom(); + } else { + /* No keydev specified */ + keyfile = strdup(keyspec); + if (!keyfile) + return log_oom(); + } - free_and_replace(d->keyfile, keyfile); - free_and_replace(d->keydev, keydev); - } else if (free_and_strdup(&arg_default_keyfile, value) < 0) - return log_oom(); - + free_and_replace(d->keyfile, keyfile); + free_and_replace(d->keydev, keydev); } else if (streq(key, "luks.name")) { if (proc_cmdline_value_missing(key, value)) diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 6a939aec04..c5deb66edf 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -531,13 +531,17 @@ static int prompt_root_password(void) { msg2 = strjoina(special_glyph(TRIANGULAR_BULLET), " Please enter new root password again: "); for (;;) { - _cleanup_string_free_erase_ char *a = NULL, *b = NULL; + _cleanup_strv_free_erase_ char **a = NULL, **b = NULL; r = ask_password_tty(-1, msg1, NULL, 0, 0, NULL, &a); if (r < 0) return log_error_errno(r, "Failed to query root password: %m"); + if (strv_length(a) != 1) { + log_warning("Received multiple passwords, where we expected one."); + return -EINVAL; + } - if (isempty(a)) { + if (isempty(*a)) { log_warning("No password entered, skipping."); break; } @@ -546,12 +550,12 @@ static int prompt_root_password(void) { if (r < 0) return log_error_errno(r, "Failed to query root password: %m"); - if (!streq(a, b)) { + if (!streq(*a, *b)) { log_error("Entered passwords did not match, please try again."); continue; } - arg_root_password = TAKE_PTR(a); + arg_root_password = TAKE_PTR(*a); break; } diff --git a/src/hibernate-resume/hibernate-resume.c b/src/hibernate-resume/hibernate-resume.c index 397757fa46..abbf357291 100644 --- a/src/hibernate-resume/hibernate-resume.c +++ b/src/hibernate-resume/hibernate-resume.c @@ -47,7 +47,7 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - r = write_string_file("/sys/power/resume", major_minor, WRITE_STRING_FILE_CREATE); + r = write_string_file("/sys/power/resume", major_minor, WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) { log_error_errno(r, "Failed to write '%s' to /sys/power/resume: %m", major_minor); return EXIT_FAILURE; diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h index 328d51f8ea..88b54933c3 100644 --- a/src/libsystemd-network/lldp-internal.h +++ b/src/libsystemd-network/lldp-internal.h @@ -34,3 +34,6 @@ struct sd_lldp { #define log_lldp_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__) #define log_lldp(fmt, ...) log_lldp_errno(0, fmt, ##__VA_ARGS__) + +const char* lldp_event_to_string(sd_lldp_event e) _const_; +sd_lldp_event lldp_event_from_string(const char *s) _pure_; diff --git a/src/libsystemd-network/ndisc-internal.h b/src/libsystemd-network/ndisc-internal.h index fdabbc1b0e..0c04fea8e5 100644 --- a/src/libsystemd-network/ndisc-internal.h +++ b/src/libsystemd-network/ndisc-internal.h @@ -38,3 +38,6 @@ struct sd_ndisc { #define log_ndisc_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "NDISC: " fmt, ##__VA_ARGS__) #define log_ndisc(fmt, ...) log_ndisc_errno(0, fmt, ##__VA_ARGS__) + +const char* ndisc_event_to_string(sd_ndisc_event e) _const_; +sd_ndisc_event ndisc_event_from_string(const char *s) _pure_; diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 949798a1d3..d35e3e2ce1 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -255,11 +255,10 @@ int config_parse_ifalias(const char *unit, return 0; } - free(*s); - if (*n) - *s = TAKE_PTR(n); + if (isempty(n)) + *s = mfree(*s); else - *s = NULL; + free_and_replace(*s, n); return 0; } @@ -294,7 +293,7 @@ int config_parse_hwaddr(const char *unit, return 0; } - *hwaddr = TAKE_PTR(n); + free_and_replace(*hwaddr, n); return 0; } diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index f72ef204b9..993ca13727 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -6,15 +6,25 @@ #include "sd-lldp.h" #include "alloc-util.h" +#include "ether-addr-util.h" #include "fd-util.h" #include "lldp-internal.h" #include "lldp-neighbor.h" #include "lldp-network.h" #include "socket-util.h" -#include "ether-addr-util.h" +#include "string-table.h" #define LLDP_DEFAULT_NEIGHBORS_MAX 128U +static const char * const lldp_event_table[_SD_LLDP_EVENT_MAX] = { + [SD_LLDP_EVENT_ADDED] = "added", + [SD_LLDP_EVENT_REMOVED] = "removed", + [SD_LLDP_EVENT_UPDATED] = "updated", + [SD_LLDP_EVENT_REFRESHED] = "refreshed", +}; + +DEFINE_STRING_TABLE_LOOKUP(lldp_event, sd_lldp_event); + static void lldp_flush_neighbors(sd_lldp *lldp) { sd_lldp_neighbor *n; @@ -26,12 +36,14 @@ static void lldp_flush_neighbors(sd_lldp *lldp) { static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) { assert(lldp); + assert(event >= 0 && event < _SD_LLDP_EVENT_MAX); - log_lldp("Invoking callback for '%c'.", event); - - if (!lldp->callback) + if (!lldp->callback) { + log_lldp("Received '%s' event.", lldp_event_to_string(event)); return; + } + log_lldp("Invoking callback for '%s' event.", lldp_event_to_string(event)); lldp->callback(lldp, event, n, lldp->userdata); } diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index d679fc8222..b2fd087987 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -16,19 +16,30 @@ #include "ndisc-router.h" #include "random-util.h" #include "socket-util.h" +#include "string-table.h" #include "string-util.h" #include "util.h" #define NDISC_TIMEOUT_NO_RA_USEC (NDISC_ROUTER_SOLICITATION_INTERVAL * NDISC_MAX_ROUTER_SOLICITATIONS) +static const char * const ndisc_event_table[_SD_NDISC_EVENT_MAX] = { + [SD_NDISC_EVENT_TIMEOUT] = "timeout", + [SD_NDISC_EVENT_ROUTER] = "router", +}; + +DEFINE_STRING_TABLE_LOOKUP(ndisc_event, sd_ndisc_event); + static void ndisc_callback(sd_ndisc *ndisc, sd_ndisc_event event, sd_ndisc_router *rt) { assert(ndisc); + assert(event >= 0 && event < _SD_NDISC_EVENT_MAX); - log_ndisc("Invoking callback for '%c'.", event); - if (!ndisc->callback) + if (!ndisc->callback) { + log_ndisc("Received '%s' event.", ndisc_event_to_string(event)); return; + } + log_ndisc("Invoking callback for '%s' event.", ndisc_event_to_string(event)); ndisc->callback(ndisc, event, rt, ndisc->userdata); } diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 8d46081ec4..1f2238ca37 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -663,4 +663,7 @@ global: sd_device_monitor_filter_add_match_tag; sd_device_monitor_filter_update; sd_device_monitor_filter_remove; + + sd_event_source_get_floating; + sd_event_source_set_floating; } LIBSYSTEMD_239; diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index 8329a3f909..20529aafd3 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -554,7 +554,7 @@ static int enumerator_scan_dir(sd_device_enumerator *enumerator, const char *bas if (!dir) return -errno; - log_debug(" device-enumerator: scanning %s", path); + log_debug("sd-device-enumerator: Scanning %s", path); FOREACH_DIRENT_ALL(dent, dir, return -errno) { int k; @@ -586,10 +586,9 @@ static int enumerator_scan_devices_tag(sd_device_enumerator *enumerator, const c dir = opendir(path); if (!dir) { - if (errno == ENOENT) - return 0; - else - return log_error_errno(errno, "sd-device-enumerator: could not open tags directory %s: %m", path); + if (errno != ENOENT) + return log_debug_errno(errno, "sd-device-enumerator: Failed to open tags directory %s: %m", path); + return 0; } /* TODO: filter away subsystems? */ @@ -714,7 +713,7 @@ static int parent_crawl_children(sd_device_enumerator *enumerator, const char *p dir = opendir(path); if (!dir) - return log_debug_errno(errno, "sd-device-enumerate: could not open parent directory %s: %m", path); + return log_debug_errno(errno, "sd-device-enumerator: Failed to open parent directory %s: %m", path); FOREACH_DIRENT_ALL(dent, dir, return -errno) { _cleanup_free_ char *child = NULL; @@ -737,7 +736,7 @@ static int parent_crawl_children(sd_device_enumerator *enumerator, const char *p if (maxdepth > 0) parent_crawl_children(enumerator, child, maxdepth - 1); else - log_debug("device-enumerate: max depth reached, %s: ignoring devices", child); + log_debug("sd-device-enumerator: Max depth reached, %s: ignoring devices", child); } return r; @@ -765,25 +764,25 @@ static int enumerator_scan_devices_children(sd_device_enumerator *enumerator) { static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) { int r = 0; - log_debug("device-enumerator: scan all dirs"); + log_debug("sd-device-enumerator: Scan all dirs"); if (access("/sys/subsystem", F_OK) >= 0) { /* we have /subsystem/, forget all the old stuff */ r = enumerator_scan_dir(enumerator, "subsystem", "devices", NULL); if (r < 0) - return log_debug_errno(r, "device-enumerator: failed to scan /sys/subsystem: %m"); + return log_debug_errno(r, "sd-device-enumerator: Failed to scan /sys/subsystem: %m"); } else { int k; k = enumerator_scan_dir(enumerator, "bus", "devices", NULL); if (k < 0) { - log_debug_errno(k, "device-enumerator: failed to scan /sys/bus: %m"); + log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/bus: %m"); r = k; } k = enumerator_scan_dir(enumerator, "class", NULL, NULL); if (k < 0) { - log_debug_errno(k, "device-enumerator: failed to scan /sys/class: %m"); + log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/class: %m"); r = k; } } @@ -904,7 +903,7 @@ int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) { if (match_subsystem(enumerator, "module")) { k = enumerator_scan_dir_and_add_devices(enumerator, "module", NULL, NULL); if (k < 0) { - log_debug_errno(k, "device-enumerator: failed to scan modules: %m"); + log_debug_errno(k, "sd-device-enumerator: Failed to scan modules: %m"); r = k; } } @@ -918,7 +917,7 @@ int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) { if (match_subsystem(enumerator, "subsystem")) { k = enumerator_scan_dir_and_add_devices(enumerator, subsysdir, NULL, NULL); if (k < 0) { - log_debug_errno(k, "device-enumerator: failed to scan subsystems: %m"); + log_debug_errno(k, "sd-device-enumerator: Failed to scan subsystems: %m"); r = k; } } @@ -927,7 +926,7 @@ int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) { if (match_subsystem(enumerator, "drivers")) { k = enumerator_scan_dir(enumerator, subsysdir, "drivers", "drivers"); if (k < 0) { - log_debug_errno(k, "device-enumerator: failed to scan drivers: %m"); + log_debug_errno(k, "sd-device-enumerator: Failed to scan drivers: %m"); r = k; } } diff --git a/src/libsystemd/sd-device/device-monitor.c b/src/libsystemd/sd-device/device-monitor.c index f79a8497ba..ea8231aa63 100644 --- a/src/libsystemd/sd-device/device-monitor.c +++ b/src/libsystemd/sd-device/device-monitor.c @@ -140,14 +140,14 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group, * will not receive any messages. */ - log_debug("The udev service seems not to be active, disabling the monitor"); + log_debug("sd-device-monitor: The udev service seems not to be active, disabling the monitor"); group = MONITOR_GROUP_NONE; } if (fd < 0) { sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT); if (sock < 0) - return log_debug_errno(errno, "Failed to create socket: %m"); + return log_debug_errno(errno, "sd-device-monitor: Failed to create socket: %m"); } m = new(sd_device_monitor, 1); @@ -165,7 +165,7 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group, if (fd >= 0) { r = monitor_set_nl_address(m); if (r < 0) - return log_debug_errno(r, "Failed to set netlink address: %m"); + return log_debug_errno(r, "sd-device-monitor: Failed to set netlink address: %m"); } *ret = TAKE_PTR(m); @@ -280,24 +280,24 @@ int device_monitor_enable_receiving(sd_device_monitor *m) { if (!m->filter_uptodate) { r = sd_device_monitor_filter_update(m); if (r < 0) - return log_debug_errno(r, "Failed to update filter: %m"); + return log_debug_errno(r, "sd-device-monitor: Failed to update filter: %m"); } if (!m->bound) { if (bind(m->sock, &m->snl.sa, sizeof(struct sockaddr_nl)) < 0) - return log_debug_errno(errno, "Failed to bind monitoring socket to event source: %m"); + return log_debug_errno(errno, "sd-device-monitor: Failed to bind monitoring socket to event source: %m"); m->bound = true; } r = monitor_set_nl_address(m); if (r < 0) - return log_debug_errno(r, "Failed to set address: %m"); + return log_debug_errno(r, "sd-device-monitor: Failed to set address: %m"); /* enable receiving of sender credentials */ r = setsockopt_int(m->sock, SOL_SOCKET, SO_PASSCRED, true); if (r < 0) - return log_debug_errno(r, "Failed to set socket option SO_PASSCRED: %m"); + return log_debug_errno(r, "sd-device-monitor: Failed to set socket option SO_PASSCRED: %m"); return 0; } @@ -392,40 +392,40 @@ int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) { buflen = recvmsg(m->sock, &smsg, 0); if (buflen < 0) { if (errno != EINTR) - log_debug_errno(errno, "Failed to receive message: %m"); + log_debug_errno(errno, "sd-device-monitor: Failed to receive message: %m"); return -errno; } if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC)) - return log_debug_errno(EINVAL, "Invalid message length."); + return log_debug_errno(EINVAL, "sd-device-monitor: Invalid message length."); if (snl.nl.nl_groups == MONITOR_GROUP_NONE) { /* unicast message, check if we trust the sender */ if (m->snl_trusted_sender.nl.nl_pid == 0 || snl.nl.nl_pid != m->snl_trusted_sender.nl.nl_pid) - return log_debug_errno(EAGAIN, "Unicast netlink message ignored."); + return log_debug_errno(EAGAIN, "sd-device-monitor: Unicast netlink message ignored."); } else if (snl.nl.nl_groups == MONITOR_GROUP_KERNEL) { if (snl.nl.nl_pid > 0) - return log_debug_errno(EAGAIN, "Multicast kernel netlink message from PID %"PRIu32" ignored.", snl.nl.nl_pid); + return log_debug_errno(EAGAIN, "sd-device-monitor: Multicast kernel netlink message from PID %"PRIu32" ignored.", snl.nl.nl_pid); } cmsg = CMSG_FIRSTHDR(&smsg); if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) - return log_debug_errno(EAGAIN, "No sender credentials received, message ignored."); + return log_debug_errno(EAGAIN, "sd-device-monitor: No sender credentials received, message ignored."); cred = (struct ucred*) CMSG_DATA(cmsg); if (cred->uid != 0) - return log_debug_errno(EAGAIN, "Sender uid="UID_FMT", message ignored.", cred->uid); + return log_debug_errno(EAGAIN, "sd-device-monitor: Sender uid="UID_FMT", message ignored.", cred->uid); if (streq(buf.raw, "libudev")) { /* udev message needs proper version magic */ if (buf.nlh.magic != htobe32(UDEV_MONITOR_MAGIC)) - return log_debug_errno(EAGAIN, "Invalid message signature (%x != %x)", + return log_debug_errno(EAGAIN, "sd-device-monitor: Invalid message signature (%x != %x)", buf.nlh.magic, htobe32(UDEV_MONITOR_MAGIC)); if (buf.nlh.properties_off+32 > (size_t) buflen) - return log_debug_errno(EAGAIN, "Invalid message length (%u > %zd)", + return log_debug_errno(EAGAIN, "sd-device-monitor: Invalid message length (%u > %zd)", buf.nlh.properties_off+32, buflen); bufpos = buf.nlh.properties_off; @@ -437,16 +437,16 @@ int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) { /* kernel message with header */ bufpos = strlen(buf.raw) + 1; if ((size_t) bufpos < sizeof("a@/d") || bufpos >= buflen) - return log_debug_errno(EAGAIN, "Invalid message length"); + return log_debug_errno(EAGAIN, "sd-device-monitor: Invalid message length"); /* check message header */ if (!strstr(buf.raw, "@/")) - return log_debug_errno(EAGAIN, "Invalid message header"); + return log_debug_errno(EAGAIN, "sd-device-monitor: Invalid message header"); } r = device_new_from_nulstr(&device, (uint8_t*) &buf.raw[bufpos], buflen - bufpos); if (r < 0) - return log_debug_errno(r, "Failed to create device: %m"); + return log_debug_errno(r, "sd-device-monitor: Failed to create device from received message: %m"); if (is_initialized) device_set_is_initialized(device); @@ -454,9 +454,9 @@ int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) { /* Skip device, if it does not pass the current filter */ r = passes_filter(m, device); if (r < 0) - return log_device_debug_errno(device, r, "Failed to check received device passing filter: %m"); + return log_device_debug_errno(device, r, "sd-device-monitor: Failed to check received device passing filter: %m"); if (r == 0) - log_device_debug(device, "Received device does not pass filter, ignoring"); + log_device_debug(device, "sd-device-monitor: Received device does not pass filter, ignoring"); else *ret = TAKE_PTR(device); @@ -512,16 +512,16 @@ int device_monitor_send_device( r = device_get_properties_nulstr(device, (const uint8_t **) &buf, &blen); if (r < 0) - return log_debug_errno(r, "Failed to get device properties: %m"); + return log_device_debug_errno(device, r, "sd-device-monitor: Failed to get device properties: %m"); if (blen < 32) { - log_debug("Device buffer is too small to contain a valid device"); + log_device_debug(device, "sd-device-monitor: Length of device property nulstr is too small to contain valid device information"); return -EINVAL; } /* fill in versioned header */ r = sd_device_get_subsystem(device, &val); if (r < 0) - return log_device_debug_errno(device, r, "Failed to get device subsystem: %m"); + return log_device_debug_errno(device, r, "sd-device-monitor: Failed to get device subsystem: %m"); nlh.filter_subsystem_hash = htobe32(string_hash32(val)); if (sd_device_get_devtype(device, &val) >= 0) @@ -556,13 +556,13 @@ int device_monitor_send_device( count = sendmsg(m->sock, &smsg, 0); if (count < 0) { if (!destination && errno == ECONNREFUSED) { - log_device_debug(device, "Passed to netlink monitor"); + log_device_debug(device, "sd-device-monitor: Passed to netlink monitor"); return 0; } else - return log_device_debug_errno(device, errno, "Failed to send device to netlink monitor: %m"); + return log_device_debug_errno(device, errno, "sd-device-monitor: Failed to send device to netlink monitor: %m"); } - log_device_debug(device, "Passed %zi byte to netlink monitor", count); + log_device_debug(device, "sd-device-monitor: Passed %zi byte to netlink monitor", count); return count; } diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c index 0bd31216bf..fa0829885a 100644 --- a/src/libsystemd/sd-device/device-private.c +++ b/src/libsystemd/sd-device/device-private.c @@ -115,7 +115,7 @@ static int handle_db_line(sd_device *device, char key, const char *value) { break; default: - log_debug("device db: unknown key '%c'", key); + log_device_debug(device, "sd-device: Unknown key '%c' in device db, ignoring", key); } return 0; @@ -189,7 +189,7 @@ static int device_read_db(sd_device *device) { if (r == -ENOENT) return 0; else - return log_debug_errno(r, "sd-device: failed to read db '%s': %m", path); + return log_device_debug_errno(device, r, "sd-device: Failed to read db '%s': %m", path); } /* devices with a database entry are initialized */ @@ -207,7 +207,7 @@ static int device_read_db(sd_device *device) { break; case KEY: if (db[i] != ':') { - log_debug("sd-device: ignoring invalid db entry with key '%c'", key); + log_device_debug(device, "sd-device: Invalid db entry with key '%c', ignoring", key); state = INVALID_LINE; } else { @@ -233,14 +233,14 @@ static int device_read_db(sd_device *device) { db[i] = '\0'; r = handle_db_line(device, key, value); if (r < 0) - log_debug_errno(r, "sd-device: failed to handle db entry '%c:%s': %m", key, value); + log_device_debug_errno(device, r, "sd-device: Failed to handle db entry '%c:%s', ignoring: %m", key, value); state = PRE_KEY; } break; default: - assert_not_reached("invalid state when parsing db"); + assert_not_reached("Invalid state when parsing db"); } } @@ -376,43 +376,43 @@ static int device_amend(sd_device *device, const char *key, const char *value) { /* the caller must verify or trust this data (e.g., if it comes from the kernel) */ r = device_set_syspath(device, path, false); if (r < 0) - return log_debug_errno(r, "sd-device: could not set syspath to '%s': %m", path); + return log_device_debug_errno(device, r, "sd-device: Failed to set syspath to '%s': %m", path); } else if (streq(key, "SUBSYSTEM")) { r = device_set_subsystem(device, value); if (r < 0) - return log_debug_errno(r, "sd-device: could not set subsystem to '%s': %m", value); + return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem to '%s': %m", value); } else if (streq(key, "DEVTYPE")) { r = device_set_devtype(device, value); if (r < 0) - return log_debug_errno(r, "sd-device: could not set devtype to '%s': %m", value); + return log_device_debug_errno(device, r, "sd-device: Failed to set devtype to '%s': %m", value); } else if (streq(key, "DEVNAME")) { r = device_set_devname(device, value); if (r < 0) - return log_debug_errno(r, "sd-device: could not set devname to '%s': %m", value); + return log_device_debug_errno(device, r, "sd-device: Failed to set devname to '%s': %m", value); } else if (streq(key, "USEC_INITIALIZED")) { r = device_set_usec_initialized(device, value); if (r < 0) - return log_debug_errno(r, "sd-device: could not set usec-initialized to '%s': %m", value); + return log_device_debug_errno(device, r, "sd-device: Failed to set usec-initialized to '%s': %m", value); } else if (streq(key, "DRIVER")) { r = device_set_driver(device, value); if (r < 0) - return log_debug_errno(r, "sd-device: could not set driver to '%s': %m", value); + return log_device_debug_errno(device, r, "sd-device: Failed to set driver to '%s': %m", value); } else if (streq(key, "IFINDEX")) { r = device_set_ifindex(device, value); if (r < 0) - return log_debug_errno(r, "sd-device: could not set ifindex to '%s': %m", value); + return log_device_debug_errno(device, r, "sd-device: Failed to set ifindex to '%s': %m", value); } else if (streq(key, "DEVMODE")) { r = device_set_devmode(device, value); if (r < 0) - return log_debug_errno(r, "sd-device: could not set devmode to '%s': %m", value); + return log_device_debug_errno(device, r, "sd-device: Failed to set devmode to '%s': %m", value); } else if (streq(key, "DEVUID")) { r = device_set_devuid(device, value); if (r < 0) - return log_debug_errno(r, "sd-device: could not set devuid to '%s': %m", value); + return log_device_debug_errno(device, r, "sd-device: Failed to set devuid to '%s': %m", value); } else if (streq(key, "DEVGID")) { r = device_set_devgid(device, value); if (r < 0) - return log_debug_errno(r, "sd-device: could not set devgid to '%s': %m", value); + return log_device_debug_errno(device, r, "sd-device: Failed to set devgid to '%s': %m", value); } else if (streq(key, "DEVLINKS")) { const char *word, *state; size_t l; @@ -425,7 +425,7 @@ static int device_amend(sd_device *device, const char *key, const char *value) { r = device_add_devlink(device, devlink); if (r < 0) - return log_debug_errno(r, "sd-device: could not add devlink '%s': %m", devlink); + return log_device_debug_errno(device, r, "sd-device: Failed to add devlink '%s': %m", devlink); } } else if (streq(key, "TAGS")) { const char *word, *state; @@ -439,12 +439,12 @@ static int device_amend(sd_device *device, const char *key, const char *value) { r = device_add_tag(device, tag); if (r < 0) - return log_debug_errno(r, "sd-device: could not add tag '%s': %m", tag); + return log_device_debug_errno(device, r, "sd-device: Failed to add tag '%s': %m", tag); } } else { r = device_add_property_internal(device, key, value); if (r < 0) - return log_debug_errno(r, "sd-device: could not add property '%s=%s': %m", key, value); + return log_device_debug_errno(device, r, "sd-device: Failed to add property '%s=%s': %m", key, value); } return 0; @@ -480,7 +480,7 @@ static int device_append(sd_device *device, char *key, const char **_major, cons value = strchr(key, '='); if (!value) { - log_debug("sd-device: not a key-value pair: '%s'", key); + log_device_debug(device, "sd-device: Not a key-value pair: '%s'", key); return -EINVAL; } @@ -536,7 +536,7 @@ static int device_verify(sd_device *device, DeviceAction action, uint64_t seqnum assert(device); if (!device->devpath || !device->subsystem || action == _DEVICE_ACTION_INVALID || seqnum == 0) { - log_debug("sd-device: device created from strv lacks devpath, subsystem, action or seqnum"); + log_device_debug(device, "sd-device: Device created from strv or nulstr lacks devpath, subsystem, action or seqnum."); return -EINVAL; } @@ -569,7 +569,7 @@ int device_new_from_strv(sd_device **ret, char **strv) { if (major) { r = device_set_devnum(device, major, minor); if (r < 0) - return log_debug_errno(r, "sd-device: could not set devnum %s:%s: %m", major, minor); + return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor); } r = device_verify(device, action, seqnum); @@ -604,7 +604,7 @@ int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len) { key = (char*)&nulstr[i]; end = memchr(key, '\0', len - i); if (!end) { - log_debug("sd-device: failed to parse nulstr"); + log_device_debug(device, "sd-device: Failed to parse nulstr"); return -EINVAL; } i += end - key + 1; @@ -617,7 +617,7 @@ int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len) { if (major) { r = device_set_devnum(device, major, minor); if (r < 0) - return log_debug_errno(r, "sd-device: could not set devnum %s:%s: %m", major, minor); + return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor); } r = device_verify(device, action, seqnum); @@ -1083,8 +1083,8 @@ int device_update_db(sd_device *device) { goto fail; } - log_debug("created %s file '%s' for '%s'", has_info ? "db" : "empty", - path, device->devpath); + log_device_debug(device, "sd-device: Created %s file '%s' for '%s'", has_info ? "db" : "empty", + path, device->devpath); return 0; @@ -1092,7 +1092,7 @@ fail: (void) unlink(path); (void) unlink(path_tmp); - return log_error_errno(r, "failed to create %s file '%s' for '%s'", has_info ? "db" : "empty", path, device->devpath); + return log_device_debug_errno(device, r, "sd-device: Failed to create %s file '%s' for '%s'", has_info ? "db" : "empty", path, device->devpath); } int device_delete_db(sd_device *device) { diff --git a/src/libsystemd/sd-device/device-util.h b/src/libsystemd/sd-device/device-util.h index e25350edc5..94f6174bff 100644 --- a/src/libsystemd/sd-device/device-util.h +++ b/src/libsystemd/sd-device/device-util.h @@ -33,17 +33,15 @@ #define log_device_full(device, level, error, ...) \ ({ \ - const char *_sysname = NULL, *_subsystem = NULL; \ + const char *_sysname = NULL; \ sd_device *_d = (device); \ int _level = (level), _error = (error); \ \ - if (_d && _unlikely_(log_get_max_level() >= _level)) { \ + if (_d && _unlikely_(log_get_max_level() >= _level)) \ (void) sd_device_get_sysname(_d, &_sysname); \ - (void) sd_device_get_subsystem(_d, &_subsystem); \ - } \ log_object_internal(_level, _error, __FILE__, __LINE__, __func__, \ _sysname ? "DEVICE=" : NULL, _sysname, \ - _subsystem ? "SUBSYSTEM=" : NULL, _subsystem, ##__VA_ARGS__); \ + NULL, NULL, ##__VA_ARGS__); \ }) #define log_device_debug(device, ...) log_device_full(device, LOG_DEBUG, 0, ##__VA_ARGS__) diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index d0f5e1efcf..11115400dc 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -138,7 +138,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) { /* must be a subdirectory of /sys */ if (!path_startswith(_syspath, "/sys/")) { - log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath); + log_debug("sd-device: Syspath '%s' is not a subdirectory of /sys", _syspath); return -EINVAL; } @@ -147,7 +147,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) { if (r == -ENOENT) return -ENODEV; /* the device does not exist (any more?) */ if (r < 0) - return log_debug_errno(r, "sd-device: could not get target of '%s': %m", _syspath); + return log_debug_errno(r, "sd-device: Failed to get target of '%s': %m", _syspath); if (!path_startswith(syspath, "/sys")) { _cleanup_free_ char *real_sys = NULL, *new_syspath = NULL; @@ -156,17 +156,17 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) { /* /sys is a symlink to somewhere sysfs is mounted on? In that case, we convert the path to real sysfs to "/sys". */ r = chase_symlinks("/sys", NULL, 0, &real_sys); if (r < 0) - return log_debug_errno(r, "sd-device: could not chase symlink /sys: %m"); + return log_debug_errno(r, "sd-device: Failed to chase symlink /sys: %m"); p = path_startswith(syspath, real_sys); if (!p) { - log_debug("sd-device: canonicalized path '%s' does not starts with sysfs mount point '%s'", syspath, real_sys); + log_debug("sd-device: Canonicalized path '%s' does not starts with sysfs mount point '%s'", syspath, real_sys); return -ENODEV; } new_syspath = strjoin("/sys/", p); if (!new_syspath) - return log_oom(); + return -ENOMEM; free_and_replace(syspath, new_syspath); path_simplify(syspath, false); @@ -513,7 +513,7 @@ int device_read_uevent_file(sd_device *device) { /* some devices may not have uevent files, see set_syspath() */ return 0; else if (r < 0) - return log_debug_errno(r, "sd-device: failed to read uevent file '%s': %m", path); + return log_device_debug_errno(device, r, "sd-device: Failed to read uevent file '%s': %m", path); for (i = 0; i < uevent_len; i++) switch (state) { @@ -532,7 +532,7 @@ int device_read_uevent_file(sd_device *device) { state = PRE_VALUE; } else if (strchr(NEWLINE, uevent[i])) { uevent[i] = '\0'; - log_debug("sd-device: ignoring invalid uevent line '%s'", key); + log_device_debug(device, "sd-device: Invalid uevent line '%s', ignoring", key); state = PRE_KEY; } @@ -549,20 +549,20 @@ int device_read_uevent_file(sd_device *device) { r = handle_uevent_line(device, key, value, &major, &minor); if (r < 0) - log_debug_errno(r, "sd-device: failed to handle uevent entry '%s=%s': %m", key, value); + log_device_debug_errno(device, r, "sd-device: Failed to handle uevent entry '%s=%s', ignoring: %m", key, value); state = PRE_KEY; } break; default: - assert_not_reached("invalid state when parsing uevent file"); + assert_not_reached("Invalid state when parsing uevent file"); } if (major) { r = device_set_devnum(device, major, minor); if (r < 0) - log_debug_errno(r, "sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %m", major, minor, path); + log_device_debug_errno(device, r, "sd-device: Failed to set 'MAJOR=%s' or 'MINOR=%s' from '%s', ignoring: %m", major, minor, path); } return 0; @@ -798,7 +798,7 @@ _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) { path_startswith(device->devpath, "/bus/"))) r = device_set_subsystem(device, "subsystem"); if (r < 0 && r != -ENOENT) - return log_debug_errno(r, "sd-device: could not set subsystem for %s: %m", device->devpath); + return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem for %s: %m", device->devpath); device->subsystem_set = true; } else if (!device->driver_subsystem_set) @@ -821,7 +821,7 @@ _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) { r = device_set_drivers_subsystem(device, subsys + 1); } if (r < 0 && r != -ENOENT) - return log_debug_errno(r, "sd-device: could not set subsystem for driver %s: %m", device->devpath); + return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem for driver %s: %m", device->devpath); } device->driver_subsystem_set = true; @@ -944,11 +944,11 @@ _public_ int sd_device_get_driver(sd_device *device, const char **ret) { if (r >= 0) { r = device_set_driver(device, driver); if (r < 0) - return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath); + return log_device_debug_errno(device, r, "sd-device: Failed to set driver for %s: %m", device->devpath); } else if (r == -ENOENT) device->driver_set = true; else - return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath); + return log_device_debug_errno(device, r, "sd-device: Failed to set driver for %s: %m", device->devpath); } if (!device->driver) @@ -1211,7 +1211,7 @@ static int handle_db_line(sd_device *device, char key, const char *value) { break; default: - log_debug("device db: unknown key '%c'", key); + log_device_debug(device, "sd-device: Unknown key '%c' in device db, ignoring", key); } return 0; @@ -1312,7 +1312,7 @@ int device_read_db_aux(sd_device *device, bool force) { if (r == -ENOENT) return 0; else - return log_debug_errno(r, "sd-device: failed to read db '%s': %m", path); + return log_device_debug_errno(device, r, "sd-device: Failed to read db '%s': %m", path); } /* devices with a database entry are initialized */ @@ -1330,7 +1330,7 @@ int device_read_db_aux(sd_device *device, bool force) { break; case KEY: if (db[i] != ':') { - log_debug("sd-device: ignoring invalid db entry with key '%c'", key); + log_device_debug(device, "sd-device: Invalid db entry with key '%c', ignoring", key); state = INVALID_LINE; } else { @@ -1356,14 +1356,14 @@ int device_read_db_aux(sd_device *device, bool force) { db[i] = '\0'; r = handle_db_line(device, key, value); if (r < 0) - log_debug_errno(r, "sd-device: failed to handle db entry '%c:%s': %m", key, value); + log_device_debug_errno(device, r, "sd-device: Failed to handle db entry '%c:%s', ignoring: %m", key, value); state = PRE_KEY; } break; default: - assert_not_reached("invalid state when parsing db"); + assert_not_reached("Invalid state when parsing db"); } } @@ -1827,12 +1827,9 @@ static void device_remove_sysattr_value(sd_device *device, const char *_key) { /* set the attribute and save it in the cache. If a NULL value is passed the * attribute is cleared from the cache */ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *_value) { - _cleanup_close_ int fd = -1; _cleanup_free_ char *value = NULL; - const char *syspath; - char *path; - size_t len = 0; - ssize_t size; + const char *syspath, *path; + size_t len; int r; assert_return(device, -EINVAL); @@ -1850,25 +1847,6 @@ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, path = strjoina(syspath, "/", sysattr); - fd = open(path, O_WRONLY | O_CLOEXEC | O_NOFOLLOW); - if (fd < 0) { - if (errno == ELOOP) - return -EINVAL; - if (errno == EISDIR) - return -EISDIR; - - value = strdup(""); - if (!value) - return -ENOMEM; - - r = device_add_sysattr_value(device, sysattr, value); - if (r < 0) - return r; - value = NULL; - - return -ENXIO; - } - len = strlen(_value); /* drop trailing newlines */ @@ -1883,17 +1861,30 @@ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, if (!value) return -ENOMEM; - size = write(fd, value, len); - if (size < 0) - return -errno; + r = write_string_file(path, value, WRITE_STRING_FILE_DISABLE_BUFFER | WRITE_STRING_FILE_NOFOLLOW); + if (r < 0) { + if (r == -ELOOP) + return -EINVAL; + if (r == -EISDIR) + return r; - if ((size_t)size != len) - return -EIO; + free(value); + value = strdup(""); + if (!value) + return -ENOMEM; + + r = device_add_sysattr_value(device, sysattr, value); + if (r < 0) + return r; + + value = NULL; + return -ENXIO; + } r = device_add_sysattr_value(device, sysattr, value); if (r < 0) return r; - value = NULL; + value = NULL; return 0; } diff --git a/src/libsystemd/sd-device/test-sd-device.c b/src/libsystemd/sd-device/test-sd-device.c index 25ed3ecfea..1dda6625d2 100644 --- a/src/libsystemd/sd-device/test-sd-device.c +++ b/src/libsystemd/sd-device/test-sd-device.c @@ -12,10 +12,12 @@ static void test_sd_device_basic(void) { _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; sd_device *d; + log_info("/* %s */", __func__); + assert_se(sd_device_enumerator_new(&e) >= 0); assert_se(sd_device_enumerator_allow_uninitialized(e) >= 0); FOREACH_DEVICE(e, d) { - const char *syspath, *devpath, *subsystem, *val; + const char *syspath, *subsystem, *val; dev_t devnum; usec_t usec; int i, r; @@ -37,7 +39,7 @@ static void test_sd_device_basic(void) { r = sd_device_get_driver(d, &val); assert_se(r >= 0 || r == -ENOENT); - assert_se(sd_device_get_devpath(d, &devpath) >= 0); + assert_se(sd_device_get_devpath(d, &val) >= 0); r = sd_device_get_devname(d, &val); assert_se(r >= 0 || r == -ENOENT); @@ -47,11 +49,11 @@ static void test_sd_device_basic(void) { r = sd_device_get_sysnum(d, &val); assert_se(r >= 0 || r == -ENOENT); - r = sd_device_get_is_initialized(d); - assert_se(r >= 0); - if (r > 0) { + i = sd_device_get_is_initialized(d); + assert_se(i >= 0); + if (i > 0) { r = sd_device_get_usec_since_initialized(d, &usec); - assert_se(r >= 0 || r == -ENODATA); + assert_se((r >= 0 && usec > 0) || r == -ENODATA); } r = sd_device_get_sysattr_value(d, "name_assign_type", &val); @@ -60,7 +62,7 @@ static void test_sd_device_basic(void) { r = sd_device_get_property_value(d, "ID_NET_DRIVER", &val); assert_se(r >= 0 || r == -ENOENT); - log_debug("syspath:%s devpath:%s subsystem:%s", syspath, devpath, strempty(subsystem)); + log_debug("subsystem:%s syspath:%s initialized:%s", strna(subsystem), syspath, yes_no(i)); } } @@ -91,6 +93,8 @@ static void test_sd_device_enumerator_filter_subsystem(void) { Hashmap *h; char *s; + log_info("/* %s */", __func__); + assert_se(subsystems = hashmap_new(&string_hash_ops)); assert_se(sd_device_enumerator_new(&e) >= 0); diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index f44e6b4cca..27caa8681c 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -3702,3 +3702,31 @@ _public_ int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_d return !!s->destroy_callback; } + +_public_ int sd_event_source_get_floating(sd_event_source *s) { + assert_return(s, -EINVAL); + + return s->floating; +} + +_public_ int sd_event_source_set_floating(sd_event_source *s, int b) { + assert_return(s, -EINVAL); + + if (s->floating == !!b) + return 0; + + if (!s->event) /* Already disconnected */ + return -ESTALE; + + s->floating = b; + + if (b) { + sd_event_source_ref(s); + sd_event_unref(s->event); + } else { + sd_event_ref(s->event); + sd_event_source_unref(s); + } + + return 1; +} diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index 3365906813..4e42ab175f 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -224,6 +224,9 @@ static const NLType rtnl_link_info_data_bond_types[] = { [IFLA_BOND_AD_LACP_RATE] = { .type = NETLINK_TYPE_U8 }, [IFLA_BOND_AD_SELECT] = { .type = NETLINK_TYPE_U8 }, [IFLA_BOND_AD_INFO] = { .type = NETLINK_TYPE_NESTED }, + [IFLA_BOND_AD_ACTOR_SYS_PRIO] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BOND_AD_USER_PORT_KEY] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BOND_AD_ACTOR_SYSTEM] = { .type = NETLINK_TYPE_ETHER_ADDR }, }; static const NLType rtnl_link_info_data_iptun_types[] = { diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index 61876781c0..1fbab9dbf9 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -94,6 +94,7 @@ struct sd_resolve_query { }; void *userdata; + sd_resolve_destroy_t destroy_callback; LIST_FIELDS(sd_resolve_query, queries); }; @@ -1095,6 +1096,9 @@ static sd_resolve_query *resolve_query_free(sd_resolve_query *q) { resolve_query_disconnect(q); + if (q->destroy_callback) + q->destroy_callback(q->userdata); + resolve_freeaddrinfo(q->addrinfo); free(q->host); free(q->serv); @@ -1137,6 +1141,50 @@ _public_ sd_resolve *sd_resolve_query_get_resolve(sd_resolve_query *q) { return q->resolve; } +_public_ int sd_resolve_query_get_destroy_callback(sd_resolve_query *q, sd_resolve_destroy_t *destroy_callback) { + assert_return(q, -EINVAL); + + if (destroy_callback) + *destroy_callback = q->destroy_callback; + + return !!q->destroy_callback; +} + +_public_ int sd_resolve_query_set_destroy_callback(sd_resolve_query *q, sd_resolve_destroy_t destroy_callback) { + assert_return(q, -EINVAL); + + q->destroy_callback = destroy_callback; + return 0; +} + +_public_ int sd_resolve_query_get_floating(sd_resolve_query *q) { + assert_return(q, -EINVAL); + + return q->floating; +} + +_public_ int sd_resolve_query_set_floating(sd_resolve_query *q, int b) { + assert_return(q, -EINVAL); + + if (q->floating == !!b) + return 0; + + if (!q->resolve) /* Already disconnected */ + return -ESTALE; + + q->floating = b; + + if (b) { + sd_resolve_query_ref(q); + sd_resolve_unref(q->resolve); + } else { + sd_resolve_ref(q->resolve); + sd_resolve_query_unref(q); + } + + return 1; +} + static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) { sd_resolve *resolve = userdata; int r; diff --git a/src/login/71-seat.rules.in b/src/login/71-seat.rules.in index 0db46adc84..1f30900392 100644 --- a/src/login/71-seat.rules.in +++ b/src/login/71-seat.rules.in @@ -12,7 +12,7 @@ ACTION=="remove", GOTO="seat_end" TAG=="uaccess", SUBSYSTEM!="sound", TAG+="seat" SUBSYSTEM=="sound", KERNEL=="card*", TAG+="seat" SUBSYSTEM=="input", KERNEL=="input*", TAG+="seat" -SUBSYSTEM=="graphics", KERNEL=="fb[0-9]*", TAG+="seat", TAG+="master-of-seat" +SUBSYSTEM=="graphics", KERNEL=="fb[0-9]*", TAG+="seat" SUBSYSTEM=="drm", KERNEL=="card[0-9]*", TAG+="seat", TAG+="master-of-seat" SUBSYSTEM=="usb", ATTR{bDeviceClass}=="09", TAG+="seat" diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 032504e63a..927e304a0c 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1226,7 +1226,7 @@ static int trigger_device(Manager *m, sd_device *d) { if (!t) return -ENOMEM; - (void) write_string_file(t, "change", 0); + (void) write_string_file(t, "change", WRITE_STRING_FILE_DISABLE_BUFFER); } return 0; diff --git a/src/network/fuzz-netdev-parser.c b/src/network/fuzz-netdev-parser.c new file mode 100644 index 0000000000..adc85549e5 --- /dev/null +++ b/src/network/fuzz-netdev-parser.c @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "fuzz.h" +#include "networkd-manager.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + _cleanup_(manager_freep) Manager *manager = NULL; + _cleanup_fclose_ FILE *f = NULL; + _cleanup_(unlink_tempfilep) char netdev_config[] = "/tmp/fuzz-networkd.XXXXXX"; + + assert_se(fmkostemp_safe(netdev_config, "r+", &f) == 0); + if (size != 0) + assert_se(fwrite(data, size, 1, f) == 1); + + rewind(f); + assert_se(manager_new(&manager) >= 0); + (void) netdev_load_one(manager, netdev_config); + return 0; +} diff --git a/src/network/fuzz-network-parser.c b/src/network/fuzz-network-parser.c new file mode 100644 index 0000000000..bfeb46cff3 --- /dev/null +++ b/src/network/fuzz-network-parser.c @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "fuzz.h" +#include "networkd-manager.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + _cleanup_(manager_freep) Manager *manager = NULL; + _cleanup_fclose_ FILE *f = NULL; + _cleanup_(unlink_tempfilep) char network_config[] = "/tmp/fuzz-networkd.XXXXXX"; + + assert_se(fmkostemp_safe(network_config, "r+", &f) == 0); + if (size != 0) + assert_se(fwrite(data, size, 1, f) == 1); + + rewind(f); + assert_se(manager_new(&manager) >= 0); + (void) network_load_one(manager, network_config); + return 0; +} diff --git a/src/network/meson.build b/src/network/meson.build index 175d2f822c..d4fa27a288 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -136,6 +136,24 @@ if conf.get('ENABLE_NETWORKD') == 1 install_data('networkd.conf', install_dir : pkgsysconfdir) + fuzzers += [ + [['src/network/fuzz-netdev-parser.c', + 'src/fuzz/fuzz.h'], + [libnetworkd_core, + libudev_static, + libsystemd_network, + libshared], + [threads]], + + [['src/network/fuzz-network-parser.c', + 'src/fuzz/fuzz.h'], + [libnetworkd_core, + libudev_static, + libsystemd_network, + libshared], + [threads]] + ] + tests += [ [['src/network/test-networkd-conf.c'], [libnetworkd_core, diff --git a/src/network/netdev/bond.c b/src/network/netdev/bond.c index 5840a966ab..70d314bc79 100644 --- a/src/network/netdev/bond.c +++ b/src/network/netdev/bond.c @@ -7,6 +7,7 @@ #include "alloc-util.h" #include "conf-parser.h" +#include "ether-addr-util.h" #include "extract-word.h" #include "missing.h" #include "netdev/bond.h" @@ -284,6 +285,24 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlin return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_MIN_LINKS attribute: %m"); } + if (b->ad_actor_sys_prio != 0) { + r = sd_netlink_message_append_u16(m, IFLA_BOND_AD_ACTOR_SYS_PRIO, b->ad_actor_sys_prio); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_ACTOR_SYS_PRIO attribute: %m"); + } + + if (b->ad_user_port_key != 0) { + r = sd_netlink_message_append_u16(m, IFLA_BOND_AD_USER_PORT_KEY, b->ad_user_port_key); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_USER_PORT_KEY attribute: %m"); + } + + if (b->ad_actor_system) { + r = sd_netlink_message_append_ether_addr(m, IFLA_BOND_AD_ACTOR_SYSTEM, b->ad_actor_system); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_ACTOR_SYSTEM attribute: %m"); + } + r = sd_netlink_message_append_u8(m, IFLA_BOND_ALL_SLAVES_ACTIVE, b->all_slaves_active); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ALL_SLAVES_ACTIVE attribute: %m"); @@ -357,10 +376,8 @@ int config_parse_arp_ip_target_address(const char *unit, return 0; } - LIST_PREPEND(arp_ip_target, b->arp_ip_targets, buffer); + LIST_PREPEND(arp_ip_target, b->arp_ip_targets, TAKE_PTR(buffer)); b->n_arp_ip_targets++; - - buffer = NULL; } if (b->n_arp_ip_targets > NETDEV_BOND_ARP_TARGETS_MAX) @@ -371,6 +388,115 @@ int config_parse_arp_ip_target_address(const char *unit, return 0; } +int config_parse_ad_actor_sys_prio(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + Bond *b = userdata; + uint16_t v; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = safe_atou16(rvalue, &v); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse actor system priority '%s', ignoring: %m", rvalue); + return 0; + } + + if (v == 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse actor system priority '%s'. Range is [1,65535], ignoring.", rvalue); + return 0; + } + + b->ad_actor_sys_prio = v; + + return 0; +} + +int config_parse_ad_user_port_key(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + Bond *b = userdata; + uint16_t v; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = safe_atou16(rvalue, &v); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse user port key '%s', ignoring: %m", rvalue); + return 0; + } + + if (v > 1023) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse user port key '%s'. Range is [0,1023], ignoring.", rvalue); + return 0; + } + + b->ad_user_port_key = v; + + return 0; +} + +int config_parse_ad_actor_system(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + Bond *b = userdata; + _cleanup_free_ struct ether_addr *n = NULL; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + n = new0(struct ether_addr, 1); + if (!n) + return log_oom(); + + r = ether_addr_from_string(rvalue, n); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Not a valid MAC address %s. Ignoring assignment: %m", rvalue); + return 0; + } + + if (ether_addr_is_null(n) || (n->ether_addr_octet[0] & 0x01)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address %s, can not be null or multicast. Ignoring assignment.", rvalue); + return 0; + } + + free_and_replace(b->ad_actor_system, n); + + return 0; +} + static void bond_done(NetDev *netdev) { ArpIpTarget *t = NULL, *n = NULL; Bond *b; @@ -381,6 +507,8 @@ static void bond_done(NetDev *netdev) { assert(b); + free(b->ad_actor_system); + LIST_FOREACH_SAFE(arp_ip_target, t, n, b->arp_ip_targets) free(t); diff --git a/src/network/netdev/bond.h b/src/network/netdev/bond.h index be03d72087..ce6e8cadef 100644 --- a/src/network/netdev/bond.h +++ b/src/network/netdev/bond.h @@ -106,6 +106,10 @@ typedef struct Bond { unsigned num_grat_arp; unsigned min_links; + uint16_t ad_actor_sys_prio; + uint16_t ad_user_port_key; + struct ether_addr *ad_actor_system; + usec_t miimon; usec_t updelay; usec_t downdelay; @@ -152,3 +156,6 @@ int config_parse_bond_arp_validate(const char *unit, const char *filename, unsig int config_parse_bond_arp_all_targets(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_bond_primary_reselect(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_arp_ip_target_address(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_ad_actor_sys_prio(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_ad_user_port_key(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_ad_actor_system(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/network/netdev/bridge.c b/src/network/netdev/bridge.c index 5a462f8376..cb00780b8a 100644 --- a/src/network/netdev/bridge.c +++ b/src/network/netdev/bridge.c @@ -130,7 +130,7 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m"); r = sd_netlink_call_async(netdev->manager->rtnl, NULL, req, netdev_bridge_set_handler, - netdev_netlink_destroy_callback, netdev, 0, __func__); + netdev_destroy_callback, netdev, 0, __func__); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m"); diff --git a/src/network/netdev/geneve.c b/src/network/netdev/geneve.c index e407a8fc5c..1742e399b8 100644 --- a/src/network/netdev/geneve.c +++ b/src/network/netdev/geneve.c @@ -137,7 +137,7 @@ static int netdev_geneve_create(NetDev *netdev) { return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m"); r = sd_netlink_call_async(netdev->manager->rtnl, NULL, m, geneve_netdev_create_handler, - netdev_netlink_destroy_callback, netdev, 0, __func__); + netdev_destroy_callback, netdev, 0, __func__); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m"); diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf index 96c8fb1832..61d73e15ff 100644 --- a/src/network/netdev/netdev-gperf.gperf +++ b/src/network/netdev/netdev-gperf.gperf @@ -108,7 +108,9 @@ GENEVE.TOS, config_parse_uint8, 0, GENEVE.TTL, config_parse_uint8, 0, offsetof(Geneve, ttl) GENEVE.UDPChecksum, config_parse_bool, 0, offsetof(Geneve, udpcsum) GENEVE.UDP6ZeroCheckSumRx, config_parse_bool, 0, offsetof(Geneve, udp6zerocsumrx) +GENEVE.UDP6ZeroChecksumRx, config_parse_bool, 0, offsetof(Geneve, udp6zerocsumrx) GENEVE.UDP6ZeroCheckSumTx, config_parse_bool, 0, offsetof(Geneve, udp6zerocsumtx) +GENEVE.UDP6ZeroChecksumTx, config_parse_bool, 0, offsetof(Geneve, udp6zerocsumtx) GENEVE.DestinationPort, config_parse_ip_port, 0, offsetof(Geneve, dest_port) GENEVE.FlowLabel, config_parse_geneve_flow_label, 0, 0 Tun.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue) @@ -141,6 +143,9 @@ Bond.UpDelaySec, config_parse_sec, 0, Bond.DownDelaySec, config_parse_sec, 0, offsetof(Bond, downdelay) Bond.ARPIntervalSec, config_parse_sec, 0, offsetof(Bond, arp_interval) Bond.LearnPacketIntervalSec, config_parse_sec, 0, offsetof(Bond, lp_interval) +Bond.AdActorSystemPriority, config_parse_ad_actor_sys_prio, 0, offsetof(Bond, ad_actor_sys_prio) +Bond.AdUserPortKey, config_parse_ad_user_port_key, 0, offsetof(Bond, ad_user_port_key) +Bond.AdActorSystem, config_parse_ad_actor_system, 0, offsetof(Bond, ad_actor_system) Bridge.HelloTimeSec, config_parse_sec, 0, offsetof(Bridge, hello_time) Bridge.MaxAgeSec, config_parse_sec, 0, offsetof(Bridge, max_age) Bridge.AgeingTimeSec, config_parse_sec, 0, offsetof(Bridge, ageing_time) diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index 6eb63355a4..9ec16579e4 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -112,13 +112,19 @@ static void netdev_callbacks_clear(NetDev *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) { assert(netdev); netdev_callbacks_clear(netdev); - if (netdev->ifname && netdev->manager) - hashmap_remove(netdev->manager->netdevs, netdev->ifname); + netdev_detach_from_manager(netdev); free(netdev->filename); @@ -149,7 +155,7 @@ static NetDev *netdev_free(NetDev *netdev) { DEFINE_TRIVIAL_REF_UNREF_FUNC(NetDev, netdev, netdev_free); -void netdev_netlink_destroy_callback(void *userdata) { +void netdev_destroy_callback(void *userdata) { NetDev *netdev = userdata; assert(userdata); @@ -167,6 +173,8 @@ void netdev_drop(NetDev *netdev) { netdev_callbacks_clear(netdev); + netdev_detach_from_manager(netdev); + netdev_unref(netdev); return; @@ -542,7 +550,7 @@ static int netdev_create(NetDev *netdev, Link *link, link_ref(link); } else { r = sd_netlink_call_async(netdev->manager->rtnl, NULL, m, netdev_create_handler, - netdev_netlink_destroy_callback, netdev, 0, __func__); + netdev_destroy_callback, netdev, 0, __func__); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m"); @@ -586,7 +594,7 @@ int netdev_join(NetDev *netdev, Link *link, sd_netlink_message_handler_t callbac return 0; } -static int netdev_load_one(Manager *manager, const char *filename) { +int netdev_load_one(Manager *manager, const char *filename) { _cleanup_(netdev_unrefp) NetDev *netdev_raw = NULL, *netdev = NULL; _cleanup_fclose_ FILE *file = NULL; const char *dropin_dirname; diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h index 2c1a59f2c4..a1557bec41 100644 --- a/src/network/netdev/netdev.h +++ b/src/network/netdev/netdev.h @@ -146,11 +146,12 @@ extern const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX]; #define NETDEV(n) (&(n)->meta) int netdev_load(Manager *manager); +int netdev_load_one(Manager *manager, const char *filename); void netdev_drop(NetDev *netdev); NetDev *netdev_unref(NetDev *netdev); NetDev *netdev_ref(NetDev *netdev); -void netdev_netlink_destroy_callback(void *userdata); +void netdev_destroy_callback(void *userdata); DEFINE_TRIVIAL_CLEANUP_FUNC(NetDev*, netdev_unref); int netdev_get(Manager *manager, const char *name, NetDev **ret); diff --git a/src/network/netdev/vcan.c b/src/network/netdev/vcan.c index f06ad0fb42..574d1cad31 100644 --- a/src/network/netdev/vcan.c +++ b/src/network/netdev/vcan.c @@ -4,5 +4,6 @@ const NetDevVTable vcan_vtable = { .object_size = sizeof(VCan), + .sections = "Match\0NetDev\0", .create_type = NETDEV_CREATE_INDEPENDENT, }; diff --git a/src/network/netdev/vrf.c b/src/network/netdev/vrf.c index b18090f7a1..5efab537cc 100644 --- a/src/network/netdev/vrf.c +++ b/src/network/netdev/vrf.c @@ -27,7 +27,7 @@ static int netdev_vrf_fill_message_create(NetDev *netdev, Link *link, sd_netlink const NetDevVTable vrf_vtable = { .object_size = sizeof(Vrf), - .sections = "NetDev\0VRF\0", + .sections = "Match\0NetDev\0VRF\0", .fill_message_create = netdev_vrf_fill_message_create, .create_type = NETDEV_CREATE_MASTER, }; diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c index 1cab31302e..d5a0a19e9f 100644 --- a/src/network/netdev/wireguard.c +++ b/src/network/netdev/wireguard.c @@ -6,6 +6,8 @@ #include <sys/ioctl.h> #include <net/if.h> +#include "sd-resolve.h" + #include "alloc-util.h" #include "parse-util.h" #include "fd-util.h" @@ -28,10 +30,13 @@ static WireguardPeer *wireguard_peer_new(Wireguard *w, unsigned section) { if (w->last_peer_section == section && w->peers) return w->peers; - peer = new0(WireguardPeer, 1); + peer = new(WireguardPeer, 1); if (!peer) return NULL; - peer->flags = WGPEER_F_REPLACE_ALLOWEDIPS; + + *peer = (WireguardPeer) { + .flags = WGPEER_F_REPLACE_ALLOWEDIPS, + }; LIST_PREPEND(peers, w->peers, peer); w->last_peer_section = section; @@ -195,12 +200,21 @@ static int set_wireguard_interface(NetDev *netdev) { static WireguardEndpoint* wireguard_endpoint_free(WireguardEndpoint *e) { if (!e) return NULL; - netdev_unref(e->netdev); e->host = mfree(e->host); e->port = mfree(e->port); return mfree(e); } +static void wireguard_endpoint_destroy_callback(void *userdata) { + WireguardEndpoint *e = userdata; + + assert(e); + assert(e->netdev); + + netdev_unref(e->netdev); + wireguard_endpoint_free(e); +} + DEFINE_TRIVIAL_CLEANUP_FUNC(WireguardEndpoint*, wireguard_endpoint_free); static int on_resolve_retry(sd_event_source *s, usec_t usec, void *userdata) { @@ -211,8 +225,11 @@ static int on_resolve_retry(sd_event_source *s, usec_t usec, void *userdata) { w = WIREGUARD(netdev); assert(w); - w->resolve_retry_event_source = sd_event_source_unref(w->resolve_retry_event_source); + if (!netdev->manager) + /* The netdev is detached. */ + return 0; + assert(!w->unresolved_endpoints); w->unresolved_endpoints = TAKE_PTR(w->failed_endpoints); resolve_endpoints(netdev); @@ -232,9 +249,10 @@ static int wireguard_resolve_handler(sd_resolve_query *q, int ret, const struct addrinfo *ai, void *userdata) { - NetDev *netdev; + _cleanup_(netdev_unrefp) NetDev *netdev_will_unrefed = NULL; + NetDev *netdev = NULL; + WireguardEndpoint *e; Wireguard *w; - _cleanup_(wireguard_endpoint_freep) WireguardEndpoint *e; int r; assert(userdata); @@ -245,14 +263,17 @@ static int wireguard_resolve_handler(sd_resolve_query *q, w = WIREGUARD(netdev); assert(w); - w->resolve_query = sd_resolve_query_unref(w->resolve_query); + if (!netdev->manager) + /* The netdev is detached. */ + return 0; if (ret != 0) { log_netdev_error(netdev, "Failed to resolve host '%s:%s': %s", e->host, e->port, gai_strerror(ret)); LIST_PREPEND(endpoints, w->failed_endpoints, e); - e = NULL; + (void) sd_resolve_query_set_destroy_callback(q, NULL); /* Avoid freeing endpoint by destroy callback. */ + netdev_will_unrefed = netdev; /* But netdev needs to be unrefed. */ } else if ((ai->ai_family == AF_INET && ai->ai_addrlen == sizeof(struct sockaddr_in)) || - (ai->ai_family == AF_INET6 && ai->ai_addrlen == sizeof(struct sockaddr_in6))) + (ai->ai_family == AF_INET6 && ai->ai_addrlen == sizeof(struct sockaddr_in6))) memcpy(&e->peer->endpoint, ai->ai_addr, ai->ai_addrlen); else log_netdev_error(netdev, "Neither IPv4 nor IPv6 address found for peer endpoint: %s:%s", e->host, e->port); @@ -264,38 +285,53 @@ static int wireguard_resolve_handler(sd_resolve_query *q, set_wireguard_interface(netdev); if (w->failed_endpoints) { + _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; + w->n_retries++; r = sd_event_add_time(netdev->manager->event, - &w->resolve_retry_event_source, + &s, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + exponential_backoff_milliseconds(w->n_retries), 0, on_resolve_retry, netdev); - if (r < 0) + if (r < 0) { log_netdev_warning_errno(netdev, r, "Could not arm resolve retry handler: %m"); + return 0; + } + + r = sd_event_source_set_destroy_callback(s, netdev_destroy_callback); + if (r < 0) { + log_netdev_warning_errno(netdev, r, "Failed to set destroy callback to event source: %m"); + return 0; + } + + (void) sd_event_source_set_floating(s, true); + netdev_ref(netdev); } return 0; } static void resolve_endpoints(NetDev *netdev) { - int r = 0; - Wireguard *w; - WireguardEndpoint *endpoint; static const struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_DGRAM, .ai_protocol = IPPROTO_UDP }; + WireguardEndpoint *endpoint; + Wireguard *w; + int r = 0; assert(netdev); w = WIREGUARD(netdev); assert(w); LIST_FOREACH(endpoints, endpoint, w->unresolved_endpoints) { + _cleanup_(sd_resolve_query_unrefp) sd_resolve_query *q = NULL; + r = sd_resolve_getaddrinfo(netdev->manager->resolve, - &w->resolve_query, + &q, endpoint->host, endpoint->port, &hints, @@ -304,11 +340,23 @@ static void resolve_endpoints(NetDev *netdev) { if (r == -ENOBUFS) break; + if (r < 0) { + log_netdev_error_errno(netdev, r, "Failed to create resolver: %m"); + continue; + } - LIST_REMOVE(endpoints, w->unresolved_endpoints, endpoint); + r = sd_resolve_query_set_destroy_callback(q, wireguard_endpoint_destroy_callback); + if (r < 0) { + log_netdev_error_errno(netdev, r, "Failed to set destroy callback to resolving query: %m"); + continue; + } - if (r < 0) - log_netdev_error_errno(netdev, r, "Failed create resolver: %m"); + (void) sd_resolve_query_set_floating(q, true); + + /* Avoid freeing netdev. It will be unrefed by the destroy callback. */ + netdev_ref(netdev); + + LIST_REMOVE(endpoints, w->unresolved_endpoints, endpoint); } } @@ -531,12 +579,15 @@ int config_parse_wireguard_allowed_ips(const char *unit, return 0; } - ipmask = new0(WireguardIPmask, 1); + ipmask = new(WireguardIPmask, 1); if (!ipmask) return log_oom(); - ipmask->family = family; - ipmask->ip.in6 = addr.in6; - ipmask->cidr = prefixlen; + + *ipmask = (WireguardIPmask) { + .family = family, + .ip.in6 = addr.in6, + .cidr = prefixlen, + }; LIST_PREPEND(ipmasks, peer->ipmasks, ipmask); } @@ -572,10 +623,6 @@ int config_parse_wireguard_endpoint(const char *unit, if (!peer) return log_oom(); - endpoint = new0(WireguardEndpoint, 1); - if (!endpoint) - return log_oom(); - if (rvalue[0] == '[') { begin = &rvalue[1]; end = strchr(rvalue, ']'); @@ -609,12 +656,17 @@ int config_parse_wireguard_endpoint(const char *unit, if (!port) return log_oom(); - endpoint->peer = TAKE_PTR(peer); - endpoint->host = TAKE_PTR(host); - endpoint->port = TAKE_PTR(port); - endpoint->netdev = netdev_ref(data); - LIST_PREPEND(endpoints, w->unresolved_endpoints, endpoint); - endpoint = NULL; + endpoint = new(WireguardEndpoint, 1); + if (!endpoint) + return log_oom(); + + *endpoint = (WireguardEndpoint) { + .peer = TAKE_PTR(peer), + .host = TAKE_PTR(host), + .port = TAKE_PTR(port), + .netdev = data, + }; + LIST_PREPEND(endpoints, w->unresolved_endpoints, TAKE_PTR(endpoint)); return 0; } @@ -673,11 +725,11 @@ static void wireguard_done(NetDev *netdev) { Wireguard *w; WireguardPeer *peer; WireguardIPmask *mask; + WireguardEndpoint *e; assert(netdev); w = WIREGUARD(netdev); - assert(!w->unresolved_endpoints); - w->resolve_retry_event_source = sd_event_source_unref(w->resolve_retry_event_source); + assert(w); while ((peer = w->peers)) { LIST_REMOVE(peers, w->peers, peer); @@ -687,6 +739,16 @@ static void wireguard_done(NetDev *netdev) { } free(peer); } + + while ((e = w->unresolved_endpoints)) { + LIST_REMOVE(endpoints, w->unresolved_endpoints, e); + wireguard_endpoint_free(e); + } + + while ((e = w->failed_endpoints)) { + LIST_REMOVE(endpoints, w->failed_endpoints, e); + wireguard_endpoint_free(e); + } } const NetDevVTable wireguard_vtable = { diff --git a/src/network/netdev/wireguard.h b/src/network/netdev/wireguard.h index 80a5bf87a0..bd97004519 100644 --- a/src/network/netdev/wireguard.h +++ b/src/network/netdev/wireguard.h @@ -2,11 +2,10 @@ typedef struct Wireguard Wireguard; +#include "in-addr-util.h" #include "netdev.h" -#include "sd-resolve.h" -#include "wireguard-netlink.h" #include "socket-util.h" -#include "in-addr-util.h" +#include "wireguard-netlink.h" #ifndef IFNAMSIZ #define IFNAMSIZ 16 @@ -58,12 +57,10 @@ struct Wireguard { LIST_HEAD(WireguardPeer, peers); size_t allocation_size; - sd_event_source *resolve_retry_event_source; LIST_HEAD(WireguardEndpoint, unresolved_endpoints); LIST_HEAD(WireguardEndpoint, failed_endpoints); unsigned n_retries; - sd_resolve_query *resolve_query; }; DEFINE_NETDEV_CAST(WIREGUARD, Wireguard); diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index cf33563bdd..1f722aca52 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -91,10 +91,8 @@ void address_free(Address *address) { assert(address->network->n_static_addresses > 0); address->network->n_static_addresses--; - if (address->section) { + if (address->section) hashmap_remove(address->network->addresses_by_section, address->section); - network_config_section_free(address->section); - } } if (address->link) { @@ -105,6 +103,8 @@ void address_free(Address *address) { memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr)); } + network_config_section_free(address->section); + free(address->label); free(address); } @@ -428,6 +428,7 @@ int address_remove( sd_netlink_message_handler_t callback) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; + _cleanup_free_ char *b = NULL; int r; assert(address); @@ -437,6 +438,11 @@ int address_remove( assert(link->manager); assert(link->manager->rtnl); + if (DEBUG_LOGGING) { + if (in_addr_to_string(address->family, &address->in_addr, &b) >= 0) + log_link_debug(link, "Removing address %s", b); + } + r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR, link->ifindex, address->family); if (r < 0) @@ -706,8 +712,8 @@ int config_parse_address(const char *unit, Network *network = userdata; _cleanup_(address_freep) Address *n = NULL; - const char *address, *e; union in_addr_union buffer; + unsigned char prefixlen; int r, f; assert(filename); @@ -727,44 +733,19 @@ int config_parse_address(const char *unit, return r; /* Address=address/prefixlen */ - - /* prefixlen */ - e = strchr(rvalue, '/'); - if (e) { - unsigned i; - - r = safe_atou(e + 1, &i); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is invalid, ignoring assignment: %s", e + 1); - return 0; - } - - n->prefixlen = (unsigned char) i; - - address = strndupa(rvalue, e - rvalue); - } else - address = rvalue; - - r = in_addr_from_string_auto(address, &f, &buffer); + r = in_addr_default_prefix_from_string_auto(rvalue, &f, &buffer, &prefixlen); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Address is invalid, ignoring assignment: %s", address); + log_syntax(unit, LOG_ERR, filename, line, r, "Invalid address '%s', ignoring assignment: %m", rvalue); return 0; } - if (!e && f == AF_INET) { - r = in4_addr_default_prefixlen(&buffer.in, &n->prefixlen); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length not specified, and a default one cannot be deduced for '%s', ignoring assignment", address); - return 0; - } - } - if (n->family != AF_UNSPEC && f != n->family) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", address); + log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", rvalue); return 0; } n->family = f; + n->prefixlen = prefixlen; if (streq(lvalue, "Address")) n->in_addr = buffer; diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c index 694065e3d9..aa0c4c800f 100644 --- a/src/network/networkd-fdb.c +++ b/src/network/networkd-fdb.c @@ -200,7 +200,7 @@ int config_parse_fdb_hwaddr( &fdb_entry->mac_addr->ether_addr_octet[4], &fdb_entry->mac_addr->ether_addr_octet[5]); - if (ETHER_ADDR_LEN != r) { + if (r != ETHER_ADDR_LEN) { log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue); return 0; } diff --git a/src/network/networkd-ipv6-proxy-ndp.c b/src/network/networkd-ipv6-proxy-ndp.c index c4e2091142..6286b37deb 100644 --- a/src/network/networkd-ipv6-proxy-ndp.c +++ b/src/network/networkd-ipv6-proxy-ndp.c @@ -43,7 +43,7 @@ static int ipv6_proxy_ndp_set(Link *link) { v = ipv6_proxy_ndp_is_needed(link); p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/proxy_ndp"); - r = write_string_file(p, one_zero(v), WRITE_STRING_FILE_VERIFY_ON_FAILURE); + r = write_string_file(p, one_zero(v), WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) log_link_warning_errno(link, r, "Cannot configure proxy NDP for interface: %m"); @@ -88,16 +88,16 @@ void ipv6_proxy_ndp_address_free(IPv6ProxyNDPAddress *ipv6_proxy_ndp_address) { } int config_parse_ipv6_proxy_ndp_address( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { Network *network = userdata; _cleanup_(ipv6_proxy_ndp_address_freep) IPv6ProxyNDPAddress *ipv6_proxy_ndp_address = NULL; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 08ea7b4139..1b233507e7 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -270,7 +270,7 @@ static int link_enable_ipv6(Link *link) { p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/disable_ipv6"); - r = write_string_file(p, one_zero(disabled), WRITE_STRING_FILE_VERIFY_ON_FAILURE); + r = write_string_file(p, one_zero(disabled), WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) log_link_warning_errno(link, r, "Cannot %s IPv6 for interface %s: %m", enable_disable(!disabled), link->ifname); @@ -503,6 +503,17 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { return 0; } +static void link_detach_from_manager(Link *link) { + if (!link || !link->manager) + return; + + 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) { Address *address; Link *carrier; @@ -552,11 +563,7 @@ static Link *link_free(Link *link) { sd_ndisc_unref(link->ndisc); sd_radv_unref(link->radv); - if (link->manager) { - hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex)); - set_remove(link->manager->links_requesting_uuid, link); - link_clean(link); - } + link_detach_from_manager(link); free(link->ifname); @@ -785,7 +792,7 @@ static int link_set_routing_policy_rule(Link *link) { 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, &rrule); - if (r == 1) { + if (r == 0) { (void) routing_policy_rule_make_local(link->manager, rrule); continue; } @@ -1256,7 +1263,7 @@ static int link_set_proxy_arp(Link *link) { p = strjoina("/proc/sys/net/ipv4/conf/", link->ifname, "/proxy_arp"); - r = write_string_file(p, one_zero(link->network->proxy_arp), WRITE_STRING_FILE_VERIFY_ON_FAILURE); + r = write_string_file(p, one_zero(link->network->proxy_arp), WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface: %m"); @@ -2265,6 +2272,9 @@ void link_drop(Link *link) { log_link_debug(link, "Link removed"); (void) unlink(link->state_file); + + link_detach_from_manager(link); + link_unref(link); return; @@ -2463,7 +2473,7 @@ static int link_set_ipv4_forward(Link *link) { * primarily to keep IPv4 and IPv6 packet forwarding behaviour * somewhat in sync (see below). */ - r = write_string_file("/proc/sys/net/ipv4/ip_forward", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE); + r = write_string_file("/proc/sys/net/ipv4/ip_forward", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) log_link_warning_errno(link, r, "Cannot turn on IPv4 packet forwarding, ignoring: %m"); @@ -2485,7 +2495,7 @@ static int link_set_ipv6_forward(Link *link) { * same behaviour there and also propagate the setting from * one to all, to keep things simple (see above). */ - r = write_string_file("/proc/sys/net/ipv6/conf/all/forwarding", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE); + r = write_string_file("/proc/sys/net/ipv6/conf/all/forwarding", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) log_link_warning_errno(link, r, "Cannot configure IPv6 packet forwarding, ignoring: %m"); @@ -2505,7 +2515,7 @@ static int link_set_ipv6_privacy_extensions(Link *link) { p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/use_tempaddr"); xsprintf(buf, "%u", (unsigned) link->network->ipv6_privacy_extensions); - r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE); + r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extension for interface: %m"); @@ -2529,7 +2539,7 @@ static int link_set_ipv6_accept_ra(Link *link) { p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/accept_ra"); /* We handle router advertisements ourselves, tell the kernel to GTFO */ - r = write_string_file(p, "0", WRITE_STRING_FILE_VERIFY_ON_FAILURE); + r = write_string_file(p, "0", WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface: %m"); @@ -2557,7 +2567,7 @@ static int link_set_ipv6_dad_transmits(Link *link) { p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/dad_transmits"); xsprintf(buf, "%i", link->network->ipv6_dad_transmits); - r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE); + r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface: %m"); @@ -2585,7 +2595,7 @@ static int link_set_ipv6_hop_limit(Link *link) { p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/hop_limit"); xsprintf(buf, "%i", link->network->ipv6_hop_limit); - r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE); + r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface: %m"); @@ -2611,13 +2621,45 @@ static int link_set_ipv6_mtu(Link *link) { xsprintf(buf, "%" PRIu32, link->network->ipv6_mtu); - r = write_string_file(p, buf, 0); + r = write_string_file(p, buf, WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) log_link_warning_errno(link, r, "Cannot set IPv6 MTU for interface: %m"); return 0; } +static bool link_is_static_address_configured(Link *link, Address *address) { + Address *net_address; + + assert(link); + assert(address); + + if (!link->network) + return false; + + LIST_FOREACH(addresses, net_address, link->network->static_addresses) + if (address_equal(net_address, address)) + return true; + + return false; +} + +static bool link_is_static_route_configured(Link *link, Route *route) { + Route *net_route; + + assert(link); + assert(route); + + if (!link->network) + return false; + + LIST_FOREACH(routes, net_route, link->network->static_routes) + if (route_equal(net_route, route)) + return true; + + return false; +} + static int link_drop_foreign_config(Link *link) { Address *address; Route *route; @@ -2629,9 +2671,15 @@ static int link_drop_foreign_config(Link *link) { if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1) continue; - r = address_remove(address, link, link_address_remove_handler); - if (r < 0) - return r; + if (link_is_static_address_configured(link, address)) { + r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL); + if (r < 0) + return log_link_error_errno(link, r, "Failed to add address: %m"); + } else { + r = address_remove(address, link, link_address_remove_handler); + if (r < 0) + return r; + } } SET_FOREACH(route, link->routes_foreign, i) { @@ -2639,9 +2687,15 @@ static int link_drop_foreign_config(Link *link) { if (route->protocol == RTPROT_KERNEL) continue; - r = route_remove(route, link, link_route_remove_handler); - if (r < 0) - return r; + if (link_is_static_route_configured(link, route)) { + r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL); + if (r < 0) + return r; + } else { + r = route_remove(route, link, link_route_remove_handler); + if (r < 0) + return r; + } } return 0; diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 7433be96ff..69861a680e 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -201,7 +201,7 @@ static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *devi } if (!STR_IN_SET(action, "add", "change")) { - log_device_debug(device, "Ignoring udev %s event for device: %m", action); + log_device_debug(device, "Ignoring udev %s event for device.", action); return 0; } @@ -1407,10 +1407,9 @@ int manager_new(Manager **ret) { } void manager_free(Manager *m) { + AddressPool *pool; Network *network; - NetDev *netdev; Link *link; - AddressPool *pool; if (!m) return; @@ -1419,6 +1418,7 @@ void manager_free(Manager *m) { sd_netlink_unref(m->rtnl); sd_netlink_unref(m->genl); + sd_resolve_unref(m->resolve); while ((network = m->networks)) network_free(network); @@ -1437,28 +1437,26 @@ void manager_free(Manager *m) { link_unref(link); } - set_free_with_destructor(m->dirty_links, link_unref); - hashmap_free(m->links); - set_free(m->links_requesting_uuid); + m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref); + m->links = hashmap_free(m->links); + m->links_requesting_uuid = set_free(m->links_requesting_uuid); set_free(m->duids_requesting_uuid); hashmap_free(m->networks_by_name); - while ((netdev = hashmap_first(m->netdevs))) - netdev_unref(netdev); - hashmap_free(m->netdevs); + m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref); while ((pool = m->address_pools)) address_pool_free(pool); - set_free_with_destructor(m->rules, routing_policy_rule_free); - set_free_with_destructor(m->rules_foreign, routing_policy_rule_free); + /* routing_policy_rule_free() access m->rules and m->rules_foreign. + * So, it is necessary to set NULL after the sets are freed. */ + m->rules = set_free_with_destructor(m->rules, routing_policy_rule_free); + m->rules_foreign = set_free_with_destructor(m->rules_foreign, routing_policy_rule_free); set_free_with_destructor(m->rules_saved, routing_policy_rule_free); sd_event_unref(m->event); - sd_resolve_unref(m->resolve); - sd_device_monitor_unref(m->device_monitor); sd_bus_unref(m->bus); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index ac924596f3..adbba5f480 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -38,8 +38,8 @@ Link.AllMulticast, config_parse_tristate, Link.Unmanaged, config_parse_bool, 0, offsetof(Network, unmanaged) Link.RequiredForOnline, config_parse_bool, 0, offsetof(Network, required_for_online) Network.Description, config_parse_string, 0, offsetof(Network, description) -Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) -Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) +Network.Bridge, config_parse_netdev, 0, 0 +Network.Bond, config_parse_netdev, 0, 0 Network.VLAN, config_parse_netdev, 0, 0 Network.MACVLAN, config_parse_netdev, 0, 0 Network.MACVTAP, config_parse_netdev, 0, 0 diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 8d7795d72c..f257ac6698 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -102,7 +102,7 @@ void network_apply_anonymize_if_set(Network *network) { network->dhcp_use_timezone = false; } -static int network_load_one(Manager *manager, const char *filename) { +int network_load_one(Manager *manager, const char *filename) { _cleanup_(network_freep) Network *network = NULL; _cleanup_fclose_ FILE *file = NULL; char *d; @@ -181,8 +181,6 @@ static int network_load_one(Manager *manager, const char *filename) { if (!d) return -EINVAL; - assert(streq(d, ".network")); - *d = '\0'; network->required_for_online = true; @@ -607,14 +605,17 @@ int config_parse_netdev(const char *unit, switch (kind) { case NETDEV_KIND_BRIDGE: + network->bridge = netdev_unref(network->bridge); network->bridge = netdev; break; case NETDEV_KIND_BOND: + network->bond = netdev_unref(network->bond); network->bond = netdev; break; case NETDEV_KIND_VRF: + network->vrf = netdev_unref(network->vrf); network->vrf = netdev; break; diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 1be7d46735..919a2c4b3c 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -78,6 +78,8 @@ typedef enum RADVPrefixDelegation { RADV_PREFIX_DELEGATION_STATIC, RADV_PREFIX_DELEGATION_DHCP6, RADV_PREFIX_DELEGATION_BOTH, + _RADV_PREFIX_DELEGATION_MAX, + _RADV_PREFIX_DELEGATION_INVALID = -1, } RADVPrefixDelegation; typedef struct NetworkConfigSection { @@ -270,6 +272,7 @@ void network_free(Network *network); DEFINE_TRIVIAL_CLEANUP_FUNC(Network*, network_free); int network_load(Manager *manager); +int network_load_one(Manager *manager, const char *filename); int network_get_by_name(Manager *manager, const char *name, Network **ret); int network_get(Manager *manager, sd_device *device, const char *ifname, const struct ether_addr *mac, Network **ret); @@ -316,3 +319,6 @@ DHCPUseDomains dhcp_use_domains_from_string(const char *s) _pure_; const char* lldp_mode_to_string(LLDPMode m) _const_; LLDPMode lldp_mode_from_string(const char *s) _pure_; + +const char* radv_prefix_delegation_to_string(RADVPrefixDelegation i) _const_; +RADVPrefixDelegation radv_prefix_delegation_from_string(const char *s) _pure_; diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c index c7d6ac2558..600fb27d75 100644 --- a/src/network/networkd-radv.c +++ b/src/network/networkd-radv.c @@ -12,8 +12,21 @@ #include "parse-util.h" #include "sd-radv.h" #include "string-util.h" +#include "string-table.h" #include "strv.h" +static const char * const radv_prefix_delegation_table[_RADV_PREFIX_DELEGATION_MAX] = { + [RADV_PREFIX_DELEGATION_NONE] = "no", + [RADV_PREFIX_DELEGATION_STATIC] = "static", + [RADV_PREFIX_DELEGATION_DHCP6] = "dhcpv6", + [RADV_PREFIX_DELEGATION_BOTH] = "yes", +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN( + radv_prefix_delegation, + RADVPrefixDelegation, + RADV_PREFIX_DELEGATION_BOTH); + int config_parse_router_prefix_delegation( const char *unit, const char *filename, @@ -27,7 +40,7 @@ int config_parse_router_prefix_delegation( void *userdata) { Network *network = userdata; - int d; + RADVPrefixDelegation d; assert(filename); assert(section); @@ -35,21 +48,14 @@ int config_parse_router_prefix_delegation( assert(rvalue); assert(data); - if (streq(rvalue, "static")) - network->router_prefix_delegation = RADV_PREFIX_DELEGATION_STATIC; - else if (streq(rvalue, "dhcpv6")) - network->router_prefix_delegation = RADV_PREFIX_DELEGATION_DHCP6; - else { - d = parse_boolean(rvalue); - if (d > 0) - network->router_prefix_delegation = RADV_PREFIX_DELEGATION_BOTH; - else - network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE; - - if (d < 0) - log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Router prefix delegation '%s' is invalid, ignoring assignment: %m", rvalue); + d = radv_prefix_delegation_from_string(rvalue); + if (d < 0) { + log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Invalid router prefix delegation '%s', ignoring assignment.", rvalue); + return 0; } + network->router_prefix_delegation = d; + return 0; } @@ -97,6 +103,7 @@ void prefix_free(Prefix *prefix) { prefix->section); } + network_config_section_free(prefix->section); prefix->radv_prefix = sd_radv_prefix_unref(prefix->radv_prefix); free(prefix); diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 529d942f15..e8cde66bef 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -201,6 +201,16 @@ static const struct hash_ops route_hash_ops = { .compare = route_compare_func }; +bool route_equal(Route *r1, Route *r2) { + if (r1 == r2) + return true; + + if (!r1 || !r2) + return false; + + return route_compare_func(r1, r2) == 0; +} + int route_get(Link *link, int family, const union in_addr_union *dst, diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index 7283f48304..fe000d61b8 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -52,6 +52,7 @@ int route_get(Link *link, int family, const union in_addr_union *dst, unsigned c int route_add(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, uint32_t table, Route **ret); int route_add_foreign(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, uint32_t table, Route **ret); void route_update(Route *route, const union in_addr_union *src, unsigned char src_prefixlen, const union in_addr_union *gw, const union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol, unsigned char type); +bool route_equal(Route *r1, Route *r2); int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata); diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index 28a2a0fcbf..739f9e6a5a 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -79,10 +79,10 @@ static void routing_policy_rule_hash_func(const void *b, struct siphash *state) siphash24_compress(&rule->table, sizeof(rule->table), state); if (rule->iif) - siphash24_compress(&rule->iif, strlen(rule->iif), state); + siphash24_compress(rule->iif, strlen(rule->iif), state); if (rule->oif) - siphash24_compress(&rule->oif, strlen(rule->oif), state); + siphash24_compress(rule->oif, strlen(rule->oif), state); break; default: @@ -188,7 +188,7 @@ int routing_policy_rule_get(Manager *m, if (existing) { if (ret) *ret = existing; - return 1; + return 0; } return -ENOENT; @@ -257,8 +257,8 @@ static int routing_policy_rule_add_internal(Manager *m, rule->tos = tos; rule->fwmark = fwmark; rule->table = table; - rule->iif = TAKE_PTR(iif); - rule->oif = TAKE_PTR(oif); + rule->iif = iif; + rule->oif = oif; r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops); if (r < 0) @@ -272,6 +272,7 @@ static int routing_policy_rule_add_internal(Manager *m, *ret = rule; rule = NULL; + iif = oif = NULL; return 0; } @@ -549,7 +550,7 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, sd_netlin r = routing_policy_rule_add(link->manager, rule->family, &rule->from, rule->from_prefixlen, &rule->to, rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, rule->iif, rule->oif, NULL); if (r < 0) - return log_error_errno(r, "Could not add rule : %m"); + return log_error_errno(r, "Could not add rule: %m"); return 0; } diff --git a/src/network/test-network-tables.c b/src/network/test-network-tables.c index 521c5c2dc5..6b110b7110 100644 --- a/src/network/test-network-tables.c +++ b/src/network/test-network-tables.c @@ -1,6 +1,8 @@ #include "dhcp6-internal.h" #include "dhcp6-protocol.h" #include "ethtool-util.h" +#include "lldp-internal.h" +#include "ndisc-internal.h" #include "netdev/bond.h" #include "netdev/ipvlan.h" #include "netdev/macvlan.h" @@ -33,7 +35,10 @@ int main(int argc, char **argv) { test_table(lldp_mode, LLDP_MODE); test_table(netdev_kind, NETDEV_KIND); test_table(nl_union_link_info_data, NL_UNION_LINK_INFO_DATA); + test_table(radv_prefix_delegation, RADV_PREFIX_DELEGATION); test_table(wol, WOL); + test_table(lldp_event, SD_LLDP_EVENT); + test_table(ndisc_event, SD_NDISC_EVENT); test_table_sparse(ipvlan_mode, NETDEV_IPVLAN_MODE); test_table_sparse(macvlan_mode, NETDEV_MACVLAN_MODE); diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c index d05680d7e1..abef6e761a 100644 --- a/src/network/test-networkd-conf.c +++ b/src/network/test-networkd-conf.c @@ -168,6 +168,49 @@ static void test_config_parse_hwaddr(void) { test_config_parse_hwaddrs_one("123.4567.89ab aa:bb:cc:dd:ee:fx hogehoge 01-23-45-67-89-ab aaaa aa:Bb:CC:dd:ee:ff", t, 2); } +static void test_config_parse_address_one(const char *rvalue, int family, unsigned n_addresses, const union in_addr_union *u, unsigned char prefixlen) { + _cleanup_(network_freep) Network *network = NULL; + + assert_se(network = new0(Network, 1)); + assert_se(network->addresses_by_section = hashmap_new(NULL)); + assert_se(config_parse_address("network", "filename", 1, "section", 1, "Address", 0, rvalue, network, network) == 0); + assert_se(network->n_static_addresses == n_addresses); + if (n_addresses > 0) { + assert_se(network->static_addresses); + assert_se(network->static_addresses->prefixlen == prefixlen); + assert_se(network->static_addresses->family == family); + assert_se(in_addr_equal(family, &network->static_addresses->in_addr, u)); + /* TODO: check Address.in_addr and Address.broadcast */ + } +} + +static void test_config_parse_address(void) { + test_config_parse_address_one("", AF_INET, 0, NULL, 0); + test_config_parse_address_one("/", AF_INET, 0, NULL, 0); + test_config_parse_address_one("/8", AF_INET, 0, NULL, 0); + test_config_parse_address_one("1.2.3.4", AF_INET, 1, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 8); + test_config_parse_address_one("1.2.3.4/0", AF_INET, 1, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 0); + test_config_parse_address_one("1.2.3.4/1", AF_INET, 1, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 1); + test_config_parse_address_one("1.2.3.4/2", AF_INET, 1, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 2); + test_config_parse_address_one("1.2.3.4/32", AF_INET, 1, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32); + test_config_parse_address_one("1.2.3.4/33", AF_INET, 0, NULL, 0); + test_config_parse_address_one("1.2.3.4/-1", AF_INET, 0, NULL, 0); + + test_config_parse_address_one("", AF_INET6, 0, NULL, 0); + test_config_parse_address_one("/", AF_INET6, 0, NULL, 0); + test_config_parse_address_one("/8", AF_INET6, 0, NULL, 0); + test_config_parse_address_one("::1", AF_INET6, 1, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0); + test_config_parse_address_one("::1/0", AF_INET6, 1, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0); + test_config_parse_address_one("::1/1", AF_INET6, 1, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 1); + test_config_parse_address_one("::1/2", AF_INET6, 1, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 2); + test_config_parse_address_one("::1/32", AF_INET6, 1, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 32); + test_config_parse_address_one("::1/33", AF_INET6, 1, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 33); + test_config_parse_address_one("::1/64", AF_INET6, 1, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 64); + test_config_parse_address_one("::1/128", AF_INET6, 1, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128); + test_config_parse_address_one("::1/129", AF_INET6, 0, NULL, 0); + test_config_parse_address_one("::1/-1", AF_INET6, 0, NULL, 0); +} + int main(int argc, char **argv) { log_parse_environment(); log_open(); @@ -175,6 +218,7 @@ int main(int argc, char **argv) { test_config_parse_duid_type(); test_config_parse_duid_rawdata(); test_config_parse_hwaddr(); + test_config_parse_address(); return 0; } diff --git a/src/nspawn/nspawn-cgroup.c b/src/nspawn/nspawn-cgroup.c index 8732c9e2aa..0a54d27e6a 100644 --- a/src/nspawn/nspawn-cgroup.c +++ b/src/nspawn/nspawn-cgroup.c @@ -122,7 +122,7 @@ int sync_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift) { (void) mkdir_parents(fn, 0755); sprintf(pid_string, PID_FMT, pid); - r = write_string_file(fn, pid_string, 0); + r = write_string_file(fn, pid_string, WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) { log_error_errno(r, "Failed to move process: %m"); goto finish; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index fb6b603040..ab19d73c27 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2176,7 +2176,7 @@ static int reset_audit_loginuid(void) { if (streq(p, "4294967295")) return 0; - r = write_string_file("/proc/self/loginuid", "4294967295", 0); + r = write_string_file("/proc/self/loginuid", "4294967295", WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) { log_error_errno(r, "Failed to reset audit login UID. This probably means that your kernel is too\n" @@ -3148,7 +3148,7 @@ static int outer_child( if (arg_network_namespace_path) { r = namespace_enter(-1, -1, netns_fd, -1, -1); if (r < 0) - return r; + return log_error_errno(r, "Failed to join network namespace: %m"); } r = inner_child(barrier, directory, secondary, kmsg_socket, rtnl_socket, fds); @@ -3265,13 +3265,13 @@ static int setup_uid_map(pid_t pid) { xsprintf(uid_map, "/proc/" PID_FMT "/uid_map", pid); xsprintf(line, UID_FMT " " UID_FMT " " UID_FMT "\n", 0, arg_uid_shift, arg_uid_range); - r = write_string_file(uid_map, line, 0); + r = write_string_file(uid_map, line, WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) return log_error_errno(r, "Failed to write UID map: %m"); /* We always assign the same UID and GID ranges */ xsprintf(uid_map, "/proc/" PID_FMT "/gid_map", pid); - r = write_string_file(uid_map, line, 0); + r = write_string_file(uid_map, line, WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) return log_error_errno(r, "Failed to write GID map: %m"); @@ -3761,10 +3761,12 @@ static int run(int master, return log_error_errno(errno, "Cannot open file %s: %m", arg_network_namespace_path); r = fd_is_network_ns(netns_fd); - if (r < 0 && r != -ENOTTY) + if (r == -EUCLEAN) + log_debug_errno(r, "Cannot determine if passed network namespace path '%s' really refers to a network namespace, assuming it does.", arg_network_namespace_path); + else if (r < 0) return log_error_errno(r, "Failed to check %s fs type: %m", arg_network_namespace_path); - if (r == 0) { - log_error("Path %s doesn't refer to a network namespace", arg_network_namespace_path); + else if (r == 0) { + log_error("Path %s doesn't refer to a network namespace, refusing.", arg_network_namespace_path); return -EINVAL; } } diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index ae3dd33b7a..0cab1759b0 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -27,6 +27,7 @@ #include "fd-util.h" #include "fileio.h" #include "format-util.h" +#include "fs-util.h" #include "io-util.h" #include "log.h" #include "macro.h" @@ -133,6 +134,9 @@ static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **pa (unsigned long) DIV_ROUND_UP(KEYRING_TIMEOUT_USEC, USEC_PER_SEC), 0, 0) < 0) log_debug_errno(errno, "Failed to adjust timeout: %m"); + /* Tell everyone to check the keyring */ + (void) touch("/run/systemd/ask-password"); + log_debug("Added key to keyring as %" PRIi32 ".", serial); return 1; @@ -211,7 +215,7 @@ int ask_password_tty( usec_t until, AskPasswordFlags flags, const char *flag_file, - char **ret) { + char ***ret) { enum { POLL_TTY, @@ -223,6 +227,7 @@ int ask_password_tty( _cleanup_close_ int cttyfd = -1, notify = -1; struct termios old_termios, new_termios; char passphrase[LINE_MAX + 1] = {}, *x; + _cleanup_strv_free_erase_ char **l = NULL; struct pollfd pollfd[_POLL_MAX]; size_t p = 0, codepoint = 0; int r; @@ -235,14 +240,25 @@ int ask_password_tty( if (!message) message = "Password:"; - if (flag_file) { + if (flag_file || ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname)) { notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK); if (notify < 0) return -errno; - + } + if (flag_file) { if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) return -errno; } + if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) { + r = ask_password_keyring(keyname, flags, ret); + if (r >= 0) + return 0; + else if (r != -ENOKEY) + return r; + + if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_ATTRIB /* for mtime */) < 0) + return -errno; + } /* If the caller didn't specify a TTY, then use the controlling tty, if we can. */ if (ttyfd < 0) @@ -324,9 +340,17 @@ int ask_password_tty( goto finish; } - if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0) + if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0) { (void) flush_fd(notify); + r = ask_password_keyring(keyname, flags, ret); + if (r >= 0) { + r = 0; + goto finish; + } else if (r != -ENOKEY) + goto finish; + } + if (pollfd[POLL_TTY].revents == 0) continue; @@ -436,10 +460,14 @@ int ask_password_tty( goto finish; } + r = strv_consume(&l, x); + if (r < 0) + goto finish; + if (keyname) - (void) add_to_keyring_and_log(keyname, flags, STRV_MAKE(x)); + (void) add_to_keyring_and_log(keyname, flags, l); - *ret = x; + *ret = TAKE_PTR(l); r = 0; finish: @@ -495,14 +523,15 @@ int ask_password_agent( enum { FD_SOCKET, FD_SIGNAL, + FD_INOTIFY, _FD_MAX }; - _cleanup_close_ int socket_fd = -1, signal_fd = -1, fd = -1; + _cleanup_close_ int socket_fd = -1, signal_fd = -1, notify = -1, fd = -1; char temp[] = "/run/systemd/ask-password/tmp.XXXXXX"; char final[sizeof(temp)] = ""; _cleanup_free_ char *socket_name = NULL; - _cleanup_strv_free_ char **l = NULL; + _cleanup_strv_free_erase_ char **l = NULL; _cleanup_fclose_ FILE *f = NULL; struct pollfd pollfd[_FD_MAX]; sigset_t mask, oldmask; @@ -519,6 +548,25 @@ int ask_password_agent( (void) mkdir_p_label("/run/systemd/ask-password", 0755); + if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) { + r = ask_password_keyring(keyname, flags, ret); + if (r >= 0) { + r = 0; + goto finish; + } else if (r != -ENOKEY) + goto finish; + + notify = inotify_init1(IN_CLOEXEC | IN_NONBLOCK); + if (notify < 0) { + r = -errno; + goto finish; + } + if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_ATTRIB /* for mtime */) < 0) { + r = -errno; + goto finish; + } + } + fd = mkostemp_safe(temp); if (fd < 0) { r = fd; @@ -589,6 +637,8 @@ int ask_password_agent( pollfd[FD_SOCKET].events = POLLIN; pollfd[FD_SIGNAL].fd = signal_fd; pollfd[FD_SIGNAL].events = POLLIN; + pollfd[FD_INOTIFY].fd = notify; + pollfd[FD_INOTIFY].events = POLLIN; for (;;) { char passphrase[LINE_MAX+1]; @@ -610,7 +660,7 @@ int ask_password_agent( goto finish; } - k = poll(pollfd, _FD_MAX, until > 0 ? (int) ((until-t)/USEC_PER_MSEC) : -1); + k = poll(pollfd, notify >= 0 ? _FD_MAX : _FD_MAX - 1, until > 0 ? (int) ((until-t)/USEC_PER_MSEC) : -1); if (k < 0) { if (errno == EINTR) continue; @@ -629,6 +679,20 @@ int ask_password_agent( goto finish; } + if (notify >= 0 && pollfd[FD_INOTIFY].revents != 0) { + (void) flush_fd(notify); + + r = ask_password_keyring(keyname, flags, ret); + if (r >= 0) { + r = 0; + goto finish; + } else if (r != -ENOKEY) + goto finish; + } + + if (pollfd[FD_SOCKET].revents == 0) + continue; + if (pollfd[FD_SOCKET].revents != POLLIN) { r = -EIO; goto finish; @@ -736,29 +800,17 @@ int ask_password_auto( assert(ret); - if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) { + if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && + keyname && + ((flags & ASK_PASSWORD_NO_TTY) || !isatty(STDIN_FILENO)) && + (flags & ASK_PASSWORD_NO_AGENT)) { r = ask_password_keyring(keyname, flags, ret); if (r != -ENOKEY) return r; } - if (!(flags & ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO)) { - char *s = NULL, **l = NULL; - - r = ask_password_tty(-1, message, keyname, until, flags, NULL, &s); - if (r < 0) - return r; - - r = strv_push(&l, s); - if (r < 0) { - string_erase(s); - free(s); - return -ENOMEM; - } - - *ret = l; - return 0; - } + if (!(flags & ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO)) + return ask_password_tty(-1, message, keyname, until, flags, NULL, ret); if (!(flags & ASK_PASSWORD_NO_AGENT)) return ask_password_agent(message, icon, id, keyname, until, flags, ret); diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h index 93ca8bff52..2d84ba6b04 100644 --- a/src/shared/ask-password-api.h +++ b/src/shared/ask-password-api.h @@ -15,7 +15,7 @@ typedef enum AskPasswordFlags { ASK_PASSWORD_CONSOLE_COLOR = 1 << 6, /* Use color if /dev/console points to a console that supports color */ } 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_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/vlan-util.c b/src/shared/vlan-util.c index 400994a354..2f9df7dd1b 100644 --- a/src/shared/vlan-util.c +++ b/src/shared/vlan-util.c @@ -9,6 +9,9 @@ int parse_vlanid(const char *p, uint16_t *ret) { uint16_t id; int r; + assert(p); + assert(ret); + r = safe_atou16(p, &id); if (r < 0) return r; diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index a4eba59851..198d45c902 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -42,7 +42,7 @@ static int write_hibernate_location_info(void) { /* if it's a swap partition, we just write the disk to /sys/power/resume */ if (streq(type, "partition")) { - r = write_string_file("/sys/power/resume", device, 0); + r = write_string_file("/sys/power/resume", device, WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) return log_debug_errno(r, "Faileed to write partitoin device to /sys/power/resume: %m"); @@ -80,12 +80,12 @@ static int write_hibernate_location_info(void) { offset = fiemap->fm_extents[0].fe_physical / page_size(); xsprintf(offset_str, "%" PRIu64, offset); - r = write_string_file("/sys/power/resume_offset", offset_str, 0); + r = write_string_file("/sys/power/resume_offset", offset_str, WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) return log_debug_errno(r, "Failed to write offset '%s': %m", offset_str); xsprintf(device_str, "%lx", (unsigned long)stb.st_dev); - r = write_string_file("/sys/power/resume", device_str, 0); + r = write_string_file("/sys/power/resume", device_str, WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) return log_debug_errno(r, "Failed to write device '%s': %m", device_str); @@ -99,7 +99,7 @@ static int write_mode(char **modes) { STRV_FOREACH(mode, modes) { int k; - k = write_string_file("/sys/power/disk", *mode, 0); + k = write_string_file("/sys/power/disk", *mode, WRITE_STRING_FILE_DISABLE_BUFFER); if (k >= 0) return 0; @@ -118,7 +118,7 @@ static int write_state(FILE **f, char **states) { STRV_FOREACH(state, states) { int k; - k = write_string_stream(*f, *state, 0); + k = write_string_stream(*f, *state, WRITE_STRING_FILE_DISABLE_BUFFER); if (k >= 0) return 0; log_debug_errno(k, "Failed to write '%s' to /sys/power/state: %m", *state); @@ -155,6 +155,8 @@ static int execute(char **modes, char **states) { if (!f) return log_error_errno(errno, "Failed to open /sys/power/state: %m"); + setvbuf(f, NULL, _IONBF, 0); + /* Configure the hibernation mode */ if (!strv_isempty(modes)) { r = write_hibernate_location_info(); @@ -211,7 +213,7 @@ static int rtc_write_wake_alarm(uint64_t sec) { xsprintf(buf, "%" PRIu64, sec); - r = write_string_file("/sys/class/rtc/rtc0/wakealarm", buf, 0); + r = write_string_file("/sys/class/rtc/rtc0/wakealarm", buf, WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) return log_error_errno(r, "Failed to write '%s' to /sys/class/rtc/rtc0/wakealarm: %m", buf); diff --git a/src/systemd/meson.build b/src/systemd/meson.build index dde0aaf781..e0c967efc5 100644 --- a/src/systemd/meson.build +++ b/src/systemd/meson.build @@ -65,11 +65,11 @@ if cxx.found() endif endif -foreach header : _systemd_headers + _not_installed_headers +foreach header : _systemd_headers + _not_installed_headers + ['../libudev/libudev.h'] foreach opt : opts - name = ''.join([header, ':'] + opt) + name = ''.join(['cc-', header.split('/')[-1], ':'] + opt) if want_tests != 'false' - test('cc-' + name, + test(name, check_compilation_sh, args : cc.cmd_array() + ['-c', '-x'] + opt + ['-Werror', '-include', diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h index c38eb84beb..b15cade20a 100644 --- a/src/systemd/sd-event.h +++ b/src/systemd/sd-event.h @@ -143,6 +143,8 @@ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid); int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *ret); int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t callback); int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_destroy_t *ret); +int sd_event_source_get_floating(sd_event_source *s); +int sd_event_source_set_floating(sd_event_source *s, int b); /* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */ _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref); diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index d650794cc0..a3e5cd6be6 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -109,10 +109,12 @@ typedef struct sd_lldp sd_lldp; typedef struct sd_lldp_neighbor sd_lldp_neighbor; typedef enum sd_lldp_event { - SD_LLDP_EVENT_ADDED = 'a', - SD_LLDP_EVENT_REMOVED = 'r', - SD_LLDP_EVENT_UPDATED = 'u', - SD_LLDP_EVENT_REFRESHED = 'f', + SD_LLDP_EVENT_ADDED, + SD_LLDP_EVENT_REMOVED, + SD_LLDP_EVENT_UPDATED, + SD_LLDP_EVENT_REFRESHED, + _SD_LLDP_EVENT_MAX, + _SD_LLDP_EVENT_INVALID = -1, } sd_lldp_event; typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata); diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h index 6b6249ca03..d1bee343a2 100644 --- a/src/systemd/sd-ndisc.h +++ b/src/systemd/sd-ndisc.h @@ -55,8 +55,10 @@ typedef struct sd_ndisc sd_ndisc; typedef struct sd_ndisc_router sd_ndisc_router; typedef enum sd_ndisc_event { - SD_NDISC_EVENT_TIMEOUT = 't', - SD_NDISC_EVENT_ROUTER = 'r', + SD_NDISC_EVENT_TIMEOUT, + SD_NDISC_EVENT_ROUTER, + _SD_NDISC_EVENT_MAX, + _SD_NDISC_EVENT_INVALID = -1, } sd_ndisc_event; typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata); diff --git a/src/systemd/sd-resolve.h b/src/systemd/sd-resolve.h index 5695119b40..089fcdee37 100644 --- a/src/systemd/sd-resolve.h +++ b/src/systemd/sd-resolve.h @@ -42,6 +42,7 @@ typedef struct sd_resolve_query sd_resolve_query; /* A callback on completion */ typedef int (*sd_resolve_getaddrinfo_handler_t)(sd_resolve_query *q, int ret, const struct addrinfo *ai, void *userdata); typedef int (*sd_resolve_getnameinfo_handler_t)(sd_resolve_query *q, int ret, const char *host, const char *serv, void *userdata); +typedef void (*sd_resolve_destroy_t)(void *userdata); enum { SD_RESOLVE_GET_HOST = 1 << 0, @@ -108,6 +109,10 @@ int sd_resolve_query_is_done(sd_resolve_query*q); void *sd_resolve_query_get_userdata(sd_resolve_query *q); void *sd_resolve_query_set_userdata(sd_resolve_query *q, void *userdata); +int sd_resolve_query_get_destroy_callback(sd_resolve_query *q, sd_resolve_destroy_t *destroy_callback); +int sd_resolve_query_set_destroy_callback(sd_resolve_query *q, sd_resolve_destroy_t destroy_callback); +int sd_resolve_query_get_floating(sd_resolve_query *q); +int sd_resolve_query_set_floating(sd_resolve_query *q, int b); sd_resolve *sd_resolve_query_get_resolve(sd_resolve_query *q); diff --git a/src/test/test-ask-password-api.c b/src/test/test-ask-password-api.c index ffd6da80fe..23b06be19b 100644 --- a/src/test/test-ask-password-api.c +++ b/src/test/test-ask-password-api.c @@ -3,15 +3,17 @@ #include "alloc-util.h" #include "ask-password-api.h" #include "log.h" +#include "strv.h" static void ask_password(void) { int r; - _cleanup_free_ char *ret; + _cleanup_strv_free_ char **ret = NULL; r = ask_password_tty(-1, "hello?", "da key", 0, 0, NULL, &ret); assert(r >= 0); + assert(strv_length(ret) == 1); - log_info("Got %s", ret); + log_info("Got %s", *ret); } int main(int argc, char **argv) { diff --git a/src/test/test-in-addr-util.c b/src/test/test-in-addr-util.c index 5b6e87bf5a..75c3e305c3 100644 --- a/src/test/test-in-addr-util.c +++ b/src/test/test-in-addr-util.c @@ -4,12 +4,12 @@ #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) { +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) { union in_addr_union q; unsigned char l; int r; - r = in_addr_prefix_from_string(p, family, &q, &l); + r = in_addr_prefix_from_string_internal(p, use_default, family, &q, &l); assert_se(r == ret); if (r >= 0) { @@ -18,7 +18,7 @@ static void test_in_addr_prefix_from_string(const char *p, int family, int ret, assert_se(in_addr_equal(family, &q, u)); assert_se(l == prefixlen); - r = in_addr_prefix_from_string_auto(p, &f, &q, &l); + r = in_addr_prefix_from_string_auto_internal(p, use_default, &f, &q, &l); assert_se(r >= 0); assert_se(f == family); @@ -28,31 +28,57 @@ static void test_in_addr_prefix_from_string(const char *p, int family, int ret, } int main(int argc, char *argv[]) { - test_in_addr_prefix_from_string("", AF_INET, -EINVAL, NULL, 0); - test_in_addr_prefix_from_string("/", AF_INET, -EINVAL, NULL, 0); - test_in_addr_prefix_from_string("/8", AF_INET, -EINVAL, NULL, 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); - 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); - 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); - 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); - 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); - test_in_addr_prefix_from_string("1.2.3.4/33", AF_INET, -ERANGE, NULL, 0); - test_in_addr_prefix_from_string("1.2.3.4/-1", AF_INET, -ERANGE, NULL, 0); - test_in_addr_prefix_from_string("::1", AF_INET, -EINVAL, NULL, 0); - - test_in_addr_prefix_from_string("", AF_INET6, -EINVAL, NULL, 0); - test_in_addr_prefix_from_string("/", AF_INET6, -EINVAL, NULL, 0); - test_in_addr_prefix_from_string("/8", AF_INET6, -EINVAL, NULL, 0); - test_in_addr_prefix_from_string("::1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128); - test_in_addr_prefix_from_string("::1/0", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0); - test_in_addr_prefix_from_string("::1/1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 1); - test_in_addr_prefix_from_string("::1/2", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 2); - test_in_addr_prefix_from_string("::1/32", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 32); - test_in_addr_prefix_from_string("::1/33", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 33); - test_in_addr_prefix_from_string("::1/64", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 64); - test_in_addr_prefix_from_string("::1/128", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128); - test_in_addr_prefix_from_string("::1/129", AF_INET6, -ERANGE, NULL, 0); - test_in_addr_prefix_from_string("::1/-1", AF_INET6, -ERANGE, NULL, 0); + 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); return 0; } diff --git a/src/test/test-stat-util.c b/src/test/test-stat-util.c index 43f56a6c20..2b0564d8a0 100644 --- a/src/test/test-stat-util.c +++ b/src/test/test-stat-util.c @@ -67,11 +67,26 @@ static void test_path_is_temporary_fs(void) { assert_se(path_is_temporary_fs("/i-dont-exist") == -ENOENT); } +static void test_fd_is_network_ns(void) { + _cleanup_close_ int fd = -1; + assert_se(fd_is_network_ns(STDIN_FILENO) == 0); + assert_se(fd_is_network_ns(STDERR_FILENO) == 0); + assert_se(fd_is_network_ns(STDOUT_FILENO) == 0); + + assert_se((fd = open("/proc/self/ns/mnt", O_CLOEXEC|O_RDONLY)) >= 0); + assert_se(IN_SET(fd_is_network_ns(fd), 0, -EUCLEAN)); + fd = safe_close(fd); + + assert_se((fd = open("/proc/self/ns/net", O_CLOEXEC|O_RDONLY)) >= 0); + assert_se(IN_SET(fd_is_network_ns(fd), 1, -EUCLEAN)); +} + int main(int argc, char *argv[]) { test_files_same(); test_is_symlink(); test_path_is_fs_type(); test_path_is_temporary_fs(); + test_fd_is_network_ns(); return 0; } diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c index 00051eb434..2ec2ade3f1 100644 --- a/src/test/test-time-util.c +++ b/src/test/test-time-util.c @@ -39,6 +39,14 @@ static void test_parse_sec(void) { assert_se(u == USEC_INFINITY); assert_se(parse_sec("+3.1s", &u) >= 0); assert_se(u == 3100 * USEC_PER_MSEC); + assert_se(parse_sec("3.1s.2", &u) >= 0); + assert_se(u == 3300 * USEC_PER_MSEC); + assert_se(parse_sec("3.1 .2", &u) >= 0); + assert_se(u == 3300 * USEC_PER_MSEC); + assert_se(parse_sec("3.1 sec .2 sec", &u) >= 0); + assert_se(u == 3300 * USEC_PER_MSEC); + assert_se(parse_sec("3.1 sec 1.2 sec", &u) >= 0); + assert_se(u == 4300 * USEC_PER_MSEC); assert_se(parse_sec(" xyz ", &u) < 0); assert_se(parse_sec("", &u) < 0); @@ -56,6 +64,10 @@ static void test_parse_sec(void) { assert_se(parse_sec("3.+1s", &u) < 0); assert_se(parse_sec("3. 1s", &u) < 0); assert_se(parse_sec("3.s", &u) < 0); + assert_se(parse_sec("12.34.56", &u) < 0); + assert_se(parse_sec("12..34", &u) < 0); + assert_se(parse_sec("..1234", &u) < 0); + assert_se(parse_sec("1234..", &u) < 0); } static void test_parse_sec_fix_0(void) { @@ -97,7 +109,7 @@ static void test_parse_time(void) { assert_se(u == 5 * USEC_PER_SEC); assert_se(parse_time("11111111111111y", &u, 1) == -ERANGE); - assert_se(parse_time("1.1111111111111y", &u, 1) == -ERANGE); + assert_se(parse_time("1.1111111111111y", &u, 1) >= 0); } static void test_parse_nsec(void) { @@ -129,6 +141,14 @@ static void test_parse_nsec(void) { assert_se(u == NSEC_INFINITY); assert_se(parse_nsec("+3.1s", &u) >= 0); assert_se(u == 3100 * NSEC_PER_MSEC); + assert_se(parse_nsec("3.1s.2", &u) >= 0); + assert_se(u == 3100 * NSEC_PER_MSEC); + assert_se(parse_nsec("3.1 .2s", &u) >= 0); + assert_se(u == 200 * NSEC_PER_MSEC + 3); + assert_se(parse_nsec("3.1 sec .2 sec", &u) >= 0); + assert_se(u == 3300 * NSEC_PER_MSEC); + assert_se(parse_nsec("3.1 sec 1.2 sec", &u) >= 0); + assert_se(u == 4300 * NSEC_PER_MSEC); assert_se(parse_nsec(" xyz ", &u) < 0); assert_se(parse_nsec("", &u) < 0); @@ -148,8 +168,12 @@ static void test_parse_nsec(void) { assert_se(parse_nsec("3.+1s", &u) < 0); assert_se(parse_nsec("3. 1s", &u) < 0); assert_se(parse_nsec("3.s", &u) < 0); + assert_se(parse_nsec("12.34.56", &u) < 0); + assert_se(parse_nsec("12..34", &u) < 0); + assert_se(parse_nsec("..1234", &u) < 0); + assert_se(parse_nsec("1234..", &u) < 0); assert_se(parse_nsec("1111111111111y", &u) == -ERANGE); - assert_se(parse_nsec("1.111111111111y", &u) == -ERANGE); + assert_se(parse_nsec("1.111111111111y", &u) >= 0); } static void test_format_timespan_one(usec_t x, usec_t accuracy) { diff --git a/src/test/test-udev.c b/src/test/test-udev.c index 1285117c32..e972b56b2c 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 "device-private.h" #include "fs-util.h" #include "log.h" #include "missing.h" @@ -52,10 +53,11 @@ static int fake_filesystems(void) { } int main(int argc, char *argv[]) { - _cleanup_(udev_event_freep) struct udev_event *event = NULL; - _cleanup_(udev_device_unrefp) struct udev_device *dev = NULL; _cleanup_(udev_rules_unrefp) struct udev_rules *rules = NULL; - const char *devpath, *action; + _cleanup_(udev_event_freep) struct udev_event *event = NULL; + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; + const char *devpath, *devname, *action; + int r; test_setup_logging(LOG_INFO); @@ -76,31 +78,35 @@ int main(int argc, char *argv[]) { rules = udev_rules_new(1); const char *syspath = strjoina("/sys", devpath); - dev = udev_device_new_from_synthetic_event(NULL, syspath, action); - if (!dev) { - log_debug("unknown device '%s'", devpath); + r = device_new_from_synthetic_event(&dev, syspath, action); + if (r < 0) { + log_debug_errno(r, "Failed to open device '%s'", devpath); goto out; } - assert_se(event = udev_event_new(dev)); + assert_se(event = udev_event_new(dev, 0, NULL)); assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) >= 0); /* do what devtmpfs usually provides us */ - if (udev_device_get_devnode(dev)) { + if (sd_device_get_devname(dev, &devname) >= 0) { + const char *subsystem; mode_t mode = 0600; - if (streq(udev_device_get_subsystem(dev), "block")) + if (sd_device_get_subsystem(dev, &subsystem) >= 0 && streq(subsystem, "block")) mode |= S_IFBLK; else mode |= S_IFCHR; if (!streq(action, "remove")) { - (void) mkdir_parents_label(udev_device_get_devnode(dev), 0755); - assert_se(mknod(udev_device_get_devnode(dev), mode, udev_device_get_devnum(dev)) == 0); + dev_t devnum = makedev(0, 0); + + (void) mkdir_parents_label(devname, 0755); + (void) sd_device_get_devnum(dev, &devnum); + assert_se(mknod(devname, mode, devnum) == 0); } else { - assert_se(unlink(udev_device_get_devnode(dev)) == 0); - (void) rmdir_parents(udev_device_get_devnode(dev), "/"); + assert_se(unlink(devname) == 0); + (void) rmdir_parents(devname, "/"); } } diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c index 088abecb7d..ba2e1d37f0 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -350,7 +350,6 @@ static int parse_password(const char *filename, char **wall) { if (arg_plymouth) r = ask_password_plymouth(message, not_after, accept_cached ? ASK_PASSWORD_ACCEPT_CACHED : 0, filename, &passwords); else { - char *password = NULL; int tty_fd = -1; if (arg_console) { @@ -368,18 +367,12 @@ static int parse_password(const char *filename, char **wall) { r = ask_password_tty(tty_fd, message, NULL, not_after, (echo ? ASK_PASSWORD_ECHO : 0) | (arg_console ? ASK_PASSWORD_CONSOLE_COLOR : 0), - filename, &password); + filename, &passwords); if (arg_console) { tty_fd = safe_close(tty_fd); release_terminal(); } - - if (r >= 0) - r = strv_push(&passwords, password); - - if (r < 0) - string_free_erase(password); } /* If the query went away, that's OK */ diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index a0f6a5daa4..c1d0b3662b 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -16,7 +16,7 @@ #include "device-util.h" #include "fd-util.h" #include "format-util.h" -#include "libudev-device-internal.h" +#include "libudev-private.h" #include "netlink-util.h" #include "path-util.h" #include "process-util.h" @@ -42,7 +42,7 @@ typedef struct Spawn { size_t result_len; } Spawn; -struct udev_event *udev_event_new(struct udev_device *dev) { +struct udev_event *udev_event_new(sd_device *dev, int exec_delay, sd_netlink *rtnl) { struct udev_event *event; assert(dev); @@ -52,8 +52,10 @@ struct udev_event *udev_event_new(struct udev_device *dev) { return NULL; *event = (struct udev_event) { - .dev = dev, + .dev = sd_device_ref(dev), .birth_usec = now(CLOCK_MONOTONIC), + .exec_delay = exec_delay, + .rtnl = sd_netlink_ref(rtnl), }; return event; @@ -65,6 +67,8 @@ struct udev_event *udev_event_free(struct udev_event *event) { if (!event) return NULL; + sd_device_unref(event->dev); + sd_device_unref(event->dev_db_clone); sd_netlink_unref(event->rtnl); while ((p = hashmap_steal_first_key(event->run_list))) free(p); @@ -125,7 +129,7 @@ static const struct subst_map_entry map[] = { static ssize_t subst_format_var(struct udev_event *event, const struct subst_map_entry *entry, char *attr, char *dest, size_t l) { - sd_device *parent, *dev = event->dev->device; + sd_device *parent, *dev = event->dev; const char *val = NULL; char *s = dest; dev_t devnum; @@ -155,7 +159,7 @@ static ssize_t subst_format_var(struct udev_event *event, case SUBST_ID: if (!event->dev_parent) return 0; - r = sd_device_get_sysname(event->dev_parent->device, &val); + r = sd_device_get_sysname(event->dev_parent, &val); if (r < 0) return r; l = strpcpy(&s, l, val); @@ -163,7 +167,7 @@ static ssize_t subst_format_var(struct udev_event *event, case SUBST_DRIVER: if (!event->dev_parent) return 0; - r = sd_device_get_driver(event->dev_parent->device, &val); + r = sd_device_get_driver(event->dev_parent, &val); if (r < 0) return r == -ENOENT ? 0 : r; l = strpcpy(&s, l, val); @@ -236,8 +240,8 @@ static ssize_t subst_format_var(struct udev_event *event, (void) sd_device_get_sysattr_value(dev, attr, &val); /* try to read the attribute of the parent device, other matches have selected */ - if (!val && event->dev_parent && event->dev_parent->device != dev) - (void) sd_device_get_sysattr_value(event->dev_parent->device, attr, &val); + if (!val && event->dev_parent && event->dev_parent != dev) + (void) sd_device_get_sysattr_value(event->dev_parent, attr, &val); if (!val) return 0; @@ -402,9 +406,9 @@ subst: subst_len = subst_format_var(event, entry, attr, s, l); if (subst_len < 0) { if (format_dollar) - log_device_warning_errno(event->dev->device, subst_len, "Failed to substitute variable '$%s', ignoring: %m", entry->name); + log_device_warning_errno(event->dev, subst_len, "Failed to substitute variable '$%s', ignoring: %m", entry->name); else - log_device_warning_errno(event->dev->device, subst_len, "Failed to apply format '%%%c', ignoring: %m", entry->fmt); + log_device_warning_errno(event->dev, subst_len, "Failed to apply format '%%%c', ignoring: %m", entry->fmt); continue; } @@ -636,9 +640,9 @@ int udev_event_spawn(struct udev_event *event, free_and_replace(argv[0], program); } - r = device_get_properties_strv(event->dev->device, &envp); + r = device_get_properties_strv(event->dev, &envp); if (r < 0) - return log_device_error_errno(event->dev->device, r, "Failed to get device properties"); + return log_device_error_errno(event->dev, r, "Failed to get device properties"); log_debug("Starting '%s'", cmd); @@ -682,7 +686,7 @@ int udev_event_spawn(struct udev_event *event, } static int rename_netif(struct udev_event *event) { - sd_device *dev = event->dev->device; + sd_device *dev = event->dev; const char *action, *oldname; char name[IFNAMSIZ]; int ifindex, r; @@ -725,7 +729,7 @@ static int rename_netif(struct udev_event *event) { } static int update_devnode(struct udev_event *event) { - sd_device *dev = event->dev->device; + sd_device *dev = event->dev; const char *action; bool apply; int r; @@ -737,8 +741,8 @@ static int update_devnode(struct udev_event *event) { return log_device_error_errno(dev, r, "Failed to get devnum: %m"); /* remove/update possible left-over symlinks from old database entry */ - if (event->dev_db) - (void) udev_node_update_old_links(dev, event->dev_db->device); + if (event->dev_db_clone) + (void) udev_node_update_old_links(dev, event->dev_db_clone); if (!event->owner_set) { r = device_get_devnode_uid(dev, &event->uid); @@ -780,7 +784,7 @@ static void event_execute_rules_on_remove( Hashmap *properties_list, struct udev_rules *rules) { - sd_device *dev = event->dev->device; + sd_device *dev = event->dev; int r; r = device_read_db_force(dev); @@ -810,8 +814,7 @@ int udev_event_execute_rules(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec, Hashmap *properties_list, struct udev_rules *rules) { - _cleanup_(sd_device_unrefp) sd_device *clone = NULL; - sd_device *dev = event->dev->device; + sd_device *dev = event->dev; const char *subsystem, *action; int r; @@ -831,28 +834,24 @@ int udev_event_execute_rules(struct udev_event *event, return 0; } - r = device_clone_with_db(dev, &clone); + r = device_clone_with_db(dev, &event->dev_db_clone); if (r < 0) log_device_debug_errno(dev, r, "Failed to clone sd_device object, ignoring: %m"); - if (clone) { - event->dev_db = udev_device_new(NULL, clone); - if (!event->dev_db) - return -ENOMEM; - + if (event->dev_db_clone) { r = sd_device_get_devnum(dev, NULL); if (r < 0) { if (r != -ENOENT) log_device_debug_errno(dev, r, "Failed to get devnum, ignoring: %m"); if (streq(action, "move")) { - r = device_copy_properties(dev, clone); + r = device_copy_properties(dev, event->dev_db_clone); if (r < 0) log_device_debug_errno(dev, r, "Failed to copy properties from cloned device, ignoring: %m"); } } else /* Disable watch during event processing. */ - (void) udev_watch_end(clone); + (void) udev_watch_end(event->dev_db_clone); } (void) udev_rules_apply_to_event(rules, event, @@ -863,12 +862,12 @@ int udev_event_execute_rules(struct udev_event *event, (void) update_devnode(event); /* preserve old, or get new initialization timestamp */ - r = device_ensure_usec_initialized(dev, clone); + r = device_ensure_usec_initialized(dev, event->dev_db_clone); if (r < 0) log_device_debug_errno(dev, r, "Failed to set initialization timestamp, ignoring: %m"); /* (re)write database file */ - r = device_tag_index(dev, clone, true); + r = device_tag_index(dev, event->dev_db_clone, true); if (r < 0) log_device_debug_errno(dev, r, "Failed to update tags under /run/udev/tag/, ignoring: %m"); @@ -878,7 +877,7 @@ int udev_event_execute_rules(struct udev_event *event, device_set_is_initialized(dev); - event->dev_db = udev_device_unref(event->dev_db); + event->dev_db_clone = sd_device_unref(event->dev_db_clone); return 0; } @@ -895,7 +894,7 @@ void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_ udev_event_apply_format(event, cmd, command, sizeof(command), false); if (builtin_cmd >= 0 && builtin_cmd < _UDEV_BUILTIN_MAX) - udev_builtin_run(event->dev->device, builtin_cmd, command, false); + udev_builtin_run(event->dev, builtin_cmd, command, false); else { if (event->exec_delay > 0) { log_debug("delay execution of '%s'", command); diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index 46445eda6a..94bebd69c7 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -73,6 +73,8 @@ static int node_symlink(sd_device *dev, const char *node, const char *slink) { } while (r == -ENOENT); if (r == 0) return 0; + if (r < 0) + log_device_debug_errno(dev, r, "Failed to create symlink '%s' to '%s', trying to replace '%s': %m", slink, target, slink); } log_device_debug(dev, "Atomically replace '%s'", slink); @@ -211,10 +213,8 @@ static int link_update(sd_device *dev, const char *slink, bool add) { log_device_debug(dev, "No reference left, removing '%s'", slink); if (unlink(slink) == 0) (void) rmdir_parents(slink, "/"); - } else { - log_device_debug(dev, "Creating link '%s' to '%s'", slink, target); + } else (void) node_symlink(dev, target, slink); - } if (add) do { diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 7703e867f8..ad4b32abea 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -16,13 +16,15 @@ #include "alloc-util.h" #include "conf-files.h" #include "def.h" +#include "device-private.h" +#include "device-util.h" #include "dirent-util.h" #include "escape.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" #include "glob-util.h" -#include "libudev-device-internal.h" +#include "libudev-private.h" #include "path-util.h" #include "proc-cmdline.h" #include "stat-util.h" @@ -556,7 +558,7 @@ static gid_t add_gid(struct udev_rules *rules, const char *group) { return gid; } -static int import_property_from_string(struct udev_device *dev, char *line) { +static int import_property_from_string(sd_device *dev, char *line) { char *key; char *val; size_t len; @@ -568,12 +570,12 @@ static int import_property_from_string(struct udev_device *dev, char *line) { /* comment or empty line */ if (IN_SET(key[0], '#', '\0')) - return -1; + return 0; /* split key/value */ val = strchr(key, '='); - if (val == NULL) - return -1; + if (!val) + return -EINVAL; val[0] = '\0'; val++; @@ -584,7 +586,7 @@ static int import_property_from_string(struct udev_device *dev, char *line) { /* terminate key */ len = strlen(key); if (len == 0) - return -1; + return -EINVAL; while (isspace(key[len-1])) len--; key[len] = '\0'; @@ -592,30 +594,28 @@ static int import_property_from_string(struct udev_device *dev, char *line) { /* terminate value */ len = strlen(val); if (len == 0) - return -1; + return -EINVAL; while (isspace(val[len-1])) len--; val[len] = '\0'; if (len == 0) - return -1; + return -EINVAL; /* unquote */ if (IN_SET(val[0], '"', '\'')) { if (len == 1 || val[len-1] != val[0]) { log_debug("inconsistent quoting: '%s', skip", line); - return -1; + return -EINVAL; } val[len-1] = '\0'; val++; } - udev_device_add_property(dev, key, val); - - return 0; + return device_add_property(dev, key, val); } -static int import_file_into_properties(struct udev_device *dev, const char *filename) { +static int import_file_into_properties(sd_device *dev, const char *filename) { _cleanup_fclose_ FILE *f = NULL; int r; @@ -665,24 +665,21 @@ static int import_program_into_properties(struct udev_event *event, return 0; } -static int import_parent_into_properties(struct udev_device *dev, const char *filter) { - struct udev_device *dev_parent; - struct udev_list_entry *list_entry; +static int import_parent_into_properties(sd_device *dev, const char *filter) { + const char *key, *val; + sd_device *parent; + int r; assert(dev); assert(filter); - dev_parent = udev_device_get_parent(dev); - if (dev_parent == NULL) - return -1; - - udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(dev_parent)) { - const char *key = udev_list_entry_get_name(list_entry); - const char *val = udev_list_entry_get_value(list_entry); + r = sd_device_get_parent(dev, &parent); + if (r < 0) + return r; + FOREACH_DEVICE_PROPERTY(parent, key, val) if (fnmatch(filter, key, 0) == 0) - udev_device_add_property(dev, key, val); - } + device_add_property(dev, key, val); return 0; } @@ -1517,16 +1514,17 @@ static int parse_file(struct udev_rules *rules, const char *filename) { struct udev_rules *udev_rules_new(int resolve_names) { struct udev_rules *rules; - struct udev_list file_list; struct token end_token; char **files, **f; int r; - rules = new0(struct udev_rules, 1); - if (rules == NULL) + rules = new(struct udev_rules, 1); + if (!rules) return NULL; - rules->resolve_names = resolve_names; - udev_list_init(NULL, &file_list, true); + + *rules = (struct udev_rules) { + .resolve_names = resolve_names, + }; /* init token array and string buffer */ rules->tokens = malloc_multiply(PREALLOC_TOKEN, sizeof(struct token)); @@ -1672,11 +1670,9 @@ static int match_key(struct udev_rules *rules, struct token *token, const char * return -1; } -static int match_attr(struct udev_rules *rules, struct udev_device *dev, struct udev_event *event, struct token *cur) { - const char *name; - char nbuf[UTIL_NAME_SIZE]; - const char *value; - char vbuf[UTIL_NAME_SIZE]; +static int match_attr(struct udev_rules *rules, sd_device *dev, struct udev_event *event, struct token *cur) { + char nbuf[UTIL_NAME_SIZE], vbuf[UTIL_NAME_SIZE]; + const char *name, *value; size_t len; name = rules_str(rules, cur->key.attr_off); @@ -1686,8 +1682,7 @@ static int match_attr(struct udev_rules *rules, struct udev_device *dev, struct name = nbuf; _fallthrough_; case SB_NONE: - value = udev_device_get_sysattr_value(dev, name); - if (value == NULL) + if (sd_device_get_sysattr_value(dev, name, &value) < 0) return -1; break; case SB_SUBSYS: @@ -1732,18 +1727,23 @@ int udev_rules_apply_to_event( usec_t timeout_usec, usec_t timeout_warn_usec, Hashmap *properties_list) { - struct token *cur; - struct token *rule; + sd_device *dev = event->dev; enum escape_type esc = ESCAPE_UNSET; + struct token *cur, *rule; + const char *action, *val; bool can_set_name; int r; if (!rules->tokens) return 0; - can_set_name = ((!streq(udev_device_get_action(event->dev), "remove")) && - (major(udev_device_get_devnum(event->dev)) > 0 || - udev_device_get_ifindex(event->dev) > 0)); + r = sd_device_get_property_value(dev, "ACTION", &action); + if (r < 0) + return r; + + can_set_name = (!streq(action, "remove") && + (sd_device_get_devnum(dev, NULL) >= 0 || + sd_device_get_ifindex(dev, NULL) >= 0)); /* loop through token list, match, run actions or forward to next rule */ cur = &rules->tokens[0]; @@ -1760,30 +1760,31 @@ int udev_rules_apply_to_event( esc = ESCAPE_UNSET; break; case TK_M_ACTION: - if (match_key(rules, cur, udev_device_get_action(event->dev)) != 0) + if (match_key(rules, cur, action) != 0) goto nomatch; break; case TK_M_DEVPATH: - if (match_key(rules, cur, udev_device_get_devpath(event->dev)) != 0) + if (sd_device_get_devpath(dev, &val) < 0) + goto nomatch; + if (match_key(rules, cur, val) != 0) goto nomatch; break; case TK_M_KERNEL: - if (match_key(rules, cur, udev_device_get_sysname(event->dev)) != 0) + if (sd_device_get_sysname(dev, &val) < 0) + goto nomatch; + if (match_key(rules, cur, val) != 0) goto nomatch; break; case TK_M_DEVLINK: { - struct udev_list_entry *list_entry; + const char *devlink; bool match = false; - udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(event->dev)) { - const char *devlink; - - devlink = udev_list_entry_get_name(list_entry) + STRLEN("/dev/"); - if (match_key(rules, cur, devlink) == 0) { + FOREACH_DEVICE_DEVLINK(dev, devlink) + if (match_key(rules, cur, devlink + STRLEN("/dev/")) == 0) { match = true; break; } - } + if (!match) goto nomatch; break; @@ -1794,43 +1795,48 @@ int udev_rules_apply_to_event( break; case TK_M_ENV: { const char *key_name = rules_str(rules, cur->key.attr_off); - const char *value; - - value = udev_device_get_property_value(event->dev, key_name); - /* check global properties */ - if (!value && properties_list) - value = hashmap_get(properties_list, key_name); + if (sd_device_get_property_value(dev, key_name, &val) < 0) { + /* check global properties */ + if (properties_list) + val = hashmap_get(properties_list, key_name); + else + val = NULL; + } - if (match_key(rules, cur, strempty(value))) + if (match_key(rules, cur, strempty(val))) goto nomatch; break; } case TK_M_TAG: { - struct udev_list_entry *list_entry; bool match = false; + const char *tag; - udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(event->dev)) { - if (streq(rules_str(rules, cur->key.value_off), udev_list_entry_get_name(list_entry))) { + FOREACH_DEVICE_TAG(dev, tag) + if (streq(rules_str(rules, cur->key.value_off), tag)) { match = true; break; } - } + if ((!match && (cur->key.op != OP_NOMATCH)) || (match && (cur->key.op == OP_NOMATCH))) goto nomatch; break; } case TK_M_SUBSYSTEM: - if (match_key(rules, cur, udev_device_get_subsystem(event->dev)) != 0) + if (sd_device_get_subsystem(dev, &val) < 0) + goto nomatch; + if (match_key(rules, cur, val) != 0) goto nomatch; break; case TK_M_DRIVER: - if (match_key(rules, cur, udev_device_get_driver(event->dev)) != 0) + if (sd_device_get_driver(dev, &val) < 0) + goto nomatch; + if (match_key(rules, cur, val) != 0) goto nomatch; break; case TK_M_ATTR: - if (match_attr(rules, event->dev, event, cur) != 0) + if (match_attr(rules, dev, event, cur) != 0) goto nomatch; break; case TK_M_SYSCTL: { @@ -1863,7 +1869,7 @@ int udev_rules_apply_to_event( next++; /* loop over parents */ - event->dev_parent = event->dev; + event->dev_parent = dev; for (;;) { struct token *key; @@ -1872,15 +1878,21 @@ int udev_rules_apply_to_event( dump_token(rules, key); switch(key->type) { case TK_M_KERNELS: - if (match_key(rules, key, udev_device_get_sysname(event->dev_parent)) != 0) + if (sd_device_get_sysname(event->dev_parent, &val) < 0) + goto try_parent; + if (match_key(rules, key, val) != 0) goto try_parent; break; case TK_M_SUBSYSTEMS: - if (match_key(rules, key, udev_device_get_subsystem(event->dev_parent)) != 0) + if (sd_device_get_subsystem(event->dev_parent, &val) < 0) + goto try_parent; + if (match_key(rules, key, val) != 0) goto try_parent; break; case TK_M_DRIVERS: - if (match_key(rules, key, udev_device_get_driver(event->dev_parent)) != 0) + if (sd_device_get_driver(event->dev_parent, &val) < 0) + goto try_parent; + if (match_key(rules, key, val) != 0) goto try_parent; break; case TK_M_ATTRS: @@ -1888,7 +1900,7 @@ int udev_rules_apply_to_event( goto try_parent; break; case TK_M_TAGS: { - bool match = udev_device_has_tag(event->dev_parent, rules_str(rules, cur->key.value_off)); + bool match = sd_device_has_tag(event->dev_parent, rules_str(rules, cur->key.value_off)); if (match && key->key.op == OP_NOMATCH) goto try_parent; @@ -1903,9 +1915,10 @@ int udev_rules_apply_to_event( break; try_parent: - event->dev_parent = udev_device_get_parent(event->dev_parent); - if (event->dev_parent == NULL) + if (sd_device_get_parent(event->dev_parent, &event->dev_parent) < 0) { + event->dev_parent = NULL; goto nomatch; + } } /* move behind our sequence of parent match keys */ cur = next; @@ -1921,9 +1934,11 @@ int udev_rules_apply_to_event( if (filename[0] != '/') { char tmp[UTIL_PATH_SIZE]; + if (sd_device_get_syspath(dev, &val) < 0) + goto nomatch; + strscpy(tmp, sizeof(tmp), filename); - strscpyl(filename, sizeof(filename), - udev_device_get_syspath(event->dev), "/", tmp, NULL); + strscpyl(filename, sizeof(filename), val, "/", tmp, NULL); } } attr_subst_subdir(filename, sizeof(filename)); @@ -1938,8 +1953,7 @@ int udev_rules_apply_to_event( break; } case TK_M_PROGRAM: { - char program[UTIL_PATH_SIZE]; - char result[UTIL_LINE_SIZE]; + char program[UTIL_PATH_SIZE], result[UTIL_LINE_SIZE]; event->program_result = mfree(event->program_result); udev_event_apply_format(event, rules_str(rules, cur->key.value_off), program, sizeof(program), false); @@ -1970,7 +1984,7 @@ int udev_rules_apply_to_event( char import[UTIL_PATH_SIZE]; udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import), false); - if (import_file_into_properties(event->dev, import) != 0) + if (import_file_into_properties(dev, import) != 0) if (cur->key.op != OP_NOMATCH) goto nomatch; break; @@ -2015,7 +2029,7 @@ int udev_rules_apply_to_event( rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); - r = udev_builtin_run(event->dev->device, cur->key.builtin_cmd, command, false); + r = udev_builtin_run(dev, cur->key.builtin_cmd, command, false); if (r < 0) { /* remember failure */ log_debug_errno(r, "IMPORT builtin '%s' fails: %m", @@ -2027,16 +2041,13 @@ int udev_rules_apply_to_event( break; } case TK_M_IMPORT_DB: { - const char *key = rules_str(rules, cur->key.value_off); - const char *value; + const char *key; - value = udev_device_get_property_value(event->dev_db, key); - if (value != NULL) - udev_device_add_property(event->dev, key, value); - else { - if (cur->key.op != OP_NOMATCH) - goto nomatch; - } + key = rules_str(rules, cur->key.value_off); + if (sd_device_get_property_value(event->dev_db_clone, key, &val) >= 0) + device_add_property(dev, key, val); + else if (cur->key.op != OP_NOMATCH) + goto nomatch; break; } case TK_M_IMPORT_CMDLINE: { @@ -2045,7 +2056,6 @@ int udev_rules_apply_to_event( const char *key; key = rules_str(rules, cur->key.value_off); - r = proc_cmdline_get_key(key, PROC_CMDLINE_VALUE_OPTIONAL, &value); if (r < 0) log_debug_errno(r, "Failed to read %s from /proc/cmdline, ignoring: %m", key); @@ -2053,10 +2063,10 @@ int udev_rules_apply_to_event( imported = true; if (value) - udev_device_add_property(event->dev, key, value); + device_add_property(dev, key, value); else /* we import simple flags as 'FLAG=1' */ - udev_device_add_property(event->dev, key, "1"); + device_add_property(dev, key, "1"); } if (!imported && cur->key.op != OP_NOMATCH) @@ -2067,7 +2077,7 @@ int udev_rules_apply_to_event( char import[UTIL_PATH_SIZE]; udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import), false); - if (import_parent_into_properties(event->dev, import) != 0) + if (import_parent_into_properties(dev, import) != 0) if (cur->key.op != OP_NOMATCH) goto nomatch; break; @@ -2083,7 +2093,7 @@ int udev_rules_apply_to_event( esc = ESCAPE_REPLACE; break; case TK_A_DB_PERSIST: - udev_device_set_db_persist(event->dev); + device_set_db_persist(dev); break; case TK_A_INOTIFY_WATCH: if (event->inotify_watch_final) @@ -2093,7 +2103,7 @@ int udev_rules_apply_to_event( event->inotify_watch = cur->key.watch; break; case TK_A_DEVLINK_PRIO: - udev_device_set_devlink_priority(event->dev, cur->key.devlink_prio); + device_set_devlink_priority(dev, cur->key.devlink_prio); break; case TK_A_OWNER: { char owner[UTIL_NAME_SIZE]; @@ -2138,9 +2148,8 @@ int udev_rules_apply_to_event( break; } case TK_A_MODE: { - char mode_str[UTIL_NAME_SIZE]; + char mode_str[UTIL_NAME_SIZE], *endptr; mode_t mode; - char *endptr; if (event->mode_final) break; @@ -2232,30 +2241,29 @@ int udev_rules_apply_to_event( break; } case TK_A_ENV: { - const char *name = rules_str(rules, cur->key.attr_off); - char *value = rules_str(rules, cur->key.value_off); char value_new[UTIL_NAME_SIZE]; - const char *value_old = NULL; + const char *name, *value_old; - if (value[0] == '\0') { + name = rules_str(rules, cur->key.attr_off); + val = rules_str(rules, cur->key.value_off); + if (val[0] == '\0') { if (cur->key.op == OP_ADD) break; - udev_device_add_property(event->dev, name, NULL); + device_add_property(dev, name, NULL); break; } - if (cur->key.op == OP_ADD) - value_old = udev_device_get_property_value(event->dev, name); - if (value_old) { + if (cur->key.op == OP_ADD && + sd_device_get_property_value(dev, name, &value_old) >= 0) { char temp[UTIL_NAME_SIZE]; /* append value separated by space */ - udev_event_apply_format(event, value, temp, sizeof(temp), false); + udev_event_apply_format(event, val, temp, sizeof(temp), false); strscpyl(value_new, sizeof(value_new), value_old, " ", temp, NULL); } else - udev_event_apply_format(event, value, value_new, sizeof(value_new), false); + udev_event_apply_format(event, val, value_new, sizeof(value_new), false); - udev_device_add_property(event->dev, name, value_new); + device_add_property(dev, name, value_new); break; } case TK_A_TAG: { @@ -2264,7 +2272,7 @@ int udev_rules_apply_to_event( udev_event_apply_format(event, rules_str(rules, cur->key.value_off), tag, sizeof(tag), false); if (IN_SET(cur->key.op, OP_ASSIGN, OP_ASSIGN_FINAL)) - udev_device_cleanup_tags_list(event->dev); + device_cleanup_tags(dev); for (p = tag; *p != '\0'; p++) { if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || @@ -2275,17 +2283,17 @@ int udev_rules_apply_to_event( break; } if (cur->key.op == OP_REMOVE) - udev_device_remove_tag(event->dev, tag); + device_remove_tag(dev, tag); else - udev_device_add_tag(event->dev, tag); + device_add_tag(dev, tag); break; } case TK_A_NAME: { - const char *name = rules_str(rules, cur->key.value_off); - char name_str[UTIL_PATH_SIZE]; + const char *name; int count; + name = rules_str(rules, cur->key.value_off); if (event->name_final) break; if (cur->key.op == OP_ASSIGN_FINAL) @@ -2296,8 +2304,9 @@ int udev_rules_apply_to_event( if (count > 0) log_debug("%i character(s) replaced", count); } - if (major(udev_device_get_devnum(event->dev)) && - !streq(name_str, udev_device_get_devnode(event->dev) + STRLEN("/dev/"))) { + if (sd_device_get_devnum(dev, NULL) >= 0 && + (sd_device_get_devname(dev, &val) < 0 || + !streq(name_str, val + STRLEN("/dev/")))) { log_error("NAME=\"%s\" ignored, kernel device nodes cannot be renamed; please fix it in %s:%u\n", name, rules_str(rules, rule->rule.filename_off), @@ -2314,19 +2323,17 @@ int udev_rules_apply_to_event( break; } case TK_A_DEVLINK: { - char temp[UTIL_PATH_SIZE]; - char filename[UTIL_PATH_SIZE]; - char *pos, *next; + char temp[UTIL_PATH_SIZE], filename[UTIL_PATH_SIZE], *pos, *next; int count = 0; if (event->devlink_final) break; - if (major(udev_device_get_devnum(event->dev)) == 0) + if (sd_device_get_devnum(dev, NULL) < 0) break; if (cur->key.op == OP_ASSIGN_FINAL) event->devlink_final = true; if (IN_SET(cur->key.op, OP_ASSIGN, OP_ASSIGN_FINAL)) - udev_device_cleanup_devlinks_list(event->dev); + device_cleanup_devlinks(dev); /* allow multiple symlinks separated by spaces */ udev_event_apply_format(event, rules_str(rules, cur->key.value_off), temp, sizeof(temp), esc != ESCAPE_NONE); @@ -2340,12 +2347,12 @@ int udev_rules_apply_to_event( while (isspace(pos[0])) pos++; next = strchr(pos, ' '); - while (next != NULL) { + while (next) { next[0] = '\0'; log_debug("LINK '%s' %s:%u", pos, rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); strscpyl(filename, sizeof(filename), "/dev/", pos, NULL); - udev_device_add_devlink(event->dev, filename); + device_add_devlink(dev, filename); while (isspace(next[1])) next++; pos = &next[1]; @@ -2355,18 +2362,19 @@ int udev_rules_apply_to_event( log_debug("LINK '%s' %s:%u", pos, rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); strscpyl(filename, sizeof(filename), "/dev/", pos, NULL); - udev_device_add_devlink(event->dev, filename); + device_add_devlink(dev, filename); } break; } case TK_A_ATTR: { - const char *key_name = rules_str(rules, cur->key.attr_off); - char attr[UTIL_PATH_SIZE]; - char value[UTIL_NAME_SIZE]; + char attr[UTIL_PATH_SIZE], value[UTIL_NAME_SIZE]; _cleanup_fclose_ FILE *f = NULL; + const char *key_name; - if (util_resolve_subsys_kernel(key_name, attr, sizeof(attr), 0) != 0) - strscpyl(attr, sizeof(attr), udev_device_get_syspath(event->dev), "/", key_name, NULL); + key_name = rules_str(rules, cur->key.attr_off); + if (util_resolve_subsys_kernel(key_name, attr, sizeof(attr), 0) != 0 && + sd_device_get_syspath(dev, &val) >= 0) + strscpyl(attr, sizeof(attr), val, "/", key_name, NULL); attr_subst_subdir(attr, sizeof(attr)); udev_event_apply_format(event, rules_str(rules, cur->key.value_off), value, sizeof(value), false); @@ -2381,8 +2389,7 @@ int udev_rules_apply_to_event( break; } case TK_A_SYSCTL: { - char filename[UTIL_PATH_SIZE]; - char value[UTIL_NAME_SIZE]; + char filename[UTIL_PATH_SIZE], value[UTIL_NAME_SIZE]; udev_event_apply_format(event, rules_str(rules, cur->key.attr_off), filename, sizeof(filename), false); sysctl_normalize(filename); diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c index 4924b75c50..cf2faa0831 100644 --- a/src/udev/udev-watch.c +++ b/src/udev/udev-watch.c @@ -24,7 +24,7 @@ static int inotify_fd = -1; int udev_watch_init(void) { inotify_fd = inotify_init1(IN_CLOEXEC); if (inotify_fd < 0) - return log_error_errno(errno, "Failed to create inotify descriptor: %m"); + return -errno; return inotify_fd; } @@ -36,18 +36,18 @@ int udev_watch_restore(void) { int r; if (inotify_fd < 0) - return log_error_errno(EINVAL, "Invalid inotify descriptor."); + return log_debug_errno(EINVAL, "Invalid inotify descriptor."); if (rename("/run/udev/watch", "/run/udev/watch.old") < 0) { if (errno != ENOENT) - return log_error_errno(errno, "Failed to move watches directory /run/udev/watch. Old watches will not be restored: %m"); + return log_warning_errno(errno, "Failed to move watches directory /run/udev/watch. Old watches will not be restored: %m"); return 0; } dir = opendir("/run/udev/watch.old"); if (!dir) - return log_error_errno(errno, "Failed to open old watches directory /run/udev/watch.old. Old watches will not be restored: %m"); + return log_warning_errno(errno, "Failed to open old watches directory /run/udev/watch.old. Old watches will not be restored: %m"); FOREACH_DIRENT_ALL(ent, dir, break) { _cleanup_(sd_device_unrefp) sd_device *dev = NULL; @@ -58,13 +58,13 @@ int udev_watch_restore(void) { r = readlinkat_malloc(dirfd(dir), ent->d_name, &device); if (r < 0) { - log_error_errno(r, "Failed to read link '/run/udev/watch.old/%s', ignoring: %m", ent->d_name); + log_debug_errno(r, "Failed to read link '/run/udev/watch.old/%s', ignoring: %m", ent->d_name); goto unlink; } r = sd_device_new_from_device_id(&dev, device); if (r < 0) { - log_error_errno(r, "Failed to create sd_device object for '%s', ignoring: %m", device); + log_debug_errno(r, "Failed to create sd_device object for '%s', ignoring: %m", device); goto unlink; } @@ -86,7 +86,7 @@ int udev_watch_begin(sd_device *dev) { int wd, r; if (inotify_fd < 0) - return log_error_errno(EINVAL, "Invalid inotify descriptor."); + return log_debug_errno(EINVAL, "Invalid inotify descriptor."); r = sd_device_get_devname(dev, &devnode); if (r < 0) @@ -120,13 +120,13 @@ int udev_watch_end(sd_device *dev) { int wd, r; if (inotify_fd < 0) - return log_error_errno(EINVAL, "Invalid inotify descriptor."); + return log_debug_errno(EINVAL, "Invalid inotify descriptor."); r = device_get_watch_handle(dev, &wd); if (r == -ENOENT) return 0; if (r < 0) - return log_device_error_errno(dev, r, "Failed to get watch handle, ignoring: %m"); + return log_device_debug_errno(dev, r, "Failed to get watch handle, ignoring: %m"); log_device_debug(dev, "Removing watch"); (void) inotify_rm_watch(inotify_fd, wd); @@ -147,22 +147,23 @@ int udev_watch_lookup(int wd, sd_device **ret) { assert(ret); if (inotify_fd < 0) - return log_error_errno(EINVAL, "Invalid inotify descriptor."); + return log_debug_errno(EINVAL, "Invalid inotify descriptor."); if (wd < 0) - return log_error_errno(EINVAL, "Invalid watch handle."); + return log_debug_errno(EINVAL, "Invalid watch handle."); xsprintf(filename, "/run/udev/watch/%d", wd); r = readlink_malloc(filename, &device); - if (r < 0) { - if (r != -ENOENT) - return log_error_errno(errno, "Failed to read link '%s': %m", filename); + if (r == -ENOENT) return 0; - } + if (r < 0) + return log_debug_errno(r, "Failed to read link '%s': %m", filename); r = sd_device_new_from_device_id(ret, device); + if (r == -ENODEV) + return 0; if (r < 0) - return log_error_errno(r, "Failed to create sd_device object for '%s': %m", device); + return log_debug_errno(r, "Failed to create sd_device object for '%s': %m", device); - return 0; + return 1; } diff --git a/src/udev/udev.h b/src/udev/udev.h index f723dd7067..162859ab40 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -9,7 +9,6 @@ #include <sys/sysmacros.h> #include <sys/types.h> -#include "libudev.h" #include "sd-device.h" #include "sd-netlink.h" @@ -21,9 +20,9 @@ #include "util.h" struct udev_event { - struct udev_device *dev; - struct udev_device *dev_parent; - struct udev_device *dev_db; + sd_device *dev; + sd_device *dev_parent; + sd_device *dev_db_clone; char *name; char *program_result; mode_t mode; @@ -60,7 +59,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event int udev_rules_apply_static_dev_perms(struct udev_rules *rules); /* udev-event.c */ -struct udev_event *udev_event_new(struct udev_device *dev); +struct udev_event *udev_event_new(sd_device *dev, int exec_delay, sd_netlink *rtnl); struct udev_event *udev_event_free(struct udev_event *event); ssize_t udev_event_apply_format(struct udev_event *event, const char *src, char *dest, size_t size, diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c index 4eb2897b21..e9a1af65fc 100644 --- a/src/udev/udevadm-hwdb.c +++ b/src/udev/udevadm-hwdb.c @@ -80,8 +80,6 @@ static int parse_argv(int argc, char *argv[]) { int hwdb_main(int argc, char *argv[], void *userdata) { int r; - log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level()); - r = parse_argv(argc, argv); if (r <= 0) return r; diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c index 20f713d738..cfaaf03db9 100644 --- a/src/udev/udevadm-test.c +++ b/src/udev/udevadm-test.c @@ -12,6 +12,10 @@ #include <sys/signalfd.h> #include <unistd.h> +#include "sd-device.h" + +#include "device-private.h" +#include "device-util.h" #include "string-util.h" #include "udev-builtin.h" #include "udev.h" @@ -88,11 +92,10 @@ static int parse_argv(int argc, char *argv[]) { int test_main(int argc, char *argv[], void *userdata) { _cleanup_(udev_rules_unrefp) struct udev_rules *rules = NULL; - _cleanup_(udev_device_unrefp) struct udev_device *dev = NULL; _cleanup_(udev_event_freep) struct udev_event *event = NULL; - struct udev_list_entry *entry; + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; + const char *cmd, *key, *value; sigset_t mask, sigmask_orig; - const char *cmd; Iterator i; void *val; int r; @@ -119,16 +122,16 @@ int test_main(int argc, char *argv[], void *userdata) { goto out; } - dev = udev_device_new_from_synthetic_event(NULL, arg_syspath, arg_action); - if (dev == NULL) { - r = log_error_errno(errno, "Failed to open device '%s': %m", arg_syspath); + r = device_new_from_synthetic_event(&dev, arg_syspath, arg_action); + if (r < 0) { + log_error_errno(r, "Failed to open device '%s': %m", arg_syspath); goto out; } /* don't read info from the db */ - udev_device_set_info_loaded(dev); + device_seal(dev); - event = udev_event_new(dev); + event = udev_event_new(dev, 0, NULL); sigfillset(&mask); sigprocmask(SIG_SETMASK, &mask, &sigmask_orig); @@ -138,8 +141,8 @@ int test_main(int argc, char *argv[], void *userdata) { NULL, rules); - udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev)) - printf("%s=%s\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry)); + FOREACH_DEVICE_PROPERTY(dev, key, value) + printf("%s=%s\n", key, value); HASHMAP_FOREACH_KEY(val, cmd, event->run_list, i) { char program[UTIL_PATH_SIZE]; diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index 66ed0aee59..185fe29be0 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -8,6 +8,7 @@ #include "device-enumerator-private.h" #include "fd-util.h" +#include "fileio.h" #include "path-util.h" #include "set.h" #include "string-util.h" @@ -24,7 +25,6 @@ static int exec_list(sd_device_enumerator *e, const char *action, Set *settle_se FOREACH_DEVICE_AND_SUBSYSTEM(e, d) { _cleanup_free_ char *filename = NULL; - _cleanup_close_ int fd = -1; const char *syspath; if (sd_device_get_syspath(d, &syspath) < 0) @@ -39,18 +39,17 @@ static int exec_list(sd_device_enumerator *e, const char *action, Set *settle_se if (!filename) return log_oom(); - fd = open(filename, O_WRONLY|O_CLOEXEC); - if (fd < 0) + r = write_string_file(filename, action, WRITE_STRING_FILE_DISABLE_BUFFER); + if (r < 0) { + log_debug_errno(r, "Failed to write '%s' to '%s', ignoring: %m", action, filename); continue; + } if (settle_set) { r = set_put_strdup(settle_set, syspath); if (r < 0) return log_oom(); } - - if (write(fd, action, strlen(action)) < 0) - log_debug_errno(errno, "Failed to write '%s' to '%s', ignoring: %m", action, filename); } return 0; diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c index e627c50ff9..8ed679698a 100644 --- a/src/udev/udevadm.c +++ b/src/udev/udevadm.c @@ -112,6 +112,7 @@ int main(int argc, char *argv[]) { udev_parse_config(); log_parse_environment(); log_open(); + log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level()); mac_selinux_init(); r = parse_argv(argc, argv); diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 7ec30b92c3..0757628d0d 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -86,6 +86,7 @@ typedef struct Manager { sd_event_source *ctrl_event; sd_event_source *uevent_event; sd_event_source *inotify_event; + sd_event_source *kill_workers_event; usec_t last_usec; @@ -284,6 +285,7 @@ static void manager_free(Manager *manager) { sd_event_source_unref(manager->ctrl_event); sd_event_source_unref(manager->uevent_event); sd_event_source_unref(manager->inotify_event); + sd_event_source_unref(manager->kill_workers_event); sd_event_unref(manager->event); manager_workers_free(manager); @@ -340,7 +342,7 @@ static void worker_spawn(Manager *manager, struct event *event) { pid = fork(); switch (pid) { case 0: { - struct udev_device *dev = NULL; + _cleanup_(udev_device_unrefp) struct udev_device *dev = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; int fd_monitor; _cleanup_close_ int fd_signal = -1, fd_ep = -1; @@ -364,6 +366,7 @@ static void worker_spawn(Manager *manager, struct event *event) { manager->ctrl_event = sd_event_source_unref(manager->ctrl_event); manager->uevent_event = sd_event_source_unref(manager->uevent_event); manager->inotify_event = sd_event_source_unref(manager->inotify_event); + manager->kill_workers_event = sd_event_source_unref(manager->kill_workers_event); manager->event = sd_event_unref(manager->event); @@ -395,7 +398,9 @@ static void worker_spawn(Manager *manager, struct event *event) { (void) prctl(PR_SET_PDEATHSIG, SIGTERM); /* Reset OOM score, we only protect the main daemon. */ - write_string_file("/proc/self/oom_score_adj", "0", 0); + r = set_oom_score_adjust(0); + if (r < 0) + log_debug_errno(r, "Failed to reset OOM score, ignoring: %m"); for (;;) { _cleanup_(udev_event_freep) struct udev_event *udev_event = NULL; @@ -404,15 +409,12 @@ static void worker_spawn(Manager *manager, struct event *event) { assert(dev); log_debug("seq %llu running", udev_device_get_seqnum(dev)); - udev_event = udev_event_new(dev); - if (udev_event == NULL) { + udev_event = udev_event_new(dev->device, arg_exec_delay, rtnl); + if (!udev_event) { r = -ENOMEM; goto out; } - if (arg_exec_delay > 0) - udev_event->exec_delay = arg_exec_delay; - /* * Take a shared lock on the device node; this establishes * a concept of device "ownership" to serialize device @@ -438,9 +440,6 @@ static void worker_spawn(Manager *manager, struct event *event) { } } - /* needed for renaming netifs */ - udev_event->rtnl = rtnl; - /* apply rules, create node, symlinks */ udev_event_execute_rules(udev_event, arg_event_timeout_usec, arg_event_timeout_warn_usec, @@ -450,7 +449,7 @@ static void worker_spawn(Manager *manager, struct event *event) { udev_event_execute_run(udev_event, arg_event_timeout_usec, arg_event_timeout_warn_usec); - if (udev_event->rtnl) + if (!rtnl) /* in case rtnl was initialized */ rtnl = sd_netlink_ref(udev_event->rtnl); @@ -474,8 +473,7 @@ skip: log_error_errno(r, "failed to send result of seq %llu to main daemon: %m", udev_device_get_seqnum(dev)); - udev_device_unref(dev); - dev = NULL; + dev = udev_device_unref(dev); /* wait for more device messages from main udevd, or term signal */ while (dev == NULL) { @@ -765,6 +763,73 @@ static void manager_reload(Manager *manager) { "STATUS=Processing with %u children at max", arg_children_max); } +static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userdata) { + Manager *manager = userdata; + + assert(manager); + + log_debug("Cleanup idle workers"); + manager_kill_workers(manager); + + return 1; +} + +static int manager_enable_kill_workers_event(Manager *manager) { + int enabled, r; + + assert(manager); + + if (!manager->kill_workers_event) + goto create_new; + + r = sd_event_source_get_enabled(manager->kill_workers_event, &enabled); + if (r < 0) { + log_debug_errno(r, "Failed to query whether event source for killing idle workers is enabled or not, trying to create new event source: %m"); + manager->kill_workers_event = sd_event_source_unref(manager->kill_workers_event); + goto create_new; + } + + if (enabled == SD_EVENT_ONESHOT) + return 0; + + r = sd_event_source_set_time(manager->kill_workers_event, now(CLOCK_MONOTONIC) + 3 * USEC_PER_SEC); + if (r < 0) { + log_debug_errno(r, "Failed to set time to event source for killing idle workers, trying to create new event source: %m"); + manager->kill_workers_event = sd_event_source_unref(manager->kill_workers_event); + goto create_new; + } + + r = sd_event_source_set_enabled(manager->kill_workers_event, SD_EVENT_ONESHOT); + if (r < 0) { + log_debug_errno(r, "Failed to enable event source for killing idle workers, trying to create new event source: %m"); + manager->kill_workers_event = sd_event_source_unref(manager->kill_workers_event); + goto create_new; + } + + return 0; + +create_new: + r = sd_event_add_time(manager->event, &manager->kill_workers_event, CLOCK_MONOTONIC, + now(CLOCK_MONOTONIC) + 3 * USEC_PER_SEC, USEC_PER_SEC, on_kill_workers_event, manager); + if (r < 0) + return log_warning_errno(r, "Failed to create timer event for killing idle workers: %m"); + + return 0; +} + +static int manager_disable_kill_workers_event(Manager *manager) { + int r; + + if (!manager->kill_workers_event) + return 0; + + r = sd_event_source_set_enabled(manager->kill_workers_event, SD_EVENT_OFF); + if (r < 0) + return log_warning_errno(r, "Failed to disable event source for cleaning up idle workers, ignoring: %m"); + + return 0; +} + static void event_queue_start(Manager *manager) { struct event *event; usec_t usec; @@ -786,6 +851,8 @@ static void event_queue_start(Manager *manager) { manager->last_usec = usec; } + (void) manager_disable_kill_workers_event(manager); + udev_builtin_init(); if (!manager->rules) { @@ -1121,7 +1188,7 @@ static int synthesize_change(sd_device *dev) { */ log_debug("Device '%s' is closed, synthesising 'change'", devname); strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL); - write_string_file(filename, "change", WRITE_STRING_FILE_CREATE); + write_string_file(filename, "change", WRITE_STRING_FILE_DISABLE_BUFFER); FOREACH_DEVICE(e, d) { const char *t, *n, *s; @@ -1136,7 +1203,7 @@ static int synthesize_change(sd_device *dev) { log_debug("Device '%s' is closed, synthesising partition '%s' 'change'", devname, n); strscpyl(filename, sizeof(filename), s, "/uevent", NULL); - write_string_file(filename, "change", WRITE_STRING_FILE_CREATE); + write_string_file(filename, "change", WRITE_STRING_FILE_DISABLE_BUFFER); } return 0; @@ -1144,7 +1211,7 @@ static int synthesize_change(sd_device *dev) { log_debug("Device %s is closed, synthesising 'change'", devname); strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL); - write_string_file(filename, "change", WRITE_STRING_FILE_CREATE); + write_string_file(filename, "change", WRITE_STRING_FILE_DISABLE_BUFFER); return 0; } @@ -1157,6 +1224,8 @@ static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userda assert(manager); + (void) manager_disable_kill_workers_event(manager); + l = read(fd, &buffer, sizeof(buffer)); if (l < 0) { if (IN_SET(errno, EAGAIN, EINTR)) @@ -1169,23 +1238,16 @@ static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userda _cleanup_(sd_device_unrefp) sd_device *dev = NULL; const char *devnode; - if (udev_watch_lookup(e->wd, &dev) < 0) + if (udev_watch_lookup(e->wd, &dev) <= 0) continue; if (sd_device_get_devname(dev, &devnode) < 0) continue; - log_debug("inotify event: %x for %s", e->mask, devnode); - if (e->mask & IN_CLOSE_WRITE) { + log_device_debug(dev, "Inotify event: %x for %s", e->mask, devnode); + if (e->mask & IN_CLOSE_WRITE) synthesize_change(dev); - - /* settle might be waiting on us to determine the queue - * state. If we just handled an inotify event, we might have - * generated a "change" event, but we won't have queued up - * the resultant uevent yet. Do that. - */ - on_uevent(NULL, -1, 0, manager); - } else if (e->mask & IN_IGNORED) + else if (e->mask & IN_IGNORED) udev_watch_end(dev); } @@ -1248,15 +1310,13 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi } else log_warning("worker ["PID_FMT"] exit with status 0x%04x", pid, status); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - if (worker->event) { - log_error("worker ["PID_FMT"] failed while handling '%s'", pid, worker->event->devpath); - /* delete state from disk */ - udev_device_delete_db(worker->event->dev); - udev_device_tag_index(worker->event->dev, NULL, false); - /* forward kernel event without amending it */ - udev_monitor_send_device(manager->monitor, NULL, worker->event->dev_kernel); - } + if ((!WIFEXITED(status) || WEXITSTATUS(status) != 0) && worker->event) { + log_error("worker ["PID_FMT"] failed while handling '%s'", pid, worker->event->devpath); + /* delete state from disk */ + udev_device_delete_db(worker->event->dev); + udev_device_tag_index(worker->event->dev, NULL, false); + /* forward kernel event without amending it */ + udev_monitor_send_device(manager->monitor, NULL, worker->event->dev_kernel); } worker_free(worker); @@ -1265,33 +1325,38 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi /* we can start new workers, try to schedule events */ event_queue_start(manager); + /* Disable unnecessary cleanup event */ + if (hashmap_isempty(manager->workers) && manager->kill_workers_event) + (void) sd_event_source_set_enabled(manager->kill_workers_event, SD_EVENT_OFF); + return 1; } static int on_post(sd_event_source *s, void *userdata) { Manager *manager = userdata; - int r; assert(manager); - if (LIST_IS_EMPTY(manager->events)) { - /* no pending events */ - if (!hashmap_isempty(manager->workers)) { - /* there are idle workers */ - log_debug("cleanup idle workers"); - manager_kill_workers(manager); - } else { - /* we are idle */ - if (manager->exit) { - r = sd_event_exit(manager->event, 0); - if (r < 0) - return r; - } else if (manager->cgroup) - /* cleanup possible left-over processes in our cgroup */ - cg_kill(SYSTEMD_CGROUP_CONTROLLER, manager->cgroup, SIGKILL, CGROUP_IGNORE_SELF, NULL, NULL, NULL); - } + if (!LIST_IS_EMPTY(manager->events)) + return 1; + + /* There are no pending events. Let's cleanup idle process. */ + + if (!hashmap_isempty(manager->workers)) { + /* There are idle workers */ + (void) manager_enable_kill_workers_event(manager); + return 1; } + /* There are no idle workers. */ + + if (manager->exit) + return sd_event_exit(manager->event, 0); + + if (manager->cgroup) + /* cleanup possible left-over processes in our cgroup */ + (void) cg_kill(SYSTEMD_CGROUP_CONTROLLER, manager->cgroup, SIGKILL, CGROUP_IGNORE_SELF, NULL, NULL, NULL); + return 1; } @@ -1578,9 +1643,10 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg if (r < 0) return log_error_errno(r, "could not enable SO_PASSCRED: %m"); - manager->fd_inotify = udev_watch_init(); - if (manager->fd_inotify < 0) - return log_error_errno(ENOMEM, "error initializing inotify"); + r = udev_watch_init(); + if (r < 0) + return log_error_errno(r, "Failed to create inotify descriptor: %m"); + manager->fd_inotify = r; udev_watch_restore(); @@ -1702,6 +1768,8 @@ int main(int argc, char *argv[]) { log_set_max_level(LOG_DEBUG); } + log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level()); + r = must_be_root(); if (r < 0) goto exit; @@ -1713,7 +1781,7 @@ int main(int argc, char *argv[]) { arg_children_max = 8; if (sched_getaffinity(0, sizeof(cpu_set), &cpu_set) == 0) - arg_children_max += CPU_COUNT(&cpu_set) * 2; + arg_children_max += CPU_COUNT(&cpu_set) * 8; mem_limit = physical_memory() / (128LU*1024*1024); arg_children_max = MAX(10U, MIN(arg_children_max, mem_limit)); @@ -1790,7 +1858,9 @@ int main(int argc, char *argv[]) { setsid(); - write_string_file("/proc/self/oom_score_adj", "-1000", 0); + r = set_oom_score_adjust(-1000); + if (r < 0) + log_debug_errno(r, "Failed to adjust OOM score, ignoring: %m"); } r = run(fd_ctrl, fd_uevent, cgroup); diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c index f162d29220..4c55ed7cb5 100644 --- a/src/vconsole/vconsole-setup.c +++ b/src/vconsole/vconsole-setup.c @@ -112,7 +112,7 @@ static int toggle_utf8(const char *name, int fd, bool utf8) { static int toggle_utf8_sysfs(bool utf8) { int r; - r = write_string_file("/sys/module/vt/parameters/default_utf8", one_zero(utf8), 0); + r = write_string_file("/sys/module/vt/parameters/default_utf8", one_zero(utf8), WRITE_STRING_FILE_DISABLE_BUFFER); if (r < 0) return log_warning_errno(r, "Failed to %s sysfs UTF-8 flag: %m", enable_disable(utf8)); |