From f678a1ae4ddf57c69fe0dedce356928a8c41e487 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 2 Jun 2015 00:49:42 +0200 Subject: [PATCH] systemd: Apply some upstream bug fixes --- pkgs/os-specific/linux/systemd/default.nix | 5 +- pkgs/os-specific/linux/systemd/fixes.patch | 481 ++++++++++++++++++++- 2 files changed, 482 insertions(+), 4 deletions(-) diff --git a/pkgs/os-specific/linux/systemd/default.nix b/pkgs/os-specific/linux/systemd/default.nix index ae7596078891..214e6e8e39b4 100644 --- a/pkgs/os-specific/linux/systemd/default.nix +++ b/pkgs/os-specific/linux/systemd/default.nix @@ -69,7 +69,7 @@ stdenv.mkDerivation rec { preConfigure = '' # FIXME: patch this in systemd properly (and send upstream). - for i in src/remount-fs/remount-fs.c src/core/mount.c src/core/swap.c src/fsck/fsck.c units/emergency.service.in units/rescue.service.in src/journal/cat.c src/core/shutdown.c src/nspawn/nspawn.c; do + for i in src/remount-fs/remount-fs.c src/core/mount.c src/core/swap.c src/fsck/fsck.c units/emergency.service.in units/rescue.service.in src/journal/cat.c src/core/shutdown.c src/nspawn/nspawn.c src/shared/generator.c; do test -e $i substituteInPlace $i \ --replace /usr/bin/getent ${stdenv.glibc}/bin/getent \ @@ -79,7 +79,8 @@ stdenv.mkDerivation rec { --replace /sbin/swapoff ${utillinux}/sbin/swapoff \ --replace /bin/echo ${coreutils}/bin/echo \ --replace /bin/cat ${coreutils}/bin/cat \ - --replace /sbin/sulogin ${utillinux}/sbin/sulogin + --replace /sbin/sulogin ${utillinux}/sbin/sulogin \ + --replace /usr/lib/systemd/systemd-fsck $out/lib/systemd/systemd-fsck done substituteInPlace src/journal/catalog.c \ diff --git a/pkgs/os-specific/linux/systemd/fixes.patch b/pkgs/os-specific/linux/systemd/fixes.patch index b05e0bae8de5..ab687ba4ca34 100644 --- a/pkgs/os-specific/linux/systemd/fixes.patch +++ b/pkgs/os-specific/linux/systemd/fixes.patch @@ -1,3 +1,16 @@ +diff --git a/rules/60-persistent-storage.rules b/rules/60-persistent-storage.rules +index 3f803ce..2aa15f3 100644 +--- a/rules/60-persistent-storage.rules ++++ b/rules/60-persistent-storage.rules +@@ -6,7 +6,7 @@ + ACTION=="remove", GOTO="persistent_storage_end" + + SUBSYSTEM!="block", GOTO="persistent_storage_end" +-KERNEL!="loop*|mmcblk*[0-9]|msblk*[0-9]|mspblk*[0-9]|nvme*|sd*|sr*|vd*", GOTO="persistent_storage_end" ++KERNEL!="loop*|mmcblk*[0-9]|msblk*[0-9]|mspblk*[0-9]|nvme*|sd*|sr*|vd*|bcache*", GOTO="persistent_storage_end" + + # ignore partitions that span the entire disk + TEST=="whole_disk", GOTO="persistent_storage_end" diff --git a/rules/99-systemd.rules.in b/rules/99-systemd.rules.in index 10b90b8..db63c11 100644 --- a/rules/99-systemd.rules.in @@ -92,10 +105,124 @@ index 9bbe9ff..d8a2889 100644 cmdline[i++] = arg_repair; cmdline[i++] = "-T"; +diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c +index ce4862d..3692d46 100644 +--- a/src/libsystemd/sd-device/device-enumerator.c ++++ b/src/libsystemd/sd-device/device-enumerator.c +@@ -367,11 +367,11 @@ static bool match_sysattr(sd_device_enumerator *enumerator, sd_device *device) { + assert(enumerator); + assert(device); + +- HASHMAP_FOREACH_KEY(sysattr, value, enumerator->nomatch_sysattr, i) ++ HASHMAP_FOREACH_KEY(value, sysattr, enumerator->nomatch_sysattr, i) + if (match_sysattr_value(device, sysattr, value)) + return false; + +- HASHMAP_FOREACH_KEY(sysattr, value, enumerator->match_sysattr, i) ++ HASHMAP_FOREACH_KEY(value, sysattr, enumerator->match_sysattr, i) + if (!match_sysattr_value(device, sysattr, value)) + return false; + +@@ -389,7 +389,7 @@ static bool match_property(sd_device_enumerator *enumerator, sd_device *device) + if (hashmap_isempty(enumerator->match_property)) + return true; + +- HASHMAP_FOREACH_KEY(property, value, enumerator->match_property, i) { ++ HASHMAP_FOREACH_KEY(value, property, enumerator->match_property, i) { + const char *property_dev, *value_dev; + + FOREACH_DEVICE_PROPERTY(device, property_dev, value_dev) { +diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c +index 3cadedb..deb8efd 100644 +--- a/src/libsystemd/sd-device/device-private.c ++++ b/src/libsystemd/sd-device/device-private.c +@@ -636,10 +636,9 @@ int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len) { + + static int device_update_properties_bufs(sd_device *device) { + const char *val, *prop; +- char **buf_strv = NULL; + uint8_t *buf_nulstr = NULL; +- size_t allocated_nulstr = 0, allocated_strv = 0; +- size_t nulstr_len = 0, strv_size = 0; ++ size_t allocated_nulstr = 0; ++ size_t nulstr_len = 0, num = 0, i; + + assert(device); + +@@ -655,20 +654,24 @@ static int device_update_properties_bufs(sd_device *device) { + if (!buf_nulstr) + return -ENOMEM; + +- buf_strv = GREEDY_REALLOC0(buf_strv, allocated_strv, strv_size + 2); +- if (!buf_strv) +- return -ENOMEM; +- +- buf_strv[++ strv_size] = (char *)&buf_nulstr[nulstr_len]; + strscpyl((char *)buf_nulstr + nulstr_len, len + 1, prop, "=", val, NULL); + nulstr_len += len + 1; ++ ++num; + } + + free(device->properties_nulstr); +- free(device->properties_strv); + device->properties_nulstr = buf_nulstr; + device->properties_nulstr_len = nulstr_len; +- device->properties_strv = buf_strv; ++ ++ /* build strv from buf_nulstr */ ++ free(device->properties_strv); ++ device->properties_strv = new0(char *, num + 1); ++ i = 0; ++ NULSTR_FOREACH(val, (char*) buf_nulstr) { ++ device->properties_strv[i] = (char *) val; ++ assert(i < num); ++ i++; ++ } + + device->properties_buf_outdated = false; + +diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c +index 1f5cf86..3555bcc 100644 +--- a/src/login/logind-dbus.c ++++ b/src/login/logind-dbus.c +@@ -1964,6 +1964,11 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd + m->scheduled_shutdown_type = NULL; + m->scheduled_shutdown_timeout = 0; + ++ if (m->unlink_nologin) { ++ unlink("/run/nologin"); ++ m->unlink_nologin = false; ++ } ++ + if (cancelled) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + const char *tty = NULL; +diff --git a/src/network/networkctl.c b/src/network/networkctl.c +index 69b4ab4..3454394 100644 +--- a/src/network/networkctl.c ++++ b/src/network/networkctl.c +@@ -62,7 +62,7 @@ static int link_get_type_string(int iftype, sd_device *d, char **ret) { + assert(ret); + + if (iftype == ARPHRD_ETHER && d) { +- const char *devtype, *id = NULL; ++ const char *devtype = NULL, *id = NULL; + /* WLANs have iftype ARPHRD_ETHER, but we want + * to show a more useful type string for + * them */ diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c -index 5009363..72c6887 100644 +index 5009363..62a8dba 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c +@@ -2627,7 +2627,7 @@ static int setup_veth(pid_t pid, char iface_name[IFNAMSIZ], int *ifi) { + + r = sd_rtnl_call(rtnl, m, 0, NULL); + if (r < 0) +- return log_error_errno(r, "Failed to add new veth interfaces: %m"); ++ return log_error_errno(r, "Failed to add new veth interfaces (host0, %s): %m", iface_name); + + i = (int) if_nametoindex(iface_name); + if (i <= 0) @@ -4589,6 +4589,7 @@ int main(int argc, char *argv[]) { goto finish; } @@ -168,8 +295,108 @@ index f6a1271..9bec8e9 100644 STRV_IFNOTNULL(generator_late), NULL); +diff --git a/src/shared/path-util.c b/src/shared/path-util.c +index 7090989..8be479c 100644 +--- a/src/shared/path-util.c ++++ b/src/shared/path-util.c +@@ -509,7 +509,7 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id + return safe_atoi(p, mnt_id); + } + +-int fd_is_mount_point(int fd) { ++int fd_is_mount_point(int fd, const char *filename, int flags) { + union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT; + int mount_id = -1, mount_id_parent = -1; + bool nosupp = false, check_st_dev = true; +@@ -517,6 +517,7 @@ int fd_is_mount_point(int fd) { + int r; + + assert(fd >= 0); ++ assert(filename); + + /* First we will try the name_to_handle_at() syscall, which + * tells us the mount id and an opaque file "handle". It is +@@ -541,7 +542,7 @@ int fd_is_mount_point(int fd) { + * subvolumes have different st_dev, even though they aren't + * real mounts of their own. */ + +- r = name_to_handle_at(fd, "", &h.handle, &mount_id, AT_EMPTY_PATH); ++ r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags); + if (r < 0) { + if (errno == ENOSYS) + /* This kernel does not support name_to_handle_at() +@@ -558,7 +559,7 @@ int fd_is_mount_point(int fd) { + return -errno; + } + +- r = name_to_handle_at(fd, "..", &h_parent.handle, &mount_id_parent, 0); ++ r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH); + if (r < 0) { + if (errno == EOPNOTSUPP) { + if (nosupp) +@@ -593,13 +594,13 @@ int fd_is_mount_point(int fd) { + return mount_id != mount_id_parent; + + fallback_fdinfo: +- r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id); ++ r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id); + if (r == -EOPNOTSUPP) + goto fallback_fstat; + if (r < 0) + return r; + +- r = fd_fdinfo_mnt_id(fd, "..", 0, &mount_id_parent); ++ r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent); + if (r < 0) + return r; + +@@ -615,10 +616,16 @@ fallback_fdinfo: + check_st_dev = false; + + fallback_fstat: +- if (fstatat(fd, "", &a, AT_EMPTY_PATH) < 0) ++ /* yay for fstatat() taking a different set of flags than the other ++ * _at() above */ ++ if (flags & AT_SYMLINK_FOLLOW) ++ flags &= ~AT_SYMLINK_FOLLOW; ++ else ++ flags |= AT_SYMLINK_NOFOLLOW; ++ if (fstatat(fd, filename, &a, flags) < 0) + return -errno; + +- if (fstatat(fd, "..", &b, 0) < 0) ++ if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0) + return -errno; + + /* A directory with same device and inode as its parent? Must +@@ -632,17 +639,23 @@ fallback_fstat: + + int path_is_mount_point(const char *t, bool allow_symlink) { + _cleanup_close_ int fd = -1; ++ _cleanup_free_ char *parent = NULL; ++ int r; + + assert(t); + + if (path_equal(t, "/")) + return 1; + +- fd = openat(AT_FDCWD, t, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|(allow_symlink ? 0 : O_PATH)); ++ r = path_get_parent(t, &parent); ++ if (r < 0) ++ return r; ++ ++ fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH); + if (fd < 0) + return -errno; + +- return fd_is_mount_point(fd); ++ return fd_is_mount_point(fd, basename(t), (allow_symlink ? AT_SYMLINK_FOLLOW : 0)); + } + + int path_is_read_only_fs(const char *path) { diff --git a/src/shared/path-util.h b/src/shared/path-util.h -index 4f45cfd..e015606 100644 +index 4f45cfd..a8a0662 100644 --- a/src/shared/path-util.h +++ b/src/shared/path-util.h @@ -26,7 +26,7 @@ @@ -181,6 +408,256 @@ index 4f45cfd..e015606 100644 #define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":/sbin:/bin" #ifdef HAVE_SPLIT_USR +@@ -53,7 +53,7 @@ char** path_strv_make_absolute_cwd(char **l); + char** path_strv_resolve(char **l, const char *prefix); + char** path_strv_resolve_uniq(char **l, const char *prefix); + +-int fd_is_mount_point(int fd); ++int fd_is_mount_point(int fd, const char *filename, int flags); + int path_is_mount_point(const char *path, bool allow_symlink); + int path_is_read_only_fs(const char *path); + int path_is_os_tree(const char *path); +diff --git a/src/shared/rm-rf.c b/src/shared/rm-rf.c +index a89e8af..bafd483 100644 +--- a/src/shared/rm-rf.c ++++ b/src/shared/rm-rf.c +@@ -103,7 +103,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { + } + + /* Stop at mount points */ +- r = fd_is_mount_point(subdir_fd); ++ r = fd_is_mount_point(fd, de->d_name, 0); + if (r < 0) { + if (ret == 0 && r != -ENOENT) + ret = r; +diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c +index 09f0f2f..80782ff 100644 +--- a/src/test/test-path-util.c ++++ b/src/test/test-path-util.c +@@ -21,6 +21,7 @@ + + #include + #include ++#include + + #include "path-util.h" + #include "util.h" +@@ -88,21 +89,9 @@ static void test_path(void) { + test_parent("/aa///file...", "/aa///"); + test_parent("file.../", NULL); + +- assert_se(path_is_mount_point("/", true) > 0); +- assert_se(path_is_mount_point("/", false) > 0); +- + fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY); + assert_se(fd >= 0); +- assert_se(fd_is_mount_point(fd) > 0); +- +- assert_se(path_is_mount_point("/proc", true) > 0); +- assert_se(path_is_mount_point("/proc", false) > 0); +- +- assert_se(path_is_mount_point("/proc/1", true) == 0); +- assert_se(path_is_mount_point("/proc/1", false) == 0); +- +- assert_se(path_is_mount_point("/sys", true) > 0); +- assert_se(path_is_mount_point("/sys", false) > 0); ++ assert_se(fd_is_mount_point(fd, "/", 0) > 0); + + { + char p1[] = "aaa/bbb////ccc"; +@@ -322,6 +311,66 @@ static void test_prefix_root(void) { + test_prefix_root_one("/foo///", "//bar", "/foo/bar"); + } + ++static void test_path_is_mount_point(void) { ++ int fd, rt, rf, rlt, rlf; ++ char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX"; ++ _cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL; ++ ++ assert_se(path_is_mount_point("/", true) > 0); ++ assert_se(path_is_mount_point("/", false) > 0); ++ ++ assert_se(path_is_mount_point("/proc", true) > 0); ++ assert_se(path_is_mount_point("/proc", false) > 0); ++ ++ assert_se(path_is_mount_point("/proc/1", true) == 0); ++ assert_se(path_is_mount_point("/proc/1", false) == 0); ++ ++ assert_se(path_is_mount_point("/sys", true) > 0); ++ assert_se(path_is_mount_point("/sys", false) > 0); ++ ++ /* file mountpoints */ ++ assert_se(mkdtemp(tmp_dir) != NULL); ++ file1 = path_join(NULL, tmp_dir, "file1"); ++ assert_se(file1); ++ file2 = path_join(NULL, tmp_dir, "file2"); ++ assert_se(file2); ++ fd = open(file1, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664); ++ assert_se(fd > 0); ++ close(fd); ++ fd = open(file2, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664); ++ assert_se(fd > 0); ++ close(fd); ++ link1 = path_join(NULL, tmp_dir, "link1"); ++ assert_se(link1); ++ assert_se(symlink("file1", link1) == 0); ++ link2 = path_join(NULL, tmp_dir, "link2"); ++ assert_se(link1); ++ assert_se(symlink("file2", link2) == 0); ++ ++ assert_se(path_is_mount_point(file1, true) == 0); ++ assert_se(path_is_mount_point(file1, false) == 0); ++ assert_se(path_is_mount_point(link1, true) == 0); ++ assert_se(path_is_mount_point(link1, false) == 0); ++ ++ /* this test will only work as root */ ++ if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) { ++ rf = path_is_mount_point(file2, false); ++ rt = path_is_mount_point(file2, true); ++ rlf = path_is_mount_point(link2, false); ++ rlt = path_is_mount_point(link2, true); ++ ++ assert_se(umount(file2) == 0); ++ ++ assert_se(rf == 1); ++ assert_se(rt == 1); ++ assert_se(rlf == 0); ++ assert_se(rlt == 1); ++ } else ++ printf("Skipping bind mount file test: %m\n"); ++ ++ assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0); ++} ++ + int main(int argc, char **argv) { + test_path(); + test_find_binary(argv[0], true); +@@ -333,6 +382,7 @@ int main(int argc, char **argv) { + test_strv_resolve(); + test_path_startswith(); + test_prefix_root(); ++ test_path_is_mount_point(); + + return 0; + } +diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c +index 78aef20..4489205 100644 +--- a/src/udev/udev-builtin-net_id.c ++++ b/src/udev/udev-builtin-net_id.c +@@ -91,6 +91,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -166,15 +167,15 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) { + + /* read the 256 bytes PCI configuration space to check the multi-function bit */ + static bool is_pci_multifunction(struct udev_device *dev) { +- _cleanup_fclose_ FILE *f = NULL; ++ _cleanup_close_ int fd = -1; + const char *filename; + uint8_t config[64]; + + filename = strjoina(udev_device_get_syspath(dev), "/config"); +- f = fopen(filename, "re"); +- if (!f) ++ fd = open(filename, O_RDONLY | O_CLOEXEC); ++ if (fd < 0) + return false; +- if (fread(&config, sizeof(config), 1, f) != 1) ++ if (read(fd, &config, sizeof(config)) != sizeof(config)) + return false; + + /* bit 0-6 header type, bit 7 multi/single function device */ +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index afd4640..b5dadbc 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -564,7 +564,10 @@ static int event_queue_insert(Manager *manager, struct udev_device *dev) { + assert(manager); + assert(dev); + +- /* only the main process can add events to the queue */ ++ /* only one process can add events to the queue */ ++ if (manager->pid == 0) ++ manager->pid = getpid(); ++ + assert(manager->pid == getpid()); + + event = new0(struct event, 1); +@@ -1286,13 +1289,6 @@ static int parse_argv(int argc, char *argv[]) { + + static int manager_new(Manager **ret) { + _cleanup_(manager_freep) Manager *manager = NULL; +- struct epoll_event ep_ctrl = { .events = EPOLLIN }; +- struct epoll_event ep_inotify = { .events = EPOLLIN }; +- struct epoll_event ep_signal = { .events = EPOLLIN }; +- struct epoll_event ep_netlink = { .events = EPOLLIN }; +- struct epoll_event ep_worker = { .events = EPOLLIN }; +- sigset_t mask; +- int r, one = 1; + + assert(ret); + +@@ -1300,8 +1296,6 @@ static int manager_new(Manager **ret) { + if (!manager) + return log_oom(); + +- manager->pid = getpid(); +- + manager->fd_ep = -1; + manager->fd_ctrl = -1; + manager->fd_uevent = -1; +@@ -1323,6 +1317,23 @@ static int manager_new(Manager **ret) { + udev_list_node_init(&manager->events); + udev_list_init(manager->udev, &manager->properties, true); + ++ *ret = manager; ++ manager = NULL; ++ ++ return 0; ++} ++ ++static int manager_listen(Manager *manager) { ++ struct epoll_event ep_ctrl = { .events = EPOLLIN }; ++ struct epoll_event ep_inotify = { .events = EPOLLIN }; ++ struct epoll_event ep_signal = { .events = EPOLLIN }; ++ struct epoll_event ep_netlink = { .events = EPOLLIN }; ++ struct epoll_event ep_worker = { .events = EPOLLIN }; ++ sigset_t mask; ++ int r, one = 1; ++ ++ assert(manager); ++ + r = systemd_fds(&manager->fd_ctrl, &manager->fd_uevent); + if (r >= 0) { + /* get control and netlink socket from systemd */ +@@ -1404,10 +1415,7 @@ static int manager_new(Manager **ret) { + epoll_ctl(manager->fd_ep, EPOLL_CTL_ADD, manager->fd_worker, &ep_worker) < 0) + return log_error_errno(errno, "fail to add fds to epoll: %m"); + +- *ret = manager; +- manager = NULL; +- +- return 1; ++ return 0; + } + + int main(int argc, char *argv[]) { +@@ -1518,6 +1526,10 @@ int main(int argc, char *argv[]) { + } else + sd_notify(1, "READY=1"); + ++ r = manager_listen(manager); ++ if (r < 0) ++ return log_error_errno(r, "failed to set up fds and listen for events: %m"); ++ + for (;;) { + static usec_t last_usec; + struct epoll_event ev[8]; diff --git a/units/console-getty.service.m4.in b/units/console-getty.service.m4.in index 413d940..972b86a 100644 --- a/units/console-getty.service.m4.in