diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2018-03-05 23:15:56 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-05 23:15:56 +0100 |
commit | e6131c6ea6893f4c46dbf709182428b42041b0ac (patch) | |
tree | 4bfb3fdd05c56bc6b31534674a9bd83f11543558 | |
parent | Merge pull request #8341 from yuwata/test-execute-ambient (diff) | |
parent | test: add tests for systemd-tmpfiles (diff) | |
download | systemd-e6131c6ea6893f4c46dbf709182428b42041b0ac.tar.xz systemd-e6131c6ea6893f4c46dbf709182428b42041b0ac.zip |
Merge pull request #8358 from fbuihuu/tmpfiles-dont-resolve-pathnames-when-traversing-recursively
Tmpfiles dont resolve pathnames when traversing recursively
-rw-r--r-- | src/tmpfiles/tmpfiles.c | 365 | ||||
-rw-r--r-- | test/TEST-22-TMPFILES/Makefile | 4 | ||||
-rwxr-xr-x | test/TEST-22-TMPFILES/run-tmpfiles-tests.sh | 13 | ||||
-rwxr-xr-x | test/TEST-22-TMPFILES/test-01.sh | 13 | ||||
-rwxr-xr-x | test/TEST-22-TMPFILES/test.sh | 38 | ||||
-rw-r--r-- | test/TEST-22-TMPFILES/testsuite.service | 8 | ||||
-rw-r--r-- | test/test-functions | 4 |
7 files changed, 318 insertions, 127 deletions
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 98368c36f1..f1890f3261 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -777,100 +777,111 @@ static bool dangerous_hardlinks(void) { return cached; } -static bool hardlink_vulnerable(struct stat *st) { +static bool hardlink_vulnerable(const struct stat *st) { assert(st); return !S_ISDIR(st->st_mode) && st->st_nlink > 1 && dangerous_hardlinks(); } -static int path_set_perms(Item *i, const char *path) { - char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; - _cleanup_close_ int fd = -1; - struct stat st; +static int fd_set_perms(Item *i, int fd, const struct stat *st) { + _cleanup_free_ char *path = NULL; + int r; assert(i); - assert(path); - - if (!i->mode_set && !i->uid_set && !i->gid_set) - goto shortcut; - - /* We open the file with O_PATH here, to make the operation - * somewhat atomic. Also there's unfortunately no fchmodat() - * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via - * O_PATH. */ - - fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); - if (fd < 0) { - int level = LOG_ERR, r = -errno; + assert(fd); - /* Option "e" operates only on existing objects. Do not - * print errors about non-existent files or directories */ - if (i->type == EMPTY_DIRECTORY && errno == ENOENT) { - level = LOG_DEBUG; - r = 0; - } - - log_full_errno(level, errno, "Adjusting owner and mode for %s failed: %m", path); + r = fd_get_path(fd, &path); + if (r < 0) return r; - } - if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0) - return log_error_errno(errno, "Failed to fstat() file %s: %m", path); + if (!i->mode_set && !i->uid_set && !i->gid_set) + goto shortcut; - if (hardlink_vulnerable(&st)) { + if (hardlink_vulnerable(st)) { log_error("Refusing to set permissions on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path); return -EPERM; } - xsprintf(fn, "/proc/self/fd/%i", fd); - if (i->mode_set) { - if (S_ISLNK(st.st_mode)) + if (S_ISLNK(st->st_mode)) log_debug("Skipping mode fix for symlink %s.", path); else { mode_t m = i->mode; if (i->mask_perms) { - if (!(st.st_mode & 0111)) + if (!(st->st_mode & 0111)) m &= ~0111; - if (!(st.st_mode & 0222)) + if (!(st->st_mode & 0222)) m &= ~0222; - if (!(st.st_mode & 0444)) + if (!(st->st_mode & 0444)) m &= ~0444; - if (!S_ISDIR(st.st_mode)) + if (!S_ISDIR(st->st_mode)) m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */ } - if (m == (st.st_mode & 07777)) - log_debug("\"%s\" has correct mode %o already.", path, st.st_mode); + if (m == (st->st_mode & 07777)) + log_debug("\"%s\" has correct mode %o already.", path, st->st_mode); else { + char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + log_debug("Changing \"%s\" to mode %o.", path, m); - if (chmod(fn, m) < 0) - return log_error_errno(errno, "chmod() of %s via %s failed: %m", path, fn); + /* fchmodat() still doesn't have AT_EMPTY_PATH flag. */ + xsprintf(procfs_path, "/proc/self/fd/%i", fd); + + if (chmod(procfs_path, m) < 0) + return log_error_errno(errno, "chmod() of %s via %s failed: %m", path, procfs_path); } } } - if ((i->uid_set && i->uid != st.st_uid) || - (i->gid_set && i->gid != st.st_gid)) { + if ((i->uid_set && i->uid != st->st_uid) || + (i->gid_set && i->gid != st->st_gid)) { log_debug("Changing \"%s\" to owner "UID_FMT":"GID_FMT, path, i->uid_set ? i->uid : UID_INVALID, i->gid_set ? i->gid : GID_INVALID); - if (chown(fn, - i->uid_set ? i->uid : UID_INVALID, - i->gid_set ? i->gid : GID_INVALID) < 0) - return log_error_errno(errno, "chown() of %s via %s failed: %m", path, fn); + if (fchownat(fd, + "", + i->uid_set ? i->uid : UID_INVALID, + i->gid_set ? i->gid : GID_INVALID, + AT_EMPTY_PATH) < 0) + return log_error_errno(errno, "fchownat() of %s failed: %m", path); } - fd = safe_close(fd); - shortcut: return label_fix(path, false, false); } +static int path_set_perms(Item *i, const char *path) { + _cleanup_close_ int fd = -1; + struct stat st; + + assert(i); + assert(path); + + fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); + if (fd < 0) { + int level = LOG_ERR, r = -errno; + + /* Option "e" operates only on existing objects. Do not + * print errors about non-existent files or directories */ + if (i->type == EMPTY_DIRECTORY && errno == ENOENT) { + level = LOG_DEBUG; + r = 0; + } + + log_full_errno(level, errno, "Adjusting owner and mode for %s failed: %m", path); + return r; + } + + if (fstat(fd, &st) < 0) + return log_error_errno(errno, "Failed to fstat() file %s: %m", path); + + return fd_set_perms(i, fd, &st); +} + static int parse_xattrs_from_arg(Item *i) { const char *p; int r; @@ -909,21 +920,43 @@ static int parse_xattrs_from_arg(Item *i) { return 0; } -static int path_set_xattrs(Item *i, const char *path) { +static int fd_set_xattrs(Item *i, int fd, const struct stat *st) { + char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + _cleanup_free_ char *path = NULL; char **name, **value; + int r; assert(i); - assert(path); + assert(fd); + + r = fd_get_path(fd, &path); + if (r < 0) + return r; + + xsprintf(procfs_path, "/proc/self/fd/%i", fd); STRV_FOREACH_PAIR(name, value, i->xattrs) { log_debug("Setting extended attribute '%s=%s' on %s.", *name, *value, path); - if (lsetxattr(path, *name, *value, strlen(*value), 0) < 0) + if (setxattr(procfs_path, *name, *value, strlen(*value), 0) < 0) return log_error_errno(errno, "Setting extended attribute %s=%s on %s failed: %m", *name, *value, path); } return 0; } +static int path_set_xattrs(Item *i, const char *path) { + _cleanup_close_ int fd = -1; + + assert(i); + assert(path); + + fd = open(path, O_CLOEXEC|O_NOFOLLOW|O_PATH); + if (fd < 0) + return log_error_errno(errno, "Cannot open '%s': %m", path); + + return fd_set_xattrs(i, fd, NULL); +} + static int parse_acls_from_arg(Item *item) { #if HAVE_ACL int r; @@ -989,52 +1022,71 @@ static int path_set_acl(const char *path, const char *pretty, acl_type_t type, a } #endif -static int path_set_acls(Item *item, const char *path) { +static int fd_set_acls(Item *item, int fd, const struct stat *st) { int r = 0; #if HAVE_ACL - char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; - _cleanup_close_ int fd = -1; - struct stat st; + char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + _cleanup_free_ char *path = NULL; assert(item); - assert(path); - - fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); - if (fd < 0) - return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path); + assert(fd); + assert(st); - if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0) - return log_error_errno(errno, "Failed to fstat() file %s: %m", path); + r = fd_get_path(fd, &path); + if (r < 0) + return r; - if (hardlink_vulnerable(&st)) { + if (hardlink_vulnerable(st)) { log_error("Refusing to set ACLs on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path); return -EPERM; } - if (S_ISLNK(st.st_mode)) { + if (S_ISLNK(st->st_mode)) { log_debug("Skipping ACL fix for symlink %s.", path); return 0; } - xsprintf(fn, "/proc/self/fd/%i", fd); + xsprintf(procfs_path, "/proc/self/fd/%i", fd); if (item->acl_access) - r = path_set_acl(fn, path, ACL_TYPE_ACCESS, item->acl_access, item->force); + r = path_set_acl(procfs_path, path, ACL_TYPE_ACCESS, item->acl_access, item->force); if (r == 0 && item->acl_default) - r = path_set_acl(fn, path, ACL_TYPE_DEFAULT, item->acl_default, item->force); + r = path_set_acl(procfs_path, path, ACL_TYPE_DEFAULT, item->acl_default, item->force); if (r > 0) return -r; /* already warned */ - else if (r == -EOPNOTSUPP) { + if (r == -EOPNOTSUPP) { log_debug_errno(r, "ACLs not supported by file system at %s", path); return 0; - } else if (r < 0) - log_error_errno(r, "ACL operation on \"%s\" failed: %m", path); + } + if (r < 0) + return log_error_errno(r, "ACL operation on \"%s\" failed: %m", path); #endif return r; } +static int path_set_acls(Item *item, const char *path) { + int r = 0; +#ifdef HAVE_ACL + _cleanup_close_ int fd = -1; + struct stat st; + + assert(item); + assert(path); + + fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); + if (fd < 0) + return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path); + + if (fstat(fd, &st) < 0) + return log_error_errno(errno, "Failed to fstat() file %s: %m", path); + + r = fd_set_acls(item, fd, &st); + #endif + return r; + } + #define ATTRIBUTES_ALL \ (FS_NOATIME_FL | \ FS_SYNC_FL | \ @@ -1134,30 +1186,24 @@ static int parse_attribute_from_arg(Item *item) { return 0; } -static int path_set_attribute(Item *item, const char *path) { - _cleanup_close_ int fd = -1; - struct stat st; +static int fd_set_attribute(Item *item, int fd, const struct stat *st) { + char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + _cleanup_close_ int procfs_fd = -1; + _cleanup_free_ char *path = NULL; unsigned f; int r; if (!item->attribute_set || item->attribute_mask == 0) return 0; - fd = open(path, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOATIME|O_NOFOLLOW); - if (fd < 0) { - if (errno == ELOOP) - return log_error_errno(errno, "Skipping file attributes adjustment on symlink %s.", path); - - return log_error_errno(errno, "Cannot open '%s': %m", path); - } - - if (fstat(fd, &st) < 0) - return log_error_errno(errno, "Cannot stat '%s': %m", path); + r = fd_get_path(fd, &path); + if (r < 0) + return r; /* Issuing the file attribute ioctls on device nodes is not * safe, as that will be delivered to the drivers, not the * file system containing the device node. */ - if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) { + if (!S_ISREG(st->st_mode) && !S_ISDIR(st->st_mode)) { log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path); return -EINVAL; } @@ -1165,10 +1211,16 @@ static int path_set_attribute(Item *item, const char *path) { f = item->attribute_value & item->attribute_mask; /* Mask away directory-specific flags */ - if (!S_ISDIR(st.st_mode)) + if (!S_ISDIR(st->st_mode)) f &= ~FS_DIRSYNC_FL; - r = chattr_fd(fd, f, item->attribute_mask); + xsprintf(procfs_path, "/proc/self/fd/%i", fd); + + procfs_fd = open(procfs_path, O_RDONLY|O_CLOEXEC|O_NOATIME); + if (procfs_fd < 0) + return -errno; + + r = chattr_fd(procfs_fd, f, item->attribute_mask); if (r < 0) log_full_errno(IN_SET(r, -ENOTTY, -EOPNOTSUPP) ? LOG_DEBUG : LOG_WARNING, r, @@ -1178,6 +1230,23 @@ static int path_set_attribute(Item *item, const char *path) { return 0; } +static int path_set_attribute(Item *item, const char *path) { + _cleanup_close_ int fd = -1; + struct stat st; + + if (!item->attribute_set || item->attribute_mask == 0) + return 0; + + fd = open(path, O_CLOEXEC|O_NOFOLLOW|O_PATH); + if (fd < 0) + return log_error_errno(errno, "Cannot open '%s': %m", path); + + if (fstat(fd, &st) < 0) + return log_error_errno(errno, "Cannot stat '%s': %m", path); + + return fd_set_attribute(item, fd, &st); +} + static int write_one_file(Item *i, const char *path) { _cleanup_close_ int fd = -1; int flags, r = 0; @@ -1242,48 +1311,58 @@ done: } typedef int (*action_t)(Item *, const char *); +typedef int (*fdaction_t)(Item *, int fd, const struct stat *st); -static int item_do_children(Item *i, const char *path, action_t action) { - _cleanup_closedir_ DIR *d; - struct dirent *de; - int r = 0; +static int item_do(Item *i, int fd, const struct stat *st, fdaction_t action) { + int r = 0, q; assert(i); - assert(path); + assert(fd >= 0); + assert(st); /* This returns the first error we run into, but nevertheless * tries to go on */ + r = action(i, fd, st); - d = opendir_nomod(path); - if (!d) - return IN_SET(errno, ENOENT, ENOTDIR, ELOOP) ? 0 : -errno; + if (S_ISDIR(st->st_mode)) { + char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; - FOREACH_DIRENT_ALL(de, d, r = -errno) { - _cleanup_free_ char *p = NULL; - int q; + /* The passed 'fd' was opened with O_PATH. We need to convert + * it into a 'regular' fd before reading the directory content. */ + xsprintf(procfs_path, "/proc/self/fd/%i", fd); - if (dot_or_dot_dot(de->d_name)) - continue; + d = opendir(procfs_path); + if (!d) { + r = r ?: -errno; + goto finish; + } - p = strjoin(path, "/", de->d_name); - if (!p) - return -ENOMEM; + FOREACH_DIRENT_ALL(de, d, q = -errno; goto finish) { + struct stat de_st; + int de_fd; + + if (dot_or_dot_dot(de->d_name)) + continue; - q = action(i, p); - if (q < 0 && q != -ENOENT && r == 0) - r = q; + de_fd = openat(fd, de->d_name, O_NOFOLLOW|O_CLOEXEC|O_PATH); + if (de_fd >= 0 && fstat(de_fd, &de_st) >= 0) + /* pass ownership of dirent fd over */ + q = item_do(i, de_fd, &de_st, action); + else + q = -errno; - if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) { - q = item_do_children(i, p, action); if (q < 0 && r == 0) r = q; } } - +finish: + safe_close(fd); return r; } -static int glob_item(Item *i, action_t action, bool recursive) { +static int glob_item(Item *i, action_t action) { _cleanup_globfree_ glob_t g = { .gl_opendir = (void *(*)(const char *)) opendir_nomod, }; @@ -1298,12 +1377,48 @@ static int glob_item(Item *i, action_t action, bool recursive) { k = action(i, *fn); if (k < 0 && r == 0) r = k; + } - if (recursive) { - k = item_do_children(i, *fn, action); - if (k < 0 && r == 0) - r = k; + return r; +} + +static int glob_item_recursively(Item *i, fdaction_t action) { + _cleanup_globfree_ glob_t g = { + .gl_opendir = (void *(*)(const char *)) opendir_nomod, + }; + int r = 0, k; + char **fn; + + k = safe_glob(i->path, GLOB_NOSORT|GLOB_BRACE, &g); + if (k < 0 && k != -ENOENT) + return log_error_errno(k, "glob(%s) failed: %m", i->path); + + STRV_FOREACH(fn, g.gl_pathv) { + _cleanup_close_ int fd = -1; + struct stat st; + + /* Make sure we won't trigger/follow file object (such as + * device nodes, automounts, ...) pointed out by 'fn' with + * O_PATH. Note, when O_PATH is used, flags other than + * O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored. */ + + fd = open(*fn, O_CLOEXEC|O_NOFOLLOW|O_PATH); + if (fd < 0) { + r = r ?: -errno; + continue; + } + + if (fstat(fd, &st) < 0) { + r = r ?: -errno; + continue; } + + k = item_do(i, fd, &st, action); + if (k < 0 && r == 0) + r = k; + + /* we passed fd ownership to the previous call */ + fd = -1; } return r; @@ -1392,7 +1507,7 @@ static int create_item(Item *i) { break; case WRITE_FILE: - r = glob_item(i, write_one_file, false); + r = glob_item(i, write_one_file); if (r < 0) return r; @@ -1651,49 +1766,49 @@ static int create_item(Item *i) { case ADJUST_MODE: case RELABEL_PATH: - r = glob_item(i, path_set_perms, false); + r = glob_item(i, path_set_perms); if (r < 0) return r; break; case RECURSIVE_RELABEL_PATH: - r = glob_item(i, path_set_perms, true); + r = glob_item_recursively(i, fd_set_perms); if (r < 0) return r; break; case SET_XATTR: - r = glob_item(i, path_set_xattrs, false); + r = glob_item(i, path_set_xattrs); if (r < 0) return r; break; case RECURSIVE_SET_XATTR: - r = glob_item(i, path_set_xattrs, true); + r = glob_item_recursively(i, fd_set_xattrs); if (r < 0) return r; break; case SET_ACL: - r = glob_item(i, path_set_acls, false); + r = glob_item(i, path_set_acls); if (r < 0) return r; break; case RECURSIVE_SET_ACL: - r = glob_item(i, path_set_acls, true); + r = glob_item_recursively(i, fd_set_acls); if (r < 0) return r; break; case SET_ATTRIBUTE: - r = glob_item(i, path_set_attribute, false); + r = glob_item(i, path_set_attribute); if (r < 0) return r; break; case RECURSIVE_SET_ATTRIBUTE: - r = glob_item(i, path_set_attribute, true); + r = glob_item_recursively(i, fd_set_attribute); if (r < 0) return r; break; @@ -1743,7 +1858,7 @@ static int remove_item(Item *i) { case REMOVE_PATH: case TRUNCATE_DIRECTORY: case RECURSIVE_REMOVE_PATH: - return glob_item(i, remove_item_instance, false); + return glob_item(i, remove_item_instance); default: return 0; @@ -1817,7 +1932,7 @@ static int clean_item(Item *i) { return 0; case EMPTY_DIRECTORY: case IGNORE_DIRECTORY_PATH: - return glob_item(i, clean_item_instance, false); + return glob_item(i, clean_item_instance); default: return 0; } diff --git a/test/TEST-22-TMPFILES/Makefile b/test/TEST-22-TMPFILES/Makefile new file mode 100644 index 0000000000..34d7cc6cdf --- /dev/null +++ b/test/TEST-22-TMPFILES/Makefile @@ -0,0 +1,4 @@ +BUILD_DIR=$(shell ../../tools/find-build-dir.sh) + +all setup clean run: + @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@ diff --git a/test/TEST-22-TMPFILES/run-tmpfiles-tests.sh b/test/TEST-22-TMPFILES/run-tmpfiles-tests.sh new file mode 100755 index 0000000000..3ad652f4ed --- /dev/null +++ b/test/TEST-22-TMPFILES/run-tmpfiles-tests.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -x +set -e + +>/failed + +for t in test-*.sh; do + echo "Running $t"; ./$t +done + +touch /testok +rm /failed diff --git a/test/TEST-22-TMPFILES/test-01.sh b/test/TEST-22-TMPFILES/test-01.sh new file mode 100755 index 0000000000..d233e37fb2 --- /dev/null +++ b/test/TEST-22-TMPFILES/test-01.sh @@ -0,0 +1,13 @@ +#! /bin/bash +# +# With "e" don't attempt to set permissions when file doesn't exist, see +# https://github.com/systemd/systemd/pull/6682. +# + +set -e + +rm -fr /tmp/test + +echo "e /tmp/test - root root 1d" | systemd-tmpfiles --create - + +! test -e /tmp/test diff --git a/test/TEST-22-TMPFILES/test.sh b/test/TEST-22-TMPFILES/test.sh new file mode 100755 index 0000000000..ca78933380 --- /dev/null +++ b/test/TEST-22-TMPFILES/test.sh @@ -0,0 +1,38 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +set -e +TEST_DESCRIPTION="Tmpfiles related tests" +TEST_NO_QEMU=1 + +. $TEST_BASE_DIR/test-functions + +test_setup() { + # create the basic filesystem layout + setup_basic_environment >/dev/null + inst_binary mv + inst_binary stat + inst_binary seq + inst_binary xargs + + # mask some services that we do not want to run in these tests + ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service + ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service + ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service + ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket + ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service + ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service + + # setup the testsuite service + cp testsuite.service $initdir/etc/systemd/system/ + setup_testsuite + + mkdir -p $initdir/testsuite + cp run-tmpfiles-tests.sh $initdir/testsuite/ + cp test-*.sh $initdir/testsuite/ + + # create dedicated rootfs for nspawn (located in $TESTDIR/nspawn-root) + setup_nspawn_root +} + +do_test "$@" diff --git a/test/TEST-22-TMPFILES/testsuite.service b/test/TEST-22-TMPFILES/testsuite.service new file mode 100644 index 0000000000..3a44b41989 --- /dev/null +++ b/test/TEST-22-TMPFILES/testsuite.service @@ -0,0 +1,8 @@ +[Unit] +Description=Testsuite service +After=multi-user.target + +[Service] +WorkingDirectory=/testsuite +ExecStart=/testsuite/run-tmpfiles-tests.sh +Type=oneshot diff --git a/test/test-functions b/test/test-functions index 2ece55414a..17e83ccf3f 100644 --- a/test/test-functions +++ b/test/test-functions @@ -1383,8 +1383,8 @@ inst_libdir_file() { } setup_suse() { - ln -s ../usr/bin/systemctl $initdir/bin/systemctl - ln -s ../usr/lib/systemd $initdir/lib/systemd + ln -fs ../usr/bin/systemctl $initdir/bin/ + ln -fs ../usr/lib/systemd $initdir/lib/ inst_simple "/usr/lib/systemd/system/haveged.service" } |