diff options
Diffstat (limited to 'src')
85 files changed, 2417 insertions, 1611 deletions
diff --git a/src/basic/formats-util.h b/src/basic/formats-util.h index 9b4e8e98fa..39a185f59b 100644 --- a/src/basic/formats-util.h +++ b/src/basic/formats-util.h @@ -61,3 +61,19 @@ #else # error Unknown rlim_t size #endif + +#if SIZEOF_DEV_T == 8 +# define DEV_FMT "%" PRIu64 +#elif SIZEOF_DEV_T == 4 +# define DEV_FMT "%" PRIu32 +#else +# error Unknown dev_t size +#endif + +#if SIZEOF_INO_T == 8 +# define INO_FMT "%" PRIu64 +#elif SIZEOF_INO_T == 4 +# define INO_FMT "%" PRIu32 +#else +# error Unknown ino_t size +#endif diff --git a/src/basic/missing.h b/src/basic/missing.h index 8b977871e9..b1272f8799 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -577,6 +577,9 @@ struct btrfs_ioctl_quota_ctl_args { #define IN6_ADDR_GEN_MODE_EUI64 0 #define IN6_ADDR_GEN_MODE_NONE 1 +#endif + +#if !HAVE_DECL_IN6_ADDR_GEN_MODE_STABLE_PRIVACY #define IN6_ADDR_GEN_MODE_STABLE_PRIVACY 2 #endif @@ -834,6 +837,10 @@ struct btrfs_ioctl_quota_ctl_args { #define IFLA_BRPORT_PROXYARP 10 #endif +#if !HAVE_DECL_IFLA_VRF_TABLE +#define IFLA_VRF_TABLE 1 +#endif + #if !HAVE_DECL_NDA_IFINDEX #define NDA_UNSPEC 0 #define NDA_DST 1 diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index 6c11b605a9..503a895731 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -532,3 +532,22 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) { return 0; } + +int parse_percent(const char *p) { + const char *pc, *n; + unsigned v; + int r; + + pc = endswith(p, "%"); + if (!pc) + return -EINVAL; + + n = strndupa(p, pc - p); + r = safe_atou(n, &v); + if (r < 0) + return r; + if (v > 100) + return -ERANGE; + + return (int) v; +} diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h index 7dc579a159..73441bb6fd 100644 --- a/src/basic/parse-util.h +++ b/src/basic/parse-util.h @@ -105,3 +105,5 @@ static inline int safe_atozu(const char *s, size_t *ret_u) { int safe_atod(const char *s, double *ret_d); int parse_fractional_part_u(const char **s, size_t digits, unsigned *res); + +int parse_percent(const char *p); diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c index 3505fa9c9a..0430beadaa 100644 --- a/src/basic/proc-cmdline.c +++ b/src/basic/proc-cmdline.c @@ -160,17 +160,29 @@ static const char * const rlmap[] = { "3", SPECIAL_MULTI_USER_TARGET, "4", SPECIAL_MULTI_USER_TARGET, "5", SPECIAL_GRAPHICAL_TARGET, + NULL +}; + +static const char * const rlmap_initrd[] = { + "emergency", SPECIAL_EMERGENCY_TARGET, + "rescue", SPECIAL_RESCUE_TARGET, + NULL }; const char* runlevel_to_target(const char *word) { size_t i; + const char * const *rlmap_ptr = in_initrd() ? rlmap_initrd + : rlmap; if (!word) return NULL; - for (i = 0; i < ELEMENTSOF(rlmap); i += 2) - if (streq(word, rlmap[i])) - return rlmap[i+1]; + if (in_initrd() && (word = startswith(word, "rd.")) == NULL) + return NULL; + + for (i = 0; rlmap_ptr[i] != NULL; i += 2) + if (streq(word, rlmap_ptr[i])) + return rlmap_ptr[i+1]; return NULL; } diff --git a/src/basic/process-util.c b/src/basic/process-util.c index f6bde20fc5..20768b715a 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -110,6 +110,15 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * assert(line); assert(pid >= 0); + /* Retrieves a process' command line. Replaces unprintable characters while doing so by whitespace (coalescing + * multiple sequential ones into one). If max_length is != 0 will return a string of the specified size at most + * (the trailing NUL byte does count towards the length here!), abbreviated with a "..." ellipsis. If + * comm_fallback is true and the process has no command line set (the case for kernel threads), or has a + * command line that resolves to the empty string will return the "comm" name of the process instead. + * + * Returns -ESRCH if the process doesn't exist, and -ENOENT if the process has no command line (and + * comm_fallback is false). */ + p = procfs_file_alloca(pid, "cmdline"); f = fopen(p, "re"); @@ -119,12 +128,22 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * return -errno; } - if (max_length == 0) { + if (max_length == 1) { + + /* If there's only room for one byte, return the empty string */ + r = new0(char, 1); + if (!r) + return -ENOMEM; + + *line = r; + return 0; + + } else if (max_length == 0) { size_t len = 0, allocated = 0; while ((c = getc(f)) != EOF) { - if (!GREEDY_REALLOC(r, allocated, len+2)) { + if (!GREEDY_REALLOC(r, allocated, len+3)) { free(r); return -ENOMEM; } @@ -136,14 +155,17 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * } r[len++] = c; - } else + } else if (len > 0) space = true; } if (len > 0) r[len] = 0; + else + r = mfree(r); } else { + bool dotdotdot = false; size_t left; r = new(char, max_length); @@ -155,28 +177,46 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * while ((c = getc(f)) != EOF) { if (isprint(c)) { + if (space) { - if (left <= 4) + if (left <= 2) { + dotdotdot = true; break; + } *(k++) = ' '; left--; space = false; } - if (left <= 4) + if (left <= 1) { + dotdotdot = true; break; + } *(k++) = (char) c; left--; - } else + } else if (k > r) space = true; } - if (left <= 4) { - size_t n = MIN(left-1, 3U); - memcpy(k, "...", n); - k[n] = 0; + if (dotdotdot) { + if (max_length <= 4) { + k = r; + left = max_length; + } else { + k = r + max_length - 4; + left = 4; + + /* Eat up final spaces */ + while (k > r && isspace(k[-1])) { + k--; + left++; + } + } + + strncpy(k, "...", left-1); + k[left-1] = 0; } else *k = 0; } @@ -195,7 +235,37 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * if (h < 0) return h; - r = strjoin("[", t, "]", NULL); + if (max_length == 0) + r = strjoin("[", t, "]", NULL); + else { + size_t l; + + l = strlen(t); + + if (l + 3 <= max_length) + r = strjoin("[", t, "]", NULL); + else if (max_length <= 6) { + + r = new(char, max_length); + if (!r) + return -ENOMEM; + + memcpy(r, "[...]", max_length-1); + r[max_length-1] = 0; + } else { + char *e; + + t[max_length - 6] = 0; + + /* Chop off final spaces */ + e = strchr(t, 0); + while (e > t && isspace(e[-1])) + e--; + *e = 0; + + r = strjoin("[", t, "...]", NULL); + } + } if (!r) return -ENOMEM; } @@ -325,9 +395,6 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) { assert(field); assert(uid); - if (pid == 0) - return getuid(); - p = procfs_file_alloca(pid, "status"); f = fopen(p, "re"); if (!f) { diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index c8769a54f4..385c3e4df3 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -85,7 +85,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { return -EINVAL; a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htons((uint16_t) u); + a->sockaddr.in6.sin6_port = htobe16((uint16_t)u); a->size = sizeof(struct sockaddr_in6); } else if (*s == '/') { @@ -133,7 +133,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { if (r > 0) { /* Gotcha, it's a traditional IPv4 address */ a->sockaddr.in.sin_family = AF_INET; - a->sockaddr.in.sin_port = htons((uint16_t) u); + a->sockaddr.in.sin_port = htobe16((uint16_t)u); a->size = sizeof(struct sockaddr_in); } else { unsigned idx; @@ -147,7 +147,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { return -EINVAL; a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htons((uint16_t) u); + a->sockaddr.in6.sin6_port = htobe16((uint16_t)u); a->sockaddr.in6.sin6_scope_id = idx; a->sockaddr.in6.sin6_addr = in6addr_any; a->size = sizeof(struct sockaddr_in6); @@ -164,12 +164,12 @@ int socket_address_parse(SocketAddress *a, const char *s) { if (socket_ipv6_is_supported()) { a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htons((uint16_t) u); + a->sockaddr.in6.sin6_port = htobe16((uint16_t)u); a->sockaddr.in6.sin6_addr = in6addr_any; a->size = sizeof(struct sockaddr_in6); } else { a->sockaddr.in.sin_family = AF_INET; - a->sockaddr.in.sin_port = htons((uint16_t) u); + a->sockaddr.in.sin_port = htobe16((uint16_t)u); a->sockaddr.in.sin_addr.s_addr = INADDR_ANY; a->size = sizeof(struct sockaddr_in); } @@ -488,9 +488,7 @@ int sockaddr_port(const struct sockaddr *_sa) { if (!IN_SET(sa->sa.sa_family, AF_INET, AF_INET6)) return -EAFNOSUPPORT; - return ntohs(sa->sa.sa_family == AF_INET6 ? - sa->in6.sin6_port : - sa->in.sin_port); + return be16toh(sa->sa.sa_family == AF_INET6 ? sa->in6.sin6_port : sa->in.sin_port); } int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) { @@ -506,13 +504,13 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ case AF_INET: { uint32_t a; - a = ntohl(sa->in.sin_addr.s_addr); + a = be32toh(sa->in.sin_addr.s_addr); if (include_port) r = asprintf(&p, "%u.%u.%u.%u:%u", a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF, - ntohs(sa->in.sin_port)); + be16toh(sa->in.sin_port)); else r = asprintf(&p, "%u.%u.%u.%u", @@ -534,7 +532,7 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ r = asprintf(&p, "%u.%u.%u.%u:%u", a[0], a[1], a[2], a[3], - ntohs(sa->in6.sin6_port)); + be16toh(sa->in6.sin6_port)); else r = asprintf(&p, "%u.%u.%u.%u", @@ -550,7 +548,7 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ r = asprintf(&p, "[%s]:%u", a, - ntohs(sa->in6.sin6_port)); + be16toh(sa->in6.sin6_port)); if (r < 0) return -ENOMEM; } else { @@ -988,7 +986,7 @@ ssize_t next_datagram_size_fd(int fd) { l = recv(fd, NULL, 0, MSG_PEEK|MSG_TRUNC); if (l < 0) { - if (errno == EOPNOTSUPP) + if (errno == EOPNOTSUPP || errno == EFAULT) goto fallback; return -errno; diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h index f209a84634..44eadf0347 100644 --- a/src/basic/unit-name.h +++ b/src/basic/unit-name.h @@ -195,7 +195,6 @@ typedef enum SwapState { _SWAP_STATE_INVALID = -1 } SwapState; - typedef enum TargetState { TARGET_DEAD, TARGET_ACTIVE, diff --git a/src/basic/util.c b/src/basic/util.c index 756c663be4..09d16697b7 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -36,6 +36,7 @@ #include "alloc-util.h" #include "build.h" +#include "cgroup-util.h" #include "def.h" #include "dirent-util.h" #include "fd-util.h" @@ -64,6 +65,7 @@ assert_cc(EAGAIN == EWOULDBLOCK); int saved_argc = 0; char **saved_argv = NULL; +static int saved_in_initrd = -1; size_t page_size(void) { static thread_local size_t pgsz = 0; @@ -454,11 +456,10 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa } bool in_initrd(void) { - static int saved = -1; struct statfs s; - if (saved >= 0) - return saved; + if (saved_in_initrd >= 0) + return saved_in_initrd; /* We make two checks here: * @@ -470,11 +471,15 @@ bool in_initrd(void) { * emptying when transititioning to the main systemd. */ - saved = access("/etc/initrd-release", F_OK) >= 0 && - statfs("/", &s) >= 0 && - is_temporary_fs(&s); + saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 && + statfs("/", &s) >= 0 && + is_temporary_fs(&s); - return saved; + return saved_in_initrd; +} + +void in_initrd_force(bool value) { + saved_in_initrd = value; } /* hey glibc, APIs with callbacks without a user pointer are so useless */ @@ -767,15 +772,64 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int } uint64_t physical_memory(void) { - long mem; + _cleanup_free_ char *root = NULL, *value = NULL; + uint64_t mem, lim; + size_t ps; + long sc; + + /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of + * memory. + * + * In order to support containers nicely that have a configured memory limit we'll take the minimum of the + * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */ + + sc = sysconf(_SC_PHYS_PAGES); + assert(sc > 0); + + ps = page_size(); + mem = (uint64_t) sc * (uint64_t) ps; + + if (cg_get_root_path(&root) < 0) + return mem; + + if (cg_get_attribute("memory", root, "memory.limit_in_bytes", &value)) + return mem; + + if (safe_atou64(value, &lim) < 0) + return mem; + + /* Make sure the limit is a multiple of our own page size */ + lim /= ps; + lim *= ps; + + return MIN(mem, lim); +} + +uint64_t physical_memory_scale(uint64_t v, uint64_t max) { + uint64_t p, m, ps, r; + + assert(max > 0); + + /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success + * the result is a multiple of the page size (rounds down). */ + + ps = page_size(); + assert(ps > 0); + + p = physical_memory() / ps; + assert(p > 0); + + m = p * v; + if (m / p != v) + return UINT64_MAX; - /* We return this as uint64_t in case we are running as 32bit - * process on a 64bit kernel with huge amounts of memory */ + m /= max; - mem = sysconf(_SC_PHYS_PAGES); - assert(mem > 0); + r = m * ps; + if (r / ps != m) + return UINT64_MAX; - return (uint64_t) mem * (uint64_t) page_size(); + return r; } int update_reboot_parameter_and_warn(const char *param) { diff --git a/src/basic/util.h b/src/basic/util.h index 1c032c15c9..db105197e8 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -86,6 +86,7 @@ int prot_from_flags(int flags) _const_; int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...); bool in_initrd(void); +void in_initrd_force(bool value); void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, int (*compar) (const void *, const void *, void *), @@ -183,6 +184,7 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int * int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd); uint64_t physical_memory(void); +uint64_t physical_memory_scale(uint64_t v, uint64_t max); int update_reboot_parameter_and_warn(const char *param); diff --git a/src/core/busname.c b/src/core/busname.c index f03a95c24e..730be2ee14 100644 --- a/src/core/busname.c +++ b/src/core/busname.c @@ -998,12 +998,7 @@ static int busname_get_timeout(Unit *u, usec_t *timeout) { } static bool busname_supported(void) { - static int supported = -1; - - if (supported < 0) - supported = is_kdbus_available(); - - return supported; + return false; } static int busname_control_pid(Unit *u) { diff --git a/src/core/cgroup.c b/src/core/cgroup.c index f3e0c54b76..799296ad28 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -1723,7 +1723,7 @@ int manager_setup_cgroup(Manager *m) { return log_error_errno(r, "Failed to determine supported controllers: %m"); for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) - log_debug("Controller '%s' supported: %s", cgroup_controller_to_string(c), yes_no(m->cgroup_supported & c)); + log_debug("Controller '%s' supported: %s", cgroup_controller_to_string(c), yes_no(m->cgroup_supported & CGROUP_CONTROLLER_TO_MASK(c))); return 0; } diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 8525fa1bf1..27bbe2d26d 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -641,7 +641,7 @@ int bus_cgroup_set_property( return 1; - } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) { + } else if (STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) { const char *path; bool read = true; unsigned n = 0; @@ -835,6 +835,8 @@ int bus_cgroup_set_property( r = sd_bus_message_read(message, "t", &v); if (r < 0) return r; + if (v <= 0) + return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name); if (mode != UNIT_CHECK) { if (streq(name, "MemoryLow")) @@ -847,19 +849,53 @@ int bus_cgroup_set_property( unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); if (v == CGROUP_LIMIT_MAX) - unit_write_drop_in_private_format(u, mode, name, "%s=max", name); + unit_write_drop_in_private_format(u, mode, name, "%s=infinity", name); else unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, v); } return 1; + } else if (STR_IN_SET(name, "MemoryLowByPhysicalMemory", "MemoryHighByPhysicalMemory", "MemoryMaxByPhysicalMemory")) { + uint32_t raw; + uint64_t v; + + r = sd_bus_message_read(message, "u", &raw); + if (r < 0) + return r; + + v = physical_memory_scale(raw, UINT32_MAX); + if (v <= 0 || v == UINT64_MAX) + return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name); + + if (mode != UNIT_CHECK) { + const char *e; + + /* Chop off suffix */ + assert_se(e = endswith(name, "ByPhysicalMemory")); + name = strndupa(name, e - name); + + if (streq(name, "MemoryLow")) + c->memory_low = v; + else if (streq(name, "MemoryHigh")) + c->memory_high = v; + else + c->memory_max = v; + + unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); + unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu32 "%%", name, (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100, (uint64_t) UINT32_MAX))); + } + + return 1; + } else if (streq(name, "MemoryLimit")) { uint64_t limit; r = sd_bus_message_read(message, "t", &limit); if (r < 0) return r; + if (limit <= 0) + return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name); if (mode != UNIT_CHECK) { c->memory_limit = limit; @@ -873,6 +909,26 @@ int bus_cgroup_set_property( return 1; + } else if (streq(name, "MemoryLimitByPhysicalMemory")) { + uint64_t limit; + uint32_t raw; + + r = sd_bus_message_read(message, "u", &raw); + if (r < 0) + return r; + + limit = physical_memory_scale(raw, UINT32_MAX); + if (limit <= 0 || limit == UINT64_MAX) + return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name); + + if (mode != UNIT_CHECK) { + c->memory_limit = limit; + unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); + unit_write_drop_in_private_format(u, mode, "MemoryLimit", "MemoryLimit=%" PRIu32 "%%", (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100, (uint64_t) UINT32_MAX))); + } + + return 1; + } else if (streq(name, "DevicePolicy")) { const char *policy; CGroupDevicePolicy p; diff --git a/src/core/execute.c b/src/core/execute.c index c20650626c..3c3369373f 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -289,7 +289,15 @@ static int connect_journal_socket(int fd, uid_t uid, gid_t gid) { return r; } -static int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, const char *unit_id, int nfd, uid_t uid, gid_t gid) { +static int connect_logger_as( + const ExecContext *context, + ExecOutput output, + const char *ident, + const char *unit_id, + int nfd, + uid_t uid, + gid_t gid) { + int fd, r; assert(context); @@ -310,7 +318,7 @@ static int connect_logger_as(const ExecContext *context, ExecOutput output, cons return -errno; } - fd_inc_sndbuf(fd, SNDBUF_SIZE); + (void) fd_inc_sndbuf(fd, SNDBUF_SIZE); dprintf(fd, "%s\n" @@ -328,11 +336,11 @@ static int connect_logger_as(const ExecContext *context, ExecOutput output, cons output == EXEC_OUTPUT_KMSG || output == EXEC_OUTPUT_KMSG_AND_CONSOLE, is_terminal_output(output)); - if (fd != nfd) { - r = dup2(fd, nfd) < 0 ? -errno : nfd; - safe_close(fd); - } else - r = nfd; + if (fd == nfd) + return nfd; + + r = dup2(fd, nfd) < 0 ? -errno : nfd; + safe_close(fd); return r; } @@ -446,7 +454,10 @@ static int setup_output( int fileno, int socket_fd, const char *ident, - uid_t uid, gid_t gid) { + uid_t uid, + gid_t gid, + dev_t *journal_stream_dev, + ino_t *journal_stream_ino) { ExecOutput o; ExecInput i; @@ -456,6 +467,8 @@ static int setup_output( assert(context); assert(params); assert(ident); + assert(journal_stream_dev); + assert(journal_stream_ino); if (fileno == STDOUT_FILENO && params->stdout_fd >= 0) { @@ -535,6 +548,17 @@ static int setup_output( if (r < 0) { log_unit_error_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m", fileno == STDOUT_FILENO ? "stdout" : "stderr"); r = open_null_as(O_WRONLY, fileno); + } else { + struct stat st; + + /* If we connected this fd to the journal via a stream, patch the device/inode into the passed + * parameters, but only then. This is useful so that we can set $JOURNAL_STREAM that permits + * services to detect whether they are connected to the journal or not. */ + + if (fstat(fileno, &st) >= 0) { + *journal_stream_dev = st.st_dev; + *journal_stream_ino = st.st_ino; + } } return r; @@ -1278,6 +1302,8 @@ static int build_environment( const char *home, const char *username, const char *shell, + dev_t journal_stream_dev, + ino_t journal_stream_ino, char ***ret) { _cleanup_strv_free_ char **our_env = NULL; @@ -1287,7 +1313,7 @@ static int build_environment( assert(c); assert(ret); - our_env = new0(char*, 11); + our_env = new0(char*, 12); if (!our_env) return -ENOMEM; @@ -1359,8 +1385,15 @@ static int build_environment( our_env[n_env++] = x; } + if (journal_stream_dev != 0 && journal_stream_ino != 0) { + if (asprintf(&x, "JOURNAL_STREAM=" DEV_FMT ":" INO_FMT, journal_stream_dev, journal_stream_ino) < 0) + return -ENOMEM; + + our_env[n_env++] = x; + } + our_env[n_env++] = NULL; - assert(n_env <= 11); + assert(n_env <= 12); *ret = our_env; our_env = NULL; @@ -1473,10 +1506,12 @@ static int exec_child( _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **final_argv = NULL; _cleanup_free_ char *mac_selinux_context_net = NULL; const char *username = NULL, *home = NULL, *shell = NULL, *wd; + dev_t journal_stream_dev = 0; + ino_t journal_stream_ino = 0; + bool needs_mount_namespace; uid_t uid = UID_INVALID; gid_t gid = GID_INVALID; int i, r; - bool needs_mount_namespace; assert(unit); assert(command); @@ -1576,13 +1611,13 @@ static int exec_child( return r; } - r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid); + r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino); if (r < 0) { *exit_status = EXIT_STDOUT; return r; } - r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid); + r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino); if (r < 0) { *exit_status = EXIT_STDERR; return r; @@ -1721,7 +1756,16 @@ static int exec_child( } } - r = build_environment(context, params, n_fds, home, username, shell, &our_env); + r = build_environment( + context, + params, + n_fds, + home, + username, + shell, + journal_stream_dev, + journal_stream_ino, + &our_env); if (r < 0) { *exit_status = EXIT_MEMORY; return r; diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c index 3503db52ed..fd1021f706 100644 --- a/src/core/kmod-setup.c +++ b/src/core/kmod-setup.c @@ -64,9 +64,6 @@ int kmod_setup(void) { /* this should never be a module */ { "unix", "/proc/net/unix", true, true, NULL }, - /* IPC is needed before we bring up any other services */ - { "kdbus", "/sys/fs/kdbus", false, false, is_kdbus_wanted }, - #ifdef HAVE_LIBIPTC /* netfilter is needed by networkd, nspawn among others, and cannot be autoloaded */ { "ip_tables", "/proc/net/ip_tables_names", false, false, NULL }, diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 17c72aed88..8295cf45a6 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2774,7 +2774,7 @@ int config_parse_cpu_quota( void *userdata) { CGroupContext *c = data; - double percent; + int r; assert(filename); assert(lvalue); @@ -2785,18 +2785,13 @@ int config_parse_cpu_quota( return 0; } - if (!endswith(rvalue, "%")) { - log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue); - return 0; - } - - if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' invalid. Ignoring.", rvalue); + r = parse_percent(rvalue); + if (r <= 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "CPU quota '%s' invalid. Ignoring.", rvalue); return 0; } - c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100); - + c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 100U; return 0; } @@ -2817,9 +2812,19 @@ int config_parse_memory_limit( int r; if (!isempty(rvalue) && !streq(rvalue, "infinity")) { - r = parse_size(rvalue, 1024, &bytes); - if (r < 0 || bytes < 1) { - log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue); + + r = parse_percent(rvalue); + if (r < 0) { + r = parse_size(rvalue, 1024, &bytes); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue); + return 0; + } + } else + bytes = physical_memory_scale(r, 100U); + + if (bytes < 1) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' too small. Ignoring.", rvalue); return 0; } } @@ -3830,7 +3835,15 @@ static int load_from_path(Unit *u, const char *path) { if (r >= 0) break; filename = mfree(filename); - if (r != -ENOENT) + + /* ENOENT means that the file is missing or is a dangling symlink. + * ENOTDIR means that one of paths we expect to be is a directory + * is not a directory, we should just ignore that. + * EACCES means that the directory or file permissions are wrong. + */ + if (r == -EACCES) + log_debug_errno(r, "Cannot access \"%s\": %m", filename); + else if (!IN_SET(r, -ENOENT, -ENOTDIR)) return r; /* Empty the symlink names for the next run */ diff --git a/src/core/main.c b/src/core/main.c index 6124a984c3..237c9c9ebe 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -409,7 +409,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { if (detect_container() > 0) log_set_target(LOG_TARGET_CONSOLE); - } else if (!in_initrd() && !value) { + } else if (!value) { const char *target; /* SysV compatibility */ diff --git a/src/core/manager.c b/src/core/manager.c index ec8acdff5b..012aa6cd53 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -814,28 +814,6 @@ static int manager_setup_cgroups_agent(Manager *m) { return 0; } -static int manager_setup_kdbus(Manager *m) { - _cleanup_free_ char *p = NULL; - - assert(m); - - if (m->test_run || m->kdbus_fd >= 0) - return 0; - if (!is_kdbus_available()) - return -ESOCKTNOSUPPORT; - - m->kdbus_fd = bus_kernel_create_bus( - MANAGER_IS_SYSTEM(m) ? "system" : "user", - MANAGER_IS_SYSTEM(m), &p); - - if (m->kdbus_fd < 0) - return log_debug_errno(m->kdbus_fd, "Failed to set up kdbus: %m"); - - log_debug("Successfully set up kdbus on %s", p); - - return 0; -} - static int manager_connect_bus(Manager *m, bool reexecuting) { bool try_bus_connect; @@ -877,6 +855,19 @@ enum { _GC_OFFSET_MAX }; +static void unit_gc_mark_good(Unit *u, unsigned gc_marker) +{ + Iterator i; + Unit *other; + + u->gc_marker = gc_marker + GC_OFFSET_GOOD; + + /* Recursively mark referenced units as GOOD as well */ + SET_FOREACH(other, u->dependencies[UNIT_REFERENCES], i) + if (other->gc_marker == gc_marker + GC_OFFSET_UNSURE) + unit_gc_mark_good(other, gc_marker); +} + static void unit_gc_sweep(Unit *u, unsigned gc_marker) { Iterator i; Unit *other; @@ -886,6 +877,7 @@ static void unit_gc_sweep(Unit *u, unsigned gc_marker) { if (u->gc_marker == gc_marker + GC_OFFSET_GOOD || u->gc_marker == gc_marker + GC_OFFSET_BAD || + u->gc_marker == gc_marker + GC_OFFSET_UNSURE || u->gc_marker == gc_marker + GC_OFFSET_IN_PATH) return; @@ -926,7 +918,7 @@ bad: return; good: - u->gc_marker = gc_marker + GC_OFFSET_GOOD; + unit_gc_mark_good(u, gc_marker); } static unsigned manager_dispatch_gc_queue(Manager *m) { @@ -1230,7 +1222,6 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { /* We might have deserialized the kdbus control fd, but if we * didn't, then let's create the bus now. */ - manager_setup_kdbus(m); manager_connect_bus(m, !!serialization); bus_track_coldplug(m, &m->subscribed, &m->deserialized_subscribed); diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index 40fc548b42..f9c9b4a91f 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -108,8 +108,6 @@ static const MountPoint mount_table[] = { { "efivarfs", "/sys/firmware/efi/efivars", "efivarfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, is_efi_boot, MNT_NONE }, #endif - { "kdbusfs", "/sys/fs/kdbus", "kdbusfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, - is_kdbus_wanted, MNT_IN_CONTAINER }, }; /* These are API file systems that might be mounted by other software, diff --git a/src/core/scope.c b/src/core/scope.c index 238f63a729..decd1a1f3f 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -428,8 +428,9 @@ static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) { unit_tidy_watch_pids(u, 0, 0); unit_watch_all_pids(u); - /* If the PID set is empty now, then let's finish this off */ - if (set_isempty(u->pids)) + /* If the PID set is empty now, then let's finish this off + (On unified we use proper notifications) */ + if (cg_unified() <= 0 && set_isempty(u->pids)) scope_notify_cgroup_empty_event(u); } diff --git a/src/core/service.c b/src/core/service.c index 7ebabca5d6..78c33b1530 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -574,20 +574,9 @@ static int service_setup_bus_name(Service *s) { if (!s->bus_name) return 0; - if (is_kdbus_available()) { - const char *n; - - n = strjoina(s->bus_name, ".busname"); - r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, n, NULL, true); - if (r < 0) - return log_unit_error_errno(UNIT(s), r, "Failed to add dependency to .busname unit: %m"); - - } else { - /* If kdbus is not available, we know the dbus socket is required, hence pull it in, and require it */ - r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true); - if (r < 0) - return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m"); - } + r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true); + if (r < 0) + return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m"); /* Regardless if kdbus is used or not, we always want to be ordered against dbus.socket if both are in the transaction. */ r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, NULL, true); @@ -2800,8 +2789,9 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { unit_tidy_watch_pids(u, s->main_pid, s->control_pid); unit_watch_all_pids(u); - /* If the PID set is empty now, then let's finish this off */ - if (set_isempty(u->pids)) + /* If the PID set is empty now, then let's finish this off + (On unified we use proper notifications) */ + if (cg_unified() <= 0 && set_isempty(u->pids)) service_notify_cgroup_empty_event(u); } diff --git a/src/core/socket.c b/src/core/socket.c index f6204d04bf..e098055885 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -730,16 +730,16 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) { case AF_INET: { uint32_t - a = ntohl(local.in.sin_addr.s_addr), - b = ntohl(remote.in.sin_addr.s_addr); + a = be32toh(local.in.sin_addr.s_addr), + b = be32toh(remote.in.sin_addr.s_addr); if (asprintf(&r, "%u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u", nr, a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF, - ntohs(local.in.sin_port), + be16toh(local.in.sin_port), b >> 24, (b >> 16) & 0xFF, (b >> 8) & 0xFF, b & 0xFF, - ntohs(remote.in.sin_port)) < 0) + be16toh(remote.in.sin_port)) < 0) return -ENOMEM; break; @@ -760,9 +760,9 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) { "%u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u", nr, a[0], a[1], a[2], a[3], - ntohs(local.in6.sin6_port), + be16toh(local.in6.sin6_port), b[0], b[1], b[2], b[3], - ntohs(remote.in6.sin6_port)) < 0) + be16toh(remote.in6.sin6_port)) < 0) return -ENOMEM; } else { char a[INET6_ADDRSTRLEN], b[INET6_ADDRSTRLEN]; @@ -771,9 +771,9 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) { "%u-%s:%u-%s:%u", nr, inet_ntop(AF_INET6, &local.in6.sin6_addr, a, sizeof(a)), - ntohs(local.in6.sin6_port), + be16toh(local.in6.sin6_port), inet_ntop(AF_INET6, &remote.in6.sin6_addr, b, sizeof(b)), - ntohs(remote.in6.sin6_port)) < 0) + be16toh(remote.in6.sin6_port)) < 0) return -ENOMEM; } diff --git a/src/core/unit.c b/src/core/unit.c index e98086a3f6..581962eba6 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -3375,7 +3375,7 @@ int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, co return -EINVAL; wrapped = strjoina("# This is a drop-in unit file extension, created via \"systemctl set-property\"\n" - "or an equivalent operation. Do not edit.\n", + "# or an equivalent operation. Do not edit.\n", data, "\n"); diff --git a/src/dbus1-generator/dbus1-generator.c b/src/dbus1-generator/dbus1-generator.c deleted file mode 100644 index 717cb9558e..0000000000 --- a/src/dbus1-generator/dbus1-generator.c +++ /dev/null @@ -1,331 +0,0 @@ -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include "alloc-util.h" -#include "bus-internal.h" -#include "bus-util.h" -#include "cgroup-util.h" -#include "conf-parser.h" -#include "dirent-util.h" -#include "fd-util.h" -#include "fileio.h" -#include "mkdir.h" -#include "special.h" -#include "unit-name.h" -#include "util.h" - -static const char *arg_dest_late = "/tmp", *arg_dest = "/tmp"; - -static int create_dbus_files( - const char *path, - const char *name, - const char *service, - const char *exec, - const char *user, - const char *type) { - - _cleanup_free_ char *b = NULL, *s = NULL, *lnk = NULL; - _cleanup_fclose_ FILE *f = NULL; - int r; - - assert(path); - assert(name); - assert(service || exec); - - if (!service) { - _cleanup_free_ char *a = NULL; - - s = strjoin("dbus-", name, ".service", NULL); - if (!s) - return log_oom(); - - a = strjoin(arg_dest_late, "/", s, NULL); - if (!a) - return log_oom(); - - f = fopen(a, "wxe"); - if (!f) - return log_error_errno(errno, "Failed to create %s: %m", a); - - fprintf(f, - "# Automatically generated by systemd-dbus1-generator\n\n" - "[Unit]\n" - "SourcePath=%s\n" - "Description=DBUS1: %s\n" - "Documentation=man:systemd-dbus1-generator(8)\n\n" - "[Service]\n" - "ExecStart=%s\n" - "Type=dbus\n" - "BusName=%s\n", - path, - name, - exec, - name); - - if (user) - fprintf(f, "User=%s\n", user); - - - if (type) { - fprintf(f, "Environment=DBUS_STARTER_BUS_TYPE=%s\n", type); - - if (streq(type, "system")) - fprintf(f, "Environment=DBUS_STARTER_ADDRESS=" DEFAULT_SYSTEM_BUS_ADDRESS "\n"); - else if (streq(type, "session")) { - char *run; - - run = getenv("XDG_RUNTIME_DIR"); - if (!run) { - log_error("XDG_RUNTIME_DIR not set."); - return -EINVAL; - } - - fprintf(f, "Environment=DBUS_STARTER_ADDRESS="KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT "\n", - getuid(), run); - } - } - - r = fflush_and_check(f); - if (r < 0) - return log_error_errno(r, "Failed to write %s: %m", a); - - f = safe_fclose(f); - - service = s; - } - - b = strjoin(arg_dest_late, "/", name, ".busname", NULL); - if (!b) - return log_oom(); - - f = fopen(b, "wxe"); - if (!f) - return log_error_errno(errno, "Failed to create %s: %m", b); - - fprintf(f, - "# Automatically generated by systemd-dbus1-generator\n\n" - "[Unit]\n" - "SourcePath=%s\n" - "Description=DBUS1: %s\n" - "Documentation=man:systemd-dbus1-generator(8)\n\n" - "[BusName]\n" - "Name=%s\n" - "Service=%s\n" - "AllowWorld=talk\n", - path, - name, - name, - service); - - r = fflush_and_check(f); - if (r < 0) - return log_error_errno(r, "Failed to write %s: %m", b); - - lnk = strjoin(arg_dest_late, "/" SPECIAL_BUSNAMES_TARGET ".wants/", name, ".busname", NULL); - if (!lnk) - return log_oom(); - - mkdir_parents_label(lnk, 0755); - if (symlink(b, lnk)) - return log_error_errno(errno, "Failed to create symlink %s: %m", lnk); - - return 0; -} - -static int add_dbus(const char *path, const char *fname, const char *type) { - _cleanup_free_ char *name = NULL, *exec = NULL, *user = NULL, *service = NULL; - - const ConfigTableItem table[] = { - { "D-BUS Service", "Name", config_parse_string, 0, &name }, - { "D-BUS Service", "Exec", config_parse_string, 0, &exec }, - { "D-BUS Service", "User", config_parse_string, 0, &user }, - { "D-BUS Service", "SystemdService", config_parse_string, 0, &service }, - { }, - }; - - char *p; - int r; - - assert(path); - assert(fname); - - p = strjoina(path, "/", fname); - r = config_parse(NULL, p, NULL, - "D-BUS Service\0", - config_item_table_lookup, table, - true, false, true, NULL); - if (r < 0) - return r; - - if (!name) { - log_warning("Activation file %s lacks name setting, ignoring.", p); - return 0; - } - - if (!service_name_is_valid(name)) { - log_warning("Bus service name %s is not valid, ignoring.", name); - return 0; - } - - if (streq(name, "org.freedesktop.systemd1")) { - log_debug("Skipping %s, identified as systemd.", p); - return 0; - } - - if (service) { - if (!unit_name_is_valid(service, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) { - log_warning("Unit name %s is not valid, ignoring.", service); - return 0; - } - if (!endswith(service, ".service")) { - log_warning("Bus names can only activate services, ignoring %s.", p); - return 0; - } - } else { - if (streq(exec, "/bin/false") || !exec) { - log_warning("Neither service name nor binary path specified, ignoring %s.", p); - return 0; - } - - if (exec[0] != '/') { - log_warning("Exec= in %s does not start with an absolute path, ignoring.", p); - return 0; - } - } - - return create_dbus_files(p, name, service, exec, user, type); -} - -static int parse_dbus_fragments(const char *path, const char *type) { - _cleanup_closedir_ DIR *d = NULL; - struct dirent *de; - int r; - - assert(path); - assert(type); - - d = opendir(path); - if (!d) { - if (errno == -ENOENT) - return 0; - - return log_error_errno(errno, "Failed to enumerate D-Bus activated services: %m"); - } - - r = 0; - FOREACH_DIRENT(de, d, goto fail) { - int q; - - if (!endswith(de->d_name, ".service")) - continue; - - q = add_dbus(path, de->d_name, type); - if (q < 0) - r = q; - } - - return r; - -fail: - return log_error_errno(errno, "Failed to read D-Bus services directory: %m"); -} - -static int link_busnames_target(const char *units) { - const char *f, *t; - - f = strjoina(units, "/" SPECIAL_BUSNAMES_TARGET); - t = strjoina(arg_dest, "/" SPECIAL_BASIC_TARGET ".wants/" SPECIAL_BUSNAMES_TARGET); - - mkdir_parents_label(t, 0755); - if (symlink(f, t) < 0) - return log_error_errno(errno, "Failed to create symlink %s: %m", t); - - return 0; -} - -static int link_compatibility(const char *units) { - const char *f, *t; - - f = strjoina(units, "/systemd-bus-proxyd.socket"); - t = strjoina(arg_dest, "/" SPECIAL_DBUS_SOCKET); - mkdir_parents_label(t, 0755); - if (symlink(f, t) < 0) - return log_error_errno(errno, "Failed to create symlink %s: %m", t); - - f = strjoina(units, "/systemd-bus-proxyd.socket"); - t = strjoina(arg_dest, "/" SPECIAL_SOCKETS_TARGET ".wants/systemd-bus-proxyd.socket"); - mkdir_parents_label(t, 0755); - if (symlink(f, t) < 0) - return log_error_errno(errno, "Failed to create symlink %s: %m", t); - - t = strjoina(arg_dest, "/" SPECIAL_DBUS_SERVICE); - if (symlink("/dev/null", t) < 0) - return log_error_errno(errno, "Failed to mask %s: %m", t); - - return 0; -} - -int main(int argc, char *argv[]) { - const char *path, *type, *units; - int r, q; - - if (argc > 1 && argc != 4) { - log_error("This program takes three or no arguments."); - return EXIT_FAILURE; - } - - if (argc > 1) { - arg_dest = argv[1]; - arg_dest_late = argv[3]; - } - - log_set_target(LOG_TARGET_SAFE); - log_parse_environment(); - log_open(); - - umask(0022); - - if (!is_kdbus_available()) - return 0; - - r = cg_pid_get_owner_uid(0, NULL); - if (r >= 0) { - path = "/usr/share/dbus-1/services"; - type = "session"; - units = USER_DATA_UNIT_PATH; - } else if (r == -ENXIO) { - path = "/usr/share/dbus-1/system-services"; - type = "system"; - units = SYSTEM_DATA_UNIT_PATH; - } else - return log_error_errno(r, "Failed to determine whether we are running as user or system instance: %m"); - - r = parse_dbus_fragments(path, type); - - /* FIXME: One day this should just be pulled in statically from basic.target */ - q = link_busnames_target(units); - if (q < 0) - r = q; - - q = link_compatibility(units); - if (q < 0) - r = q; - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/libsystemd-network/arp-util.c b/src/libsystemd-network/arp-util.c index 4660c7ea09..02028bf28a 100644 --- a/src/libsystemd-network/arp-util.c +++ b/src/libsystemd-network/arp-util.c @@ -79,7 +79,7 @@ int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_ }; union sockaddr_union link = { .ll.sll_family = AF_PACKET, - .ll.sll_protocol = htons(ETH_P_ARP), + .ll.sll_protocol = htobe16(ETH_P_ARP), .ll.sll_ifindex = ifindex, .ll.sll_halen = ETH_ALEN, .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, @@ -112,17 +112,17 @@ static int arp_send_packet(int fd, int ifindex, bool announce) { union sockaddr_union link = { .ll.sll_family = AF_PACKET, - .ll.sll_protocol = htons(ETH_P_ARP), + .ll.sll_protocol = htobe16(ETH_P_ARP), .ll.sll_ifindex = ifindex, .ll.sll_halen = ETH_ALEN, .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, }; struct ether_arp arp = { - .ea_hdr.ar_hrd = htons(ARPHRD_ETHER), /* HTYPE */ - .ea_hdr.ar_pro = htons(ETHERTYPE_IP), /* PTYPE */ + .ea_hdr.ar_hrd = htobe16(ARPHRD_ETHER), /* HTYPE */ + .ea_hdr.ar_pro = htobe16(ETHERTYPE_IP), /* PTYPE */ .ea_hdr.ar_hln = ETH_ALEN, /* HLEN */ .ea_hdr.ar_pln = sizeof(be32_t), /* PLEN */ - .ea_hdr.ar_op = htons(ARPOP_REQUEST), /* REQUEST */ + .ea_hdr.ar_op = htobe16(ARPOP_REQUEST), /* REQUEST */ }; int r; diff --git a/src/libsystemd-network/dhcp-network.c b/src/libsystemd-network/dhcp-network.c index fac25e0fa2..a9f5a0a5de 100644 --- a/src/libsystemd-network/dhcp-network.c +++ b/src/libsystemd-network/dhcp-network.c @@ -107,9 +107,9 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, return -errno; link->ll.sll_family = AF_PACKET; - link->ll.sll_protocol = htons(ETH_P_IP); + link->ll.sll_protocol = htobe16(ETH_P_IP); link->ll.sll_ifindex = ifindex; - link->ll.sll_hatype = htons(arp_type); + link->ll.sll_hatype = htobe16(arp_type); link->ll.sll_halen = mac_addr_len; memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len); diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c index f031760351..59c25598e9 100644 --- a/src/libsystemd-network/lldp-network.c +++ b/src/libsystemd-network/lldp-network.c @@ -57,7 +57,8 @@ int lldp_network_bind_raw_socket(int ifindex) { assert(ifindex > 0); - fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, htons(ETHERTYPE_LLDP)); + fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, + htobe16(ETHERTYPE_LLDP)); if (fd < 0) return -errno; diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index ea4f03df1d..11ee2e252e 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -260,7 +260,7 @@ static int dhcp_server_send_unicast_raw(sd_dhcp_server *server, DHCPPacket *packet, size_t len) { union sockaddr_union link = { .ll.sll_family = AF_PACKET, - .ll.sll_protocol = htons(ETH_P_IP), + .ll.sll_protocol = htobe16(ETH_P_IP), .ll.sll_ifindex = server->ifindex, .ll.sll_halen = ETH_ALEN, }; diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index ea3fe369ce..07b0d7f704 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -307,7 +307,7 @@ static int ndisc_recv(sd_event_source *s, int fd, uint32_t revents, void *userda if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMP && cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) - triple_timestamp_from_realtime(&rt->timestamp, timeval_load(CMSG_DATA(cmsg))); + triple_timestamp_from_realtime(&rt->timestamp, timeval_load((struct timeval*) CMSG_DATA(cmsg))); } if (!triple_timestamp_is_set(&rt->timestamp)) diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index bfe967bfb0..eb042e9c81 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -1987,7 +1987,7 @@ static int busctl_main(sd_bus *bus, int argc, char *argv[]) { } int main(int argc, char *argv[]) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + sd_bus *bus = NULL; int r; log_parse_environment(); @@ -2078,6 +2078,7 @@ int main(int argc, char *argv[]) { r = busctl_main(bus, argc, argv); finish: + sd_bus_flush_close_unref(bus); pager_close(); strv_free(arg_matches); diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c index 4da9dbfd63..b20a7ebb4c 100644 --- a/src/libsystemd/sd-daemon/sd-daemon.c +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -310,12 +310,12 @@ _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint if (l < sizeof(struct sockaddr_in)) return -EINVAL; - return htons(port) == sockaddr.in.sin_port; + return htobe16(port) == sockaddr.in.sin_port; } else { if (l < sizeof(struct sockaddr_in6)) return -EINVAL; - return htons(port) == sockaddr.in6.sin6_port; + return htobe16(port) == sockaddr.in6.sin6_port; } } diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index 3a4bac2ced..566a050432 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -278,6 +278,10 @@ static const NLType rtnl_link_info_data_ip6tnl_types[] = { [IFLA_IPTUN_FLOWINFO] = { .type = NETLINK_TYPE_U32 }, }; +static const NLType rtnl_link_info_data_vrf_types[] = { + [IFLA_VRF_TABLE] = { .type = NETLINK_TYPE_U32 }, +}; + /* these strings must match the .kind entries in the kernel */ static const char* const nl_union_link_info_data_table[] = { [NL_UNION_LINK_INFO_DATA_BOND] = "bond", @@ -298,6 +302,7 @@ static const char* const nl_union_link_info_data_table[] = { [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = "vti", [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] = "vti6", [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = "ip6tnl", + [NL_UNION_LINK_INFO_DATA_VRF] = "vrf", }; DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData); @@ -338,6 +343,9 @@ static const NLTypeSystem rtnl_link_info_data_type_systems[] = { [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ip6tnl_types), .types = rtnl_link_info_data_ip6tnl_types }, + [NL_UNION_LINK_INFO_DATA_VRF] = { .count = ELEMENTSOF(rtnl_link_info_data_vrf_types), + .types = rtnl_link_info_data_vrf_types }, + }; static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = { diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h index ecb20bfcdc..7c0e598b26 100644 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ b/src/libsystemd/sd-netlink/netlink-types.h @@ -86,6 +86,7 @@ typedef enum NLUnionLinkInfoData { NL_UNION_LINK_INFO_DATA_VTI_TUNNEL, NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL, NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL, + NL_UNION_LINK_INFO_DATA_VRF, _NL_UNION_LINK_INFO_DATA_MAX, _NL_UNION_LINK_INFO_DATA_INVALID = -1 } NLUnionLinkInfoData; diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c index f870eba9eb..1f9d16c450 100644 --- a/src/libudev/libudev-monitor.c +++ b/src/libudev/libudev-monitor.c @@ -650,9 +650,9 @@ retry: if (memcmp(buf.raw, "libudev", 8) == 0) { /* udev message needs proper version magic */ - if (buf.nlh.magic != htonl(UDEV_MONITOR_MAGIC)) { + if (buf.nlh.magic != htobe32(UDEV_MONITOR_MAGIC)) { log_debug("unrecognized message signature (%x != %x)", - buf.nlh.magic, htonl(UDEV_MONITOR_MAGIC)); + buf.nlh.magic, htobe32(UDEV_MONITOR_MAGIC)); return NULL; } if (buf.nlh.properties_off+32 > (size_t)buflen) { @@ -715,7 +715,7 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor, ssize_t blen, count; struct udev_monitor_netlink_header nlh = { .prefix = "libudev", - .magic = htonl(UDEV_MONITOR_MAGIC), + .magic = htobe32(UDEV_MONITOR_MAGIC), .header_size = sizeof nlh, }; struct iovec iov[2] = { @@ -736,19 +736,19 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor, /* fill in versioned header */ val = udev_device_get_subsystem(udev_device); - nlh.filter_subsystem_hash = htonl(util_string_hash32(val)); + nlh.filter_subsystem_hash = htobe32(util_string_hash32(val)); val = udev_device_get_devtype(udev_device); if (val != NULL) - nlh.filter_devtype_hash = htonl(util_string_hash32(val)); + nlh.filter_devtype_hash = htobe32(util_string_hash32(val)); /* add tag bloom filter */ tag_bloom_bits = 0; udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device)) tag_bloom_bits |= util_string_bloom64(udev_list_entry_get_name(list_entry)); if (tag_bloom_bits > 0) { - nlh.filter_tag_bloom_hi = htonl(tag_bloom_bits >> 32); - nlh.filter_tag_bloom_lo = htonl(tag_bloom_bits & 0xffffffff); + nlh.filter_tag_bloom_hi = htobe32(tag_bloom_bits >> 32); + nlh.filter_tag_bloom_lo = htobe32(tag_bloom_bits & 0xffffffff); } /* add properties list */ diff --git a/src/locale/keymap-util.c b/src/locale/keymap-util.c new file mode 100644 index 0000000000..a6bcd1ad54 --- /dev/null +++ b/src/locale/keymap-util.c @@ -0,0 +1,724 @@ +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <errno.h> +#include <string.h> +#include <unistd.h> + +#include "def.h" +#include "env-util.h" +#include "fd-util.h" +#include "fileio-label.h" +#include "fileio.h" +#include "keymap-util.h" +#include "locale-util.h" +#include "macro.h" +#include "mkdir.h" +#include "string-util.h" +#include "strv.h" + +static bool startswith_comma(const char *s, const char *prefix) { + s = startswith(s, prefix); + if (!s) + return false; + + return *s == ',' || *s == '\0'; +} + +static const char* strnulldash(const char *s) { + return isempty(s) || streq(s, "-") ? NULL : s; +} + +static const char* systemd_kbd_model_map(void) { + const char* s; + + s = getenv("SYSTEMD_KBD_MODEL_MAP"); + if (s) + return s; + + return SYSTEMD_KBD_MODEL_MAP; +} + +static const char* systemd_language_fallback_map(void) { + const char* s; + + s = getenv("SYSTEMD_LANGUAGE_FALLBACK_MAP"); + if (s) + return s; + + return SYSTEMD_LANGUAGE_FALLBACK_MAP; +} + +static void context_free_x11(Context *c) { + c->x11_layout = mfree(c->x11_layout); + c->x11_options = mfree(c->x11_options); + c->x11_model = mfree(c->x11_model); + c->x11_variant = mfree(c->x11_variant); +} + +static void context_free_vconsole(Context *c) { + c->vc_keymap = mfree(c->vc_keymap); + c->vc_keymap_toggle = mfree(c->vc_keymap_toggle); +} + +static void context_free_locale(Context *c) { + int p; + + for (p = 0; p < _VARIABLE_LC_MAX; p++) + c->locale[p] = mfree(c->locale[p]); +} + +void context_free(Context *c) { + context_free_locale(c); + context_free_x11(c); + context_free_vconsole(c); +}; + +void locale_simplify(Context *c) { + int p; + + for (p = VARIABLE_LANG+1; p < _VARIABLE_LC_MAX; p++) + if (isempty(c->locale[p]) || streq_ptr(c->locale[VARIABLE_LANG], c->locale[p])) + c->locale[p] = mfree(c->locale[p]); +} + +static int locale_read_data(Context *c) { + int r; + + context_free_locale(c); + + r = parse_env_file("/etc/locale.conf", NEWLINE, + "LANG", &c->locale[VARIABLE_LANG], + "LANGUAGE", &c->locale[VARIABLE_LANGUAGE], + "LC_CTYPE", &c->locale[VARIABLE_LC_CTYPE], + "LC_NUMERIC", &c->locale[VARIABLE_LC_NUMERIC], + "LC_TIME", &c->locale[VARIABLE_LC_TIME], + "LC_COLLATE", &c->locale[VARIABLE_LC_COLLATE], + "LC_MONETARY", &c->locale[VARIABLE_LC_MONETARY], + "LC_MESSAGES", &c->locale[VARIABLE_LC_MESSAGES], + "LC_PAPER", &c->locale[VARIABLE_LC_PAPER], + "LC_NAME", &c->locale[VARIABLE_LC_NAME], + "LC_ADDRESS", &c->locale[VARIABLE_LC_ADDRESS], + "LC_TELEPHONE", &c->locale[VARIABLE_LC_TELEPHONE], + "LC_MEASUREMENT", &c->locale[VARIABLE_LC_MEASUREMENT], + "LC_IDENTIFICATION", &c->locale[VARIABLE_LC_IDENTIFICATION], + NULL); + + if (r == -ENOENT) { + int p; + + /* Fill in what we got passed from systemd. */ + for (p = 0; p < _VARIABLE_LC_MAX; p++) { + const char *name; + + name = locale_variable_to_string(p); + assert(name); + + r = free_and_strdup(&c->locale[p], empty_to_null(getenv(name))); + if (r < 0) + return r; + } + + r = 0; + } + + locale_simplify(c); + return r; +} + +static int vconsole_read_data(Context *c) { + int r; + + context_free_vconsole(c); + + r = parse_env_file("/etc/vconsole.conf", NEWLINE, + "KEYMAP", &c->vc_keymap, + "KEYMAP_TOGGLE", &c->vc_keymap_toggle, + NULL); + + if (r < 0 && r != -ENOENT) + return r; + + return 0; +} + +static int x11_read_data(Context *c) { + _cleanup_fclose_ FILE *f; + char line[LINE_MAX]; + bool in_section = false; + int r; + + context_free_x11(c); + + f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re"); + if (!f) + return errno == ENOENT ? 0 : -errno; + + while (fgets(line, sizeof(line), f)) { + char *l; + + char_array_0(line); + l = strstrip(line); + + if (l[0] == 0 || l[0] == '#') + continue; + + if (in_section && first_word(l, "Option")) { + _cleanup_strv_free_ char **a = NULL; + + r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES); + if (r < 0) + return r; + + if (strv_length(a) == 3) { + char **p = NULL; + + if (streq(a[1], "XkbLayout")) + p = &c->x11_layout; + else if (streq(a[1], "XkbModel")) + p = &c->x11_model; + else if (streq(a[1], "XkbVariant")) + p = &c->x11_variant; + else if (streq(a[1], "XkbOptions")) + p = &c->x11_options; + + if (p) { + free(*p); + *p = a[2]; + a[2] = NULL; + } + } + + } else if (!in_section && first_word(l, "Section")) { + _cleanup_strv_free_ char **a = NULL; + + r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES); + if (r < 0) + return -ENOMEM; + + if (strv_length(a) == 2 && streq(a[1], "InputClass")) + in_section = true; + + } else if (in_section && first_word(l, "EndSection")) + in_section = false; + } + + return 0; +} + +int context_read_data(Context *c) { + int r, q, p; + + r = locale_read_data(c); + q = vconsole_read_data(c); + p = x11_read_data(c); + + return r < 0 ? r : q < 0 ? q : p; +} + +int locale_write_data(Context *c, char ***settings) { + int r, p; + _cleanup_strv_free_ char **l = NULL; + + /* Set values will be returned as strv in *settings on success. */ + + r = load_env_file(NULL, "/etc/locale.conf", NULL, &l); + if (r < 0 && r != -ENOENT) + return r; + + for (p = 0; p < _VARIABLE_LC_MAX; p++) { + _cleanup_free_ char *t = NULL; + char **u; + const char *name; + + name = locale_variable_to_string(p); + assert(name); + + if (isempty(c->locale[p])) { + l = strv_env_unset(l, name); + continue; + } + + if (asprintf(&t, "%s=%s", name, c->locale[p]) < 0) + return -ENOMEM; + + u = strv_env_set(l, t); + if (!u) + return -ENOMEM; + + strv_free(l); + l = u; + } + + if (strv_isempty(l)) { + if (unlink("/etc/locale.conf") < 0) + return errno == ENOENT ? 0 : -errno; + + return 0; + } + + r = write_env_file_label("/etc/locale.conf", l); + if (r < 0) + return r; + + *settings = l; + l = NULL; + return 0; +} + +int vconsole_write_data(Context *c) { + int r; + _cleanup_strv_free_ char **l = NULL; + + r = load_env_file(NULL, "/etc/vconsole.conf", NULL, &l); + if (r < 0 && r != -ENOENT) + return r; + + if (isempty(c->vc_keymap)) + l = strv_env_unset(l, "KEYMAP"); + else { + _cleanup_free_ char *s = NULL; + char **u; + + s = strappend("KEYMAP=", c->vc_keymap); + if (!s) + return -ENOMEM; + + u = strv_env_set(l, s); + if (!u) + return -ENOMEM; + + strv_free(l); + l = u; + } + + if (isempty(c->vc_keymap_toggle)) + l = strv_env_unset(l, "KEYMAP_TOGGLE"); + else { + _cleanup_free_ char *s = NULL; + char **u; + + s = strappend("KEYMAP_TOGGLE=", c->vc_keymap_toggle); + if (!s) + return -ENOMEM; + + u = strv_env_set(l, s); + if (!u) + return -ENOMEM; + + strv_free(l); + l = u; + } + + if (strv_isempty(l)) { + if (unlink("/etc/vconsole.conf") < 0) + return errno == ENOENT ? 0 : -errno; + + return 0; + } + + return write_env_file_label("/etc/vconsole.conf", l); +} + +int x11_write_data(Context *c) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *temp_path = NULL; + int r; + + if (isempty(c->x11_layout) && + isempty(c->x11_model) && + isempty(c->x11_variant) && + isempty(c->x11_options)) { + + if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) + return errno == ENOENT ? 0 : -errno; + + return 0; + } + + mkdir_p_label("/etc/X11/xorg.conf.d", 0755); + + r = fopen_temporary("/etc/X11/xorg.conf.d/00-keyboard.conf", &f, &temp_path); + if (r < 0) + return r; + + fchmod(fileno(f), 0644); + + fputs("# Read and parsed by systemd-localed. It's probably wise not to edit this file\n" + "# manually too freely.\n" + "Section \"InputClass\"\n" + " Identifier \"system-keyboard\"\n" + " MatchIsKeyboard \"on\"\n", f); + + if (!isempty(c->x11_layout)) + fprintf(f, " Option \"XkbLayout\" \"%s\"\n", c->x11_layout); + + if (!isempty(c->x11_model)) + fprintf(f, " Option \"XkbModel\" \"%s\"\n", c->x11_model); + + if (!isempty(c->x11_variant)) + fprintf(f, " Option \"XkbVariant\" \"%s\"\n", c->x11_variant); + + if (!isempty(c->x11_options)) + fprintf(f, " Option \"XkbOptions\" \"%s\"\n", c->x11_options); + + fputs("EndSection\n", f); + + r = fflush_and_check(f); + if (r < 0) + goto fail; + + if (rename(temp_path, "/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) { + r = -errno; + goto fail; + } + + return 0; + +fail: + (void) unlink("/etc/X11/xorg.conf.d/00-keyboard.conf"); + + if (temp_path) + (void) unlink(temp_path); + + return r; +} + +static int read_next_mapping(const char* filename, + unsigned min_fields, unsigned max_fields, + FILE *f, unsigned *n, char ***a) { + assert(f); + assert(n); + assert(a); + + for (;;) { + char line[LINE_MAX]; + char *l, **b; + int r; + size_t length; + + errno = 0; + if (!fgets(line, sizeof(line), f)) { + + if (ferror(f)) + return errno > 0 ? -errno : -EIO; + + return 0; + } + + (*n)++; + + l = strstrip(line); + if (l[0] == 0 || l[0] == '#') + continue; + + r = strv_split_extract(&b, l, WHITESPACE, EXTRACT_QUOTES); + if (r < 0) + return r; + + length = strv_length(b); + if (length < min_fields || length > max_fields) { + log_error("Invalid line %s:%u, ignoring.", filename, *n); + strv_free(b); + continue; + + } + + *a = b; + return 1; + } +} + +int vconsole_convert_to_x11(Context *c) { + const char *map; + int modified = -1; + + map = systemd_kbd_model_map(); + + if (isempty(c->vc_keymap)) { + modified = + !isempty(c->x11_layout) || + !isempty(c->x11_model) || + !isempty(c->x11_variant) || + !isempty(c->x11_options); + + context_free_x11(c); + } else { + _cleanup_fclose_ FILE *f = NULL; + unsigned n = 0; + + f = fopen(map, "re"); + if (!f) + return -errno; + + for (;;) { + _cleanup_strv_free_ char **a = NULL; + int r; + + r = read_next_mapping(map, 5, UINT_MAX, f, &n, &a); + if (r < 0) + return r; + if (r == 0) + break; + + if (!streq(c->vc_keymap, a[0])) + continue; + + if (!streq_ptr(c->x11_layout, strnulldash(a[1])) || + !streq_ptr(c->x11_model, strnulldash(a[2])) || + !streq_ptr(c->x11_variant, strnulldash(a[3])) || + !streq_ptr(c->x11_options, strnulldash(a[4]))) { + + if (free_and_strdup(&c->x11_layout, strnulldash(a[1])) < 0 || + free_and_strdup(&c->x11_model, strnulldash(a[2])) < 0 || + free_and_strdup(&c->x11_variant, strnulldash(a[3])) < 0 || + free_and_strdup(&c->x11_options, strnulldash(a[4])) < 0) + return -ENOMEM; + + modified = true; + } + + break; + } + } + + if (modified > 0) + log_info("Changing X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'", + strempty(c->x11_layout), + strempty(c->x11_model), + strempty(c->x11_variant), + strempty(c->x11_options)); + else if (modified < 0) + log_notice("X11 keyboard layout was not modified: no conversion found for \"%s\".", + c->vc_keymap); + else + log_debug("X11 keyboard layout did not need to be modified."); + + return modified > 0; +} + +int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap) { + const char *dir; + _cleanup_free_ char *n; + + if (x11_variant) + n = strjoin(x11_layout, "-", x11_variant, NULL); + else + n = strdup(x11_layout); + if (!n) + return -ENOMEM; + + NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) { + _cleanup_free_ char *p = NULL, *pz = NULL; + bool uncompressed; + + p = strjoin(dir, "xkb/", n, ".map", NULL); + pz = strjoin(dir, "xkb/", n, ".map.gz", NULL); + if (!p || !pz) + return -ENOMEM; + + uncompressed = access(p, F_OK) == 0; + if (uncompressed || access(pz, F_OK) == 0) { + log_debug("Found converted keymap %s at %s", + n, uncompressed ? p : pz); + + *new_keymap = n; + n = NULL; + return 1; + } + } + + return 0; +} + +int find_legacy_keymap(Context *c, char **new_keymap) { + const char *map; + _cleanup_fclose_ FILE *f = NULL; + unsigned n = 0; + unsigned best_matching = 0; + int r; + + assert(!isempty(c->x11_layout)); + + map = systemd_kbd_model_map(); + + f = fopen(map, "re"); + if (!f) + return -errno; + + for (;;) { + _cleanup_strv_free_ char **a = NULL; + unsigned matching = 0; + + r = read_next_mapping(map, 5, UINT_MAX, f, &n, &a); + if (r < 0) + return r; + if (r == 0) + break; + + /* Determine how well matching this entry is */ + if (streq(c->x11_layout, a[1])) + /* If we got an exact match, this is best */ + matching = 10; + else { + /* We have multiple X layouts, look for an + * entry that matches our key with everything + * but the first layout stripped off. */ + if (startswith_comma(c->x11_layout, a[1])) + matching = 5; + else { + char *x; + + /* If that didn't work, strip off the + * other layouts from the entry, too */ + x = strndupa(a[1], strcspn(a[1], ",")); + if (startswith_comma(c->x11_layout, x)) + matching = 1; + } + } + + if (matching > 0) { + if (isempty(c->x11_model) || streq_ptr(c->x11_model, a[2])) { + matching++; + + if (streq_ptr(c->x11_variant, a[3])) { + matching++; + + if (streq_ptr(c->x11_options, a[4])) + matching++; + } + } + } + + /* The best matching entry so far, then let's save that */ + if (matching >= MAX(best_matching, 1u)) { + log_debug("Found legacy keymap %s with score %u", + a[0], matching); + + if (matching > best_matching) { + best_matching = matching; + + r = free_and_strdup(new_keymap, a[0]); + if (r < 0) + return r; + } + } + } + + if (best_matching < 10 && c->x11_layout) { + /* The best match is only the first part of the X11 + * keymap. Check if we have a converted map which + * matches just the first layout. + */ + char *l, *v = NULL, *converted; + + l = strndupa(c->x11_layout, strcspn(c->x11_layout, ",")); + if (c->x11_variant) + v = strndupa(c->x11_variant, strcspn(c->x11_variant, ",")); + r = find_converted_keymap(l, v, &converted); + if (r < 0) + return r; + if (r > 0) { + free(*new_keymap); + *new_keymap = converted; + } + } + + return (bool) *new_keymap; +} + +int find_language_fallback(const char *lang, char **language) { + const char *map; + _cleanup_fclose_ FILE *f = NULL; + unsigned n = 0; + + assert(lang); + assert(language); + + map = systemd_language_fallback_map(); + + f = fopen(map, "re"); + if (!f) + return -errno; + + for (;;) { + _cleanup_strv_free_ char **a = NULL; + int r; + + r = read_next_mapping(map, 2, 2, f, &n, &a); + if (r <= 0) + return r; + + if (streq(lang, a[0])) { + assert(strv_length(a) == 2); + *language = a[1]; + a[1] = NULL; + return 1; + } + } + + assert_not_reached("should not be here"); +} + +int x11_convert_to_vconsole(Context *c) { + bool modified = false; + + if (isempty(c->x11_layout)) { + modified = + !isempty(c->vc_keymap) || + !isempty(c->vc_keymap_toggle); + + context_free_vconsole(c); + } else { + char *new_keymap = NULL; + int r; + + r = find_converted_keymap(c->x11_layout, c->x11_variant, &new_keymap); + if (r < 0) + return r; + else if (r == 0) { + r = find_legacy_keymap(c, &new_keymap); + if (r < 0) + return r; + } + if (r == 0) + /* We search for layout-variant match first, but then we also look + * for anything which matches just the layout. So it's accurate to say + * that we couldn't find anything which matches the layout. */ + log_notice("No conversion to virtual console map found for \"%s\".", + c->x11_layout); + + if (!streq_ptr(c->vc_keymap, new_keymap)) { + free(c->vc_keymap); + c->vc_keymap = new_keymap; + c->vc_keymap_toggle = mfree(c->vc_keymap_toggle); + modified = true; + } else + free(new_keymap); + } + + if (modified) + log_info("Changing virtual console keymap to '%s' toggle '%s'", + strempty(c->vc_keymap), strempty(c->vc_keymap_toggle)); + else + log_debug("Virtual console keymap was not modified."); + + return modified; +} diff --git a/src/locale/keymap-util.h b/src/locale/keymap-util.h new file mode 100644 index 0000000000..20ef2a4a34 --- /dev/null +++ b/src/locale/keymap-util.h @@ -0,0 +1,46 @@ +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "locale-util.h" + +typedef struct Context { + char *locale[_VARIABLE_LC_MAX]; + + char *x11_layout; + char *x11_model; + char *x11_variant; + char *x11_options; + + char *vc_keymap; + char *vc_keymap_toggle; +} Context; + +int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap); +int find_legacy_keymap(Context *c, char **new_keymap); +int find_language_fallback(const char *lang, char **language); + +int context_read_data(Context *c); +void context_free(Context *c); +int vconsole_convert_to_x11(Context *c); +int vconsole_write_data(Context *c); +int x11_convert_to_vconsole(Context *c); +int x11_write_data(Context *c); +void locale_simplify(Context *c); +int locale_write_data(Context *c, char ***settings); diff --git a/src/locale/localectl.c b/src/locale/localectl.c index 4865335349..81afb4909f 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -656,7 +656,7 @@ static int localectl_main(sd_bus *bus, int argc, char *argv[]) { } int main(int argc, char*argv[]) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); @@ -676,6 +676,7 @@ int main(int argc, char*argv[]) { r = localectl_main(bus, argc, argv); finish: + sd_bus_flush_close_unref(bus); pager_close(); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/src/locale/localed.c b/src/locale/localed.c index 6af59fc830..298f176e40 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -34,288 +34,16 @@ #include "bus-message.h" #include "bus-util.h" #include "def.h" -#include "env-util.h" -#include "fd-util.h" -#include "fileio-label.h" -#include "fileio.h" +#include "keymap-util.h" #include "locale-util.h" -#include "mkdir.h" +#include "macro.h" #include "path-util.h" #include "selinux-util.h" +#include "string-util.h" #include "strv.h" #include "user-util.h" -#include "util.h" - -enum { - /* We don't list LC_ALL here on purpose. People should be - * using LANG instead. */ - LOCALE_LANG, - LOCALE_LANGUAGE, - LOCALE_LC_CTYPE, - LOCALE_LC_NUMERIC, - LOCALE_LC_TIME, - LOCALE_LC_COLLATE, - LOCALE_LC_MONETARY, - LOCALE_LC_MESSAGES, - LOCALE_LC_PAPER, - LOCALE_LC_NAME, - LOCALE_LC_ADDRESS, - LOCALE_LC_TELEPHONE, - LOCALE_LC_MEASUREMENT, - LOCALE_LC_IDENTIFICATION, - _LOCALE_MAX -}; - -static const char * const names[_LOCALE_MAX] = { - [LOCALE_LANG] = "LANG", - [LOCALE_LANGUAGE] = "LANGUAGE", - [LOCALE_LC_CTYPE] = "LC_CTYPE", - [LOCALE_LC_NUMERIC] = "LC_NUMERIC", - [LOCALE_LC_TIME] = "LC_TIME", - [LOCALE_LC_COLLATE] = "LC_COLLATE", - [LOCALE_LC_MONETARY] = "LC_MONETARY", - [LOCALE_LC_MESSAGES] = "LC_MESSAGES", - [LOCALE_LC_PAPER] = "LC_PAPER", - [LOCALE_LC_NAME] = "LC_NAME", - [LOCALE_LC_ADDRESS] = "LC_ADDRESS", - [LOCALE_LC_TELEPHONE] = "LC_TELEPHONE", - [LOCALE_LC_MEASUREMENT] = "LC_MEASUREMENT", - [LOCALE_LC_IDENTIFICATION] = "LC_IDENTIFICATION" -}; - -typedef struct Context { - char *locale[_LOCALE_MAX]; - - char *x11_layout; - char *x11_model; - char *x11_variant; - char *x11_options; - - char *vc_keymap; - char *vc_keymap_toggle; - - Hashmap *polkit_registry; -} Context; - -static bool startswith_comma(const char *s, const char *prefix) { - const char *t; - - return s && (t = startswith(s, prefix)) && (*t == ','); -} - -static void context_free_x11(Context *c) { - c->x11_layout = mfree(c->x11_layout); - c->x11_options = mfree(c->x11_options); - c->x11_model = mfree(c->x11_model); - c->x11_variant = mfree(c->x11_variant); -} - -static void context_free_vconsole(Context *c) { - c->vc_keymap = mfree(c->vc_keymap); - c->vc_keymap_toggle = mfree(c->vc_keymap_toggle); -} - -static void context_free_locale(Context *c) { - int p; - - for (p = 0; p < _LOCALE_MAX; p++) - c->locale[p] = mfree(c->locale[p]); -} - -static void context_free(Context *c) { - context_free_locale(c); - context_free_x11(c); - context_free_vconsole(c); - - bus_verify_polkit_async_registry_free(c->polkit_registry); -}; - -static void locale_simplify(Context *c) { - int p; - - for (p = LOCALE_LANG+1; p < _LOCALE_MAX; p++) - if (isempty(c->locale[p]) || streq_ptr(c->locale[LOCALE_LANG], c->locale[p])) - c->locale[p] = mfree(c->locale[p]); -} - -static int locale_read_data(Context *c) { - int r; - - context_free_locale(c); - - r = parse_env_file("/etc/locale.conf", NEWLINE, - "LANG", &c->locale[LOCALE_LANG], - "LANGUAGE", &c->locale[LOCALE_LANGUAGE], - "LC_CTYPE", &c->locale[LOCALE_LC_CTYPE], - "LC_NUMERIC", &c->locale[LOCALE_LC_NUMERIC], - "LC_TIME", &c->locale[LOCALE_LC_TIME], - "LC_COLLATE", &c->locale[LOCALE_LC_COLLATE], - "LC_MONETARY", &c->locale[LOCALE_LC_MONETARY], - "LC_MESSAGES", &c->locale[LOCALE_LC_MESSAGES], - "LC_PAPER", &c->locale[LOCALE_LC_PAPER], - "LC_NAME", &c->locale[LOCALE_LC_NAME], - "LC_ADDRESS", &c->locale[LOCALE_LC_ADDRESS], - "LC_TELEPHONE", &c->locale[LOCALE_LC_TELEPHONE], - "LC_MEASUREMENT", &c->locale[LOCALE_LC_MEASUREMENT], - "LC_IDENTIFICATION", &c->locale[LOCALE_LC_IDENTIFICATION], - NULL); - - if (r == -ENOENT) { - int p; - - /* Fill in what we got passed from systemd. */ - for (p = 0; p < _LOCALE_MAX; p++) { - assert(names[p]); - - r = free_and_strdup(&c->locale[p], empty_to_null(getenv(names[p]))); - if (r < 0) - return r; - } - - r = 0; - } - - locale_simplify(c); - return r; -} - -static int vconsole_read_data(Context *c) { - int r; - context_free_vconsole(c); - - r = parse_env_file("/etc/vconsole.conf", NEWLINE, - "KEYMAP", &c->vc_keymap, - "KEYMAP_TOGGLE", &c->vc_keymap_toggle, - NULL); - - if (r < 0 && r != -ENOENT) - return r; - - return 0; -} - -static int x11_read_data(Context *c) { - _cleanup_fclose_ FILE *f; - char line[LINE_MAX]; - bool in_section = false; - int r; - - context_free_x11(c); - - f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re"); - if (!f) - return errno == ENOENT ? 0 : -errno; - - while (fgets(line, sizeof(line), f)) { - char *l; - - char_array_0(line); - l = strstrip(line); - - if (l[0] == 0 || l[0] == '#') - continue; - - if (in_section && first_word(l, "Option")) { - _cleanup_strv_free_ char **a = NULL; - - r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES); - if (r < 0) - return r; - - if (strv_length(a) == 3) { - char **p = NULL; - - if (streq(a[1], "XkbLayout")) - p = &c->x11_layout; - else if (streq(a[1], "XkbModel")) - p = &c->x11_model; - else if (streq(a[1], "XkbVariant")) - p = &c->x11_variant; - else if (streq(a[1], "XkbOptions")) - p = &c->x11_options; - - if (p) { - free(*p); - *p = a[2]; - a[2] = NULL; - } - } - - } else if (!in_section && first_word(l, "Section")) { - _cleanup_strv_free_ char **a = NULL; - - r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES); - if (r < 0) - return -ENOMEM; - - if (strv_length(a) == 2 && streq(a[1], "InputClass")) - in_section = true; - - } else if (in_section && first_word(l, "EndSection")) - in_section = false; - } - - return 0; -} - -static int context_read_data(Context *c) { - int r, q, p; - - r = locale_read_data(c); - q = vconsole_read_data(c); - p = x11_read_data(c); - - return r < 0 ? r : q < 0 ? q : p; -} - -static int locale_write_data(Context *c, char ***settings) { - int r, p; - _cleanup_strv_free_ char **l = NULL; - - /* Set values will be returned as strv in *settings on success. */ - - r = load_env_file(NULL, "/etc/locale.conf", NULL, &l); - if (r < 0 && r != -ENOENT) - return r; - - for (p = 0; p < _LOCALE_MAX; p++) { - _cleanup_free_ char *t = NULL; - char **u; - - assert(names[p]); - - if (isempty(c->locale[p])) { - l = strv_env_unset(l, names[p]); - continue; - } - - if (asprintf(&t, "%s=%s", names[p], c->locale[p]) < 0) - return -ENOMEM; - - u = strv_env_set(l, t); - if (!u) - return -ENOMEM; - - strv_free(l); - l = u; - } - - if (strv_isempty(l)) { - if (unlink("/etc/locale.conf") < 0) - return errno == ENOENT ? 0 : -errno; - - return 0; - } - - r = write_env_file_label("/etc/locale.conf", l); - if (r < 0) - return r; - - *settings = l; - l = NULL; - return 0; -} +static Hashmap *polkit_registry = NULL; static int locale_update_system_manager(Context *c, sd_bus *bus) { _cleanup_free_ char **l_unset = NULL; @@ -327,30 +55,33 @@ static int locale_update_system_manager(Context *c, sd_bus *bus) { assert(bus); - l_unset = new0(char*, _LOCALE_MAX); + l_unset = new0(char*, _VARIABLE_LC_MAX); if (!l_unset) return -ENOMEM; - l_set = new0(char*, _LOCALE_MAX); + l_set = new0(char*, _VARIABLE_LC_MAX); if (!l_set) return -ENOMEM; - for (p = 0, c_set = 0, c_unset = 0; p < _LOCALE_MAX; p++) { - assert(names[p]); + for (p = 0, c_set = 0, c_unset = 0; p < _VARIABLE_LC_MAX; p++) { + const char *name; + + name = locale_variable_to_string(p); + assert(name); if (isempty(c->locale[p])) - l_unset[c_set++] = (char*) names[p]; + l_unset[c_set++] = (char*) name; else { char *s; - if (asprintf(&s, "%s=%s", names[p], c->locale[p]) < 0) + if (asprintf(&s, "%s=%s", name, c->locale[p]) < 0) return -ENOMEM; l_set[c_unset++] = s; } } - assert(c_set + c_unset == _LOCALE_MAX); + assert(c_set + c_unset == _VARIABLE_LC_MAX); r = sd_bus_message_new_method_call(bus, &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -374,124 +105,6 @@ static int locale_update_system_manager(Context *c, sd_bus *bus) { return 0; } -static int vconsole_write_data(Context *c) { - int r; - _cleanup_strv_free_ char **l = NULL; - - r = load_env_file(NULL, "/etc/vconsole.conf", NULL, &l); - if (r < 0 && r != -ENOENT) - return r; - - if (isempty(c->vc_keymap)) - l = strv_env_unset(l, "KEYMAP"); - else { - _cleanup_free_ char *s = NULL; - char **u; - - s = strappend("KEYMAP=", c->vc_keymap); - if (!s) - return -ENOMEM; - - u = strv_env_set(l, s); - if (!u) - return -ENOMEM; - - strv_free(l); - l = u; - } - - if (isempty(c->vc_keymap_toggle)) - l = strv_env_unset(l, "KEYMAP_TOGGLE"); - else { - _cleanup_free_ char *s = NULL; - char **u; - - s = strappend("KEYMAP_TOGGLE=", c->vc_keymap_toggle); - if (!s) - return -ENOMEM; - - u = strv_env_set(l, s); - if (!u) - return -ENOMEM; - - strv_free(l); - l = u; - } - - if (strv_isempty(l)) { - if (unlink("/etc/vconsole.conf") < 0) - return errno == ENOENT ? 0 : -errno; - - return 0; - } - - return write_env_file_label("/etc/vconsole.conf", l); -} - -static int x11_write_data(Context *c) { - _cleanup_fclose_ FILE *f = NULL; - _cleanup_free_ char *temp_path = NULL; - int r; - - if (isempty(c->x11_layout) && - isempty(c->x11_model) && - isempty(c->x11_variant) && - isempty(c->x11_options)) { - - if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) - return errno == ENOENT ? 0 : -errno; - - return 0; - } - - mkdir_p_label("/etc/X11/xorg.conf.d", 0755); - - r = fopen_temporary("/etc/X11/xorg.conf.d/00-keyboard.conf", &f, &temp_path); - if (r < 0) - return r; - - fchmod(fileno(f), 0644); - - fputs("# Read and parsed by systemd-localed. It's probably wise not to edit this file\n" - "# manually too freely.\n" - "Section \"InputClass\"\n" - " Identifier \"system-keyboard\"\n" - " MatchIsKeyboard \"on\"\n", f); - - if (!isempty(c->x11_layout)) - fprintf(f, " Option \"XkbLayout\" \"%s\"\n", c->x11_layout); - - if (!isempty(c->x11_model)) - fprintf(f, " Option \"XkbModel\" \"%s\"\n", c->x11_model); - - if (!isempty(c->x11_variant)) - fprintf(f, " Option \"XkbVariant\" \"%s\"\n", c->x11_variant); - - if (!isempty(c->x11_options)) - fprintf(f, " Option \"XkbOptions\" \"%s\"\n", c->x11_options); - - fputs("EndSection\n", f); - - r = fflush_and_check(f); - if (r < 0) - goto fail; - - if (rename(temp_path, "/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) { - r = -errno; - goto fail; - } - - return 0; - -fail: - (void) unlink("/etc/X11/xorg.conf.d/00-keyboard.conf"); - - if (temp_path) - (void) unlink(temp_path); - - return r; -} - static int vconsole_reload(sd_bus *bus) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; @@ -512,337 +125,48 @@ static int vconsole_reload(sd_bus *bus) { return r; } -static const char* strnulldash(const char *s) { - return isempty(s) || streq(s, "-") ? NULL : s; -} - -static int read_next_mapping(const char* filename, - unsigned min_fields, unsigned max_fields, - FILE *f, unsigned *n, char ***a) { - assert(f); - assert(n); - assert(a); - - for (;;) { - char line[LINE_MAX]; - char *l, **b; - int r; - size_t length; - - errno = 0; - if (!fgets(line, sizeof(line), f)) { - - if (ferror(f)) - return errno > 0 ? -errno : -EIO; - - return 0; - } - - (*n)++; - - l = strstrip(line); - if (l[0] == 0 || l[0] == '#') - continue; - - r = strv_split_extract(&b, l, WHITESPACE, EXTRACT_QUOTES); - if (r < 0) - return r; - - length = strv_length(b); - if (length < min_fields || length > max_fields) { - log_error("Invalid line %s:%u, ignoring.", filename, *n); - strv_free(b); - continue; - - } - - *a = b; - return 1; - } -} - -static int vconsole_convert_to_x11(Context *c, sd_bus *bus) { - bool modified = false; - - assert(bus); - - if (isempty(c->vc_keymap)) { - - modified = - !isempty(c->x11_layout) || - !isempty(c->x11_model) || - !isempty(c->x11_variant) || - !isempty(c->x11_options); - - context_free_x11(c); - } else { - _cleanup_fclose_ FILE *f = NULL; - unsigned n = 0; - - f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); - if (!f) - return -errno; - - for (;;) { - _cleanup_strv_free_ char **a = NULL; - int r; - - r = read_next_mapping(SYSTEMD_KBD_MODEL_MAP, 5, UINT_MAX, f, &n, &a); - if (r < 0) - return r; - if (r == 0) - break; - - if (!streq(c->vc_keymap, a[0])) - continue; - - if (!streq_ptr(c->x11_layout, strnulldash(a[1])) || - !streq_ptr(c->x11_model, strnulldash(a[2])) || - !streq_ptr(c->x11_variant, strnulldash(a[3])) || - !streq_ptr(c->x11_options, strnulldash(a[4]))) { - - if (free_and_strdup(&c->x11_layout, strnulldash(a[1])) < 0 || - free_and_strdup(&c->x11_model, strnulldash(a[2])) < 0 || - free_and_strdup(&c->x11_variant, strnulldash(a[3])) < 0 || - free_and_strdup(&c->x11_options, strnulldash(a[4])) < 0) - return -ENOMEM; - - modified = true; - } - - break; - } - } - - if (modified) { - int r; - - r = x11_write_data(c); - if (r < 0) - return log_error_errno(r, "Failed to set X11 keyboard layout: %m"); - - log_info("Changed X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'", - strempty(c->x11_layout), - strempty(c->x11_model), - strempty(c->x11_variant), - strempty(c->x11_options)); - - sd_bus_emit_properties_changed(bus, - "/org/freedesktop/locale1", - "org.freedesktop.locale1", - "X11Layout", "X11Model", "X11Variant", "X11Options", NULL); - } else - log_debug("X11 keyboard layout was not modified."); - - return 0; -} - -static int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap) { - const char *dir; - _cleanup_free_ char *n; - - if (x11_variant) - n = strjoin(x11_layout, "-", x11_variant, NULL); - else - n = strdup(x11_layout); - if (!n) - return -ENOMEM; - - NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) { - _cleanup_free_ char *p = NULL, *pz = NULL; - bool uncompressed; - - p = strjoin(dir, "xkb/", n, ".map", NULL); - pz = strjoin(dir, "xkb/", n, ".map.gz", NULL); - if (!p || !pz) - return -ENOMEM; - - uncompressed = access(p, F_OK) == 0; - if (uncompressed || access(pz, F_OK) == 0) { - log_debug("Found converted keymap %s at %s", - n, uncompressed ? p : pz); - - *new_keymap = n; - n = NULL; - return 1; - } - } - - return 0; -} - -static int find_legacy_keymap(Context *c, char **new_keymap) { - _cleanup_fclose_ FILE *f; - unsigned n = 0; - unsigned best_matching = 0; +static int vconsole_convert_to_x11_and_emit(Context *c, sd_bus *bus) { int r; - f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); - if (!f) - return -errno; - - for (;;) { - _cleanup_strv_free_ char **a = NULL; - unsigned matching = 0; - - r = read_next_mapping(SYSTEMD_KBD_MODEL_MAP, 5, UINT_MAX, f, &n, &a); - if (r < 0) - return r; - if (r == 0) - break; - - /* Determine how well matching this entry is */ - if (streq_ptr(c->x11_layout, a[1])) - /* If we got an exact match, this is best */ - matching = 10; - else { - /* We have multiple X layouts, look for an - * entry that matches our key with everything - * but the first layout stripped off. */ - if (startswith_comma(c->x11_layout, a[1])) - matching = 5; - else { - char *x; - - /* If that didn't work, strip off the - * other layouts from the entry, too */ - x = strndupa(a[1], strcspn(a[1], ",")); - if (startswith_comma(c->x11_layout, x)) - matching = 1; - } - } - - if (matching > 0) { - if (isempty(c->x11_model) || streq_ptr(c->x11_model, a[2])) { - matching++; - - if (streq_ptr(c->x11_variant, a[3])) { - matching++; - - if (streq_ptr(c->x11_options, a[4])) - matching++; - } - } - } - - /* The best matching entry so far, then let's save that */ - if (matching >= MAX(best_matching, 1u)) { - log_debug("Found legacy keymap %s with score %u", - a[0], matching); - - if (matching > best_matching) { - best_matching = matching; - - r = free_and_strdup(new_keymap, a[0]); - if (r < 0) - return r; - } - } - } - - if (best_matching < 10 && c->x11_layout) { - /* The best match is only the first part of the X11 - * keymap. Check if we have a converted map which - * matches just the first layout. - */ - char *l, *v = NULL, *converted; - - l = strndupa(c->x11_layout, strcspn(c->x11_layout, ",")); - if (c->x11_variant) - v = strndupa(c->x11_variant, strcspn(c->x11_variant, ",")); - r = find_converted_keymap(l, v, &converted); - if (r < 0) - return r; - if (r > 0) { - free(*new_keymap); - *new_keymap = converted; - } - } - - return 0; -} - -static int find_language_fallback(const char *lang, char **language) { - _cleanup_fclose_ FILE *f = NULL; - unsigned n = 0; - - assert(language); - - f = fopen(SYSTEMD_LANGUAGE_FALLBACK_MAP, "re"); - if (!f) - return -errno; + assert(bus); - for (;;) { - _cleanup_strv_free_ char **a = NULL; - int r; + r = vconsole_convert_to_x11(c); + if (r <= 0) + return r; - r = read_next_mapping(SYSTEMD_LANGUAGE_FALLBACK_MAP, 2, 2, f, &n, &a); - if (r <= 0) - return r; + /* modified */ + r = x11_write_data(c); + if (r < 0) + return log_error_errno(r, "Failed to write X11 keyboard layout: %m"); - if (streq(lang, a[0])) { - assert(strv_length(a) == 2); - *language = a[1]; - a[1] = NULL; - return 1; - } - } + sd_bus_emit_properties_changed(bus, + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + "X11Layout", "X11Model", "X11Variant", "X11Options", NULL); - assert_not_reached("should not be here"); + return 1; } -static int x11_convert_to_vconsole(Context *c, sd_bus *bus) { - bool modified = false; +static int x11_convert_to_vconsole_and_emit(Context *c, sd_bus *bus) { int r; assert(bus); - if (isempty(c->x11_layout)) { - - modified = - !isempty(c->vc_keymap) || - !isempty(c->vc_keymap_toggle); - - context_free_x11(c); - } else { - char *new_keymap = NULL; - - r = find_converted_keymap(c->x11_layout, c->x11_variant, &new_keymap); - if (r < 0) - return r; - else if (r == 0) { - r = find_legacy_keymap(c, &new_keymap); - if (r < 0) - return r; - } - - if (!streq_ptr(c->vc_keymap, new_keymap)) { - free(c->vc_keymap); - c->vc_keymap = new_keymap; - c->vc_keymap_toggle = mfree(c->vc_keymap_toggle); - modified = true; - } else - free(new_keymap); - } - - if (modified) { - r = vconsole_write_data(c); - if (r < 0) - log_error_errno(r, "Failed to set virtual console keymap: %m"); - - log_info("Changed virtual console keymap to '%s' toggle '%s'", - strempty(c->vc_keymap), strempty(c->vc_keymap_toggle)); + r = x11_convert_to_vconsole(c); + if (r <= 0) + return r; - sd_bus_emit_properties_changed(bus, - "/org/freedesktop/locale1", - "org.freedesktop.locale1", - "VConsoleKeymap", "VConsoleKeymapToggle", NULL); + /* modified */ + r = vconsole_write_data(c); + if (r < 0) + log_error_errno(r, "Failed to save virtual console keymap: %m"); - return vconsole_reload(bus); - } else - log_debug("Virtual console keymap was not modified."); + sd_bus_emit_properties_changed(bus, + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + "VConsoleKeymap", "VConsoleKeymapToggle", NULL); - return 0; + return vconsole_reload(bus); } static int property_get_locale( @@ -858,17 +182,21 @@ static int property_get_locale( _cleanup_strv_free_ char **l = NULL; int p, q; - l = new0(char*, _LOCALE_MAX+1); + l = new0(char*, _VARIABLE_LC_MAX+1); if (!l) return -ENOMEM; - for (p = 0, q = 0; p < _LOCALE_MAX; p++) { + for (p = 0, q = 0; p < _VARIABLE_LC_MAX; p++) { char *t; + const char *name; + + name = locale_variable_to_string(p); + assert(name); if (isempty(c->locale[p])) continue; - if (asprintf(&t, "%s=%s", names[p], c->locale[p]) < 0) + if (asprintf(&t, "%s=%s", name, c->locale[p]) < 0) return -ENOMEM; l[q++] = t; @@ -884,7 +212,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er const char *lang = NULL; int interactive; bool modified = false; - bool have[_LOCALE_MAX] = {}; + bool have[_VARIABLE_LC_MAX] = {}; int p; int r; @@ -903,17 +231,21 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er STRV_FOREACH(i, l) { bool valid = false; - for (p = 0; p < _LOCALE_MAX; p++) { + for (p = 0; p < _VARIABLE_LC_MAX; p++) { size_t k; + const char *name; + + name = locale_variable_to_string(p); + assert(name); - k = strlen(names[p]); - if (startswith(*i, names[p]) && + k = strlen(name); + if (startswith(*i, name) && (*i)[k] == '=' && locale_is_valid((*i) + k + 1)) { valid = true; have[p] = true; - if (p == LOCALE_LANG) + if (p == VARIABLE_LANG) lang = (*i) + k + 1; if (!streq_ptr(*i + k + 1, c->locale[p])) @@ -929,7 +261,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er /* If LANG was specified, but not LANGUAGE, check if we should * set it based on the language fallback table. */ - if (have[LOCALE_LANG] && !have[LOCALE_LANGUAGE]) { + if (have[VARIABLE_LANG] && !have[VARIABLE_LANGUAGE]) { _cleanup_free_ char *language = NULL; assert(lang); @@ -937,12 +269,12 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er (void) find_language_fallback(lang, &language); if (language) { log_debug("Converted LANG=%s to LANGUAGE=%s", lang, language); - if (!streq_ptr(language, c->locale[LOCALE_LANGUAGE])) { + if (!streq_ptr(language, c->locale[VARIABLE_LANGUAGE])) { r = strv_extendf(&l, "LANGUAGE=%s", language); if (r < 0) return r; - have[LOCALE_LANGUAGE] = true; + have[VARIABLE_LANGUAGE] = true; modified = true; } } @@ -950,7 +282,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er /* Check whether a variable is unset */ if (!modified) - for (p = 0; p < _LOCALE_MAX; p++) + for (p = 0; p < _VARIABLE_LC_MAX; p++) if (!isempty(c->locale[p]) && !have[p]) { modified = true; break; @@ -966,7 +298,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er NULL, interactive, UID_INVALID, - &c->polkit_registry, + &polkit_registry, error); if (r < 0) return r; @@ -974,11 +306,15 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ STRV_FOREACH(i, l) - for (p = 0; p < _LOCALE_MAX; p++) { + for (p = 0; p < _VARIABLE_LC_MAX; p++) { size_t k; + const char *name; - k = strlen(names[p]); - if (startswith(*i, names[p]) && (*i)[k] == '=') { + name = locale_variable_to_string(p); + assert(name); + + k = strlen(name); + if (startswith(*i, name) && (*i)[k] == '=') { r = free_and_strdup(&c->locale[p], *i + k + 1); if (r < 0) return r; @@ -986,7 +322,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er } } - for (p = 0; p < _LOCALE_MAX; p++) { + for (p = 0; p < _VARIABLE_LC_MAX; p++) { if (have[p]) continue; @@ -1053,7 +389,7 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro NULL, interactive, UID_INVALID, - &c->polkit_registry, + &polkit_registry, error); if (r < 0) return r; @@ -1084,7 +420,7 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro "VConsoleKeymap", "VConsoleKeymapToggle", NULL); if (convert) { - r = vconsole_convert_to_x11(c, sd_bus_message_get_bus(m)); + r = vconsole_convert_to_x11_and_emit(c, sd_bus_message_get_bus(m)); if (r < 0) log_error_errno(r, "Failed to convert keymap data: %m"); } @@ -1229,7 +565,7 @@ static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_err NULL, interactive, UID_INVALID, - &c->polkit_registry, + &polkit_registry, error); if (r < 0) return r; @@ -1272,7 +608,7 @@ static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_err "X11Layout", "X11Model", "X11Variant", "X11Options", NULL); if (convert) { - r = x11_convert_to_vconsole(c, sd_bus_message_get_bus(m)); + r = x11_convert_to_vconsole_and_emit(c, sd_bus_message_get_bus(m)); if (r < 0) log_error_errno(r, "Failed to convert keymap data: %m"); } @@ -1364,11 +700,11 @@ int main(int argc, char *argv[]) { } r = bus_event_loop_with_idle(event, bus, "org.freedesktop.locale1", DEFAULT_EXIT_USEC, NULL, NULL); - if (r < 0) { + if (r < 0) log_error_errno(r, "Failed to run event loop: %m"); - goto finish; - } finish: + bus_verify_polkit_async_registry_free(polkit_registry); + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/locale/test-keymap-util.c b/src/locale/test-keymap-util.c new file mode 100644 index 0000000000..2adda3da2b --- /dev/null +++ b/src/locale/test-keymap-util.c @@ -0,0 +1,220 @@ +/*** + This file is part of systemd. + + Copyright 2016 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "keymap-util.h" +#include "log.h" +#include "string-util.h" + +static void test_find_language_fallback(void) { + _cleanup_free_ char *ans = NULL, *ans2 = NULL; + + log_info("/*** %s ***/", __func__); + + assert_se(find_language_fallback("foobar", &ans) == 0); + assert_se(ans == NULL); + + assert_se(find_language_fallback("csb", &ans) == 0); + assert_se(ans == NULL); + + assert_se(find_language_fallback("csb_PL", &ans) == 1); + assert_se(streq(ans, "csb:pl")); + + assert_se(find_language_fallback("szl_PL", &ans2) == 1); + assert_se(streq(ans2, "szl:pl")); +} + +static void test_find_converted_keymap(void) { + _cleanup_free_ char *ans = NULL, *ans2 = NULL; + int r; + + log_info("/*** %s ***/", __func__); + + assert_se(find_converted_keymap("pl", "foobar", &ans) == 0); + assert_se(ans == NULL); + + r = find_converted_keymap("pl", NULL, &ans); + if (r == 0) { + log_info("Skipping rest of %s: keymaps are not installed", __func__); + return; + } + + assert_se(r == 1); + assert_se(streq(ans, "pl")); + + assert_se(find_converted_keymap("pl", "dvorak", &ans2) == 1); + assert_se(streq(ans2, "pl-dvorak")); +} + +static void test_find_legacy_keymap(void) { + Context c = {}; + _cleanup_free_ char *ans = NULL, *ans2 = NULL; + + log_info("/*** %s ***/", __func__); + + c.x11_layout = (char*) "foobar"; + assert_se(find_legacy_keymap(&c, &ans) == 0); + assert_se(ans == NULL); + + c.x11_layout = (char*) "pl"; + assert_se(find_legacy_keymap(&c, &ans) == 1); + assert_se(streq(ans, "pl2")); + + c.x11_layout = (char*) "pl,ru"; + assert_se(find_legacy_keymap(&c, &ans2) == 1); + assert_se(streq(ans, "pl2")); +} + +static void test_vconsole_convert_to_x11(void) { + _cleanup_(context_free) Context c = {}; + + log_info("/*** %s ***/", __func__); + + log_info("/* test emptying first (:) */"); + assert_se(free_and_strdup(&c.x11_layout, "foo") >= 0); + assert_se(free_and_strdup(&c.x11_variant, "bar") >= 0); + assert_se(vconsole_convert_to_x11(&c) == 1); + assert_se(c.x11_layout == NULL); + assert_se(c.x11_variant == NULL); + + log_info("/* test emptying second (:) */"); + + assert_se(vconsole_convert_to_x11(&c) == 0); + assert_se(c.x11_layout == NULL); + assert_se(c.x11_variant == NULL); + + log_info("/* test without variant, new mapping (es:) */"); + assert_se(free_and_strdup(&c.vc_keymap, "es") >= 0); + + assert_se(vconsole_convert_to_x11(&c) == 1); + assert_se(streq(c.x11_layout, "es")); + assert_se(c.x11_variant == NULL); + + log_info("/* test with known variant, new mapping (es:dvorak) */"); + assert_se(free_and_strdup(&c.vc_keymap, "es-dvorak") >= 0); + + assert_se(vconsole_convert_to_x11(&c) == 0); // FIXME + assert_se(streq(c.x11_layout, "es")); + assert_se(c.x11_variant == NULL); // FIXME: "dvorak" + + log_info("/* test with old mapping (fr:latin9) */"); + assert_se(free_and_strdup(&c.vc_keymap, "fr-latin9") >= 0); + + assert_se(vconsole_convert_to_x11(&c) == 1); + assert_se(streq(c.x11_layout, "fr")); + assert_se(streq(c.x11_variant, "latin9")); + + log_info("/* test with a compound mapping (ru,us) */"); + assert_se(free_and_strdup(&c.vc_keymap, "ru") >= 0); + + assert_se(vconsole_convert_to_x11(&c) == 1); + assert_se(streq(c.x11_layout, "ru,us")); + assert_se(c.x11_variant == NULL); + + log_info("/* test with a simple mapping (us) */"); + assert_se(free_and_strdup(&c.vc_keymap, "us") >= 0); + + assert_se(vconsole_convert_to_x11(&c) == 1); + assert_se(streq(c.x11_layout, "us")); + assert_se(c.x11_variant == NULL); +} + +static void test_x11_convert_to_vconsole(void) { + _cleanup_(context_free) Context c = {}; + int r; + + log_info("/*** %s ***/", __func__); + + log_info("/* test emptying first (:) */"); + assert_se(free_and_strdup(&c.vc_keymap, "foobar") >= 0); + assert_se(x11_convert_to_vconsole(&c) == 1); + assert_se(c.vc_keymap == NULL); + + log_info("/* test emptying second (:) */"); + + assert_se(x11_convert_to_vconsole(&c) == 0); + assert_se(c.vc_keymap == NULL); + + log_info("/* test without variant, new mapping (es:) */"); + assert_se(free_and_strdup(&c.x11_layout, "es") >= 0); + + assert_se(x11_convert_to_vconsole(&c) == 1); + assert_se(streq(c.vc_keymap, "es")); + + log_info("/* test with unknown variant, new mapping (es:foobar) */"); + assert_se(free_and_strdup(&c.x11_variant, "foobar") >= 0); + + assert_se(x11_convert_to_vconsole(&c) == 0); + assert_se(streq(c.vc_keymap, "es")); + + log_info("/* test with known variant, new mapping (es:dvorak) */"); + assert_se(free_and_strdup(&c.x11_variant, "dvorak") >= 0); + + r = x11_convert_to_vconsole(&c); + if (r == 0) { + log_info("Skipping rest of %s: keymaps are not installed", __func__); + return; + } + + assert_se(r == 1); + assert_se(streq(c.vc_keymap, "es-dvorak")); + + log_info("/* test with old mapping (fr:latin9) */"); + assert_se(free_and_strdup(&c.x11_layout, "fr") >= 0); + assert_se(free_and_strdup(&c.x11_variant, "latin9") >= 0); + + assert_se(x11_convert_to_vconsole(&c) == 1); + assert_se(streq(c.vc_keymap, "fr-latin9")); + + log_info("/* test with a compound mapping (us,ru:) */"); + assert_se(free_and_strdup(&c.x11_layout, "us,ru") >= 0); + assert_se(free_and_strdup(&c.x11_variant, NULL) >= 0); + + assert_se(x11_convert_to_vconsole(&c) == 1); + assert_se(streq(c.vc_keymap, "us")); + + log_info("/* test with a compound mapping (ru,us:) */"); + assert_se(free_and_strdup(&c.x11_layout, "ru,us") >= 0); + assert_se(free_and_strdup(&c.x11_variant, NULL) >= 0); + + assert_se(x11_convert_to_vconsole(&c) == 1); + assert_se(streq(c.vc_keymap, "ru")); + + /* https://bugzilla.redhat.com/show_bug.cgi?id=1333998 */ + log_info("/* test with a simple new mapping (ru:) */"); + assert_se(free_and_strdup(&c.x11_layout, "ru") >= 0); + assert_se(free_and_strdup(&c.x11_variant, NULL) >= 0); + + assert_se(x11_convert_to_vconsole(&c) == 0); + assert_se(streq(c.vc_keymap, "ru")); +} + +int main(int argc, char **argv) { + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + + test_find_language_fallback(); + test_find_converted_keymap(); + test_find_legacy_keymap(); + + test_vconsole_convert_to_x11(); + test_x11_convert_to_vconsole(); + + return 0; +} diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 1c75565636..0fc2720b43 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -1554,7 +1554,7 @@ static int loginctl_main(int argc, char *argv[], sd_bus *bus) { } int main(int argc, char *argv[]) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); @@ -1576,6 +1576,8 @@ int main(int argc, char *argv[]) { r = loginctl_main(argc, argv, bus); finish: + sd_bus_flush_close_unref(bus); + pager_close(); polkit_agent_close(); diff --git a/src/login/logind-user.c b/src/login/logind-user.c index a826321bf0..de44d369cf 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -843,7 +843,6 @@ int config_parse_tmpfs_size( void *userdata) { size_t *sz = data; - const char *e; int r; assert(filename); @@ -851,29 +850,17 @@ int config_parse_tmpfs_size( assert(rvalue); assert(data); - e = endswith(rvalue, "%"); - if (e) { - unsigned long ul; - char *f; - - errno = 0; - ul = strtoul(rvalue, &f, 10); - if (errno > 0 || f != e) { - log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse percentage value, ignoring: %s", rvalue); - return 0; - } - - if (ul <= 0 || ul >= 100) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Percentage value out of range, ignoring: %s", rvalue); - return 0; - } - - *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100)); - } else { + /* First, try to parse as percentage */ + r = parse_percent(rvalue); + if (r > 0 && r < 100) + *sz = physical_memory_scale(r, 100U); + else { uint64_t k; + /* If the passed argument was not a percentage, or out of range, parse as byte size */ + r = parse_size(rvalue, 1024, &k); - if (r < 0 || (uint64_t) (size_t) k != k) { + if (r < 0 || k <= 0 || (uint64_t) (size_t) k != k) { log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue); return 0; } diff --git a/src/login/logind.c b/src/login/logind.c index caf149cfb7..d01dd110ea 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -61,7 +61,7 @@ static void manager_reset_config(Manager *m) { m->idle_action_usec = 30 * USEC_PER_MINUTE; m->idle_action = HANDLE_IGNORE; - m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */ + m->runtime_dir_size = physical_memory_scale(10U, 100U); /* 10% */ m->user_tasks_max = 12288; m->sessions_max = 8192; m->inhibitors_max = 8192; diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index 98dc201340..4f023640f6 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -182,25 +182,20 @@ static int export_legacy_dbus_address( _cleanup_free_ char *s = NULL; int r = PAM_BUF_ERR; - if (is_kdbus_available()) { - if (asprintf(&s, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, uid, runtime) < 0) - goto error; - } else { - /* FIXME: We *really* should move the access() check into the - * daemons that spawn dbus-daemon, instead of forcing - * DBUS_SESSION_BUS_ADDRESS= here. */ - - s = strjoin(runtime, "/bus", NULL); - if (!s) - goto error; - - if (access(s, F_OK) < 0) - return PAM_SUCCESS; + /* FIXME: We *really* should move the access() check into the + * daemons that spawn dbus-daemon, instead of forcing + * DBUS_SESSION_BUS_ADDRESS= here. */ - s = mfree(s); - if (asprintf(&s, UNIX_USER_BUS_ADDRESS_FMT, runtime) < 0) - goto error; - } + s = strjoin(runtime, "/bus", NULL); + if (!s) + goto error; + + if (access(s, F_OK) < 0) + return PAM_SUCCESS; + + s = mfree(s); + if (asprintf(&s, UNIX_USER_BUS_ADDRESS_FMT, runtime) < 0) + goto error; r = pam_misc_setenv(handle, "DBUS_SESSION_BUS_ADDRESS", s, 0); if (r != PAM_SUCCESS) diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index afe5026373..583d2a21e7 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -2751,7 +2751,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) { } int main(int argc, char*argv[]) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); @@ -2773,6 +2773,7 @@ int main(int argc, char*argv[]) { r = machinectl_main(argc, argv, bus); finish: + sd_bus_flush_close_unref(bus); pager_close(); polkit_agent_close(); diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index 735c231a4c..2d81311e81 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -138,7 +138,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) { ll_addr->family = AF_INET; ll_addr->in_addr.in = address; ll_addr->prefixlen = 16; - ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen); + ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htobe32(0xfffffffflu >> ll_addr->prefixlen); ll_addr->scope = RT_SCOPE_LINK; r = address_configure(ll_addr, link, ipv4ll_address_handler, false); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 0302f57f26..1842685180 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1600,7 +1600,7 @@ static int link_up(Link *link) { return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m"); /* set it free if not enslaved with networkd */ - if (!link->network->bridge && !link->network->bond) { + if (!link->network->bridge && !link->network->bond && !link->network->vrf) { r = sd_netlink_message_append_u32(req, IFLA_MASTER, 0); if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_MASTER attribute: %m"); @@ -2005,7 +2005,7 @@ static int link_joined(Link *link) { log_link_error_errno(link, r, "Could not set bridge message: %m"); } - if (link->network->bridge || streq("bridge", link->kind)) { + if (link->network->bridge || streq_ptr("bridge", link->kind)) { r = link_set_bridge_vlan(link); if (r < 0) log_link_error_errno(link, r, "Could not set bridge vlan: %m"); @@ -2055,6 +2055,7 @@ static int link_enter_join_netdev(Link *link) { if (!link->network->bridge && !link->network->bond && + !link->network->vrf && hashmap_isempty(link->network->stacked_netdevs)) return link_joined(link); @@ -2101,6 +2102,26 @@ static int link_enter_join_netdev(Link *link) { link->enslaving++; } + if (link->network->vrf) { + log_struct(LOG_DEBUG, + LOG_LINK_INTERFACE(link), + LOG_NETDEV_INTERFACE(link->network->vrf), + LOG_LINK_MESSAGE(link, "Enslaving by '%s'", link->network->vrf->ifname), + NULL); + r = netdev_join(link->network->vrf, link, netdev_join_handler); + if (r < 0) { + log_struct_errno(LOG_WARNING, r, + LOG_LINK_INTERFACE(link), + LOG_NETDEV_INTERFACE(link->network->vrf), + LOG_LINK_MESSAGE(link, "Could not join netdev '%s': %m", link->network->vrf->ifname), + NULL); + link_enter_failed(link); + return r; + } + + link->enslaving++; + } + HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) { log_struct(LOG_DEBUG, diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index a9512cd77b..9d69f61376 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -11,6 +11,7 @@ #include "networkd-netdev-veth.h" #include "networkd-netdev-vlan.h" #include "networkd-netdev-vxlan.h" +#include "networkd-netdev-vrf.h" #include "networkd-netdev.h" #include "vlan-util.h" %} @@ -42,6 +43,9 @@ Tunnel.Local, config_parse_tunnel_address, 0, Tunnel.Remote, config_parse_tunnel_address, 0, offsetof(Tunnel, remote) Tunnel.TOS, config_parse_unsigned, 0, offsetof(Tunnel, tos) Tunnel.TTL, config_parse_unsigned, 0, offsetof(Tunnel, ttl) +Tunnel.Key, config_parse_tunnel_key, 0, offsetof(Tunnel, key) +Tunnel.InputKey, config_parse_tunnel_key, 0, offsetof(Tunnel, ikey) +Tunnel.OutputKey, config_parse_tunnel_key, 0, offsetof(Tunnel, okey) Tunnel.DiscoverPathMTU, config_parse_bool, 0, offsetof(Tunnel, pmtudisc) Tunnel.Mode, config_parse_ip6tnl_mode, 0, offsetof(Tunnel, ip6tnl_mode) Tunnel.IPv6FlowLabel, config_parse_ipv6_flowlabel, 0, offsetof(Tunnel, ipv6_flowlabel) @@ -102,3 +106,4 @@ Bridge.ForwardDelaySec, config_parse_sec, 0, Bridge.MulticastQuerier, config_parse_tristate, 0, offsetof(Bridge, mcast_querier) Bridge.MulticastSnooping, config_parse_tristate, 0, offsetof(Bridge, mcast_snooping) Bridge.VLANFiltering, config_parse_tristate, 0, offsetof(Bridge, vlan_filtering) +VRF.TableId, config_parse_uint32, 0, offsetof(Vrf, table_id) diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c index 7aaa041ba3..77a4734df8 100644 --- a/src/network/networkd-netdev-tunnel.c +++ b/src/network/networkd-netdev-tunnel.c @@ -35,7 +35,7 @@ #include "util.h" #define DEFAULT_TNL_HOP_LIMIT 64 -#define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF) +#define IP6_FLOWINFO_FLOWLABEL htobe32(0x000FFFFF) static const char* const ip6tnl_mode_table[_NETDEV_IP6_TNL_MODE_MAX] = { [NETDEV_IP6_TNL_MODE_IP6IP6] = "ip6ip6", @@ -200,6 +200,33 @@ static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netl return r; } +static int netdev_vti_fill_message_key(NetDev *netdev, Link *link, sd_netlink_message *m) { + Tunnel *t = VTI(netdev); + uint32_t ikey, okey; + int r; + + assert(link); + assert(m); + assert(t); + + if (t->key != 0) + ikey = okey = htobe32(t->key); + else { + ikey = htobe32(t->ikey); + okey = htobe32(t->okey); + } + + r = sd_netlink_message_append_u32(m, IFLA_VTI_IKEY, ikey); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_IKEY attribute: %m"); + + r = sd_netlink_message_append_u32(m, IFLA_VTI_OKEY, okey); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_OKEY attribute: %m"); + + return 0; +} + static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { Tunnel *t = VTI(netdev); int r; @@ -214,6 +241,10 @@ static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m"); + r = netdev_vti_fill_message_key(netdev, link, m); + if (r < 0) + return r; + r = sd_netlink_message_append_in_addr(m, IFLA_VTI_LOCAL, &t->local.in); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m"); @@ -239,6 +270,10 @@ static int netdev_vti6_fill_message_create(NetDev *netdev, Link *link, sd_netlin if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m"); + r = netdev_vti_fill_message_key(netdev, link, m); + if (r < 0) + return r; + r = sd_netlink_message_append_in6_addr(m, IFLA_VTI_LOCAL, &t->local.in6); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m"); @@ -413,6 +448,46 @@ int config_parse_tunnel_address(const char *unit, return 0; } +int config_parse_tunnel_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) { + union in_addr_union buffer; + Tunnel *t = userdata; + uint32_t k; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = in_addr_from_string(AF_INET, rvalue, &buffer); + if (r < 0) { + r = safe_atou32(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse tunnel key ignoring assignment: %s", rvalue); + return 0; + } + } else + k = be32toh(buffer.in.s_addr); + + if (streq(lvalue, "Key")) + t->key = k; + else if (streq(lvalue, "InputKey")) + t->ikey = k; + else + t->okey = k; + + return 0; +} + int config_parse_ipv6_flowlabel(const char* unit, const char *filename, unsigned line, @@ -444,7 +519,7 @@ int config_parse_ipv6_flowlabel(const char* unit, if (k > 0xFFFFF) log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue); else { - *ipv6_flowlabel = htonl(k) & IP6_FLOWINFO_FLOWLABEL; + *ipv6_flowlabel = htobe32(k) & IP6_FLOWINFO_FLOWLABEL; t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL; } } diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h index 7d31e7b687..32a46bd82f 100644 --- a/src/network/networkd-netdev-tunnel.h +++ b/src/network/networkd-netdev-tunnel.h @@ -49,6 +49,10 @@ typedef struct Tunnel { unsigned tos; unsigned flags; + uint32_t key; + uint32_t ikey; + uint32_t okey; + union in_addr_union local; union in_addr_union remote; @@ -108,3 +112,8 @@ int config_parse_encap_limit(const char *unit, const char *filename, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_tunnel_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); diff --git a/src/network/networkd-netdev-vrf.c b/src/network/networkd-netdev-vrf.c new file mode 100644 index 0000000000..89bd142e8c --- /dev/null +++ b/src/network/networkd-netdev-vrf.c @@ -0,0 +1,50 @@ +/*** + This file is part of systemd. + + Copyright 2016 Andreas Rammhold <andreas@rammhold.de> + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <net/if.h> + +#include "sd-netlink.h" +#include "missing.h" +#include "networkd-netdev-vrf.h" + +static int netdev_vrf_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { + Vrf *v; + int r; + + assert(netdev); + assert(!link); + assert(m); + + v = VRF(netdev); + + assert(v); + + r = sd_netlink_message_append_u32(m, IFLA_VRF_TABLE, v->table_id); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IPLA_VRF_TABLE attribute: %m"); + + return r; +} + +const NetDevVTable vrf_vtable = { + .object_size = sizeof(Vrf), + .sections = "NetDev\0VRF\0", + .fill_message_create = netdev_vrf_fill_message_create, + .create_type = NETDEV_CREATE_MASTER, +}; diff --git a/src/network/networkd-netdev-vrf.h b/src/network/networkd-netdev-vrf.h new file mode 100644 index 0000000000..3d92a26a4d --- /dev/null +++ b/src/network/networkd-netdev-vrf.h @@ -0,0 +1,33 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 Andreas Rammhold <andreas@rammhold.de> + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +typedef struct Vrf Vrf; + +#include "networkd-netdev.h" + +struct Vrf { + NetDev meta; + + uint32_t table_id; +}; + +DEFINE_NETDEV_CAST(VRF, Vrf); +extern const NetDevVTable vrf_vtable; diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index 851a36290c..b192884fd9 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -55,6 +55,8 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = { [NETDEV_KIND_TUN] = &tun_vtable, [NETDEV_KIND_TAP] = &tap_vtable, [NETDEV_KIND_IP6TNL] = &ip6tnl_vtable, + [NETDEV_KIND_VRF] = &vrf_vtable, + }; static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = { @@ -78,6 +80,8 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = { [NETDEV_KIND_TUN] = "tun", [NETDEV_KIND_TAP] = "tap", [NETDEV_KIND_IP6TNL] = "ip6tnl", + [NETDEV_KIND_VRF] = "vrf", + }; DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind); @@ -198,7 +202,7 @@ static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_netlink_message_h assert(netdev->state == NETDEV_STATE_READY); assert(netdev->manager); assert(netdev->manager->rtnl); - assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND)); + assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF)); assert(link); assert(callback); @@ -281,7 +285,7 @@ int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t call assert(netdev); assert(netdev->manager); assert(netdev->manager->rtnl); - assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND)); + assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF)); if (netdev->state == NETDEV_STATE_READY) { r = netdev_enslave_ready(netdev, link, callback); diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h index 20244c0309..b92a973b85 100644 --- a/src/network/networkd-netdev.h +++ b/src/network/networkd-netdev.h @@ -55,6 +55,7 @@ typedef enum NetDevKind { NETDEV_KIND_DUMMY, NETDEV_KIND_TUN, NETDEV_KIND_TAP, + NETDEV_KIND_VRF, _NETDEV_KIND_MAX, _NETDEV_KIND_INVALID = -1 } NetDevKind; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 0b0aa58f67..affc0d00e9 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -37,6 +37,7 @@ Network.MACVTAP, config_parse_netdev, Network.IPVLAN, config_parse_netdev, 0, 0 Network.VXLAN, config_parse_netdev, 0, 0 Network.Tunnel, config_parse_tunnel, 0, 0 +Network.VRF, config_parse_netdev, 0, 0 Network.DHCP, config_parse_dhcp, 0, offsetof(Network, dhcp) Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server) Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 84bdf75b38..2b764d4f24 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -244,8 +244,8 @@ void network_free(Network *network) { strv_free(network->bind_carrier); netdev_unref(network->bridge); - netdev_unref(network->bond); + netdev_unref(network->vrf); HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) { hashmap_remove(network->stacked_netdevs, netdev->ifname); @@ -471,6 +471,10 @@ int config_parse_netdev(const char *unit, network->bond = netdev; break; + case NETDEV_KIND_VRF: + network->vrf = netdev; + + break; case NETDEV_KIND_VLAN: case NETDEV_KIND_MACVLAN: case NETDEV_KIND_MACVTAP: diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 38688cc400..08ee939faa 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -104,6 +104,7 @@ struct Network { NetDev *bridge; NetDev *bond; + NetDev *vrf; Hashmap *stacked_netdevs; /* DHCP Client Support */ diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 52037f9c6d..cedaf47cf8 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -795,6 +795,7 @@ int config_parse_route_priority(const char *unit, void *userdata) { Network *network = userdata; _cleanup_route_free_ Route *n = NULL; + uint32_t k; int r; assert(filename); @@ -807,12 +808,14 @@ int config_parse_route_priority(const char *unit, if (r < 0) return r; - r = config_parse_uint32(unit, filename, line, section, - section_line, lvalue, ltype, - rvalue, &n->priority, userdata); - if (r < 0) - return r; + r = safe_atou32(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue); + return 0; + } + n->priority = k; n = NULL; return 0; diff --git a/src/network/networkd.h b/src/network/networkd.h index ab512f0d08..c4bd712147 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -41,6 +41,7 @@ #include "networkd-netdev-tuntap.h" #include "networkd-netdev-veth.h" #include "networkd-netdev-vlan.h" +#include "networkd-netdev-vrf.h" #include "networkd-netdev-vxlan.h" #include "networkd-network.h" #include "networkd-util.h" diff --git a/src/nspawn/nspawn-seccomp.c b/src/nspawn/nspawn-seccomp.c index 2d145b68a7..54db1b47f8 100644 --- a/src/nspawn/nspawn-seccomp.c +++ b/src/nspawn/nspawn-seccomp.c @@ -44,20 +44,76 @@ static int seccomp_add_default_syscall_filter(scmp_filter_ctx ctx, uint64_t capability; int syscall_num; } blacklist[] = { - { CAP_SYS_RAWIO, SCMP_SYS(iopl) }, - { CAP_SYS_RAWIO, SCMP_SYS(ioperm) }, - { CAP_SYS_BOOT, SCMP_SYS(kexec_load) }, - { CAP_SYS_ADMIN, SCMP_SYS(swapon) }, - { CAP_SYS_ADMIN, SCMP_SYS(swapoff) }, - { CAP_SYS_ADMIN, SCMP_SYS(open_by_handle_at) }, - { CAP_SYS_MODULE, SCMP_SYS(init_module) }, - { CAP_SYS_MODULE, SCMP_SYS(finit_module) }, - { CAP_SYS_MODULE, SCMP_SYS(delete_module) }, - { CAP_SYSLOG, SCMP_SYS(syslog) }, + { 0, SCMP_SYS(_sysctl) }, /* obsolete syscall */ + { 0, SCMP_SYS(add_key) }, /* keyring is not namespaced */ + { 0, SCMP_SYS(afs_syscall) }, /* obsolete syscall */ + { 0, SCMP_SYS(bdflush) }, +#ifdef __NR_bpf + { 0, SCMP_SYS(bpf) }, +#endif + { 0, SCMP_SYS(break) }, /* obsolete syscall */ + { 0, SCMP_SYS(create_module) }, /* obsolete syscall */ + { 0, SCMP_SYS(ftime) }, /* obsolete syscall */ + { 0, SCMP_SYS(get_kernel_syms) }, /* obsolete syscall */ + { 0, SCMP_SYS(getpmsg) }, /* obsolete syscall */ + { 0, SCMP_SYS(gtty) }, /* obsolete syscall */ +#ifdef __NR_kexec_file_load + { 0, SCMP_SYS(kexec_file_load) }, +#endif + { 0, SCMP_SYS(kexec_load) }, + { 0, SCMP_SYS(keyctl) }, /* keyring is not namespaced */ + { 0, SCMP_SYS(lock) }, /* obsolete syscall */ + { 0, SCMP_SYS(lookup_dcookie) }, + { 0, SCMP_SYS(mpx) }, /* obsolete syscall */ + { 0, SCMP_SYS(nfsservctl) }, /* obsolete syscall */ + { 0, SCMP_SYS(open_by_handle_at) }, + { 0, SCMP_SYS(perf_event_open) }, + { 0, SCMP_SYS(prof) }, /* obsolete syscall */ + { 0, SCMP_SYS(profil) }, /* obsolete syscall */ + { 0, SCMP_SYS(putpmsg) }, /* obsolete syscall */ + { 0, SCMP_SYS(query_module) }, /* obsolete syscall */ + { 0, SCMP_SYS(quotactl) }, + { 0, SCMP_SYS(request_key) }, /* keyring is not namespaced */ + { 0, SCMP_SYS(security) }, /* obsolete syscall */ + { 0, SCMP_SYS(sgetmask) }, /* obsolete syscall */ + { 0, SCMP_SYS(ssetmask) }, /* obsolete syscall */ + { 0, SCMP_SYS(stty) }, /* obsolete syscall */ + { 0, SCMP_SYS(swapoff) }, + { 0, SCMP_SYS(swapon) }, + { 0, SCMP_SYS(sysfs) }, /* obsolete syscall */ + { 0, SCMP_SYS(tuxcall) }, /* obsolete syscall */ + { 0, SCMP_SYS(ulimit) }, /* obsolete syscall */ + { 0, SCMP_SYS(uselib) }, /* obsolete syscall */ + { 0, SCMP_SYS(ustat) }, /* obsolete syscall */ + { 0, SCMP_SYS(vserver) }, /* obsolete syscall */ + { CAP_SYSLOG, SCMP_SYS(syslog) }, + { CAP_SYS_MODULE, SCMP_SYS(delete_module) }, + { CAP_SYS_MODULE, SCMP_SYS(finit_module) }, + { CAP_SYS_MODULE, SCMP_SYS(init_module) }, + { CAP_SYS_PACCT, SCMP_SYS(acct) }, + { CAP_SYS_PTRACE, SCMP_SYS(process_vm_readv) }, + { CAP_SYS_PTRACE, SCMP_SYS(process_vm_writev) }, + { CAP_SYS_PTRACE, SCMP_SYS(ptrace) }, + { CAP_SYS_RAWIO, SCMP_SYS(ioperm) }, + { CAP_SYS_RAWIO, SCMP_SYS(iopl) }, + { CAP_SYS_RAWIO, SCMP_SYS(pciconfig_iobase) }, + { CAP_SYS_RAWIO, SCMP_SYS(pciconfig_read) }, + { CAP_SYS_RAWIO, SCMP_SYS(pciconfig_write) }, +#ifdef __NR_s390_pci_mmio_read + { CAP_SYS_RAWIO, SCMP_SYS(s390_pci_mmio_read) }, +#endif +#ifdef __NR_s390_pci_mmio_write + { CAP_SYS_RAWIO, SCMP_SYS(s390_pci_mmio_write) }, +#endif + { CAP_SYS_TIME, SCMP_SYS(adjtimex) }, + { CAP_SYS_TIME, SCMP_SYS(clock_adjtime) }, + { CAP_SYS_TIME, SCMP_SYS(clock_settime) }, + { CAP_SYS_TIME, SCMP_SYS(settimeofday) }, + { CAP_SYS_TIME, SCMP_SYS(stime) }, }; for (i = 0; i < ELEMENTSOF(blacklist); i++) { - if (cap_list_retain & (1ULL << blacklist[i].capability)) + if (blacklist[i].capability != 0 && (cap_list_retain & (1ULL << blacklist[i].capability))) continue; r = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), blacklist[i].syscall_num, 0); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index ea24de7608..73c56d7310 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -137,6 +137,8 @@ static bool arg_ephemeral = false; static LinkJournal arg_link_journal = LINK_AUTO; static bool arg_link_journal_try = false; static uint64_t arg_caps_retain = + (1ULL << CAP_AUDIT_CONTROL) | + (1ULL << CAP_AUDIT_WRITE) | (1ULL << CAP_CHOWN) | (1ULL << CAP_DAC_OVERRIDE) | (1ULL << CAP_DAC_READ_SEARCH) | @@ -146,23 +148,21 @@ static uint64_t arg_caps_retain = (1ULL << CAP_KILL) | (1ULL << CAP_LEASE) | (1ULL << CAP_LINUX_IMMUTABLE) | + (1ULL << CAP_MKNOD) | (1ULL << CAP_NET_BIND_SERVICE) | (1ULL << CAP_NET_BROADCAST) | (1ULL << CAP_NET_RAW) | - (1ULL << CAP_SETGID) | (1ULL << CAP_SETFCAP) | + (1ULL << CAP_SETGID) | (1ULL << CAP_SETPCAP) | (1ULL << CAP_SETUID) | (1ULL << CAP_SYS_ADMIN) | + (1ULL << CAP_SYS_BOOT) | (1ULL << CAP_SYS_CHROOT) | (1ULL << CAP_SYS_NICE) | (1ULL << CAP_SYS_PTRACE) | - (1ULL << CAP_SYS_TTY_CONFIG) | (1ULL << CAP_SYS_RESOURCE) | - (1ULL << CAP_SYS_BOOT) | - (1ULL << CAP_AUDIT_WRITE) | - (1ULL << CAP_AUDIT_CONTROL) | - (1ULL << CAP_MKNOD); + (1ULL << CAP_SYS_TTY_CONFIG); static CustomMount *arg_custom_mounts = NULL; static unsigned arg_n_custom_mounts = 0; static char **arg_setenv = NULL; diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c index 2b83d127b7..9a6e157e12 100644 --- a/src/nss-myhostname/nss-myhostname.c +++ b/src/nss-myhostname/nss-myhostname.c @@ -38,7 +38,7 @@ * IPv6 we use ::1 which unfortunately will not translate back to the * hostname but instead something like "localhost" or so. */ -#define LOCALADDRESS_IPV4 (htonl(0x7F000002)) +#define LOCALADDRESS_IPV4 (htobe32(0x7F000002)) #define LOCALADDRESS_IPV6 &in6addr_loopback NSS_GETHOSTBYNAME_PROTOTYPES(myhostname); @@ -75,7 +75,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r( * is optional */ canonical = "localhost"; - local_address_ipv4 = htonl(INADDR_LOOPBACK); + local_address_ipv4 = htobe32(INADDR_LOOPBACK); } else if (is_gateway_hostname(name)) { @@ -348,7 +348,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r( if (is_localhost(name)) { canonical = "localhost"; - local_address_ipv4 = htonl(INADDR_LOOPBACK); + local_address_ipv4 = htobe32(INADDR_LOOPBACK); } else if (is_gateway_hostname(name)) { @@ -437,9 +437,9 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r( if ((*(uint32_t*) addr) == LOCALADDRESS_IPV4) goto found; - if ((*(uint32_t*) addr) == htonl(INADDR_LOOPBACK)) { + if ((*(uint32_t*) addr) == htobe32(INADDR_LOOPBACK)) { canonical = "localhost"; - local_address_ipv4 = htonl(INADDR_LOOPBACK); + local_address_ipv4 = htobe32(INADDR_LOOPBACK); goto found; } diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index bc6dcf04a4..2cb2e42b23 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -199,7 +199,7 @@ static int resolve_host(sd_bus *bus, const char *name) { if (ifindex > 0 && !if_indextoname(ifindex, ifname)) log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex); - r = in_addr_to_string(family, a, &pretty); + r = in_addr_ifindex_to_string(family, a, ifindex, &pretty); if (r < 0) return log_error_errno(r, "Failed to print address for %s: %m", name); @@ -253,7 +253,7 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a if (ifindex <= 0) ifindex = arg_ifindex; - r = in_addr_to_string(family, address, &pretty); + r = in_addr_ifindex_to_string(family, address, ifindex, &pretty); if (r < 0) return log_oom(); @@ -345,31 +345,6 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a return 0; } -static int parse_address(const char *s, int *family, union in_addr_union *address, int *ifindex) { - const char *percent, *a; - int ifi = 0; - int r; - - percent = strchr(s, '%'); - if (percent) { - if (parse_ifindex(percent+1, &ifi) < 0) { - ifi = if_nametoindex(percent+1); - if (ifi <= 0) - return -EINVAL; - } - - a = strndupa(s, percent - s); - } else - a = s; - - r = in_addr_from_string_auto(a, family, address); - if (r < 0) - return r; - - *ifindex = ifi; - return 0; -} - static int output_rr_packet(const void *d, size_t l, int ifindex) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; @@ -1392,7 +1367,7 @@ int main(int argc, char **argv) { if (startswith(argv[optind], "dns:")) k = resolve_rfc4501(bus, argv[optind]); else { - k = parse_address(argv[optind], &family, &a, &ifindex); + k = in_addr_ifindex_from_string_auto(argv[optind], &family, &a, &ifindex); if (k >= 0) k = resolve_address(bus, family, &a, ifindex); else diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 6d86cbf123..f08c6c0637 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -245,17 +245,22 @@ static int parse_as_address(sd_bus_message *m, int ifindex, const char *hostname _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *canonical = NULL; union in_addr_union parsed; - int r, ff; + int r, ff, parsed_ifindex = 0; /* Check if the hostname is actually already an IP address formatted as string. In that case just parse it, * let's not attempt to look it up. */ - r = in_addr_from_string_auto(hostname, &ff, &parsed); + r = in_addr_ifindex_from_string_auto(hostname, &ff, &parsed, &parsed_ifindex); if (r < 0) /* not an address */ return 0; if (family != AF_UNSPEC && ff != family) return sd_bus_reply_method_errorf(m, BUS_ERROR_NO_SUCH_RR, "The specified address is not of the requested family."); + if (ifindex > 0 && parsed_ifindex > 0 && parsed_ifindex != ifindex) + return sd_bus_reply_method_errorf(m, BUS_ERROR_NO_SUCH_RR, "The specified address interface index does not match requested interface."); + + if (parsed_ifindex > 0) + ifindex = parsed_ifindex; r = sd_bus_message_new_method_return(m, &reply); if (r < 0) @@ -288,7 +293,7 @@ static int parse_as_address(sd_bus_message *m, int ifindex, const char *hostname /* When an IP address is specified we just return it as canonical name, in order to avoid a DNS * look-up. However, we reformat it to make sure it's in a truly canonical form (i.e. on IPv6 the inner * omissions are always done the same way). */ - r = in_addr_to_string(ff, &parsed, &canonical); + r = in_addr_ifindex_to_string(ff, &parsed, ifindex, &canonical); if (r < 0) return r; diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c index 0dadf8b1dd..13dcba8421 100644 --- a/src/resolve/resolved-dns-answer.c +++ b/src/resolve/resolved-dns-answer.c @@ -185,7 +185,7 @@ int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, Dns return dns_answer_add(*a, rr, ifindex, flags); } -int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl) { +int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl, int ifindex) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *soa = NULL; soa = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SOA, name); @@ -208,7 +208,7 @@ int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl) { soa->soa.expire = 1; soa->soa.minimum = ttl; - return dns_answer_add(a, soa, 0, DNS_ANSWER_AUTHENTICATED); + return dns_answer_add(a, soa, ifindex, DNS_ANSWER_AUTHENTICATED); } int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *ret_flags) { diff --git a/src/resolve/resolved-dns-answer.h b/src/resolve/resolved-dns-answer.h index 0679c610f5..b2b86d1772 100644 --- a/src/resolve/resolved-dns-answer.h +++ b/src/resolve/resolved-dns-answer.h @@ -56,7 +56,7 @@ DnsAnswer *dns_answer_unref(DnsAnswer *a); int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags); int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags); -int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl); +int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl, int ifindex); int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *combined_flags); int dns_answer_contains_rr(DnsAnswer *a, DnsResourceRecord *rr, DnsAnswerFlags *combined_flags); diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 6a69d7b7c2..9d484d0a48 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -721,7 +721,7 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) { assert(p->question->n_keys == 1); key = p->question->keys[0]; - r = dns_zone_lookup(&s->zone, key, &answer, &soa, &tentative); + r = dns_zone_lookup(&s->zone, key, 0, &answer, &soa, &tentative); if (r < 0) { log_debug_errno(r, "Failed to lookup key: %m"); return; @@ -1029,3 +1029,12 @@ bool dns_scope_network_good(DnsScope *s) { return manager_routable(s->manager, AF_UNSPEC); } + +int dns_scope_ifindex(DnsScope *s) { + assert(s); + + if (s->link) + return s->link->ifindex; + + return 0; +} diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index 291e5817d0..538bc61f81 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -107,3 +107,5 @@ DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s); bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name); bool dns_scope_network_good(DnsScope *s); + +int dns_scope_ifindex(DnsScope *s); diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index a4a67623e7..bcb1b6d8a7 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -404,8 +404,12 @@ static void dns_transaction_retry(DnsTransaction *t) { } static int dns_transaction_maybe_restart(DnsTransaction *t) { + int r; + assert(t); + /* Returns > 0 if the transaction was restarted, 0 if not */ + if (!t->server) return 0; @@ -420,7 +424,12 @@ static int dns_transaction_maybe_restart(DnsTransaction *t) { log_debug("Server feature level is now lower than when we began our transaction. Restarting with new ID."); dns_transaction_shuffle_id(t); - return dns_transaction_go(t); + + r = dns_transaction_go(t); + if (r < 0) + return r; + + return 1; } static int on_stream_complete(DnsStream *s, int error) { @@ -557,8 +566,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) { /* The interface index is difficult to determine if we are * connecting to the local host, hence fill this in right away * instead of determining it from the socket */ - if (t->scope->link) - t->stream->ifindex = t->scope->link->ifindex; + t->stream->ifindex = dns_scope_ifindex(t->scope); dns_transaction_reset_answer(t); @@ -798,12 +806,9 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { switch (t->scope->protocol) { case DNS_PROTOCOL_LLMNR: - assert(t->scope->link); - - /* For LLMNR we will not accept any packets from other - * interfaces */ + /* For LLMNR we will not accept any packets from other interfaces */ - if (p->ifindex != t->scope->link->ifindex) + if (p->ifindex != dns_scope_ifindex(t->scope)) return; if (p->family != t->scope->family) @@ -820,10 +825,9 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { break; case DNS_PROTOCOL_MDNS: - assert(t->scope->link); - /* For mDNS we will not accept any packets from other interfaces */ - if (p->ifindex != t->scope->link->ifindex) + + if (p->ifindex != dns_scope_ifindex(t->scope)) return; if (p->family != t->scope->family) @@ -1246,7 +1250,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) { * for probing or verifying a zone item. */ if (set_isempty(t->notify_zone_items)) { - r = dns_zone_lookup(&t->scope->zone, t->key, &t->answer, NULL, NULL); + r = dns_zone_lookup(&t->scope->zone, t->key, dns_scope_ifindex(t->scope), &t->answer, NULL, NULL); if (r < 0) return r; if (r > 0) { @@ -1426,6 +1430,9 @@ int dns_transaction_go(DnsTransaction *t) { assert(t); + /* Returns > 0 if the transaction is now pending, returns 0 if could be processed immediately and has finished + * now. */ + assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0); r = dns_transaction_prepare(t, ts); diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c index 850eed8cb8..746a979f47 100644 --- a/src/resolve/resolved-dns-zone.c +++ b/src/resolve/resolved-dns-zone.c @@ -287,13 +287,16 @@ int dns_zone_put(DnsZone *z, DnsScope *s, DnsResourceRecord *rr, bool probe) { return 0; } -int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, DnsAnswer **ret_soa, bool *ret_tentative) { +int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, int ifindex, DnsAnswer **ret_answer, DnsAnswer **ret_soa, bool *ret_tentative) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL; unsigned n_answer = 0; DnsZoneItem *j, *first; bool tentative = true, need_soa = false; int r; + /* Note that we don't actually need the ifindex for anything. However when it is passed we'll initialize the + * ifindex field in the answer with it */ + assert(z); assert(key); assert(ret_answer); @@ -389,7 +392,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns if (k < 0) return k; if (k > 0) { - r = dns_answer_add(answer, j->rr, 0, DNS_ANSWER_AUTHENTICATED); + r = dns_answer_add(answer, j->rr, ifindex, DNS_ANSWER_AUTHENTICATED); if (r < 0) return r; @@ -398,7 +401,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns } if (found && !added) { - r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL); + r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL, ifindex); if (r < 0) return r; } @@ -415,7 +418,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns if (j->state != DNS_ZONE_ITEM_PROBING) tentative = false; - r = dns_answer_add(answer, j->rr, 0, DNS_ANSWER_AUTHENTICATED); + r = dns_answer_add(answer, j->rr, ifindex, DNS_ANSWER_AUTHENTICATED); if (r < 0) return r; } @@ -435,7 +438,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns } if (add_soa) { - r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL); + r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL, ifindex); if (r < 0) return r; } diff --git a/src/resolve/resolved-dns-zone.h b/src/resolve/resolved-dns-zone.h index 408833c359..a41df37e6b 100644 --- a/src/resolve/resolved-dns-zone.h +++ b/src/resolve/resolved-dns-zone.h @@ -65,7 +65,7 @@ void dns_zone_flush(DnsZone *z); int dns_zone_put(DnsZone *z, DnsScope *s, DnsResourceRecord *rr, bool probe); void dns_zone_remove_rr(DnsZone *z, DnsResourceRecord *rr); -int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **answer, DnsAnswer **soa, bool *tentative); +int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, int ifindex, DnsAnswer **answer, DnsAnswer **soa, bool *tentative); void dns_zone_item_conflict(DnsZoneItem *i); void dns_zone_item_notify(DnsZoneItem *i); diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index a46f13b92f..23101cb760 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -474,7 +474,6 @@ static int manager_sigusr2(sd_event_source *s, const struct signalfd_siginfo *si assert(m); manager_flush_caches(m); - log_info("Flushed all caches."); return 0; } @@ -1257,4 +1256,6 @@ void manager_flush_caches(Manager *m) { LIST_FOREACH(scopes, scope, m->dns_scopes) dns_cache_flush(&scope->cache); + + log_info("Flushed all caches."); } diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 8f4f93ee0c..04471e2373 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -83,18 +83,14 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen if (isempty(eq)) r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", USEC_INFINITY); - else if (endswith(eq, "%")) { - double percent; - - if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) { - log_error("CPU quota '%s' invalid.", eq); + else { + r = parse_percent(eq); + if (r <= 0) { + log_error_errno(r, "CPU quota '%s' invalid.", eq); return -EINVAL; } - r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", (usec_t) percent * USEC_PER_SEC / 100); - } else { - log_error("CPU quota needs to be in percent."); - return -EINVAL; + r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", (usec_t) r * USEC_PER_SEC / 100U); } goto finish; @@ -110,6 +106,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen char *n; usec_t t; size_t l; + r = parse_sec(eq, &t); if (r < 0) return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq); @@ -123,6 +120,34 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen strcpy(mempcpy(n, field, l - 3), "USec"); r = sd_bus_message_append(m, "sv", n, "t", t); goto finish; + + } else if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemoryLimit")) { + uint64_t bytes; + + if (isempty(eq) || streq(eq, "infinity")) + bytes = CGROUP_LIMIT_MAX; + else { + r = parse_percent(eq); + if (r >= 0) { + char *n; + + /* When this is a percentage we'll convert this into a relative value in the range + * 0…UINT32_MAX and pass it in the MemoryLowByPhysicalMemory property (and related + * ones). This way the physical memory size can be determined server-side */ + + n = strjoina(field, "ByPhysicalMemory"); + r = sd_bus_message_append(m, "sv", n, "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U)); + goto finish; + + } else { + r = parse_size(eq, 1024, &bytes); + if (r < 0) + return log_error_errno(r, "Failed to parse bytes specification %s", assignment); + } + } + + r = sd_bus_message_append(m, "sv", field, "t", bytes); + goto finish; } r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); @@ -166,21 +191,6 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "b", r); - } else if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemoryLimit")) { - uint64_t bytes; - - if (isempty(eq) || streq(eq, "infinity")) - bytes = CGROUP_LIMIT_MAX; - else { - r = parse_size(eq, 1024, &bytes); - if (r < 0) { - log_error("Failed to parse bytes specification %s", assignment); - return -EINVAL; - } - } - - r = sd_bus_message_append(m, "v", "t", bytes); - } else if (streq(field, "TasksMax")) { uint64_t n; @@ -1113,7 +1123,8 @@ static int dump_processes( assert(n == cg->n_children); qsort_safe(children, n, sizeof(struct CGroupInfo*), cgroup_info_compare_func); - n_columns = MAX(LESS_BY(n_columns, 2U), 20U); + if (n_columns != 0) + n_columns = MAX(LESS_BY(n_columns, 2U), 20U); for (i = 0; i < n; i++) { _cleanup_free_ char *pp = NULL; diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 8cfa936347..8e3307dc24 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -1505,40 +1505,6 @@ int bus_path_decode_unique(const char *path, const char *prefix, char **ret_send return 1; } -bool is_kdbus_wanted(void) { - _cleanup_free_ char *value = NULL; -#ifdef ENABLE_KDBUS - const bool configured = true; -#else - const bool configured = false; -#endif - - int r; - - if (get_proc_cmdline_key("kdbus", NULL) > 0) - return true; - - r = get_proc_cmdline_key("kdbus=", &value); - if (r <= 0) - return configured; - - return parse_boolean(value) == 1; -} - -bool is_kdbus_available(void) { - _cleanup_close_ int fd = -1; - struct kdbus_cmd cmd = { .size = sizeof(cmd), .flags = KDBUS_FLAG_NEGOTIATE }; - - if (!is_kdbus_wanted()) - return false; - - fd = open("/sys/fs/kdbus/control", O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY); - if (fd < 0) - return false; - - return ioctl(fd, KDBUS_CMD_BUS_MAKE, &cmd) >= 0; -} - int bus_property_get_rlimit( sd_bus *bus, const char *path, diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index d792258ecd..db6b1acba2 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -157,7 +157,4 @@ int bus_log_create_error(int r); int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path); int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external); -bool is_kdbus_wanted(void); -bool is_kdbus_available(void); - int bus_property_get_rlimit(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); diff --git a/src/shared/install.c b/src/shared/install.c index 64d66a45d3..23cab96c50 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -779,7 +779,7 @@ static int find_symlinks( fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); if (fd < 0) { - if (errno == ENOENT) + if (IN_SET(errno, ENOENT, ENOTDIR, EACCES)) return 0; return -errno; } @@ -1271,7 +1271,7 @@ static int unit_file_search( info->path = path; path = NULL; return r; - } else if (r != -ENOENT) + } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES)) return r; } @@ -1296,7 +1296,7 @@ static int unit_file_search( info->path = path; path = NULL; return r; - } else if (r != -ENOENT) + } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES)) return r; } } @@ -2870,6 +2870,10 @@ int unit_file_get_list( if (!d) { if (errno == ENOENT) continue; + if (IN_SET(errno, ENOTDIR, EACCES)) { + log_debug("Failed to open \"%s\": %m", *i); + continue; + } return -errno; } diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index 30d22d2242..8656d112b8 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -95,7 +95,31 @@ const SystemCallFilterSet syscall_filter_sets[] = { .set_name = "@clock", .value = "adjtimex\0" + "clock_adjtime\0" + "clock_settime\0" "settimeofday\0" + "stime\0" + }, { + /* CPU emulation calls */ + .set_name = "@cpu-emulation", + .value = + "modify_ldt\0" + "subpage_prot\0" + "switch_endian\0" + "vm86\0" + "vm86old\0" + }, { + /* Debugging/Performance Monitoring/Tracing */ + .set_name = "@debug", + .value = + "lookup_dcookie\0" + "perf_event_open\0" + "process_vm_readv\0" + "process_vm_writev\0" + "ptrace\0" + "rtas\0" + "s390_runtime_instr\0" + "sys_debug_setcontext\0" }, { /* Default list */ .set_name = "@default", @@ -148,10 +172,16 @@ const SystemCallFilterSet syscall_filter_sets[] = { "shmdt\0" "shmget\0" }, { + /* Keyring */ + .set_name = "@keyring", + .value = + "add_key\0" + "keyctl\0" + "request_key\0" + }, { /* Kernel module control */ .set_name = "@module", .value = - "create_module\0" "delete_module\0" "finit_module\0" "init_module\0" @@ -197,40 +227,26 @@ const SystemCallFilterSet syscall_filter_sets[] = { "_sysctl\0" "afs_syscall\0" "break\0" - "fattach\0" - "fdetach\0" + "create_module\0" "ftime\0" "get_kernel_syms\0" - "get_mempolicy\0" - "getmsg\0" "getpmsg\0" "gtty\0" - "isastream\0" "lock\0" - "madvise1\0" - "modify_ldt\0" "mpx\0" - "pciconfig_iobase\0" - "perf_event_open\0" "prof\0" "profil\0" - "putmsg\0" "putpmsg\0" "query_module\0" - "rtas\0" - "s390_runtime_instr\0" "security\0" "sgetmask\0" "ssetmask\0" "stty\0" - "subpage_prot\0" - "switch_endian\0" - "sys_debug_setcontext\0" + "sysfs\0" "tuxcall\0" "ulimit\0" "uselib\0" - "vm86\0" - "vm86old\0" + "ustat\0" "vserver\0" }, { /* Nice grab-bag of all system calls which need superuser capabilities */ @@ -242,6 +258,7 @@ const SystemCallFilterSet syscall_filter_sets[] = { "acct\0" "bdflush\0" "bpf\0" + "capset\0" "chown32\0" "chown\0" "chroot\0" @@ -268,7 +285,6 @@ const SystemCallFilterSet syscall_filter_sets[] = { "setreuid\0" "setuid32\0" "setuid\0" - "stime\0" "swapoff\0" "swapon\0" "sysctl\0" @@ -295,6 +311,7 @@ const SystemCallFilterSet syscall_filter_sets[] = { .value = "ioperm\0" "iopl\0" + "pciconfig_iobase\0" "pciconfig_read\0" "pciconfig_write\0" "s390_pci_mmio_read\0" diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 784c1cd7b5..0dfdae4538 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -588,7 +588,8 @@ static int get_unit_list( return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, &reply); - if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) { + if (r < 0 && (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD) || + sd_bus_error_has_name(&error, SD_BUS_ERROR_ACCESS_DENIED))) { /* Fallback to legacy ListUnitsFiltered method */ fallback = true; log_debug_errno(r, "Failed to list units: %s Falling back to ListUnitsFiltered method.", bus_error_message(&error, r)); @@ -734,12 +735,12 @@ static int list_units(int argc, char *argv[], void *userdata) { sd_bus *bus; int r; - pager_open(arg_no_pager, false); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + pager_open(arg_no_pager, false); + r = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines); if (r < 0) return r; @@ -946,12 +947,12 @@ static int list_sockets(int argc, char *argv[], void *userdata) { int r = 0, n; sd_bus *bus; - pager_open(arg_no_pager, false); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + pager_open(arg_no_pager, false); + n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines); if (n < 0) return n; @@ -1253,12 +1254,12 @@ static int list_timers(int argc, char *argv[], void *userdata) { sd_bus *bus; int r = 0; - pager_open(arg_no_pager, false); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + pager_open(arg_no_pager, false); + n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines); if (n < 0) return n; @@ -1424,8 +1425,6 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { int r; bool fallback = false; - pager_open(arg_no_pager, false); - if (install_client_side()) { Hashmap *h; UnitFileList *u; @@ -1540,6 +1539,8 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { return bus_log_parse_error(r); } + pager_open(arg_no_pager, false); + qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list); output_unit_file_list(units, c); @@ -1788,12 +1789,12 @@ static int list_dependencies(int argc, char *argv[], void *userdata) { } else u = SPECIAL_DEFAULT_TARGET; - pager_open(arg_no_pager, false); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + pager_open(arg_no_pager, false); + puts(u); return list_dependencies_one(bus, u, 0, &units, 0); @@ -2019,8 +2020,6 @@ static int list_machines(int argc, char *argv[], void *userdata) { return -EPERM; } - pager_open(arg_no_pager, false); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; @@ -2029,6 +2028,8 @@ static int list_machines(int argc, char *argv[], void *userdata) { if (r < 0) return r; + pager_open(arg_no_pager, false); + qsort_safe(machine_infos, r, sizeof(struct machine_info), compare_machine_info); output_machines_list(machine_infos, r); free_machines_list(machine_infos, r); @@ -2232,8 +2233,6 @@ static int list_jobs(int argc, char *argv[], void *userdata) { int r; bool skipped = false; - pager_open(arg_no_pager, false); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; @@ -2274,6 +2273,8 @@ static int list_jobs(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_parse_error(r); + pager_open(arg_no_pager, false); + output_jobs_list(jobs, c, skipped); return 0; } @@ -2286,12 +2287,12 @@ static int cancel_job(int argc, char *argv[], void *userdata) { if (argc <= 1) return trivial_method(argc, argv, userdata); - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + STRV_FOREACH(name, strv_skip(argv, 1)) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; uint32_t id; @@ -2827,13 +2828,13 @@ static int start_unit(int argc, char *argv[], void *userdata) { char **name; int r = 0; - ask_password_agent_open_if_enabled(); - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + ask_password_agent_open_if_enabled(); + polkit_agent_open_if_enabled(); + if (arg_action == ACTION_SYSTEMCTL) { enum action action; @@ -2953,9 +2954,6 @@ static int logind_reboot(enum action a) { sd_bus *bus; int r; - polkit_agent_open_if_enabled(); - (void) logind_set_wall_message(); - r = acquire_bus(BUS_FULL, &bus); if (r < 0) return r; @@ -2991,6 +2989,9 @@ static int logind_reboot(enum action a) { return -EINVAL; } + polkit_agent_open_if_enabled(); + (void) logind_set_wall_message(); + r = sd_bus_call_method( bus, "org.freedesktop.login1", @@ -3337,12 +3338,12 @@ static int kill_unit(int argc, char *argv[], void *userdata) { sd_bus *bus; int r, q; - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + if (!arg_kill_who) arg_kill_who = "all"; @@ -3847,14 +3848,13 @@ static void print_status_info( printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC)); } - if (i->control_group) - printf(" CGroup: %s\n", i->control_group); - - { + if (i->control_group) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; static const char prefix[] = " "; unsigned c; + printf(" CGroup: %s\n", i->control_group); + c = columns(); if (c > sizeof(prefix) - 1) c -= sizeof(prefix) - 1; @@ -4559,12 +4559,20 @@ static int show_one( const char *verb, sd_bus *bus, const char *path, + const char *unit, bool show_properties, bool *new_line, bool *ellipsized) { + static const struct bus_properties_map property_map[] = { + { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) }, + { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) }, + {} + }; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_set_free_ Set *found_properties = NULL; UnitStatusInfo info = { .memory_current = (uint64_t) -1, .memory_high = CGROUP_LIMIT_MAX, @@ -4574,14 +4582,6 @@ static int show_one( .tasks_current = (uint64_t) -1, .tasks_max = (uint64_t) -1, }; - struct property_info { - const char *load_state, *active_state; - } property_info = {}; - static const struct bus_properties_map property_map[] = { - { "LoadState", "s", NULL, offsetof(struct property_info, load_state) }, - { "ActiveState", "s", NULL, offsetof(struct property_info, active_state) }, - {} - }; ExecStatusInfo *p; int r; @@ -4602,16 +4602,24 @@ static int show_one( if (r < 0) return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r)); - r = bus_message_map_all_properties(reply, property_map, &property_info); - if (r < 0) - return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r)); + if (unit) { + r = bus_message_map_all_properties(reply, property_map, &info); + if (r < 0) + return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r)); - if (streq_ptr(property_info.load_state, "not-found") && streq_ptr(property_info.active_state, "inactive")) - return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN; + if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) { + log_error("Unit %s could not be found.", unit); - r = sd_bus_message_rewind(reply, true); - if (r < 0) - return log_error_errno(r, "Failed to rewind: %s", bus_error_message(&error, r)); + if (streq(verb, "status")) + return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN; + + return -ENOENT; + } + + r = sd_bus_message_rewind(reply, true); + if (r < 0) + return log_error_errno(r, "Failed to rewind: %s", bus_error_message(&error, r)); + } r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}"); if (r < 0) @@ -4637,9 +4645,17 @@ static int show_one( if (r < 0) return bus_log_parse_error(r); - if (show_properties) + if (show_properties) { + r = set_ensure_allocated(&found_properties, &string_hash_ops); + if (r < 0) + return log_oom(); + + r = set_put(found_properties, name); + if (r < 0 && r != EEXIST) + return log_oom(); + r = print_property(name, reply, contents); - else + } else r = status_property(name, reply, &info, contents); if (r < 0) return r; @@ -4661,35 +4677,30 @@ static int show_one( r = 0; - if (!show_properties) { - if (streq(verb, "help")) - show_unit_help(&info); + if (show_properties) { + char **pp; + + STRV_FOREACH(pp, arg_properties) { + if (!set_contains(found_properties, *pp)) { + log_warning("Property %s does not exist.", *pp); + r = -ENXIO; + } + } + } else if (streq(verb, "help")) + show_unit_help(&info); + else if (streq(verb, "status")) { + print_status_info(bus, &info, ellipsized); + + if (info.active_state && STR_IN_SET(info.active_state, "inactive", "failed")) + r = EXIT_PROGRAM_NOT_RUNNING; else - print_status_info(bus, &info, ellipsized); + r = EXIT_PROGRAM_RUNNING_OR_SERVICE_OK; } strv_free(info.documentation); strv_free(info.dropin_paths); strv_free(info.listen); - if (!streq_ptr(info.active_state, "active") && - !streq_ptr(info.active_state, "reloading") && - streq(verb, "status")) { - /* According to LSB: "program not running" */ - /* 0: program is running or service is OK - * 1: program is dead and /run PID file exists - * 2: program is dead and /run/lock lock file exists - * 3: program is not running - * 4: program or service status is unknown - */ - if (info.pid_file && access(info.pid_file, F_OK) == 0) - r = EXIT_PROGRAM_DEAD_AND_PID_EXISTS; - else if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) - r = EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN; - else - r = EXIT_PROGRAM_NOT_RUNNING; - } - while ((p = info.exec)) { LIST_REMOVE(exec, info.exec, p); exec_status_info_free(p); @@ -4762,7 +4773,7 @@ static int show_all( if (!p) return log_oom(); - r = show_one(verb, bus, p, show_properties, new_line, ellipsized); + r = show_one(verb, bus, p, u->id, show_properties, new_line, ellipsized); if (r < 0) return r; else if (r > 0 && ret == 0) @@ -4844,6 +4855,10 @@ static int show(int argc, char *argv[], void *userdata) { return -EINVAL; } + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + pager_open(arg_no_pager, false); if (show_status) @@ -4852,17 +4867,12 @@ static int show(int argc, char *argv[], void *userdata) { * be split up into many files. */ setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384)); - r = acquire_bus(BUS_MANAGER, &bus); - if (r < 0) - return r; - /* If no argument is specified inspect the manager itself */ if (show_properties && argc <= 1) - return show_one(argv[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized); + return show_one(argv[0], bus, "/org/freedesktop/systemd1", NULL, show_properties, &new_line, &ellipsized); if (show_status && argc <= 1) { - pager_open(arg_no_pager, false); show_system_status(bus); new_line = true; @@ -4873,7 +4883,7 @@ static int show(int argc, char *argv[], void *userdata) { char **name; STRV_FOREACH(name, strv_skip(argv, 1)) { - _cleanup_free_ char *unit = NULL; + _cleanup_free_ char *path = NULL, *unit = NULL; uint32_t id; if (safe_atou32(*name, &id) < 0) { @@ -4883,19 +4893,23 @@ static int show(int argc, char *argv[], void *userdata) { continue; } else if (show_properties) { /* Interpret as job id */ - if (asprintf(&unit, "/org/freedesktop/systemd1/job/%u", id) < 0) + if (asprintf(&path, "/org/freedesktop/systemd1/job/%u", id) < 0) return log_oom(); } else { /* Interpret as PID */ - r = get_unit_dbus_path_by_pid(bus, id, &unit); + r = get_unit_dbus_path_by_pid(bus, id, &path); if (r < 0) { ret = r; continue; } + + r = unit_name_from_dbus_path(path, &unit); + if (r < 0) + return log_oom(); } - r = show_one(argv[0], bus, unit, show_properties, &new_line, &ellipsized); + r = show_one(argv[0], bus, path, unit, show_properties, &new_line, &ellipsized); if (r < 0) return r; else if (r > 0 && ret == 0) @@ -4910,20 +4924,17 @@ static int show(int argc, char *argv[], void *userdata) { return log_error_errno(r, "Failed to expand names: %m"); STRV_FOREACH(name, names) { - _cleanup_free_ char *unit; + _cleanup_free_ char *path; - unit = unit_dbus_path_from_name(*name); - if (!unit) + path = unit_dbus_path_from_name(*name); + if (!path) return log_oom(); - r = show_one(argv[0], bus, unit, show_properties, &new_line, &ellipsized); + r = show_one(argv[0], bus, path, *name, show_properties, &new_line, &ellipsized); if (r < 0) return r; - else if (r > 0 && ret == 0) + if (r > 0 && ret == 0) ret = r; - - if (r == EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN) - log_error("Can't display property %s. Unit %s does not exist.", *patterns, *name); } } } @@ -5018,12 +5029,12 @@ static int set_property(int argc, char *argv[], void *userdata) { char **i; int r; - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + r = sd_bus_message_new_method_call( bus, &m, @@ -5070,12 +5081,12 @@ static int daemon_reload(int argc, char *argv[], void *userdata) { sd_bus *bus; int r; - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + switch (arg_action) { case ACTION_RELOAD: @@ -5130,12 +5141,12 @@ static int trivial_method(int argc, char *argv[], void *userdata) { sd_bus *bus; int r; - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + method = streq(argv[0], "clear-jobs") || streq(argv[0], "cancel") ? "ClearJobs" : @@ -5173,12 +5184,12 @@ static int reset_failed(int argc, char *argv[], void *userdata) { if (argc <= 1) return trivial_method(argc, argv, userdata); - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + r = expand_names(bus, strv_skip(argv, 1), NULL, &names); if (r < 0) return log_error_errno(r, "Failed to expand names: %m"); @@ -5212,12 +5223,12 @@ static int show_environment(int argc, char *argv[], void *userdata) { sd_bus *bus; int r; - pager_open(arg_no_pager, false); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + pager_open(arg_no_pager, false); + r = sd_bus_get_property( bus, "org.freedesktop.systemd1", @@ -5321,12 +5332,12 @@ static int set_environment(int argc, char *argv[], void *userdata) { assert(argc > 1); assert(argv); - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + method = streq(argv[0], "set-environment") ? "SetEnvironment" : "UnsetEnvironment"; @@ -5358,12 +5369,12 @@ static int import_environment(int argc, char *argv[], void *userdata) { sd_bus *bus; int r; - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + r = sd_bus_message_new_method_call( bus, &m, @@ -5655,12 +5666,12 @@ static int enable_unit(int argc, char *argv[], void *userdata) { const char *method; sd_bus *bus; - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + if (streq(verb, "enable")) { method = "EnableUnitFiles"; expect_carries_install_info = true; @@ -5821,12 +5832,12 @@ static int add_dependency(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus; - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + r = sd_bus_message_new_method_call( bus, &m, @@ -5883,12 +5894,12 @@ static int preset_all(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; sd_bus *bus; - polkit_agent_open_if_enabled(); - r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) return r; + polkit_agent_open_if_enabled(); + r = sd_bus_call_method( bus, "org.freedesktop.systemd1", @@ -7709,8 +7720,6 @@ static int logind_schedule_shutdown(void) { sd_bus *bus; int r; - (void) logind_set_wall_message(); - r = acquire_bus(BUS_FULL, &bus); if (r < 0) return r; @@ -7737,6 +7746,8 @@ static int logind_schedule_shutdown(void) { if (arg_dry) action = strjoina("dry-", action); + (void) logind_set_wall_message(); + r = sd_bus_call_method( bus, "org.freedesktop.login1", @@ -7927,6 +7938,8 @@ int main(int argc, char*argv[]) { } finish: + release_busses(); + pager_close(); ask_password_agent_close(); polkit_agent_close(); @@ -7938,8 +7951,6 @@ finish: strv_free(arg_wall); free(arg_root); - release_busses(); - /* Note that we return r here, not EXIT_SUCCESS, so that we can implement the LSB-like return codes */ return r < 0 ? EXIT_FAILURE : r; } diff --git a/src/test/test-nss.c b/src/test/test-nss.c index 55af592287..c43bda5917 100644 --- a/src/test/test-nss.c +++ b/src/test/test-nss.c @@ -400,8 +400,8 @@ int main(int argc, char **argv) { _cleanup_free_ char *dir = NULL, *hostname = NULL; const char *module; - const uint32_t local_address_ipv4 = htonl(0x7F000001); - const uint32_t local_address_ipv4_2 = htonl(0x7F000002); + const uint32_t local_address_ipv4 = htobe32(0x7F000001); + const uint32_t local_address_ipv4_2 = htobe32(0x7F000002); _cleanup_free_ struct local_address *addresses = NULL; int n_addresses; diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c index 7d8677e17c..0a76308f72 100644 --- a/src/test/test-parse-util.c +++ b/src/test/test-parse-util.c @@ -475,6 +475,24 @@ static void test_safe_atod(void) { assert_se(*e == ','); } +static void test_parse_percent(void) { + assert_se(parse_percent("") == -EINVAL); + assert_se(parse_percent("foo") == -EINVAL); + assert_se(parse_percent("0") == -EINVAL); + assert_se(parse_percent("50") == -EINVAL); + assert_se(parse_percent("100") == -EINVAL); + assert_se(parse_percent("-1") == -EINVAL); + assert_se(parse_percent("0%") == 0); + assert_se(parse_percent("55%") == 55); + assert_se(parse_percent("100%") == 100); + assert_se(parse_percent("-7%") == -ERANGE); + assert_se(parse_percent("107%") == -ERANGE); + assert_se(parse_percent("%") == -EINVAL); + assert_se(parse_percent("%%") == -EINVAL); + assert_se(parse_percent("%1") == -EINVAL); + assert_se(parse_percent("1%%") == -EINVAL); +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -488,6 +506,7 @@ int main(int argc, char *argv[]) { test_safe_atou16(); test_safe_atoi16(); test_safe_atod(); + test_parse_percent(); return 0; } diff --git a/src/test/test-proc-cmdline.c b/src/test/test-proc-cmdline.c index a7a8f621a2..80ad5ed98b 100644 --- a/src/test/test-proc-cmdline.c +++ b/src/test/test-proc-cmdline.c @@ -23,6 +23,7 @@ #include "proc-cmdline.h" #include "special.h" #include "string-util.h" +#include "util.h" static int parse_item(const char *key, const char *value) { assert_se(key); @@ -36,9 +37,19 @@ static void test_parse_proc_cmdline(void) { } static void test_runlevel_to_target(void) { + in_initrd_force(false); assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("rd.unknown-runlevel"), NULL)); assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET)); + assert_se(streq_ptr(runlevel_to_target("rd.rescue"), NULL)); + + in_initrd_force(true); + assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); + assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("rd.unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("3"), NULL)); + assert_se(streq_ptr(runlevel_to_target("rd.rescue"), SPECIAL_RESCUE_TARGET)); } int main(void) { diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index 4616314200..99c92780b8 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -18,82 +18,87 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <sched.h> +#include <sys/mount.h> #include <sys/personality.h> +#include <sys/prctl.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> +#ifdef HAVE_VALGRIND_VALGRIND_H +#include <valgrind/valgrind.h> +#endif #include "alloc-util.h" #include "architecture.h" +#include "fd-util.h" #include "log.h" #include "macro.h" +#include "parse-util.h" #include "process-util.h" +#include "stdio-util.h" #include "string-util.h" #include "terminal-util.h" #include "util.h" #include "virt.h" -static void test_get_process_comm(void) { +static void test_get_process_comm(pid_t pid) { struct stat st; _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL, *cwd = NULL, *root = NULL; _cleanup_free_ char *env = NULL; + char path[strlen("/proc//comm") + DECIMAL_STR_MAX(pid_t)]; pid_t e; uid_t u; gid_t g; dev_t h; int r; - pid_t me; - - if (stat("/proc/1/comm", &st) == 0) { - assert_se(get_process_comm(1, &a) >= 0); - log_info("pid1 comm: '%s'", a); - } else - log_warning("/proc/1/comm does not exist."); - assert_se(get_process_cmdline(1, 0, true, &c) >= 0); - log_info("pid1 cmdline: '%s'", c); + xsprintf(path, "/proc/"PID_FMT"/comm", pid); - assert_se(get_process_cmdline(1, 8, false, &d) >= 0); - log_info("pid1 cmdline truncated: '%s'", d); + if (stat(path, &st) == 0) { + assert_se(get_process_comm(pid, &a) >= 0); + log_info("PID"PID_FMT" comm: '%s'", pid, a); + } else + log_warning("%s not exist.", path); - assert_se(get_process_ppid(1, &e) >= 0); - log_info("pid1 ppid: "PID_FMT, e); - assert_se(e == 0); + assert_se(get_process_cmdline(pid, 0, true, &c) >= 0); + log_info("PID"PID_FMT" cmdline: '%s'", pid, c); - assert_se(is_kernel_thread(1) == 0); + assert_se(get_process_cmdline(pid, 8, false, &d) >= 0); + log_info("PID"PID_FMT" cmdline truncated to 8: '%s'", pid, d); - r = get_process_exe(1, &f); - assert_se(r >= 0 || r == -EACCES); - log_info("pid1 exe: '%s'", strna(f)); + free(d); + assert_se(get_process_cmdline(pid, 1, false, &d) >= 0); + log_info("PID"PID_FMT" cmdline truncated to 1: '%s'", pid, d); - assert_se(get_process_uid(1, &u) == 0); - log_info("pid1 uid: "UID_FMT, u); - assert_se(u == 0); + assert_se(get_process_ppid(pid, &e) >= 0); + log_info("PID"PID_FMT" PPID: "PID_FMT, pid, e); + assert_se(pid == 1 ? e == 0 : e > 0); - assert_se(get_process_gid(1, &g) == 0); - log_info("pid1 gid: "GID_FMT, g); - assert_se(g == 0); + assert_se(is_kernel_thread(pid) == 0 || pid != 1); - me = getpid(); - - r = get_process_cwd(me, &cwd); + r = get_process_exe(pid, &f); assert_se(r >= 0 || r == -EACCES); - log_info("pid1 cwd: '%s'", cwd); + log_info("PID"PID_FMT" exe: '%s'", pid, strna(f)); - r = get_process_root(me, &root); - assert_se(r >= 0 || r == -EACCES); - log_info("pid1 root: '%s'", root); + assert_se(get_process_uid(pid, &u) == 0); + log_info("PID"PID_FMT" UID: "UID_FMT, pid, u); + assert_se(u == 0 || pid != 1); - r = get_process_environ(me, &env); + assert_se(get_process_gid(pid, &g) == 0); + log_info("PID"PID_FMT" GID: "GID_FMT, pid, g); + assert_se(g == 0 || pid != 1); + + r = get_process_environ(pid, &env); assert_se(r >= 0 || r == -EACCES); - log_info("self strlen(environ): '%zu'", strlen(env)); + log_info("PID"PID_FMT" strlen(environ): %zi", pid, env ? (ssize_t)strlen(env) : (ssize_t)-errno); if (!detect_container()) - assert_se(get_ctty_devnr(1, &h) == -ENXIO); + assert_se(get_ctty_devnr(pid, &h) == -ENXIO || pid != 1); - getenv_for_pid(1, "PATH", &i); - log_info("pid1 $PATH: '%s'", strna(i)); + getenv_for_pid(pid, "PATH", &i); + log_info("PID"PID_FMT" $PATH: '%s'", pid, strna(i)); } static void test_pid_is_unwaited(void) { @@ -153,14 +158,213 @@ static void test_personality(void) { #endif } +static void test_get_process_cmdline_harder(void) { + char path[] = "/tmp/test-cmdlineXXXXXX"; + _cleanup_close_ int fd = -1; + _cleanup_free_ char *line = NULL; + pid_t pid; + + if (geteuid() != 0) + return; + +#ifdef HAVE_VALGRIND_VALGRIND_H + /* valgrind patches open(/proc//cmdline) + * so, test_get_process_cmdline_harder fails always + * See https://github.com/systemd/systemd/pull/3555#issuecomment-226564908 */ + if (RUNNING_ON_VALGRIND) + return; +#endif + + pid = fork(); + if (pid > 0) { + siginfo_t si; + + (void) wait_for_terminate(pid, &si); + + assert_se(si.si_code == CLD_EXITED); + assert_se(si.si_status == 0); + + return; + } + + assert_se(pid == 0); + assert_se(unshare(CLONE_NEWNS) >= 0); + + fd = mkostemp(path, O_CLOEXEC); + assert_se(fd >= 0); + assert_se(mount(path, "/proc/self/cmdline", "bind", MS_BIND, NULL) >= 0); + assert_se(unlink(path) >= 0); + + assert_se(prctl(PR_SET_NAME, "testa") >= 0); + + assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT); + + assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); + assert_se(streq(line, "[testa]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 1, true, &line) >= 0); + assert_se(streq(line, "")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 2, true, &line) >= 0); + assert_se(streq(line, "[")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 3, true, &line) >= 0); + assert_se(streq(line, "[.")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 4, true, &line) >= 0); + assert_se(streq(line, "[..")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 5, true, &line) >= 0); + assert_se(streq(line, "[...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 6, true, &line) >= 0); + assert_se(streq(line, "[...]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 7, true, &line) >= 0); + assert_se(streq(line, "[t...]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 8, true, &line) >= 0); + assert_se(streq(line, "[testa]")); + line = mfree(line); + + assert_se(write(fd, "\0\0\0\0\0\0\0\0\0", 10) == 10); + + assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT); + + assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); + assert_se(streq(line, "[testa]")); + line = mfree(line); + + assert_se(write(fd, "foo\0bar\0\0\0\0\0", 10) == 10); + + assert_se(get_process_cmdline(getpid(), 0, false, &line) >= 0); + assert_se(streq(line, "foo bar")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); + assert_se(streq(line, "foo bar")); + line = mfree(line); + + assert_se(write(fd, "quux", 4) == 4); + assert_se(get_process_cmdline(getpid(), 0, false, &line) >= 0); + assert_se(streq(line, "foo bar quux")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); + assert_se(streq(line, "foo bar quux")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 1, true, &line) >= 0); + assert_se(streq(line, "")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 2, true, &line) >= 0); + assert_se(streq(line, ".")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 3, true, &line) >= 0); + assert_se(streq(line, "..")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 4, true, &line) >= 0); + assert_se(streq(line, "...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 5, true, &line) >= 0); + assert_se(streq(line, "f...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 6, true, &line) >= 0); + assert_se(streq(line, "fo...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 7, true, &line) >= 0); + assert_se(streq(line, "foo...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 8, true, &line) >= 0); + assert_se(streq(line, "foo...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 9, true, &line) >= 0); + assert_se(streq(line, "foo b...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 10, true, &line) >= 0); + assert_se(streq(line, "foo ba...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 11, true, &line) >= 0); + assert_se(streq(line, "foo bar...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 12, true, &line) >= 0); + assert_se(streq(line, "foo bar...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 13, true, &line) >= 0); + assert_se(streq(line, "foo bar quux")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 14, true, &line) >= 0); + assert_se(streq(line, "foo bar quux")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 1000, true, &line) >= 0); + assert_se(streq(line, "foo bar quux")); + line = mfree(line); + + assert_se(ftruncate(fd, 0) >= 0); + assert_se(prctl(PR_SET_NAME, "aaaa bbbb cccc") >= 0); + + assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT); + + assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); + assert_se(streq(line, "[aaaa bbbb cccc]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 10, true, &line) >= 0); + assert_se(streq(line, "[aaaa...]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 11, true, &line) >= 0); + assert_se(streq(line, "[aaaa...]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 12, true, &line) >= 0); + assert_se(streq(line, "[aaaa b...]")); + line = mfree(line); + + safe_close(fd); + _exit(0); +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - test_get_process_comm(); + if (argc > 1) { + pid_t pid = 0; + + (void) parse_pid(argv[1], &pid); + test_get_process_comm(pid); + } else { + test_get_process_comm(1); + test_get_process_comm(getpid()); + } + test_pid_is_unwaited(); test_pid_is_alive(); test_personality(); + test_get_process_cmdline_harder(); return 0; } diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index 1a439bd0d4..1f853a7f16 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -353,7 +353,7 @@ static void test_nameinfo_pretty(void) { union sockaddr_union s = { .in.sin_family = AF_INET, .in.sin_port = 0, - .in.sin_addr.s_addr = htonl(INADDR_ANY), + .in.sin_addr.s_addr = htobe32(INADDR_ANY), }; int r; @@ -391,17 +391,17 @@ static void test_sockaddr_equal(void) { union sockaddr_union a = { .in.sin_family = AF_INET, .in.sin_port = 0, - .in.sin_addr.s_addr = htonl(INADDR_ANY), + .in.sin_addr.s_addr = htobe32(INADDR_ANY), }; union sockaddr_union b = { .in.sin_family = AF_INET, .in.sin_port = 0, - .in.sin_addr.s_addr = htonl(INADDR_ANY), + .in.sin_addr.s_addr = htobe32(INADDR_ANY), }; union sockaddr_union c = { .in.sin_family = AF_INET, .in.sin_port = 0, - .in.sin_addr.s_addr = htonl(1234), + .in.sin_addr.s_addr = htobe32(1234), }; union sockaddr_union d = { .in6.sin6_family = AF_INET6, diff --git a/src/test/test-util.c b/src/test/test-util.c index 9b6d2a7968..e177612a9f 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -26,6 +26,7 @@ #include "def.h" #include "fileio.h" #include "fs-util.h" +#include "parse-util.h" #include "raw-clone.h" #include "rm-rf.h" #include "string-util.h" @@ -263,6 +264,53 @@ static void test_raw_clone(void) { } } +static void test_physical_memory(void) { + uint64_t p; + char buf[FORMAT_BYTES_MAX]; + + p = physical_memory(); + assert_se(p > 0); + assert_se(p < UINT64_MAX); + assert_se(p % page_size() == 0); + + log_info("Memory: %s (%" PRIu64 ")", format_bytes(buf, sizeof(buf), p), p); +} + +static void test_physical_memory_scale(void) { + uint64_t p; + + p = physical_memory(); + + assert_se(physical_memory_scale(0, 100) == 0); + assert_se(physical_memory_scale(100, 100) == p); + + log_info("Memory original: %" PRIu64, physical_memory()); + log_info("Memory scaled by 50%%: %" PRIu64, physical_memory_scale(50, 100)); + log_info("Memory divided by 2: %" PRIu64, physical_memory() / 2); + log_info("Page size: %zu", page_size()); + + /* There might be an uneven number of pages, hence permit these calculations to be half a page off... */ + assert_se(page_size()/2 + physical_memory_scale(50, 100) - p/2 <= page_size()); + assert_se(physical_memory_scale(200, 100) == p*2); + + assert_se(physical_memory_scale(0, 1) == 0); + assert_se(physical_memory_scale(1, 1) == p); + assert_se(physical_memory_scale(2, 1) == p*2); + + assert_se(physical_memory_scale(0, 2) == 0); + + assert_se(page_size()/2 + physical_memory_scale(1, 2) - p/2 <= page_size()); + assert_se(physical_memory_scale(2, 2) == p); + assert_se(physical_memory_scale(4, 2) == p*2); + + assert_se(physical_memory_scale(0, UINT32_MAX) == 0); + assert_se(physical_memory_scale(UINT32_MAX, UINT32_MAX) == p); + + /* overflow */ + assert_se(physical_memory_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX); + +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -277,6 +325,8 @@ int main(int argc, char *argv[]) { test_log2i(); test_execute_directory(); test_raw_clone(); + test_physical_memory(); + test_physical_memory_scale(); return 0; } diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c index b7871f81aa..7f61cf0181 100644 --- a/src/timedate/timedatectl.c +++ b/src/timedate/timedatectl.c @@ -480,7 +480,7 @@ static int timedatectl_main(sd_bus *bus, int argc, char *argv[]) { } int main(int argc, char *argv[]) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); @@ -500,6 +500,7 @@ int main(int argc, char *argv[]) { r = timedatectl_main(bus, argc, argv); finish: + sd_bus_flush_close_unref(bus); pager_close(); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index 66b51c1209..6753c52005 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -433,17 +433,13 @@ static int uinfo(struct udev *udev, int argc, char *argv[]) { case QUERY_PROPERTY: list_entry = udev_device_get_properties_list_entry(device); while (list_entry != NULL) { - if (export) { - const char *prefix = export_prefix; - - if (prefix == NULL) - prefix = ""; - printf("%s%s='%s'\n", prefix, + if (export) + printf("%s%s='%s'\n", strempty(export_prefix), udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); - } else { + else printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); - } + list_entry = udev_list_entry_get_next(list_entry); } break; |