diff options
Diffstat (limited to 'src')
31 files changed, 547 insertions, 140 deletions
diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index 5c820332a5..19ad20789b 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -24,6 +24,7 @@ #include <sys/stat.h> #include <unistd.h> +#include "dirent-util.h" #include "fd-util.h" #include "fs-util.h" #include "macro.h" @@ -234,12 +235,9 @@ int close_all_fds(const int except[], unsigned n_except) { return r; } - while ((de = readdir(d))) { + FOREACH_DIRENT(de, d, return -errno) { int fd = -1; - if (hidden_or_backup_file(de->d_name)) - continue; - if (safe_atoi(de->d_name, &fd) < 0) /* Let's better ignore this, just in case */ continue; diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index b30cec4f92..5b23269109 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -17,7 +17,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dirent.h> #include <errno.h> #include <stddef.h> #include <stdio.h> @@ -446,6 +445,7 @@ int mkfifo_atomic(const char *path, mode_t mode) { int get_files_in_directory(const char *path, char ***list) { _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; size_t bufsize = 0, n = 0; _cleanup_strv_free_ char **l = NULL; @@ -459,16 +459,7 @@ int get_files_in_directory(const char *path, char ***list) { if (!d) return -errno; - for (;;) { - struct dirent *de; - - errno = 0; - de = readdir(d); - if (!de && errno > 0) - return -errno; - if (!de) - break; - + FOREACH_DIRENT_ALL(de, d, return -errno) { dirent_ensure_type(d, de); if (!dirent_is_file(de)) diff --git a/src/basic/khash.c b/src/basic/khash.c new file mode 100644 index 0000000000..9a2a3edb75 --- /dev/null +++ b/src/basic/khash.c @@ -0,0 +1,275 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 <linux/if_alg.h> +#include <stdbool.h> +#include <sys/socket.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "hexdecoct.h" +#include "khash.h" +#include "macro.h" +#include "missing.h" +#include "string-util.h" +#include "util.h" + +/* On current kernels the maximum digest (according to "grep digestsize /proc/crypto | sort -u") is actually 32, but + * let's add some extra room, the few wasted bytes don't really matter... */ +#define LONGEST_DIGEST 128 + +struct khash { + int fd; + char *algorithm; + uint8_t digest[LONGEST_DIGEST+1]; + size_t digest_size; + bool digest_valid; +}; + +int khash_new_with_key(khash **ret, const char *algorithm, const void *key, size_t key_size) { + union { + struct sockaddr sa; + struct sockaddr_alg alg; + } sa = { + .alg.salg_family = AF_ALG, + .alg.salg_type = "hash", + }; + + _cleanup_(khash_unrefp) khash *h = NULL; + _cleanup_close_ int fd = -1; + ssize_t n; + + assert(ret); + assert(key || key_size == 0); + + /* Filter out an empty algorithm early, as we do not support an algorithm by that name. */ + if (isempty(algorithm)) + return -EINVAL; + + /* Overly long hash algorithm names we definitely do not support */ + if (strlen(algorithm) >= sizeof(sa.alg.salg_name)) + return -EOPNOTSUPP; + + fd = socket(AF_ALG, SOCK_SEQPACKET|SOCK_CLOEXEC, 0); + if (fd < 0) + return -errno; + + strcpy((char*) sa.alg.salg_name, algorithm); + if (bind(fd, &sa.sa, sizeof(sa)) < 0) { + if (errno == ENOENT) + return -EOPNOTSUPP; + return -errno; + } + + if (key) { + if (setsockopt(fd, SOL_ALG, ALG_SET_KEY, key, key_size) < 0) + return -errno; + } + + h = new0(khash, 1); + if (!h) + return -ENOMEM; + + h->fd = accept4(fd, NULL, 0, SOCK_CLOEXEC); + if (h->fd < 0) + return -errno; + + h->algorithm = strdup(algorithm); + if (!h->algorithm) + return -ENOMEM; + + /* Temporary fix for rc kernel bug: https://bugzilla.redhat.com/show_bug.cgi?id=1395896 */ + (void) send(h->fd, NULL, 0, 0); + + /* Figure out the digest size */ + n = recv(h->fd, h->digest, sizeof(h->digest), 0); + if (n < 0) + return -errno; + if (n >= LONGEST_DIGEST) /* longer than what we expected? If so, we don't support this */ + return -EOPNOTSUPP; + + h->digest_size = (size_t) n; + h->digest_valid = true; + + /* Temporary fix for rc kernel bug: https://bugzilla.redhat.com/show_bug.cgi?id=1395896 */ + (void) send(h->fd, NULL, 0, 0); + + *ret = h; + h = NULL; + + return 0; +} + +int khash_new(khash **ret, const char *algorithm) { + return khash_new_with_key(ret, algorithm, NULL, 0); +} + +khash* khash_unref(khash *h) { + if (!h) + return NULL; + + safe_close(h->fd); + free(h->algorithm); + free(h); + + return NULL; +} + +int khash_dup(khash *h, khash **ret) { + _cleanup_(khash_unrefp) khash *copy = NULL; + + assert(h); + assert(ret); + + copy = newdup(khash, h, 1); + if (!copy) + return -ENOMEM; + + copy->fd = -1; + copy->algorithm = strdup(h->algorithm); + if (!copy) + return -ENOMEM; + + copy->fd = accept4(h->fd, NULL, 0, SOCK_CLOEXEC); + if (copy->fd < 0) + return -errno; + + *ret = copy; + copy = NULL; + + return 0; +} + +const char *khash_get_algorithm(khash *h) { + assert(h); + + return h->algorithm; +} + +size_t khash_get_size(khash *h) { + assert(h); + + return h->digest_size; +} + +int khash_reset(khash *h) { + ssize_t n; + + assert(h); + + n = send(h->fd, NULL, 0, 0); + if (n < 0) + return -errno; + + h->digest_valid = false; + + return 0; +} + +int khash_put(khash *h, const void *buffer, size_t size) { + ssize_t n; + + assert(h); + assert(buffer || size == 0); + + if (size <= 0) + return 0; + + n = send(h->fd, buffer, size, MSG_MORE); + if (n < 0) + return -errno; + + h->digest_valid = false; + + return 0; +} + +int khash_put_iovec(khash *h, const struct iovec *iovec, size_t n) { + struct msghdr mh = { + mh.msg_iov = (struct iovec*) iovec, + mh.msg_iovlen = n, + }; + ssize_t k; + + assert(h); + assert(iovec || n == 0); + + if (n <= 0) + return 0; + + k = sendmsg(h->fd, &mh, MSG_MORE); + if (k < 0) + return -errno; + + h->digest_valid = false; + + return 0; +} + +static int retrieve_digest(khash *h) { + ssize_t n; + + assert(h); + + if (h->digest_valid) + return 0; + + n = recv(h->fd, h->digest, h->digest_size, 0); + if (n < 0) + return n; + if ((size_t) n != h->digest_size) /* digest size changed? */ + return -EIO; + + h->digest_valid = true; + + return 0; +} + +int khash_digest_data(khash *h, const void **ret) { + int r; + + assert(h); + assert(ret); + + r = retrieve_digest(h); + if (r < 0) + return r; + + *ret = h->digest; + return 0; +} + +int khash_digest_string(khash *h, char **ret) { + int r; + char *p; + + assert(h); + assert(ret); + + r = retrieve_digest(h); + if (r < 0) + return r; + + p = hexmem(h->digest, h->digest_size); + if (!p) + return -ENOMEM; + + *ret = p; + return 0; +} diff --git a/src/basic/khash.h b/src/basic/khash.h new file mode 100644 index 0000000000..f404a68236 --- /dev/null +++ b/src/basic/khash.h @@ -0,0 +1,53 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 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 <inttypes.h> +#include <sys/types.h> +#include <sys/uio.h> + +#include "macro.h" + +typedef struct khash khash; + +/* For plain hash functions. Hash functions commonly supported on today's kernels are: crc32c, crct10dif, crc32, + * sha224, sha256, sha512, sha384, sha1, md5, md4, sha3-224, sha3-256, sha3-384, sha3-512, and more.*/ +int khash_new(khash **ret, const char *algorithm); + +/* For keyed hash functions. Hash functions commonly supported on today's kernels are: hmac(sha256), cmac(aes), + * cmac(des3_ede), hmac(sha3-512), hmac(sha3-384), hmac(sha3-256), hmac(sha3-224), hmac(rmd160), hmac(rmd128), + * hmac(sha224), hmac(sha512), hmac(sha384), hmac(sha1), hmac(md5), and more. */ +int khash_new_with_key(khash **ret, const char *algorithm, const void *key, size_t key_size); + +int khash_dup(khash *h, khash **ret); +khash* khash_unref(khash *h); + +const char *khash_get_algorithm(khash *h); +size_t khash_get_size(khash *h); + +int khash_reset(khash *h); + +int khash_put(khash *h, const void *buffer, size_t size); +int khash_put_iovec(khash *h, const struct iovec *iovec, size_t n); + +int khash_digest_data(khash *h, const void **ret); +int khash_digest_string(khash *h, char **ret); + +DEFINE_TRIVIAL_CLEANUP_FUNC(khash*, khash_unref); diff --git a/src/basic/missing.h b/src/basic/missing.h index 8833617dc6..1502b3f4f4 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -1109,4 +1109,8 @@ struct ethtool_link_settings { #endif +#ifndef SOL_ALG +#define SOL_ALG 279 +#endif + #include "missing_syscall.h" diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c index baa70c2c8d..07d42f78dd 100644 --- a/src/basic/rm-rf.c +++ b/src/basic/rm-rf.c @@ -17,7 +17,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <stdbool.h> @@ -28,6 +27,7 @@ #include "btrfs-util.h" #include "cgroup-util.h" +#include "dirent-util.h" #include "fd-util.h" #include "log.h" #include "macro.h" @@ -43,6 +43,7 @@ static bool is_physical_fs(const struct statfs *sfs) { int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; int ret = 0, r; struct statfs sfs; @@ -78,19 +79,10 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { return errno == ENOENT ? 0 : -errno; } - for (;;) { - struct dirent *de; + FOREACH_DIRENT_ALL(de, d, return -errno) { bool is_dir; struct stat st; - errno = 0; - de = readdir(d); - if (!de) { - if (errno > 0 && ret == 0) - ret = -errno; - return ret; - } - if (streq(de->d_name, ".") || streq(de->d_name, "..")) continue; @@ -178,6 +170,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { } } } + return ret; } int rm_rf(const char *path, RemoveFlags flags) { diff --git a/src/basic/util.c b/src/basic/util.c index c1b5ca1ef7..8a630049d7 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -18,7 +18,6 @@ ***/ #include <alloca.h> -#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <sched.h> @@ -508,28 +507,17 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, int on_ac_power(void) { bool found_offline = false, found_online = false; _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; d = opendir("/sys/class/power_supply"); if (!d) return errno == ENOENT ? true : -errno; - for (;;) { - struct dirent *de; + FOREACH_DIRENT(de, d, return -errno) { _cleanup_close_ int fd = -1, device = -1; char contents[6]; ssize_t n; - errno = 0; - de = readdir(d); - if (!de && errno > 0) - return -errno; - - if (!de) - break; - - if (hidden_or_backup_file(de->d_name)) - continue; - device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY); if (device < 0) { if (errno == ENOENT || errno == ENOTDIR) diff --git a/src/core/killall.c b/src/core/killall.c index 3bc19e9c84..b3aa22adc5 100644 --- a/src/core/killall.c +++ b/src/core/killall.c @@ -24,6 +24,7 @@ #include "alloc-util.h" #include "def.h" +#include "dirent-util.h" #include "fd-util.h" #include "format-util.h" #include "killall.h" @@ -172,7 +173,7 @@ static int killall(int sig, Set *pids, bool send_sighup) { if (!dir) return -errno; - while ((d = readdir(dir))) { + FOREACH_DIRENT_ALL(d, dir, break) { pid_t pid; int r; diff --git a/src/core/manager.c b/src/core/manager.c index 1f663d3c1d..21cd6062c6 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -17,7 +17,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <linux/kd.h> @@ -233,6 +232,7 @@ static void manager_print_jobs_in_progress(Manager *m) { static int have_ask_password(void) { _cleanup_closedir_ DIR *dir; + struct dirent *de; dir = opendir("/run/systemd/ask-password"); if (!dir) { @@ -242,19 +242,11 @@ static int have_ask_password(void) { return -errno; } - for (;;) { - struct dirent *de; - - errno = 0; - de = readdir(dir); - if (!de && errno > 0) - return -errno; - if (!de) - return false; - + FOREACH_DIRENT_ALL(de, dir, return -errno) { if (startswith(de->d_name, "ask.")) return true; } + return false; } static int manager_dispatch_ask_password_fd(sd_event_source *source, diff --git a/src/core/service.c b/src/core/service.c index c68a7122b6..61246d831d 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -1714,7 +1714,7 @@ static void service_enter_running(Service *s, ServiceResult f) { } } else if (f != SERVICE_SUCCESS) - service_enter_signal(s, SERVICE_FINAL_SIGTERM, f); + service_enter_signal(s, SERVICE_STOP_SIGTERM, f); else if (s->remain_after_exit) service_set_state(s, SERVICE_EXITED); else @@ -1851,7 +1851,7 @@ static void service_enter_start(Service *s) { fail: log_unit_warning_errno(UNIT(s), r, "Failed to run 'start' task: %m"); - service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES); + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES); } static void service_enter_start_pre(Service *s) { @@ -1997,9 +1997,7 @@ static void service_run_next_control(Service *s) { fail: log_unit_warning_errno(UNIT(s), r, "Failed to run next control task: %m"); - if (s->state == SERVICE_START_PRE) - service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES); - else if (s->state == SERVICE_STOP) + if (IN_SET(s->state, SERVICE_START_PRE, SERVICE_STOP)) service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES); else if (s->state == SERVICE_STOP_POST) service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true); @@ -2600,7 +2598,7 @@ static void service_notify_cgroup_empty_event(Unit *u) { case SERVICE_START: if (s->type == SERVICE_NOTIFY) { /* No chance of getting a ready notification anymore */ - service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_PROTOCOL); + service_enter_stop_post(s, SERVICE_FAILURE_PROTOCOL); break; } @@ -2613,7 +2611,7 @@ static void service_notify_cgroup_empty_event(Unit *u) { service_unwatch_pid_file(s); if (s->state == SERVICE_START) - service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_PROTOCOL); + service_enter_stop_post(s, SERVICE_FAILURE_PROTOCOL); else service_enter_stop(s, SERVICE_FAILURE_PROTOCOL); } @@ -2747,17 +2745,17 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { if (f == SERVICE_SUCCESS) service_enter_start_post(s); else - service_enter_signal(s, SERVICE_FINAL_SIGTERM, f); + service_enter_signal(s, SERVICE_STOP_SIGTERM, f); break; } else if (s->type == SERVICE_NOTIFY) { /* Only enter running through a notification, so that the * SERVICE_START state signifies that no ready notification * has been received */ if (f != SERVICE_SUCCESS) - service_enter_signal(s, SERVICE_FINAL_SIGTERM, f); + service_enter_signal(s, SERVICE_STOP_SIGTERM, f); else if (!s->remain_after_exit) /* The service has never been active */ - service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_PROTOCOL); + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_PROTOCOL); break; } @@ -2837,7 +2835,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { if (f == SERVICE_SUCCESS) service_enter_start(s); else - service_enter_signal(s, SERVICE_FINAL_SIGTERM, f); + service_enter_signal(s, SERVICE_STOP_SIGTERM, f); break; case SERVICE_START: @@ -2846,7 +2844,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { break; if (f != SERVICE_SUCCESS) { - service_enter_signal(s, SERVICE_FINAL_SIGTERM, f); + service_enter_signal(s, SERVICE_STOP_SIGTERM, f); break; } @@ -2863,7 +2861,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { if (!has_start_post && r < 0) { r = service_demand_pid_file(s); if (r < 0 || !cgroup_good(s)) - service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_PROTOCOL); + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_PROTOCOL); break; } } else @@ -2959,7 +2957,7 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us case SERVICE_START_PRE: case SERVICE_START: log_unit_warning(UNIT(s), "%s operation timed out. Terminating.", s->state == SERVICE_START ? "Start" : "Start-pre"); - service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT); + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT); break; case SERVICE_START_POST: diff --git a/src/core/service.h b/src/core/service.h index e09722a952..ff9cfaeb88 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -79,6 +79,8 @@ typedef enum NotifyState { _NOTIFY_STATE_INVALID = -1 } NotifyState; +/* The values of this enum are referenced in man/systemd.exec.xml and src/shared/bus-unit-util.c. + * Update those sources for each change to this enum. */ typedef enum ServiceResult { SERVICE_SUCCESS, SERVICE_FAILURE_RESOURCES, /* a bit of a misnomer, just our catch-all error for errnos we didn't expect */ diff --git a/src/delta/delta.c b/src/delta/delta.c index 107b105fde..9a44b15da7 100644 --- a/src/delta/delta.c +++ b/src/delta/delta.c @@ -297,6 +297,7 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const char *path, bool dropins) { _cleanup_closedir_ DIR *d; + struct dirent *de; assert(top); assert(bottom); @@ -313,16 +314,10 @@ static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const ch return log_error_errno(errno, "Failed to open %s: %m", path); } - for (;;) { - struct dirent *de; + FOREACH_DIRENT_ALL(de, d, return -errno) { int k; char *p; - errno = 0; - de = readdir(d); - if (!de) - return -errno; - dirent_ensure_type(d, de); if (dropins && de->d_type == DT_DIR && endswith(de->d_name, ".d")) @@ -354,6 +349,7 @@ static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const ch return k; } } + return 0; } static int should_skip_prefix(const char* p) { diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 9d78b953fc..092a1eabb0 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -86,6 +86,28 @@ int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result return 0; } +static bool net_condition_test_strv(char * const *raw_patterns, + const char *string) { + if (strv_isempty(raw_patterns)) + return true; + + /* If the patterns begin with "!", edit it out and negate the test. */ + if (raw_patterns[0][0] == '!') { + char **patterns; + unsigned i, length; + + length = strv_length(raw_patterns) + 1; /* Include the NULL. */ + patterns = newa(char*, length); + patterns[0] = raw_patterns[0] + 1; /* Skip the "!". */ + for (i = 1; i < length; i++) + patterns[i] = raw_patterns[i]; + + return !string || !strv_fnmatch(patterns, string, 0); + } + + return string && strv_fnmatch(raw_patterns, string, 0); +} + bool net_match_config(const struct ether_addr *match_mac, char * const *match_paths, char * const *match_drivers, @@ -117,20 +139,16 @@ bool net_match_config(const struct ether_addr *match_mac, if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN))) return false; - if (!strv_isempty(match_paths) && - (!dev_path || !strv_fnmatch(match_paths, dev_path, 0))) + if (!net_condition_test_strv(match_paths, dev_path)) return false; - if (!strv_isempty(match_drivers) && - (!dev_driver || !strv_fnmatch(match_drivers, dev_driver, 0))) + if (!net_condition_test_strv(match_drivers, dev_driver)) return false; - if (!strv_isempty(match_types) && - (!dev_type || !strv_fnmatch_or_empty(match_types, dev_type, 0))) + if (!net_condition_test_strv(match_types, dev_type)) return false; - if (!strv_isempty(match_names) && - (!dev_name || !strv_fnmatch_or_empty(match_names, dev_name, 0))) + if (!net_condition_test_strv(match_names, dev_name)) return false; return true; diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index d48ef6bbe2..46c4dac7d7 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -511,3 +511,8 @@ global: sd_bus_get_exit_on_disconnect; sd_id128_get_invocation; } LIBSYSTEMD_231; + +LIBSYSTEMD_233 { +global: + sd_id128_get_machine_app_specific; +} LIBSYSTEMD_232; diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 1081979bf9..bc5e92f8fe 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -28,6 +28,7 @@ #include "device-internal.h" #include "device-private.h" #include "device-util.h" +#include "dirent-util.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" @@ -1627,7 +1628,7 @@ static int device_sysattrs_read_all(sd_device *device) { if (r < 0) return r; - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + FOREACH_DIRENT_ALL(dent, dir, return -errno) { char *path; struct stat statbuf; diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c index d4450c70a0..0d673ba655 100644 --- a/src/libsystemd/sd-id128/sd-id128.c +++ b/src/libsystemd/sd-id128/sd-id128.c @@ -27,6 +27,7 @@ #include "hexdecoct.h" #include "id128-util.h" #include "io-util.h" +#include "khash.h" #include "macro.h" #include "random-util.h" #include "util.h" @@ -181,3 +182,34 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) { *ret = make_v4_uuid(t); return 0; } + +_public_ int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret) { + _cleanup_(khash_unrefp) khash *h = NULL; + sd_id128_t m, result; + const void *p; + int r; + + assert_return(ret, -EINVAL); + + r = sd_id128_get_machine(&m); + if (r < 0) + return r; + + r = khash_new_with_key(&h, "hmac(sha256)", &m, sizeof(m)); + if (r < 0) + return r; + + r = khash_put(h, &app_id, sizeof(app_id)); + if (r < 0) + return r; + + r = khash_digest_data(h, &p); + if (r < 0) + return r; + + /* We chop off the trailing 16 bytes */ + memcpy(&result, p, MIN(khash_get_size(h), sizeof(result))); + + *ret = make_v4_uuid(result); + return 0; +} diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c index 42ea0badfc..d2cfbdf5b0 100644 --- a/src/libsystemd/sd-login/sd-login.c +++ b/src/libsystemd/sd-login/sd-login.c @@ -793,6 +793,7 @@ _public_ int sd_get_sessions(char ***sessions) { _public_ int sd_get_uids(uid_t **users) { _cleanup_closedir_ DIR *d; + struct dirent *de; int r = 0; unsigned n = 0; _cleanup_free_ uid_t *l = NULL; @@ -801,19 +802,10 @@ _public_ int sd_get_uids(uid_t **users) { if (!d) return -errno; - for (;;) { - struct dirent *de; + FOREACH_DIRENT_ALL(de, d, return -errno) { int k; uid_t uid; - errno = 0; - de = readdir(d); - if (!de && errno > 0) - return -errno; - - if (!de) - break; - dirent_ensure_type(d, de); if (!dirent_is_file(de)) diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 23ad5d7c6a..3873bf3e96 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1286,8 +1286,7 @@ static int flush_devices(Manager *m) { } else { struct dirent *de; - while ((de = readdir(d))) { - + FOREACH_DIRENT_ALL(de, d, break) { if (!dirent_is_file(de)) continue; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index de05b6c5ef..d701f2158d 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -490,7 +490,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:nU", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:nUE:", options, NULL)) >= 0) switch (c) { @@ -1326,6 +1326,8 @@ static int setup_resolv_conf(const char *dest) { * advantage that the container will be able to follow the host's DNS server configuration changes * transparently. */ + (void) touch(where); + r = mount_verbose(LOG_WARNING, "/usr/lib/systemd/resolv.conf", where, NULL, MS_BIND, NULL); if (r >= 0) return mount_verbose(LOG_ERR, NULL, where, NULL, diff --git a/src/shared/dropin.c b/src/shared/dropin.c index 2c1cd84df5..3cbfe13f4c 100644 --- a/src/shared/dropin.c +++ b/src/shared/dropin.c @@ -17,7 +17,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dirent.h> #include <errno.h> #include <stdarg.h> #include <stdio.h> @@ -25,6 +24,7 @@ #include "alloc-util.h" #include "conf-files.h" +#include "dirent-util.h" #include "dropin.h" #include "escape.h" #include "fd-util.h" @@ -124,6 +124,7 @@ static int iterate_dir( char ***strv) { _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; int r; assert(path); @@ -148,21 +149,9 @@ static int iterate_dir( return log_error_errno(errno, "Failed to open directory %s: %m", path); } - for (;;) { - struct dirent *de; + FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read directory %s: %m", path)) { _cleanup_free_ char *f = NULL; - errno = 0; - de = readdir(d); - if (!de && errno > 0) - return log_error_errno(errno, "Failed to read directory %s: %m", path); - - if (!de) - break; - - if (hidden_or_backup_file(de->d_name)) - continue; - f = strjoin(path, "/", de->d_name); if (!f) return log_oom(); diff --git a/src/shared/fdset.c b/src/shared/fdset.c index 527f27bc67..090f3fdcdd 100644 --- a/src/shared/fdset.c +++ b/src/shared/fdset.c @@ -18,13 +18,13 @@ ***/ #include <alloca.h> -#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <stddef.h> #include "sd-daemon.h" +#include "dirent-util.h" #include "fd-util.h" #include "fdset.h" #include "log.h" @@ -148,12 +148,9 @@ int fdset_new_fill(FDSet **_s) { goto finish; } - while ((de = readdir(d))) { + FOREACH_DIRENT(de, d, return -errno) { int fd = -1; - if (hidden_or_backup_file(de->d_name)) - continue; - r = safe_atoi(de->d_name, &fd); if (r < 0) goto finish; diff --git a/src/systemd/sd-id128.h b/src/systemd/sd-id128.h index ee011b1861..6cc8e4ac0e 100644 --- a/src/systemd/sd-id128.h +++ b/src/systemd/sd-id128.h @@ -39,12 +39,12 @@ union sd_id128 { #define SD_ID128_STRING_MAX 33 char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]); - int sd_id128_from_string(const char *s, sd_id128_t *ret); int sd_id128_randomize(sd_id128_t *ret); int sd_id128_get_machine(sd_id128_t *ret); +int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret); int sd_id128_get_boot(sd_id128_t *ret); int sd_id128_get_invocation(sd_id128_t *ret); diff --git a/src/test/test-hash.c b/src/test/test-hash.c new file mode 100644 index 0000000000..1972b94cfe --- /dev/null +++ b/src/test/test-hash.c @@ -0,0 +1,82 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 "log.h" +#include "string-util.h" +#include "khash.h" + +int main(int argc, char *argv[]) { + _cleanup_(khash_unrefp) khash *h = NULL, *copy = NULL; + _cleanup_free_ char *s = NULL; + + log_set_max_level(LOG_DEBUG); + + assert_se(khash_new(&h, NULL) == -EINVAL); + assert_se(khash_new(&h, "") == -EINVAL); + assert_se(khash_new(&h, "foobar") == -EOPNOTSUPP); + + assert_se(khash_new(&h, "sha256") >= 0); + assert_se(khash_get_size(h) == 32); + assert_se(streq(khash_get_algorithm(h), "sha256")); + + assert_se(khash_digest_string(h, &s) >= 0); + assert_se(streq(s, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")); + s = mfree(s); + + assert_se(khash_put(h, "foobar", 6) >= 0); + assert_se(khash_digest_string(h, &s) >= 0); + assert_se(streq(s, "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2")); + s = mfree(s); + + assert_se(khash_put(h, "piep", 4) >= 0); + assert_se(khash_digest_string(h, &s) >= 0); + assert_se(streq(s, "f114d872b5ea075d3be9040d0b7a429514b3f9324a8e8e3dc3fb24c34ee56bea")); + s = mfree(s); + + assert_se(khash_put(h, "foo", 3) >= 0); + assert_se(khash_dup(h, ©) >= 0); + + assert_se(khash_put(h, "bar", 3) >= 0); + assert_se(khash_put(copy, "bar", 3) >= 0); + + assert_se(khash_digest_string(h, &s) >= 0); + assert_se(streq(s, "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2")); + s = mfree(s); + + assert_se(khash_digest_string(copy, &s) >= 0); + assert_se(streq(s, "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2")); + s = mfree(s); + + h = khash_unref(h); + + assert_se(khash_new_with_key(&h, "hmac(sha256)", "quux", 4) >= 0); + assert_se(khash_get_size(h) == 32); + assert_se(streq(khash_get_algorithm(h), "hmac(sha256)")); + + assert_se(khash_digest_string(h, &s) >= 0); + assert_se(streq(s, "abed9f8218ab473f77218a6a7d39abf1d21fa46d0700c4898e330ba88309d5ae")); + s = mfree(s); + + assert_se(khash_put(h, "foobar", 6) >= 0); + assert_se(khash_digest_string(h, &s) >= 0); + assert_se(streq(s, "33f6c70a60db66007d5325d5d1dea37c371354e5b83347a59ad339ce9f4ba3dc")); + + return 0; +} diff --git a/src/test/test-id128.c b/src/test/test-id128.c index 1c8e5549da..ab5a111ba9 100644 --- a/src/test/test-id128.c +++ b/src/test/test-id128.c @@ -153,5 +153,11 @@ int main(int argc, char *argv[]) { assert_se(id128_read_fd(fd, ID128_UUID, &id2) >= 0); assert_se(sd_id128_equal(id, id2)); + assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(f0,3d,aa,eb,1c,33,4b,43,a7,32,17,29,44,bf,77,2e), &id) >= 0); + assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(f0,3d,aa,eb,1c,33,4b,43,a7,32,17,29,44,bf,77,2e), &id2) >= 0); + assert_se(sd_id128_equal(id, id2)); + assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(51,df,0b,4b,c3,b0,4c,97,80,e2,99,b9,8c,a3,73,b8), &id2) >= 0); + assert_se(!sd_id128_equal(id, id2)); + return 0; } diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index b881d774a0..79f75e165b 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -18,7 +18,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <fnmatch.h> @@ -44,6 +43,7 @@ #include "conf-files.h" #include "copy.h" #include "def.h" +#include "dirent-util.h" #include "escape.h" #include "fd-util.h" #include "fileio.h" @@ -380,7 +380,7 @@ static int dir_cleanup( bool deleted = false; int r = 0; - while ((dent = readdir(d))) { + FOREACH_DIRENT_ALL(dent, d, break) { struct stat s; usec_t age; _cleanup_free_ char *sub_path = NULL; @@ -1053,6 +1053,7 @@ typedef int (*action_t)(Item *, const char *); static int item_do_children(Item *i, const char *path, action_t action) { _cleanup_closedir_ DIR *d; + struct dirent *de; int r = 0; assert(i); @@ -1065,19 +1066,11 @@ static int item_do_children(Item *i, const char *path, action_t action) { if (!d) return errno == ENOENT || errno == ENOTDIR ? 0 : -errno; - for (;;) { + FOREACH_DIRENT_ALL(de, d, r = -errno) { _cleanup_free_ char *p = NULL; - struct dirent *de; int q; errno = 0; - de = readdir(d); - if (!de) { - if (errno > 0 && r == 0) - r = -errno; - - break; - } if (STR_IN_SET(de->d_name, ".", "..")) continue; diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index fe9d6f4482..5be158f527 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -100,6 +100,7 @@ #include <unistd.h> #include <linux/pci_regs.h> +#include "dirent-util.h" #include "fd-util.h" #include "fileio.h" #include "stdio-util.h" @@ -256,7 +257,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { goto out; } - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + FOREACH_DIRENT_ALL(dent, dir, break) { int i; char *rest, *address, str[PATH_MAX]; diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c index 1825ee75a7..527f0bff2d 100644 --- a/src/udev/udev-builtin-path_id.c +++ b/src/udev/udev-builtin-path_id.c @@ -20,7 +20,6 @@ */ #include <ctype.h> -#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <getopt.h> @@ -31,6 +30,7 @@ #include <unistd.h> #include "alloc-util.h" +#include "dirent-util.h" #include "string-util.h" #include "udev.h" @@ -405,7 +405,7 @@ static struct udev_device *handle_scsi_default(struct udev_device *parent, char parent = NULL; goto out; } - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + FOREACH_DIRENT_ALL(dent, dir, break) { char *rest; int i; diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index e94a814388..53cfd9c053 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -15,7 +15,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <stdbool.h> @@ -25,6 +24,7 @@ #include <sys/stat.h> #include <unistd.h> +#include "dirent-util.h" #include "format-util.h" #include "fs-util.h" #include "selinux-util.h" @@ -129,6 +129,7 @@ exit: static const char *link_find_prioritized(struct udev_device *dev, bool add, const char *stackdir, char *buf, size_t bufsize) { struct udev *udev = udev_device_get_udev(dev); DIR *dir; + struct dirent *dent; int priority = 0; const char *target = NULL; @@ -141,12 +142,10 @@ static const char *link_find_prioritized(struct udev_device *dev, bool add, cons dir = opendir(stackdir); if (dir == NULL) return target; - for (;;) { + FOREACH_DIRENT_ALL(dent, dir, break) { struct udev_device *dev_db; - struct dirent *dent; - dent = readdir(dir); - if (dent == NULL || dent->d_name[0] == '\0') + if (dent->d_name[0] == '\0') break; if (dent->d_name[0] == '.') continue; diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index d88687e9c2..b0238220e4 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -16,7 +16,6 @@ */ #include <ctype.h> -#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <fnmatch.h> @@ -31,6 +30,7 @@ #include "alloc-util.h" #include "conf-files.h" +#include "dirent-util.h" #include "escape.h" #include "fd-util.h" #include "fs-util.h" @@ -703,7 +703,7 @@ static void attr_subst_subdir(char *attr, size_t len) { if (dir == NULL) return; - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) + FOREACH_DIRENT_ALL(dent, dir, break) if (dent->d_name[0] != '.') { char n[strlen(dent->d_name) + strlen(tail) + 1]; diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c index bc9096ed0c..aa432bb90a 100644 --- a/src/udev/udev-watch.c +++ b/src/udev/udev-watch.c @@ -17,13 +17,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <dirent.h> #include <errno.h> #include <stddef.h> #include <stdio.h> #include <sys/inotify.h> #include <unistd.h> +#include "dirent-util.h" #include "stdio-util.h" #include "udev.h" @@ -57,7 +57,7 @@ void udev_watch_restore(struct udev *udev) { return; } - for (ent = readdir(dir); ent != NULL; ent = readdir(dir)) { + FOREACH_DIRENT_ALL(ent, dir, break) { char device[UTIL_PATH_SIZE]; ssize_t len; struct udev_device *dev; diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index 6753c52005..90cdfa16c7 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -16,7 +16,6 @@ */ #include <ctype.h> -#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <getopt.h> @@ -26,6 +25,7 @@ #include <sys/stat.h> #include <unistd.h> +#include "dirent-util.h" #include "fd-util.h" #include "string-util.h" #include "udev-util.h" @@ -196,7 +196,7 @@ static void cleanup_dir(DIR *dir, mode_t mask, int depth) { if (depth <= 0) return; - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + FOREACH_DIRENT_ALL(dent, dir, break) { struct stat stats; if (dent->d_name[0] == '.') |