summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2017-12-01 17:58:58 +0100
committerGitHub <noreply@github.com>2017-12-01 17:58:58 +0100
commit1a2d4d70845f483bcb3f704fa092f5fd76580d31 (patch)
tree35991bc9a914c788950c09b1abb072f0b8d350fc /src
parentNEWS: update the text a bit (#7524) (diff)
parentutil-lib: handle empty string in last_path_component (diff)
downloadsystemd-1a2d4d70845f483bcb3f704fa092f5fd76580d31.tar.xz
systemd-1a2d4d70845f483bcb3f704fa092f5fd76580d31.zip
Merge pull request #7237 from keszybz/growfs
Create and grow filesystems
Diffstat (limited to 'src')
-rw-r--r--src/basic/btrfs-util.c12
-rw-r--r--src/basic/crypt-util.c27
-rw-r--r--src/basic/crypt-util.h34
-rw-r--r--src/basic/device-nodes.h13
-rw-r--r--src/basic/fs-util.c13
-rw-r--r--src/basic/meson.build2
-rw-r--r--src/basic/missing.h4
-rw-r--r--src/basic/mount-util.c3
-rw-r--r--src/basic/path-util.c31
-rw-r--r--src/basic/path-util.h1
-rw-r--r--src/basic/stat-util.c6
-rw-r--r--src/basic/stat-util.h4
-rw-r--r--src/basic/util.c53
-rw-r--r--src/cryptsetup/cryptsetup.c20
-rw-r--r--src/fstab-generator/fstab-generator.c100
-rw-r--r--src/nspawn/nspawn-mount.c2
-rw-r--r--src/partition/growfs.c317
-rw-r--r--src/partition/makefs.c110
-rw-r--r--src/shared/bootspec.c8
-rw-r--r--src/shared/dissect-image.c69
-rw-r--r--src/shared/dissect-image.h1
-rw-r--r--src/shared/generator.c211
-rw-r--r--src/shared/generator.h21
-rw-r--r--src/test/test-fs-util.c47
-rw-r--r--src/test/test-mount-util.c162
-rw-r--r--src/test/test-path-util.c155
-rw-r--r--src/test/test-stat-util.c16
-rw-r--r--src/test/test-string-util.c14
-rw-r--r--src/udev/udev-node.c19
-rw-r--r--src/veritysetup/veritysetup.c15
30 files changed, 1152 insertions, 338 deletions
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c
index b7e237fc0d..ac96e63531 100644
--- a/src/basic/btrfs-util.c
+++ b/src/basic/btrfs-util.c
@@ -42,6 +42,7 @@
#include "btrfs-util.h"
#include "chattr-util.h"
#include "copy.h"
+#include "device-nodes.h"
#include "fd-util.h"
#include "fileio.h"
#include "io-util.h"
@@ -910,7 +911,8 @@ int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, u
int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
struct btrfs_ioctl_vol_args args = {};
- _cleanup_free_ char *p = NULL, *loop = NULL, *backing = NULL;
+ char p[SYS_BLOCK_PATH_MAX("/loop/backing_file")];
+ _cleanup_free_ char *backing = NULL;
_cleanup_close_ int loop_fd = -1, backing_fd = -1;
struct stat st;
dev_t dev = 0;
@@ -930,8 +932,7 @@ int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
if (r == 0)
return -ENODEV;
- if (asprintf(&p, "/sys/dev/block/%u:%u/loop/backing_file", major(dev), minor(dev)) < 0)
- return -ENOMEM;
+ xsprintf_sys_block_path(p, "/loop/backing_file", dev);
r = read_one_line_file(p, &backing);
if (r == -ENOENT)
return -ENODEV;
@@ -955,9 +956,8 @@ int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
if (grow_only && new_size < (uint64_t) st.st_size)
return -EINVAL;
- if (asprintf(&loop, "/dev/block/%u:%u", major(dev), minor(dev)) < 0)
- return -ENOMEM;
- loop_fd = open(loop, O_RDWR|O_CLOEXEC|O_NOCTTY);
+ xsprintf_sys_block_path(p, NULL, dev);
+ loop_fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY);
if (loop_fd < 0)
return -errno;
diff --git a/src/basic/crypt-util.c b/src/basic/crypt-util.c
new file mode 100644
index 0000000000..193cf65dfc
--- /dev/null
+++ b/src/basic/crypt-util.c
@@ -0,0 +1,27 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2017 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/>.
+***/
+
+#if HAVE_LIBCRYPTSETUP
+#include "crypt-util.h"
+#include "log.h"
+
+void cryptsetup_log_glue(int level, const char *msg, void *usrptr) {
+ log_debug("%s", msg);
+}
+#endif
diff --git a/src/basic/crypt-util.h b/src/basic/crypt-util.h
new file mode 100644
index 0000000000..537f785607
--- /dev/null
+++ b/src/basic/crypt-util.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+/***
+ This file is part of systemd.
+
+ Copyright 2017 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/>.
+***/
+
+#if HAVE_LIBCRYPTSETUP
+#include <libcryptsetup.h>
+
+#include "macro.h"
+
+/* libcryptsetup define for any LUKS version, compatible with libcryptsetup 1.x */
+#ifndef CRYPT_LUKS
+#define CRYPT_LUKS NULL
+#endif
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct crypt_device *, crypt_free);
+
+void cryptsetup_log_glue(int level, const char *msg, void *usrptr);
+#endif
diff --git a/src/basic/device-nodes.h b/src/basic/device-nodes.h
index 1e09bdc830..6136526f84 100644
--- a/src/basic/device-nodes.h
+++ b/src/basic/device-nodes.h
@@ -23,5 +23,18 @@
#include <stddef.h>
#include <sys/types.h>
+#include "macro.h"
+#include "stdio-util.h"
+
int encode_devnode_name(const char *str, char *str_enc, size_t len);
int whitelisted_char_for_devnode(char c, const char *additional);
+
+#define SYS_BLOCK_PATH_MAX(suffix) \
+ (strlen("/sys/dev/block/") + DECIMAL_STR_MAX(dev_t) + 1 + DECIMAL_STR_MAX(dev_t) + strlen_ptr(suffix))
+#define xsprintf_sys_block_path(buf, suffix, devno) \
+ xsprintf(buf, "/sys/dev/block/%u:%u%s", major(devno), minor(devno), strempty(suffix))
+
+#define DEV_NUM_PATH_MAX \
+ (strlen("/dev/block/") + DECIMAL_STR_MAX(dev_t) + 1 + DECIMAL_STR_MAX(dev_t))
+#define xsprintf_dev_num_path(buf, type, devno) \
+ xsprintf(buf, "/dev/%s/%u:%u", type, major(devno), minor(devno))
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index b5fd95ae8e..475400177a 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -661,9 +661,18 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
todo += m;
+ /* Empty? Then we reached the end. */
+ if (isempty(first))
+ break;
+
/* Just a single slash? Then we reached the end. */
- if (isempty(first) || path_equal(first, "/"))
+ if (path_equal(first, "/")) {
+ /* Preserve the trailing slash */
+ if (!strextend(&done, "/", NULL))
+ return -ENOMEM;
+
break;
+ }
/* Just a dot? Then let's eat this up. */
if (path_equal(first, "/."))
@@ -726,7 +735,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
if (fstat(child, &st) < 0)
return -errno;
if ((flags & CHASE_NO_AUTOFS) &&
- fd_check_fstype(child, AUTOFS_SUPER_MAGIC) > 0)
+ fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0)
return -EREMOTE;
if (S_ISLNK(st.st_mode)) {
diff --git a/src/basic/meson.build b/src/basic/meson.build
index bf11757b74..a37e279e57 100644
--- a/src/basic/meson.build
+++ b/src/basic/meson.build
@@ -61,6 +61,8 @@ basic_sources_plain = files('''
copy.h
cpu-set-util.c
cpu-set-util.h
+ crypt-util.c
+ crypt-util.h
def.h
device-nodes.c
device-nodes.h
diff --git a/src/basic/missing.h b/src/basic/missing.h
index 52c7ce57a0..76cb0a23ac 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -1271,4 +1271,8 @@ struct fib_rule_uid_range {
#define AF_VSOCK 40
#endif
+#ifndef EXT4_IOC_RESIZE_FS
+# define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)
+#endif
+
#include "missing_syscall.h"
diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
index e394e1adf3..e60750c531 100644
--- a/src/basic/mount-util.c
+++ b/src/basic/mount-util.c
@@ -278,6 +278,7 @@ int path_is_mount_point(const char *t, const char *root, int flags) {
int r;
assert(t);
+ assert((flags & ~AT_SYMLINK_FOLLOW) == 0);
if (path_equal(t, "/"))
return 1;
@@ -302,7 +303,7 @@ int path_is_mount_point(const char *t, const char *root, int flags) {
if (fd < 0)
return -errno;
- return fd_is_mount_point(fd, basename(t), flags);
+ return fd_is_mount_point(fd, last_path_component(t), flags);
}
int path_get_mnt_id(const char *path, int *ret) {
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index 883856abc2..3bde1d1e01 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -703,6 +703,37 @@ char* dirname_malloc(const char *path) {
return dir2;
}
+const char *last_path_component(const char *path) {
+ /* Finds the last component of the path, preserving the
+ * optional trailing slash that signifies a directory.
+ * a/b/c → c
+ * a/b/c/ → c/
+ * / → /
+ * // → /
+ * /foo/a → a
+ * /foo/a/ → a/
+ * This is different than basename, which returns "" when
+ * a trailing slash is present.
+ */
+
+ unsigned l, k;
+
+ l = k = strlen(path);
+ if (l == 0) /* special case — an empty string */
+ return path;
+
+ while (k > 0 && path[k-1] == '/')
+ k--;
+
+ if (k == 0) /* the root directory */
+ return path + l - 1;
+
+ while (k > 0 && path[k-1] != '/')
+ k--;
+
+ return path + k;
+}
+
bool filename_is_valid(const char *p) {
const char *e;
diff --git a/src/basic/path-util.h b/src/basic/path-util.h
index 9bd783eaf4..f79cdf928e 100644
--- a/src/basic/path-util.h
+++ b/src/basic/path-util.h
@@ -130,6 +130,7 @@ char *prefix_root(const char *root, const char *path);
int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg);
char* dirname_malloc(const char *path);
+const char *last_path_component(const char *path);
bool filename_is_valid(const char *p) _pure_;
bool path_is_normalized(const char *p) _pure_;
diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c
index ea554f7b73..c6b8507e9d 100644
--- a/src/basic/stat-util.c
+++ b/src/basic/stat-util.c
@@ -193,7 +193,7 @@ bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
return F_TYPE_EQUAL(s->f_type, magic_value);
}
-int fd_check_fstype(int fd, statfs_f_type_t magic_value) {
+int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
struct statfs s;
if (fstatfs(fd, &s) < 0)
@@ -202,14 +202,14 @@ int fd_check_fstype(int fd, statfs_f_type_t magic_value) {
return is_fs_type(&s, magic_value);
}
-int path_check_fstype(const char *path, statfs_f_type_t magic_value) {
+int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
_cleanup_close_ int fd = -1;
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
if (fd < 0)
return -errno;
- return fd_check_fstype(fd, magic_value);
+ return fd_is_fs_type(fd, magic_value);
}
bool is_temporary_fs(const struct statfs *s) {
diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h
index 615315f306..8b8d128121 100644
--- a/src/basic/stat-util.h
+++ b/src/basic/stat-util.h
@@ -57,8 +57,8 @@ int files_same(const char *filea, const char *fileb, int flags);
typedef typeof(((struct statfs*)NULL)->f_type) statfs_f_type_t;
bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) _pure_;
-int fd_check_fstype(int fd, statfs_f_type_t magic_value);
-int path_check_fstype(const char *path, statfs_f_type_t magic_value);
+int fd_is_fs_type(int fd, statfs_f_type_t magic_value);
+int path_is_fs_type(const char *path, statfs_f_type_t magic_value);
bool is_temporary_fs(const struct statfs *s) _pure_;
int fd_is_temporary_fs(int fd);
diff --git a/src/basic/util.c b/src/basic/util.c
index 0c278ab20e..f61d9013e6 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -39,6 +39,7 @@
#include "build.h"
#include "cgroup-util.h"
#include "def.h"
+#include "device-nodes.h"
#include "dirent-util.h"
#include "fd-util.h"
#include "fileio.h"
@@ -118,63 +119,42 @@ int socket_from_display(const char *display, char **path) {
}
int block_get_whole_disk(dev_t d, dev_t *ret) {
- char *p, *s;
+ char p[SYS_BLOCK_PATH_MAX("/partition")];
+ _cleanup_free_ char *s = NULL;
int r;
unsigned n, m;
assert(ret);
/* If it has a queue this is good enough for us */
- if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
- return -ENOMEM;
-
- r = access(p, F_OK);
- free(p);
-
- if (r >= 0) {
+ xsprintf_sys_block_path(p, "/queue", d);
+ if (access(p, F_OK) >= 0) {
*ret = d;
return 0;
}
/* If it is a partition find the originating device */
- if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
- return -ENOMEM;
-
- r = access(p, F_OK);
- free(p);
-
- if (r < 0)
+ xsprintf_sys_block_path(p, "/partition", d);
+ if (access(p, F_OK) < 0)
return -ENOENT;
/* Get parent dev_t */
- if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
- return -ENOMEM;
-
+ xsprintf_sys_block_path(p, "/../dev", d);
r = read_one_line_file(p, &s);
- free(p);
-
if (r < 0)
return r;
r = sscanf(s, "%u:%u", &m, &n);
- free(s);
-
if (r != 2)
return -EINVAL;
/* Only return this if it is really good enough for us. */
- if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
- return -ENOMEM;
-
- r = access(p, F_OK);
- free(p);
-
- if (r >= 0) {
- *ret = makedev(m, n);
- return 0;
- }
+ xsprintf_sys_block_path(p, "/queue", makedev(m, n));
+ if (access(p, F_OK) < 0)
+ return -ENOENT;
- return -ENOENT;
+ *ret = makedev(m, n);
+ return 0;
}
bool kexec_loaded(void) {
@@ -749,7 +729,8 @@ int get_block_device(const char *path, dev_t *dev) {
int get_block_device_harder(const char *path, dev_t *dev) {
_cleanup_closedir_ DIR *d = NULL;
- _cleanup_free_ char *p = NULL, *t = NULL;
+ _cleanup_free_ char *t = NULL;
+ char p[SYS_BLOCK_PATH_MAX("/slaves")];
struct dirent *de, *found = NULL;
const char *q;
unsigned maj, min;
@@ -767,9 +748,7 @@ int get_block_device_harder(const char *path, dev_t *dev) {
if (r <= 0)
return r;
- if (asprintf(&p, "/sys/dev/block/%u:%u/slaves", major(dt), minor(dt)) < 0)
- return -ENOMEM;
-
+ xsprintf_sys_block_path(p, "/slaves", dt);
d = opendir(p);
if (!d) {
if (errno == ENOENT)
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index b19d03e9f0..ab4d24ca3b 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -19,7 +19,6 @@
***/
#include <errno.h>
-#include <libcryptsetup.h>
#include <mntent.h>
#include <string.h>
#include <sys/mman.h>
@@ -28,6 +27,7 @@
#include "alloc-util.h"
#include "ask-password-api.h"
+#include "crypt-util.h"
#include "device-util.h"
#include "escape.h"
#include "fileio.h"
@@ -39,11 +39,6 @@
#include "strv.h"
#include "util.h"
-/* libcryptsetup define for any LUKS version, compatible with libcryptsetup 1.x */
-#ifndef CRYPT_LUKS
-#define CRYPT_LUKS NULL
-#endif
-
/* internal helper */
#define ANY_LUKS "LUKS"
@@ -254,10 +249,6 @@ static int parse_options(const char *options) {
return 0;
}
-static void log_glue(int level, const char *msg, void *usrptr) {
- log_debug("%s", msg);
-}
-
static int disk_major_minor(const char *path, char **ret) {
struct stat st;
@@ -604,7 +595,7 @@ static int help(void) {
}
int main(int argc, char *argv[]) {
- struct crypt_device *cd = NULL;
+ _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
int r = -EINVAL;
if (argc <= 1) {
@@ -666,7 +657,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- crypt_set_log_callback(cd, log_glue, NULL);
+ crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
status = crypt_status(cd, argv[2]);
if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) {
@@ -750,7 +741,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- crypt_set_log_callback(cd, log_glue, NULL);
+ crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
r = crypt_deactivate(cd, argv[2]);
if (r < 0) {
@@ -766,9 +757,6 @@ int main(int argc, char *argv[]) {
r = 0;
finish:
- if (cd)
- crypt_free(cd);
-
free(arg_cipher);
free(arg_hash);
free(arg_header);
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 6d6895a216..68e7c23cbe 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -47,6 +47,14 @@
#include "virt.h"
#include "volatile-util.h"
+typedef enum MountpointFlags {
+ NOAUTO = 1 << 0,
+ NOFAIL = 1 << 1,
+ AUTOMOUNT = 1 << 2,
+ MAKEFS = 1 << 3,
+ GROWFS = 1 << 4,
+} MountpointFlags;
+
static const char *arg_dest = "/tmp";
static const char *arg_dest_late = "/tmp";
static bool arg_fstab_enabled = true;
@@ -91,8 +99,7 @@ static int write_what(FILE *f, const char *what) {
static int add_swap(
const char *what,
struct mntent *me,
- bool noauto,
- bool nofail) {
+ MountpointFlags flags) {
_cleanup_free_ char *name = NULL, *unit = NULL;
_cleanup_fclose_ FILE *f = NULL;
@@ -150,9 +157,19 @@ static int add_swap(
if (r < 0)
return r;
- if (!noauto) {
+ if (flags & MAKEFS) {
+ r = generator_hook_up_mkswap(arg_dest, what);
+ if (r < 0)
+ return r;
+ }
+
+ if (flags & GROWFS)
+ /* TODO: swap devices must be wiped and recreated */
+ log_warning("%s: growing swap devices is currently unsupported.", what);
+
+ if (!(flags & NOAUTO)) {
r = generator_add_symlink(arg_dest, SPECIAL_SWAP_TARGET,
- nofail ? "wants" : "requires", name);
+ (flags & NOFAIL) ? "wants" : "requires", name);
if (r < 0)
return r;
}
@@ -297,17 +314,16 @@ static int add_mount(
const char *fstype,
const char *opts,
int passno,
- bool noauto,
- bool nofail,
- bool automount,
+ MountpointFlags flags,
const char *post,
const char *source) {
_cleanup_free_ char
- *name = NULL, *unit = NULL,
+ *name = NULL,
*automount_name = NULL, *automount_unit = NULL,
*filtered = NULL,
*where_escaped = NULL;
+ const char *unit;
_cleanup_fclose_ FILE *f = NULL;
int r;
@@ -330,23 +346,21 @@ static int add_mount(
return 0;
if (path_equal(where, "/")) {
- if (noauto)
+ if (flags & NOAUTO)
log_warning("Ignoring \"noauto\" for root device");
- if (nofail)
+ if (flags & NOFAIL)
log_warning("Ignoring \"nofail\" for root device");
- if (automount)
+ if (flags & AUTOMOUNT)
log_warning("Ignoring automount option for root device");
- noauto = nofail = automount = false;
+ SET_FLAG(flags, NOAUTO | NOFAIL | AUTOMOUNT, false);
}
r = unit_name_from_path(where, ".mount", &name);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
- unit = strjoin(dest, "/", name);
- if (!unit)
- return log_oom();
+ unit = strjoina(dest, "/", name);
f = fopen(unit, "wxe");
if (!f)
@@ -363,7 +377,7 @@ static int add_mount(
"Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
source);
- if (STRPTR_IN_SET(fstype, "nfs", "nfs4") && !automount &&
+ if (STRPTR_IN_SET(fstype, "nfs", "nfs4") && !(flags & AUTOMOUNT) &&
fstab_test_yes_no_option(opts, "bg\0" "fg\0")) {
/* The default retry timeout that mount.nfs uses for 'bg' mounts
* is 10000 minutes, where as it uses 2 minutes for 'fg' mounts.
@@ -374,13 +388,13 @@ static int add_mount(
* By placing these options first, they can be over-ridden by
* settings in /etc/fstab. */
opts = strjoina("x-systemd.mount-timeout=infinity,retry=10000,", opts, ",fg");
- nofail = true;
+ SET_FLAG(flags, NOFAIL, true);
}
- if (!nofail && !automount)
+ if (!(flags & NOFAIL) && !(flags & AUTOMOUNT))
fprintf(f, "Before=%s\n", post);
- if (!automount && opts) {
+ if (!(flags & AUTOMOUNT) && opts) {
r = write_after(f, opts);
if (r < 0)
return r;
@@ -444,14 +458,26 @@ static int add_mount(
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", unit);
- if (!noauto && !automount) {
+ if (flags & MAKEFS) {
+ r = generator_hook_up_mkfs(dest, what, where, fstype);
+ if (r < 0)
+ return r;
+ }
+
+ if (flags & GROWFS) {
+ r = generator_hook_up_growfs(dest, where, post);
+ if (r < 0)
+ return r;
+ }
+
+ if (!(flags & NOAUTO) && !(flags & AUTOMOUNT)) {
r = generator_add_symlink(dest, post,
- nofail ? "wants" : "requires", name);
+ (flags & NOFAIL) ? "wants" : "requires", name);
if (r < 0)
return r;
}
- if (automount) {
+ if (flags & AUTOMOUNT) {
r = unit_name_from_path(where, ".automount", &automount_name);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
@@ -504,7 +530,7 @@ static int add_mount(
return log_error_errno(r, "Failed to write unit file %s: %m", automount_unit);
r = generator_add_symlink(dest, post,
- nofail ? "wants" : "requires", automount_name);
+ (flags & NOFAIL) ? "wants" : "requires", automount_name);
if (r < 0)
return r;
}
@@ -529,7 +555,7 @@ static int parse_fstab(bool initrd) {
while ((me = getmntent(f))) {
_cleanup_free_ char *where = NULL, *what = NULL, *canonical_where = NULL;
- bool noauto, nofail;
+ bool makefs, growfs, noauto, nofail;
int k;
if (initrd && !mount_in_initrd(me))
@@ -571,14 +597,18 @@ static int parse_fstab(bool initrd) {
}
}
+ makefs = fstab_test_option(me->mnt_opts, "x-systemd.makefs\0");
+ growfs = fstab_test_option(me->mnt_opts, "x-systemd.growfs\0");
noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
- log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
+ log_debug("Found entry what=%s where=%s type=%s makefs=%s nofail=%s noauto=%s",
what, where, me->mnt_type,
+ yes_no(makefs),
yes_no(noauto), yes_no(nofail));
if (streq(me->mnt_type, "swap"))
- k = add_swap(what, me, noauto, nofail);
+ k = add_swap(what, me,
+ makefs*MAKEFS | growfs*GROWFS | noauto*NOAUTO | nofail*NOFAIL);
else {
bool automount;
const char *post;
@@ -600,14 +630,12 @@ static int parse_fstab(bool initrd) {
me->mnt_type,
me->mnt_opts,
me->mnt_passno,
- noauto,
- nofail,
- automount,
+ makefs*MAKEFS | growfs*GROWFS | noauto*NOAUTO | nofail*NOFAIL | automount*AUTOMOUNT,
post,
fstab_path);
}
- if (k < 0)
+ if (r >= 0 && k < 0)
r = k;
}
@@ -663,9 +691,7 @@ static int add_sysroot_mount(void) {
arg_root_fstype,
opts,
is_device_path(what) ? 1 : 0, /* passno */
- false, /* noauto off */
- false, /* nofail off */
- false, /* automount off */
+ 0, /* makefs off, growfs off, noauto off, nofail off, automount off */
SPECIAL_INITRD_ROOT_FS_TARGET,
"/proc/cmdline");
}
@@ -718,9 +744,7 @@ static int add_sysroot_usr_mount(void) {
arg_usr_fstype,
opts,
is_device_path(what) ? 1 : 0, /* passno */
- false, /* noauto off */
- false, /* nofail off */
- false, /* automount off */
+ 0,
SPECIAL_INITRD_FS_TARGET,
"/proc/cmdline");
}
@@ -759,9 +783,7 @@ static int add_volatile_var(void) {
"tmpfs",
"mode=0755",
0,
- false,
- false,
- false,
+ 0,
SPECIAL_LOCAL_FS_TARGET,
"/proc/cmdline");
}
diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c
index e6a92411ad..920e114718 100644
--- a/src/nspawn/nspawn-mount.c
+++ b/src/nspawn/nspawn-mount.c
@@ -405,7 +405,7 @@ int mount_sysfs(const char *dest, MountSettingsMask mount_settings) {
unsigned long extra_flags = 0;
top = prefix_roota(dest, "/sys");
- r = path_check_fstype(top, SYSFS_MAGIC);
+ r = path_is_fs_type(top, SYSFS_MAGIC);
if (r < 0)
return log_error_errno(r, "Failed to determine filesystem type of %s: %m", top);
/* /sys might already be mounted as sysfs by the outer child in the
diff --git a/src/partition/growfs.c b/src/partition/growfs.c
new file mode 100644
index 0000000000..8b44c1ded7
--- /dev/null
+++ b/src/partition/growfs.c
@@ -0,0 +1,317 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+/***
+ This file is part of systemd.
+
+ Copyright 2017 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 <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <linux/magic.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+
+#include "crypt-util.h"
+#include "device-nodes.h"
+#include "dissect-image.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "format-util.h"
+#include "log.h"
+#include "missing.h"
+#include "mount-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "strv.h"
+
+const char *arg_target = NULL;
+bool arg_dry_run = false;
+
+static int resize_ext4(const char *path, int mountfd, int devfd, uint64_t numblocks, uint64_t blocksize) {
+ assert((uint64_t) (int) blocksize == blocksize);
+
+ if (arg_dry_run)
+ return 0;
+
+ if (ioctl(mountfd, EXT4_IOC_RESIZE_FS, &numblocks) != 0)
+ return log_error_errno(errno, "Failed to resize \"%s\" to %"PRIu64" blocks (ext4): %m",
+ path, numblocks);
+
+ return 0;
+}
+
+static int resize_btrfs(const char *path, int mountfd, int devfd, uint64_t numblocks, uint64_t blocksize) {
+ struct btrfs_ioctl_vol_args args = {};
+ int r;
+
+ assert((uint64_t) (int) blocksize == blocksize);
+
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=118111 */
+ if (numblocks * blocksize < 256*1024*1024) {
+ log_warning("%s: resizing of btrfs volumes smaller than 256M is not supported", path);
+ return -EOPNOTSUPP;
+ }
+
+ r = snprintf(args.name, sizeof(args.name), "%"PRIu64, numblocks * blocksize);
+ /* The buffer is large enough for any number to fit... */
+ assert((size_t) r < sizeof(args.name));
+
+ if (arg_dry_run)
+ return 0;
+
+ if (ioctl(mountfd, BTRFS_IOC_RESIZE, &args) != 0)
+ return log_error_errno(errno, "Failed to resize \"%s\" to %"PRIu64" blocks (btrfs): %m",
+ path, numblocks);
+
+ return 0;
+}
+
+static int resize_crypt_luks_device(dev_t devno, const char *fstype, dev_t main_devno) {
+ char devpath[DEV_NUM_PATH_MAX], main_devpath[DEV_NUM_PATH_MAX];
+ _cleanup_close_ int main_devfd = -1;
+ _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
+ uint64_t size;
+ int r;
+
+ xsprintf_dev_num_path(main_devpath, "block", main_devno);
+ main_devfd = open(main_devpath, O_RDONLY|O_CLOEXEC);
+ if (main_devfd < 0)
+ return log_error_errno(errno, "Failed to open \"%s\": %m", main_devpath);
+
+ if (ioctl(main_devfd, BLKGETSIZE64, &size) != 0)
+ return log_error_errno(errno, "Failed to query size of \"%s\" (before resize): %m",
+ main_devpath);
+
+ log_debug("%s is %"PRIu64" bytes", main_devpath, size);
+
+ xsprintf_dev_num_path(devpath, "block", devno);
+ r = crypt_init(&cd, devpath);
+ if (r < 0)
+ return log_error_errno(r, "crypt_init(\"%s\") failed: %m", devpath);
+
+ crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
+
+ r = crypt_load(cd, CRYPT_LUKS, NULL);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to load LUKS metadata for %s: %m", devpath);
+
+ if (arg_dry_run)
+ return 0;
+
+ r = crypt_resize(cd, main_devpath, 0);
+ if (r < 0)
+ return log_error_errno(r, "crypt_resize() of %s failed: %m", devpath);
+
+ if (ioctl(main_devfd, BLKGETSIZE64, &size) != 0)
+ log_warning_errno(errno, "Failed to query size of \"%s\" (after resize): %m",
+ devpath);
+ else
+ log_debug("%s is now %"PRIu64" bytes", main_devpath, size);
+
+ return 1;
+}
+
+static int maybe_resize_slave_device(const char *mountpath, dev_t main_devno) {
+ dev_t devno;
+ char devpath[DEV_NUM_PATH_MAX];
+ _cleanup_free_ char *fstype = NULL;
+ int r;
+
+ crypt_set_log_callback(NULL, cryptsetup_log_glue, NULL);
+ crypt_set_debug_level(1);
+
+ r = get_block_device_harder(mountpath, &devno);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine underlying block device of \"%s\": %m",
+ mountpath);
+
+ log_debug("Underlying device %d:%d, main dev %d:%d, %s",
+ major(devno), minor(devno),
+ major(main_devno), minor(main_devno),
+ devno == main_devno ? "same" : "different");
+ if (devno == main_devno)
+ return 0;
+
+ xsprintf_dev_num_path(devpath, "block", devno);
+ r = probe_filesystem(devpath, &fstype);
+ if (r == -EUCLEAN)
+ return log_warning_errno(r, "Cannot reliably determine probe \"%s\", refusing to proceed.", devpath);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to probe \"%s\": %m", devpath);
+
+ if (streq_ptr(fstype, "crypto_LUKS"))
+ return resize_crypt_luks_device(devno, fstype, main_devno);
+
+ log_debug("Don't know how to resize %s of type %s, ignoring", devpath, strnull(fstype));
+ return 0;
+}
+
+static void help(void) {
+ printf("%s [OPTIONS...] /path/to/mountpoint\n\n"
+ "Grow filesystem or encrypted payload to device size.\n\n"
+ "Options:\n"
+ " -h --help Show this help and exit\n"
+ " --version Print version string and exit\n"
+ " -n --dry-run Just print what would be done\n"
+ , program_invocation_short_name);
+}
+
+static int parse_argv(int argc, char *argv[]) {
+ enum {
+ ARG_VERSION = 0x100,
+ };
+
+ int c;
+
+ static const struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version" , no_argument, NULL, ARG_VERSION },
+ { "dry-run", no_argument, NULL, 'n' },
+ {}
+ };
+
+ assert(argc >= 0);
+ assert(argv);
+
+ while ((c = getopt_long(argc, argv, "hn", options, NULL)) >= 0)
+ switch(c) {
+ case 'h':
+ help();
+ return 0;
+
+ case ARG_VERSION:
+ version();
+ return 0;
+
+ case 'n':
+ arg_dry_run = true;
+ break;
+
+ case '?':
+ return -EINVAL;
+
+ default:
+ assert_not_reached("Unhandled option");
+ }
+
+ if (optind + 1 != argc) {
+ log_error("%s excepts exactly one argument (the mount point).",
+ program_invocation_short_name);
+ return -EINVAL;
+ }
+
+ arg_target = argv[optind];
+
+ return 1;
+}
+
+int main(int argc, char *argv[]) {
+ dev_t devno;
+ _cleanup_close_ int mountfd = -1, devfd = -1;
+ int blocksize;
+ uint64_t size, numblocks;
+ char devpath[DEV_NUM_PATH_MAX], fb[FORMAT_BYTES_MAX];
+ struct statfs sfs;
+ int r;
+
+ log_set_target(LOG_TARGET_AUTO);
+ log_parse_environment();
+ log_open();
+
+ r = parse_argv(argc, argv);
+ if (r < 0)
+ return EXIT_FAILURE;
+ if (r == 0)
+ return EXIT_SUCCESS;
+
+ r = path_is_mount_point(arg_target, NULL, 0);
+ if (r < 0) {
+ log_error_errno(r, "Failed to check if \"%s\" is a mount point: %m", arg_target);
+ return EXIT_FAILURE;
+ }
+ if (r == 0) {
+ log_error_errno(r, "\"%s\" is not a mount point: %m", arg_target);
+ return EXIT_FAILURE;
+ }
+
+ r = get_block_device(arg_target, &devno);
+ if (r < 0) {
+ log_error_errno(r, "Failed to determine block device of \"%s\": %m", arg_target);
+ return EXIT_FAILURE;
+ }
+
+ r = maybe_resize_slave_device(arg_target, devno);
+ if (r < 0)
+ return EXIT_FAILURE;
+
+ mountfd = open(arg_target, O_RDONLY|O_CLOEXEC);
+ if (mountfd < 0) {
+ log_error_errno(errno, "Failed to open \"%s\": %m", arg_target);
+ return EXIT_FAILURE;
+ }
+
+ xsprintf_dev_num_path(devpath, "block", devno);
+ devfd = open(devpath, O_RDONLY|O_CLOEXEC);
+ if (devfd < 0) {
+ log_error_errno(errno, "Failed to open \"%s\": %m", devpath);
+ return EXIT_FAILURE;
+ }
+
+ if (ioctl(devfd, BLKBSZGET, &blocksize) != 0) {
+ log_error_errno(errno, "Failed to query block size of \"%s\": %m", devpath);
+ return EXIT_FAILURE;
+ }
+
+ if (ioctl(devfd, BLKGETSIZE64, &size) != 0) {
+ log_error_errno(errno, "Failed to query size of \"%s\": %m", devpath);
+ return EXIT_FAILURE;
+ }
+
+ if (size % blocksize != 0)
+ log_notice("Partition size %"PRIu64" is not a multiple of the blocksize %d,"
+ " ignoring %"PRIu64" bytes", size, blocksize, size % blocksize);
+
+ numblocks = size / blocksize;
+
+ if (fstatfs(mountfd, &sfs) < 0) {
+ log_error_errno(errno, "Failed to stat file system \"%s\": %m", arg_target);
+ return EXIT_FAILURE;
+ }
+
+ switch(sfs.f_type) {
+ case EXT4_SUPER_MAGIC:
+ r = resize_ext4(arg_target, mountfd, devfd, numblocks, blocksize);
+ break;
+ case BTRFS_SUPER_MAGIC:
+ r = resize_btrfs(arg_target, mountfd, devfd, numblocks, blocksize);
+ break;
+ default:
+ log_error("Don't know how to resize fs %llx on \"%s\"",
+ (long long unsigned) sfs.f_type, arg_target);
+ return EXIT_FAILURE;
+ }
+
+ if (r < 0)
+ return EXIT_FAILURE;
+
+ log_info("Successfully resized \"%s\" to %s bytes (%"PRIu64" blocks of %d bytes).",
+ arg_target, format_bytes(fb, sizeof fb, size), numblocks, blocksize);
+ return EXIT_SUCCESS;
+}
diff --git a/src/partition/makefs.c b/src/partition/makefs.c
new file mode 100644
index 0000000000..e5e125255b
--- /dev/null
+++ b/src/partition/makefs.c
@@ -0,0 +1,110 @@
+/***
+ SPDX-License-Identifier: LGPL-2.1+
+
+ This file is part of systemd.
+
+ Copyright 2017 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 <fcntl.h>
+#include <signal.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "alloc-util.h"
+#include "dissect-image.h"
+#include "signal-util.h"
+#include "string-util.h"
+
+static int makefs(const char *type, const char *device) {
+ const char *mkfs;
+ pid_t pid;
+
+ if (streq(type, "swap"))
+ mkfs = "/sbin/mkswap";
+ else
+ mkfs = strjoina("/sbin/mkfs.", type);
+ if (access(mkfs, X_OK) != 0)
+ return log_error_errno(errno, "%s is not executable: %m", mkfs);
+
+ pid = fork();
+ if (pid < 0)
+ return log_error_errno(errno, "fork(): %m");
+
+ if (pid == 0) {
+ const char *cmdline[3] = { mkfs, device, NULL };
+
+ /* Child */
+
+ (void) reset_all_signal_handlers();
+ (void) reset_signal_mask();
+ assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
+
+ execv(cmdline[0], (char**) cmdline);
+ _exit(EXIT_FAILURE);
+ }
+
+ return wait_for_terminate_and_warn(mkfs, pid, true);
+}
+
+int main(int argc, char *argv[]) {
+ const char *device, *type;
+ _cleanup_free_ char *detected = NULL;
+ struct stat st;
+ int r;
+
+ log_set_target(LOG_TARGET_AUTO);
+ log_parse_environment();
+ log_open();
+
+ if (argc != 3) {
+ log_error("This program expects two arguments.");
+ return EXIT_FAILURE;
+ }
+
+ type = argv[1];
+ device = argv[2];
+
+ if (stat(device, &st) < 0) {
+ r = log_error_errno(errno, "Failed to stat \"%s\": %m", device);
+ goto finish;
+ }
+
+ if (!S_ISBLK(st.st_mode))
+ log_info("%s is not a block device.", device);
+
+ r = probe_filesystem(device, &detected);
+ if (r < 0) {
+ log_warning_errno(r,
+ r == -EUCLEAN ?
+ "Cannot reliably determine probe \"%s\", refusing to proceed." :
+ "Failed to probe \"%s\": %m",
+ device);
+ goto finish;
+ }
+
+ if (detected) {
+ log_info("%s is not empty (type %s), exiting", device, detected);
+ goto finish;
+ }
+
+ r = makefs(type, device);
+
+finish:
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c
index 9f80db068d..aa722c304a 100644
--- a/src/shared/bootspec.c
+++ b/src/shared/bootspec.c
@@ -25,6 +25,7 @@
#include "bootspec.h"
#include "conf-files.h"
#include "def.h"
+#include "device-nodes.h"
#include "efivars.h"
#include "fd-util.h"
#include "fileio.h"
@@ -420,7 +421,7 @@ static int verify_esp(
sd_id128_t *ret_uuid) {
_cleanup_blkid_free_probe_ blkid_probe b = NULL;
- _cleanup_free_ char *t = NULL;
+ char t[DEV_NUM_PATH_MAX];
uint64_t pstart = 0, psize = 0;
struct stat st, st2;
const char *v, *t2;
@@ -478,10 +479,7 @@ static int verify_esp(
if (detect_container() > 0 || geteuid() != 0)
goto finish;
- r = asprintf(&t, "/dev/block/%u:%u", major(st.st_dev), minor(st.st_dev));
- if (r < 0)
- return log_oom();
-
+ xsprintf_dev_num_path(t, "block", st.st_dev);
errno = 0;
b = blkid_new_probe_from_filename(t);
if (!b)
diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c
index 219ba8cb0b..7835d99020 100644
--- a/src/shared/dissect-image.c
+++ b/src/shared/dissect-image.c
@@ -18,12 +18,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#if HAVE_LIBCRYPTSETUP
-#include <libcryptsetup.h>
-#ifndef CRYPT_LUKS
-#define CRYPT_LUKS NULL
-#endif
-#endif
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/wait.h>
@@ -32,7 +26,9 @@
#include "ask-password-api.h"
#include "blkid-util.h"
#include "copy.h"
+#include "crypt-util.h"
#include "def.h"
+#include "device-nodes.h"
#include "dissect-image.h"
#include "fd-util.h"
#include "fileio.h"
@@ -55,25 +51,34 @@
#include "udev-util.h"
#include "xattr-util.h"
-_unused_ static int probe_filesystem(const char *node, char **ret_fstype) {
+int probe_filesystem(const char *node, char **ret_fstype) {
+ /* Try to find device content type and return it in *ret_fstype. If nothing is found,
+ * 0/NULL will be returned. -EUCLEAN will be returned for ambigous results, and an
+ * different error otherwise. */
+
#if HAVE_BLKID
_cleanup_blkid_free_probe_ blkid_probe b = NULL;
const char *fstype;
int r;
+ errno = 0;
b = blkid_new_probe_from_filename(node);
if (!b)
- return -ENOMEM;
+ return -errno ?: -ENOMEM;
blkid_probe_enable_superblocks(b, 1);
blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
errno = 0;
r = blkid_do_safeprobe(b);
- if (IN_SET(r, -2, 1)) {
- log_debug("Failed to identify any partition type on partition %s", node);
+ if (r == 1) {
+ log_debug("No type detected on partition %s", node);
goto not_found;
}
+ if (r == -2) {
+ log_debug("Results ambiguous for partition %s", node);
+ return -EUCLEAN;
+ }
if (r != 0)
return -errno ?: -EIO;
@@ -611,7 +616,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectI
if (!p->fstype && p->node) {
r = probe_filesystem(p->node, &p->fstype);
- if (r < 0)
+ if (r < 0 && r != -EUCLEAN)
return r;
}
@@ -652,7 +657,7 @@ DissectedImage* dissected_image_unref(DissectedImage *m) {
}
static int is_loop_device(const char *path) {
- char s[strlen("/sys/dev/block/") + DECIMAL_STR_MAX(dev_t) + 1 + DECIMAL_STR_MAX(dev_t) + strlen("/../loop/")];
+ char s[SYS_BLOCK_PATH_MAX("/../loop/")];
struct stat st;
assert(path);
@@ -663,13 +668,13 @@ static int is_loop_device(const char *path) {
if (!S_ISBLK(st.st_mode))
return -ENOTBLK;
- xsprintf(s, "/sys/dev/block/%u:%u/loop/", major(st.st_rdev), minor(st.st_rdev));
+ xsprintf_sys_block_path(s, "/loop/", st.st_dev);
if (access(s, F_OK) < 0) {
if (errno != ENOENT)
return -errno;
/* The device itself isn't a loop device, but maybe it's a partition and its parent is? */
- xsprintf(s, "/sys/dev/block/%u:%u/../loop/", major(st.st_rdev), minor(st.st_rdev));
+ xsprintf_sys_block_path(s, "/../loop/", st.st_dev);
if (access(s, F_OK) < 0)
return errno == ENOENT ? false : -errno;
}
@@ -849,7 +854,7 @@ static int decrypt_partition(
DecryptedImage *d) {
_cleanup_free_ char *node = NULL, *name = NULL;
- struct crypt_device *cd;
+ _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
int r;
assert(m);
@@ -876,37 +881,28 @@ static int decrypt_partition(
return log_debug_errno(r, "Failed to initialize dm-crypt: %m");
r = crypt_load(cd, CRYPT_LUKS, NULL);
- if (r < 0) {
- log_debug_errno(r, "Failed to load LUKS metadata: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_debug_errno(r, "Failed to load LUKS metadata: %m");
r = crypt_activate_by_passphrase(cd, name, CRYPT_ANY_SLOT, passphrase, strlen(passphrase),
((flags & DISSECT_IMAGE_READ_ONLY) ? CRYPT_ACTIVATE_READONLY : 0) |
((flags & DISSECT_IMAGE_DISCARD_ON_CRYPTO) ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0));
- if (r < 0)
+ if (r < 0) {
log_debug_errno(r, "Failed to activate LUKS device: %m");
- if (r == -EPERM) {
- r = -EKEYREJECTED;
- goto fail;
+ return r == -EPERM ? -EKEYREJECTED : r;
}
- if (r < 0)
- goto fail;
d->decrypted[d->n_decrypted].name = name;
name = NULL;
d->decrypted[d->n_decrypted].device = cd;
+ cd = NULL;
d->n_decrypted++;
m->decrypted_node = node;
node = NULL;
return 0;
-
-fail:
- crypt_free(cd);
- return r;
}
static int verity_partition(
@@ -918,7 +914,7 @@ static int verity_partition(
DecryptedImage *d) {
_cleanup_free_ char *node = NULL, *name = NULL;
- struct crypt_device *cd;
+ _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
int r;
assert(m);
@@ -948,30 +944,27 @@ static int verity_partition(
r = crypt_load(cd, CRYPT_VERITY, NULL);
if (r < 0)
- goto fail;
+ return r;
r = crypt_set_data_device(cd, m->node);
if (r < 0)
- goto fail;
+ return r;
r = crypt_activate_by_volume_key(cd, name, root_hash, root_hash_size, CRYPT_ACTIVATE_READONLY);
if (r < 0)
- goto fail;
+ return r;
d->decrypted[d->n_decrypted].name = name;
name = NULL;
d->decrypted[d->n_decrypted].device = cd;
+ cd = NULL;
d->n_decrypted++;
m->decrypted_node = node;
node = NULL;
return 0;
-
-fail:
- crypt_free(cd);
- return r;
}
#endif
@@ -1033,7 +1026,7 @@ int dissected_image_decrypt(
if (!p->decrypted_fstype && p->decrypted_node) {
r = probe_filesystem(p->decrypted_node, &p->decrypted_fstype);
- if (r < 0)
+ if (r < 0 && r != -EUCLEAN)
return r;
}
}
diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h
index 30a12cb540..7c7ce46015 100644
--- a/src/shared/dissect-image.h
+++ b/src/shared/dissect-image.h
@@ -86,6 +86,7 @@ struct DissectedImage {
char **os_release;
};
+int probe_filesystem(const char *node, char **ret_fstype);
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DissectedImage **ret);
DissectedImage* dissected_image_unref(DissectedImage *m);
diff --git a/src/shared/generator.c b/src/shared/generator.c
index 462457e2fe..3495a7ef7d 100644
--- a/src/shared/generator.c
+++ b/src/shared/generator.c
@@ -83,8 +83,8 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) {
fprintf(f,
"# Automatically generated by %1$s\n\n"
"[Unit]\n"
- "Documentation=man:systemd-fsck-root.service(8)\n"
"Description=File System Check on %2$s\n"
+ "Documentation=man:systemd-fsck-root.service(8)\n"
"DefaultDependencies=no\n"
"BindsTo=%3$s\n"
"After=initrd-root-device.target local-fs-pre.target %3$s\n"
@@ -248,7 +248,8 @@ int generator_write_device_deps(
r = unit_name_from_path(node, ".device", &unit);
if (r < 0)
- return log_error_errno(r, "Failed to make unit name from path: %m");
+ return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
+ node);
/* See mount_add_default_dependencies for explanation why we create such
* dependencies. */
@@ -266,7 +267,8 @@ int generator_write_initrd_root_device_deps(const char *dir, const char *what) {
r = unit_name_from_path(what, ".device", &unit);
if (r < 0)
- return log_error_errno(r, "Failed to make unit name from path: %m");
+ return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
+ what);
return write_drop_in_format(dir, SPECIAL_INITRD_ROOT_DEVICE_TARGET, 50, "root-device",
"# Automatically generated by %s\n\n"
@@ -277,3 +279,206 @@ int generator_write_initrd_root_device_deps(const char *dir, const char *what) {
unit,
unit);
}
+
+int generator_hook_up_mkswap(
+ const char *dir,
+ const char *what) {
+
+ _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ const char *unit_file;
+ int r;
+
+ node = fstab_node_to_udev_node(what);
+ if (!node)
+ return log_oom();
+
+ /* Nothing to work on. */
+ if (!is_device_path(node)) {
+ log_error("Cannot format something that is not a device node: %s", node);
+ return -EINVAL;
+ }
+
+ r = unit_name_from_path_instance("systemd-mkswap", node, ".service", &unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
+ node);
+
+ unit_file = strjoina(dir, "/", unit);
+ log_debug("Creating %s", unit_file);
+
+ escaped = cescape(node);
+ if (!escaped)
+ return log_oom();
+
+ r = unit_name_from_path(what, ".swap", &where_unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
+ what);
+
+ f = fopen(unit_file, "wxe");
+ if (!f)
+ return log_error_errno(errno, "Failed to create unit file %s: %m",
+ unit_file);
+
+ fprintf(f,
+ "# Automatically generated by %s\n\n"
+ "[Unit]\n"
+ "Description=Make Swap on %%f\n"
+ "Documentation=man:systemd-mkswap@.service(8)\n"
+ "DefaultDependencies=no\n"
+ "BindsTo=%%i.device\n"
+ "After=%%i.device\n"
+ "Before=%s\n"
+ "Before=shutdown.target\n"
+ "\n"
+ "[Service]\n"
+ "Type=oneshot\n"
+ "RemainAfterExit=yes\n"
+ "ExecStart="SYSTEMD_MAKEFS_PATH " swap %s\n"
+ "TimeoutSec=0\n",
+ program_invocation_short_name,
+ where_unit,
+ escaped);
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);
+
+ return generator_add_symlink(dir, where_unit, "requires", unit);
+}
+
+int generator_hook_up_mkfs(
+ const char *dir,
+ const char *what,
+ const char *where,
+ const char *type) {
+
+ _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ const char *unit_file;
+ int r;
+
+ node = fstab_node_to_udev_node(what);
+ if (!node)
+ return log_oom();
+
+ /* Nothing to work on. */
+ if (!is_device_path(node)) {
+ log_error("Cannot format something that is not a device node: %s", node);
+ return -EINVAL;
+ }
+
+ if (!type || streq(type, "auto")) {
+ log_error("Cannot format partition %s, filesystem type is not specified", node);
+ return -EINVAL;
+ }
+
+ r = unit_name_from_path_instance("systemd-mkfs", node, ".service", &unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
+ node);
+
+ unit_file = strjoina(dir, "/", unit);
+ log_debug("Creating %s", unit_file);
+
+ escaped = cescape(node);
+ if (!escaped)
+ return log_oom();
+
+ r = unit_name_from_path(where, ".mount", &where_unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
+ where);
+
+ f = fopen(unit_file, "wxe");
+ if (!f)
+ return log_error_errno(errno, "Failed to create unit file %s: %m",
+ unit_file);
+
+ fprintf(f,
+ "# Automatically generated by %s\n\n"
+ "[Unit]\n"
+ "Description=Make File System on %%f\n"
+ "Documentation=man:systemd-mkfs@.service(8)\n"
+ "DefaultDependencies=no\n"
+ "BindsTo=%%i.device\n"
+ "After=%%i.device\n"
+ /* fsck might or might not be used, so let's be safe and order
+ * ourselves before both systemd-fsck@.service and the mount unit. */
+ "Before=systemd-fsck@%%i.service\n"
+ "Before=%s\n"
+ "Before=shutdown.target\n"
+ "\n"
+ "[Service]\n"
+ "Type=oneshot\n"
+ "RemainAfterExit=yes\n"
+ "ExecStart="SYSTEMD_MAKEFS_PATH " %s %s\n"
+ "TimeoutSec=0\n",
+ program_invocation_short_name,
+ where_unit,
+ type,
+ escaped);
+ // XXX: what about local-fs-pre.target?
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);
+
+ return generator_add_symlink(dir, where_unit, "requires", unit);
+}
+
+int generator_hook_up_growfs(
+ const char *dir,
+ const char *where,
+ const char *target) {
+
+ _cleanup_free_ char *unit = NULL, *escaped = NULL, *where_unit = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ const char *unit_file;
+ int r;
+
+ escaped = cescape(where);
+ if (!escaped)
+ return log_oom();
+
+ r = unit_name_from_path_instance("systemd-growfs", where, ".service", &unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
+ where);
+
+ r = unit_name_from_path(where, ".mount", &where_unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
+ where);
+
+ unit_file = strjoina(dir, "/", unit);
+ log_debug("Creating %s", unit_file);
+
+ f = fopen(unit_file, "wxe");
+ if (!f)
+ return log_error_errno(errno, "Failed to create unit file %s: %m",
+ unit_file);
+
+ fprintf(f,
+ "# Automatically generated by %s\n\n"
+ "[Unit]\n"
+ "Description=Grow File System on %%f\n"
+ "Documentation=man:systemd-growfs@.service(8)\n"
+ "DefaultDependencies=no\n"
+ "BindsTo=%%i.mount\n"
+ "After=%%i.mount\n"
+ "Before=shutdown.target\n"
+ "Before=%s\n"
+ "\n"
+ "[Service]\n"
+ "Type=oneshot\n"
+ "RemainAfterExit=yes\n"
+ "ExecStart="SYSTEMD_GROWFS_PATH " %s\n"
+ "TimeoutSec=0\n",
+ program_invocation_short_name,
+ target,
+ escaped);
+
+ return generator_add_symlink(dir, where_unit, "wants", unit);
+}
diff --git a/src/shared/generator.h b/src/shared/generator.h
index 39dd520f9f..32d1ad021c 100644
--- a/src/shared/generator.h
+++ b/src/shared/generator.h
@@ -39,11 +39,24 @@ int generator_write_timeouts(
char **filtered);
int generator_write_device_deps(
- const char *dir,
- const char *what,
- const char *where,
- const char *opts);
+ const char *dir,
+ const char *what,
+ const char *where,
+ const char *opts);
int generator_write_initrd_root_device_deps(
const char *dir,
const char *what);
+
+int generator_hook_up_mkswap(
+ const char *dir,
+ const char *what);
+int generator_hook_up_mkfs(
+ const char *dir,
+ const char *what,
+ const char *where,
+ const char *type);
+int generator_hook_up_growfs(
+ const char *dir,
+ const char *where,
+ const char *target);
diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c
index 3c958917bb..83ddc398b8 100644
--- a/src/test/test-fs-util.c
+++ b/src/test/test-fs-util.c
@@ -35,7 +35,7 @@
static void test_chase_symlinks(void) {
_cleanup_free_ char *result = NULL;
char temp[] = "/tmp/test-chase.XXXXXX";
- const char *top, *p, *q;
+ const char *top, *p, *pslash, *q, *qslash;
int r;
assert_se(mkdtemp(temp));
@@ -66,93 +66,114 @@ static void test_chase_symlinks(void) {
r = chase_symlinks(p, NULL, 0, &result);
assert_se(r > 0);
assert_se(path_equal(result, "/usr"));
+ result = mfree(result);
+ pslash = strjoina(p, "/");
+ r = chase_symlinks(pslash, NULL, 0, &result);
+ assert_se(r > 0);
+ assert_se(path_equal(result, "/usr/"));
result = mfree(result);
+
r = chase_symlinks(p, temp, 0, &result);
assert_se(r == -ENOENT);
+ r = chase_symlinks(pslash, temp, 0, &result);
+ assert_se(r == -ENOENT);
+
q = strjoina(temp, "/usr");
r = chase_symlinks(p, temp, CHASE_NONEXISTENT, &result);
assert_se(r == 0);
assert_se(path_equal(result, q));
+ result = mfree(result);
- assert_se(mkdir(q, 0700) >= 0);
+ qslash = strjoina(q, "/");
+ r = chase_symlinks(pslash, temp, CHASE_NONEXISTENT, &result);
+ assert_se(r == 0);
+ assert_se(path_equal(result, qslash));
result = mfree(result);
+
+ assert_se(mkdir(q, 0700) >= 0);
+
r = chase_symlinks(p, temp, 0, &result);
assert_se(r > 0);
assert_se(path_equal(result, q));
+ result = mfree(result);
+
+ r = chase_symlinks(pslash, temp, 0, &result);
+ assert_se(r > 0);
+ assert_se(path_equal(result, qslash));
+ result = mfree(result);
p = strjoina(temp, "/slash");
assert_se(symlink("/", p) >= 0);
- result = mfree(result);
r = chase_symlinks(p, NULL, 0, &result);
assert_se(r > 0);
assert_se(path_equal(result, "/"));
-
result = mfree(result);
+
r = chase_symlinks(p, temp, 0, &result);
assert_se(r > 0);
assert_se(path_equal(result, temp));
+ result = mfree(result);
/* Paths that would "escape" outside of the "root" */
p = strjoina(temp, "/6dots");
assert_se(symlink("../../..", p) >= 0);
- result = mfree(result);
r = chase_symlinks(p, temp, 0, &result);
assert_se(r > 0 && path_equal(result, temp));
+ result = mfree(result);
p = strjoina(temp, "/6dotsusr");
assert_se(symlink("../../../usr", p) >= 0);
- result = mfree(result);
r = chase_symlinks(p, temp, 0, &result);
assert_se(r > 0 && path_equal(result, q));
+ result = mfree(result);
p = strjoina(temp, "/top/8dotsusr");
assert_se(symlink("../../../../usr", p) >= 0);
- result = mfree(result);
r = chase_symlinks(p, temp, 0, &result);
assert_se(r > 0 && path_equal(result, q));
+ result = mfree(result);
/* Paths that contain repeated slashes */
p = strjoina(temp, "/slashslash");
assert_se(symlink("///usr///", p) >= 0);
- result = mfree(result);
r = chase_symlinks(p, NULL, 0, &result);
assert_se(r > 0);
assert_se(path_equal(result, "/usr"));
-
result = mfree(result);
+
r = chase_symlinks(p, temp, 0, &result);
assert_se(r > 0);
assert_se(path_equal(result, q));
+ result = mfree(result);
/* Paths using . */
- result = mfree(result);
r = chase_symlinks("/etc/./.././", NULL, 0, &result);
assert_se(r > 0);
assert_se(path_equal(result, "/"));
-
result = mfree(result);
+
r = chase_symlinks("/etc/./.././", "/etc", 0, &result);
assert_se(r > 0 && path_equal(result, "/etc"));
-
result = mfree(result);
+
r = chase_symlinks("/etc/machine-id/foo", NULL, 0, &result);
assert_se(r == -ENOTDIR);
+ result = mfree(result);
/* Path that loops back to self */
- result = mfree(result);
p = strjoina(temp, "/recursive-symlink");
assert_se(symlink("recursive-symlink", p) >= 0);
r = chase_symlinks(p, NULL, 0, &result);
diff --git a/src/test/test-mount-util.c b/src/test/test-mount-util.c
index 2aad7f387c..09a624842c 100644
--- a/src/test/test-mount-util.c
+++ b/src/test/test-mount-util.c
@@ -26,8 +26,10 @@
#include "fileio.h"
#include "hashmap.h"
#include "log.h"
+#include "log.h"
#include "mount-util.h"
#include "path-util.h"
+#include "rm-rf.h"
#include "string-util.h"
static void test_mount_propagation_flags(const char *name, int ret, unsigned long expected) {
@@ -100,6 +102,165 @@ static void test_mnt_id(void) {
hashmap_free_free(h);
}
+static void test_path_is_mount_point(void) {
+ int fd;
+ char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX";
+ _cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL;
+ _cleanup_free_ char *dir1 = NULL, *dir1file = NULL, *dirlink1 = NULL, *dirlink1file = NULL;
+ _cleanup_free_ char *dir2 = NULL, *dir2file = NULL;
+
+ assert_se(path_is_mount_point("/", NULL, AT_SYMLINK_FOLLOW) > 0);
+ assert_se(path_is_mount_point("/", NULL, 0) > 0);
+ assert_se(path_is_mount_point("//", NULL, AT_SYMLINK_FOLLOW) > 0);
+ assert_se(path_is_mount_point("//", NULL, 0) > 0);
+
+ assert_se(path_is_mount_point("/proc", NULL, AT_SYMLINK_FOLLOW) > 0);
+ assert_se(path_is_mount_point("/proc", NULL, 0) > 0);
+ assert_se(path_is_mount_point("/proc/", NULL, AT_SYMLINK_FOLLOW) > 0);
+ assert_se(path_is_mount_point("/proc/", NULL, 0) > 0);
+
+ assert_se(path_is_mount_point("/proc/1", NULL, AT_SYMLINK_FOLLOW) == 0);
+ assert_se(path_is_mount_point("/proc/1", NULL, 0) == 0);
+ assert_se(path_is_mount_point("/proc/1/", NULL, AT_SYMLINK_FOLLOW) == 0);
+ assert_se(path_is_mount_point("/proc/1/", NULL, 0) == 0);
+
+ assert_se(path_is_mount_point("/sys", NULL, AT_SYMLINK_FOLLOW) > 0);
+ assert_se(path_is_mount_point("/sys", NULL, 0) > 0);
+ assert_se(path_is_mount_point("/sys/", NULL, AT_SYMLINK_FOLLOW) > 0);
+ assert_se(path_is_mount_point("/sys/", NULL, 0) > 0);
+
+ /* we'll create a hierarchy of different kinds of dir/file/link
+ * layouts:
+ *
+ * <tmp>/file1, <tmp>/file2
+ * <tmp>/link1 -> file1, <tmp>/link2 -> file2
+ * <tmp>/dir1/
+ * <tmp>/dir1/file
+ * <tmp>/dirlink1 -> dir1
+ * <tmp>/dirlink1file -> dirlink1/file
+ * <tmp>/dir2/
+ * <tmp>/dir2/file
+ */
+
+ /* 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, NULL, AT_SYMLINK_FOLLOW) == 0);
+ assert_se(path_is_mount_point(file1, NULL, 0) == 0);
+ assert_se(path_is_mount_point(link1, NULL, AT_SYMLINK_FOLLOW) == 0);
+ assert_se(path_is_mount_point(link1, NULL, 0) == 0);
+
+ /* directory mountpoints */
+ dir1 = path_join(NULL, tmp_dir, "dir1");
+ assert_se(dir1);
+ assert_se(mkdir(dir1, 0755) == 0);
+ dirlink1 = path_join(NULL, tmp_dir, "dirlink1");
+ assert_se(dirlink1);
+ assert_se(symlink("dir1", dirlink1) == 0);
+ dirlink1file = path_join(NULL, tmp_dir, "dirlink1file");
+ assert_se(dirlink1file);
+ assert_se(symlink("dirlink1/file", dirlink1file) == 0);
+ dir2 = path_join(NULL, tmp_dir, "dir2");
+ assert_se(dir2);
+ assert_se(mkdir(dir2, 0755) == 0);
+
+ assert_se(path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW) == 0);
+ assert_se(path_is_mount_point(dir1, NULL, 0) == 0);
+ assert_se(path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW) == 0);
+ assert_se(path_is_mount_point(dirlink1, NULL, 0) == 0);
+
+ /* file in subdirectory mountpoints */
+ dir1file = path_join(NULL, dir1, "file");
+ assert_se(dir1file);
+ fd = open(dir1file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
+ assert_se(fd > 0);
+ close(fd);
+
+ assert_se(path_is_mount_point(dir1file, NULL, AT_SYMLINK_FOLLOW) == 0);
+ assert_se(path_is_mount_point(dir1file, NULL, 0) == 0);
+ assert_se(path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW) == 0);
+ assert_se(path_is_mount_point(dirlink1file, NULL, 0) == 0);
+
+ /* these tests will only work as root */
+ if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) {
+ int rf, rt, rdf, rdt, rlf, rlt, rl1f, rl1t;
+ const char *file2d;
+
+ /* files */
+ /* capture results in vars, to avoid dangling mounts on failure */
+ log_info("%s: %s", __func__, file2);
+ rf = path_is_mount_point(file2, NULL, 0);
+ rt = path_is_mount_point(file2, NULL, AT_SYMLINK_FOLLOW);
+
+ file2d = strjoina(file2, "/");
+ log_info("%s: %s", __func__, file2d);
+ rdf = path_is_mount_point(file2d, NULL, 0);
+ rdt = path_is_mount_point(file2d, NULL, AT_SYMLINK_FOLLOW);
+
+ log_info("%s: %s", __func__, link2);
+ rlf = path_is_mount_point(link2, NULL, 0);
+ rlt = path_is_mount_point(link2, NULL, AT_SYMLINK_FOLLOW);
+
+ assert_se(umount(file2) == 0);
+
+ assert_se(rf == 1);
+ assert_se(rt == 1);
+ assert_se(rdf == -ENOTDIR);
+ assert_se(rdt == -ENOTDIR);
+ assert_se(rlf == 0);
+ assert_se(rlt == 1);
+
+ /* dirs */
+ dir2file = path_join(NULL, dir2, "file");
+ assert_se(dir2file);
+ fd = open(dir2file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
+ assert_se(fd > 0);
+ close(fd);
+
+ assert_se(mount(dir2, dir1, NULL, MS_BIND, NULL) >= 0);
+
+ log_info("%s: %s", __func__, dir1);
+ rf = path_is_mount_point(dir1, NULL, 0);
+ rt = path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW);
+ log_info("%s: %s", __func__, dirlink1);
+ rlf = path_is_mount_point(dirlink1, NULL, 0);
+ rlt = path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW);
+ log_info("%s: %s", __func__, dirlink1file);
+ /* its parent is a mount point, but not /file itself */
+ rl1f = path_is_mount_point(dirlink1file, NULL, 0);
+ rl1t = path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW);
+
+ assert_se(umount(dir1) == 0);
+
+ assert_se(rf == 1);
+ assert_se(rt == 1);
+ assert_se(rlf == 0);
+ assert_se(rlt == 1);
+ assert_se(rl1f == 0);
+ assert_se(rl1t == 0);
+
+ } 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[]) {
log_set_max_level(LOG_DEBUG);
@@ -113,6 +274,7 @@ int main(int argc, char *argv[]) {
test_mount_propagation_flags(" ", -EINVAL, 0);
test_mnt_id();
+ test_path_is_mount_point();
return 0;
}
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
index 68fe941f15..0db835608a 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -19,7 +19,6 @@
***/
#include <stdio.h>
-#include <sys/mount.h>
#include <unistd.h>
#include "alloc-util.h"
@@ -376,143 +375,6 @@ static void test_prefix_root(void) {
test_prefix_root_one("/foo///", "//bar", "/foo/bar");
}
-static void test_path_is_mount_point(void) {
- int fd;
- char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX";
- _cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL;
- _cleanup_free_ char *dir1 = NULL, *dir1file = NULL, *dirlink1 = NULL, *dirlink1file = NULL;
- _cleanup_free_ char *dir2 = NULL, *dir2file = NULL;
-
- assert_se(path_is_mount_point("/", NULL, AT_SYMLINK_FOLLOW) > 0);
- assert_se(path_is_mount_point("/", NULL, 0) > 0);
-
- assert_se(path_is_mount_point("/proc", NULL, AT_SYMLINK_FOLLOW) > 0);
- assert_se(path_is_mount_point("/proc", NULL, 0) > 0);
-
- assert_se(path_is_mount_point("/proc/1", NULL, AT_SYMLINK_FOLLOW) == 0);
- assert_se(path_is_mount_point("/proc/1", NULL, 0) == 0);
-
- assert_se(path_is_mount_point("/sys", NULL, AT_SYMLINK_FOLLOW) > 0);
- assert_se(path_is_mount_point("/sys", NULL, 0) > 0);
-
- /* we'll create a hierarchy of different kinds of dir/file/link
- * layouts:
- *
- * <tmp>/file1, <tmp>/file2
- * <tmp>/link1 -> file1, <tmp>/link2 -> file2
- * <tmp>/dir1/
- * <tmp>/dir1/file
- * <tmp>/dirlink1 -> dir1
- * <tmp>/dirlink1file -> dirlink1/file
- * <tmp>/dir2/
- * <tmp>/dir2/file
- */
-
- /* 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, NULL, AT_SYMLINK_FOLLOW) == 0);
- assert_se(path_is_mount_point(file1, NULL, 0) == 0);
- assert_se(path_is_mount_point(link1, NULL, AT_SYMLINK_FOLLOW) == 0);
- assert_se(path_is_mount_point(link1, NULL, 0) == 0);
-
- /* directory mountpoints */
- dir1 = path_join(NULL, tmp_dir, "dir1");
- assert_se(dir1);
- assert_se(mkdir(dir1, 0755) == 0);
- dirlink1 = path_join(NULL, tmp_dir, "dirlink1");
- assert_se(dirlink1);
- assert_se(symlink("dir1", dirlink1) == 0);
- dirlink1file = path_join(NULL, tmp_dir, "dirlink1file");
- assert_se(dirlink1file);
- assert_se(symlink("dirlink1/file", dirlink1file) == 0);
- dir2 = path_join(NULL, tmp_dir, "dir2");
- assert_se(dir2);
- assert_se(mkdir(dir2, 0755) == 0);
-
- assert_se(path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW) == 0);
- assert_se(path_is_mount_point(dir1, NULL, 0) == 0);
- assert_se(path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW) == 0);
- assert_se(path_is_mount_point(dirlink1, NULL, 0) == 0);
-
- /* file in subdirectory mountpoints */
- dir1file = path_join(NULL, dir1, "file");
- assert_se(dir1file);
- fd = open(dir1file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
- assert_se(fd > 0);
- close(fd);
-
- assert_se(path_is_mount_point(dir1file, NULL, AT_SYMLINK_FOLLOW) == 0);
- assert_se(path_is_mount_point(dir1file, NULL, 0) == 0);
- assert_se(path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW) == 0);
- assert_se(path_is_mount_point(dirlink1file, NULL, 0) == 0);
-
- /* these tests will only work as root */
- if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) {
- int rt, rf, rlt, rlf, rl1t, rl1f;
-
- /* files */
- /* capture results in vars, to avoid dangling mounts on failure */
- rf = path_is_mount_point(file2, NULL, 0);
- rt = path_is_mount_point(file2, NULL, AT_SYMLINK_FOLLOW);
- rlf = path_is_mount_point(link2, NULL, 0);
- rlt = path_is_mount_point(link2, NULL, AT_SYMLINK_FOLLOW);
-
- assert_se(umount(file2) == 0);
-
- assert_se(rf == 1);
- assert_se(rt == 1);
- assert_se(rlf == 0);
- assert_se(rlt == 1);
-
- /* dirs */
- dir2file = path_join(NULL, dir2, "file");
- assert_se(dir2file);
- fd = open(dir2file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
- assert_se(fd > 0);
- close(fd);
-
- assert_se(mount(dir2, dir1, NULL, MS_BIND, NULL) >= 0);
-
- rf = path_is_mount_point(dir1, NULL, 0);
- rt = path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW);
- rlf = path_is_mount_point(dirlink1, NULL, 0);
- rlt = path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW);
- /* its parent is a mount point, but not /file itself */
- rl1f = path_is_mount_point(dirlink1file, NULL, 0);
- rl1t = path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW);
-
- assert_se(umount(dir1) == 0);
-
- assert_se(rf == 1);
- assert_se(rt == 1);
- assert_se(rlf == 0);
- assert_se(rlt == 1);
- assert_se(rl1f == 0);
- assert_se(rl1t == 0);
-
- } else
- printf("Skipping bind mount file test: %m\n");
-
- assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
-}
-
static void test_file_in_same_dir(void) {
char *t;
@@ -537,6 +399,21 @@ static void test_file_in_same_dir(void) {
free(t);
}
+static void test_last_path_component(void) {
+ assert_se(streq(last_path_component("a/b/c"), "c"));
+ assert_se(streq(last_path_component("a/b/c/"), "c/"));
+ assert_se(streq(last_path_component("/"), "/"));
+ assert_se(streq(last_path_component("//"), "/"));
+ assert_se(streq(last_path_component("///"), "/"));
+ assert_se(streq(last_path_component("."), "."));
+ assert_se(streq(last_path_component("./."), "."));
+ assert_se(streq(last_path_component("././"), "./"));
+ assert_se(streq(last_path_component("././/"), ".//"));
+ assert_se(streq(last_path_component("/foo/a"), "a"));
+ assert_se(streq(last_path_component("/foo/a/"), "a/"));
+ assert_se(streq(last_path_component(""), ""));
+}
+
static void test_filename_is_valid(void) {
char foo[FILENAME_MAX+2];
int i;
@@ -621,8 +498,8 @@ int main(int argc, char **argv) {
test_strv_resolve();
test_path_startswith();
test_prefix_root();
- test_path_is_mount_point();
test_file_in_same_dir();
+ test_last_path_component();
test_filename_is_valid();
test_hidden_or_backup_file();
test_skip_dev_prefix();
diff --git a/src/test/test-stat-util.c b/src/test/test-stat-util.c
index b58f31dd53..c606425d2d 100644
--- a/src/test/test-stat-util.c
+++ b/src/test/test-stat-util.c
@@ -72,16 +72,16 @@ static void test_path_is_os_tree(void) {
assert_se(path_is_os_tree("/idontexist") == -ENOENT);
}
-static void test_path_check_fstype(void) {
+static void test_path_is_fs_type(void) {
/* run might not be a mount point in build chroots */
if (path_is_mount_point("/run", NULL, AT_SYMLINK_FOLLOW) > 0) {
- assert_se(path_check_fstype("/run", TMPFS_MAGIC) > 0);
- assert_se(path_check_fstype("/run", BTRFS_SUPER_MAGIC) == 0);
+ assert_se(path_is_fs_type("/run", TMPFS_MAGIC) > 0);
+ assert_se(path_is_fs_type("/run", BTRFS_SUPER_MAGIC) == 0);
}
- assert_se(path_check_fstype("/proc", PROC_SUPER_MAGIC) > 0);
- assert_se(path_check_fstype("/proc", BTRFS_SUPER_MAGIC) == 0);
- assert_se(path_check_fstype("/proc", BTRFS_SUPER_MAGIC) == 0);
- assert_se(path_check_fstype("/i-dont-exist", BTRFS_SUPER_MAGIC) == -ENOENT);
+ assert_se(path_is_fs_type("/proc", PROC_SUPER_MAGIC) > 0);
+ assert_se(path_is_fs_type("/proc", BTRFS_SUPER_MAGIC) == 0);
+ assert_se(path_is_fs_type("/proc", BTRFS_SUPER_MAGIC) == 0);
+ assert_se(path_is_fs_type("/i-dont-exist", BTRFS_SUPER_MAGIC) == -ENOENT);
}
static void test_path_is_temporary_fs(void) {
@@ -96,7 +96,7 @@ int main(int argc, char *argv[]) {
test_files_same();
test_is_symlink();
test_path_is_os_tree();
- test_path_check_fstype();
+ test_path_is_fs_type();
test_path_is_temporary_fs();
return 0;
diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c
index ed777e1801..7a14b8efd3 100644
--- a/src/test/test-string-util.c
+++ b/src/test/test-string-util.c
@@ -320,6 +320,19 @@ static void test_delete_trailing_chars(void) {
assert_se(s == input3);
}
+static void test_delete_trailing_slashes(void) {
+ char s1[] = "foobar//",
+ s2[] = "foobar/",
+ s3[] = "foobar",
+ s4[] = "";
+
+ assert_se(streq(delete_trailing_chars(s1, "_"), "foobar//"));
+ assert_se(streq(delete_trailing_chars(s1, "/"), "foobar"));
+ assert_se(streq(delete_trailing_chars(s2, "/"), "foobar"));
+ assert_se(streq(delete_trailing_chars(s3, "/"), "foobar"));
+ assert_se(streq(delete_trailing_chars(s4, "/"), ""));
+}
+
static void test_skip_leading_chars(void) {
char input1[] = " \n \r k \n \r ",
input2[] = "kkkkthiskkkiskkkaktestkkk",
@@ -399,6 +412,7 @@ int main(int argc, char *argv[]) {
test_endswith_no_case();
test_delete_chars();
test_delete_trailing_chars();
+ test_delete_trailing_slashes();
test_skip_leading_chars();
test_in_charset();
test_split_pair();
diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
index dcea890d7f..ef893247ad 100644
--- a/src/udev/udev-node.c
+++ b/src/udev/udev-node.c
@@ -25,6 +25,7 @@
#include <sys/stat.h>
#include <unistd.h>
+#include "device-nodes.h"
#include "dirent-util.h"
#include "format-util.h"
#include "fs-util.h"
@@ -337,7 +338,7 @@ out:
void udev_node_add(struct udev_device *dev, bool apply,
mode_t mode, uid_t uid, gid_t gid,
struct udev_list *seclabel_list) {
- char filename[sizeof("/dev/block/:") + 2*DECIMAL_STR_MAX(unsigned)];
+ char filename[DEV_NUM_PATH_MAX];
struct udev_list_entry *list_entry;
log_debug("handling device node '%s', devnum=%s, mode=%#o, uid="UID_FMT", gid="GID_FMT,
@@ -347,10 +348,9 @@ void udev_node_add(struct udev_device *dev, bool apply,
return;
/* always add /dev/{block,char}/$major:$minor */
- xsprintf(filename, "/dev/%s/%u:%u",
- streq(udev_device_get_subsystem(dev), "block") ? "block" : "char",
- major(udev_device_get_devnum(dev)),
- minor(udev_device_get_devnum(dev)));
+ xsprintf_dev_num_path(filename,
+ streq(udev_device_get_subsystem(dev), "block") ? "block" : "char",
+ udev_device_get_devnum(dev));
node_symlink(dev, udev_device_get_devnode(dev), filename);
/* create/update symlinks, add symlinks to name index */
@@ -360,16 +360,15 @@ void udev_node_add(struct udev_device *dev, bool apply,
void udev_node_remove(struct udev_device *dev) {
struct udev_list_entry *list_entry;
- char filename[sizeof("/dev/block/:") + 2*DECIMAL_STR_MAX(unsigned)];
+ char filename[DEV_NUM_PATH_MAX];
/* remove/update symlinks, remove symlinks from name index */
udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev))
link_update(dev, udev_list_entry_get_name(list_entry), false);
/* remove /dev/{block,char}/$major:$minor */
- xsprintf(filename, "/dev/%s/%u:%u",
- streq(udev_device_get_subsystem(dev), "block") ? "block" : "char",
- major(udev_device_get_devnum(dev)),
- minor(udev_device_get_devnum(dev)));
+ xsprintf_dev_num_path(filename,
+ streq(udev_device_get_subsystem(dev), "block") ? "block" : "char",
+ udev_device_get_devnum(dev));
unlink(filename);
}
diff --git a/src/veritysetup/veritysetup.c b/src/veritysetup/veritysetup.c
index 18554aa231..d3066ca429 100644
--- a/src/veritysetup/veritysetup.c
+++ b/src/veritysetup/veritysetup.c
@@ -18,10 +18,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <libcryptsetup.h>
#include <stdio.h>
#include <sys/stat.h>
+#include "crypt-util.h"
#include "log.h"
#include "hexdecoct.h"
#include "string-util.h"
@@ -41,12 +41,8 @@ static int help(void) {
return 0;
}
-static void log_glue(int level, const char *msg, void *usrptr) {
- log_debug("%s", msg);
-}
-
int main(int argc, char *argv[]) {
- struct crypt_device *cd = NULL;
+ _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
int r;
if (argc <= 1) {
@@ -89,7 +85,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- crypt_set_log_callback(cd, log_glue, NULL);
+ crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
status = crypt_status(cd, argv[2]);
if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) {
@@ -127,7 +123,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- crypt_set_log_callback(cd, log_glue, NULL);
+ crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
r = crypt_deactivate(cd, argv[2]);
if (r < 0) {
@@ -144,9 +140,6 @@ int main(int argc, char *argv[]) {
r = 0;
finish:
- if (cd)
- crypt_free(cd);
-
free(arg_root_hash);
free(arg_data_what);
free(arg_hash_what);