diff options
-rw-r--r-- | src/basic/blockdev-util.c | 199 | ||||
-rw-r--r-- | src/basic/blockdev-util.h | 38 | ||||
-rw-r--r-- | src/basic/btrfs-util.c | 1 | ||||
-rw-r--r-- | src/basic/device-nodes.h | 5 | ||||
-rw-r--r-- | src/basic/meson.build | 6 | ||||
-rw-r--r-- | src/basic/util.c | 168 | ||||
-rw-r--r-- | src/basic/util.h | 5 | ||||
-rw-r--r-- | src/core/cgroup.c | 3 | ||||
-rw-r--r-- | src/core/umount.c | 3 | ||||
-rw-r--r-- | src/gpt-auto-generator/gpt-auto-generator.c | 1 | ||||
-rw-r--r-- | src/partition/growfs.c | 1 | ||||
-rw-r--r-- | src/shared/dissect-image.c | 1 |
12 files changed, 249 insertions, 182 deletions
diff --git a/src/basic/blockdev-util.c b/src/basic/blockdev-util.c new file mode 100644 index 0000000000..3a8f8d1c27 --- /dev/null +++ b/src/basic/blockdev-util.c @@ -0,0 +1,199 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sys/stat.h> +#include <sys/statfs.h> + +#include "alloc-util.h" +#include "blockdev-util.h" +#include "btrfs-util.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "missing.h" +#include "stat-util.h" + +int block_get_whole_disk(dev_t d, dev_t *ret) { + char p[SYS_BLOCK_PATH_MAX("/partition")]; + _cleanup_free_ char *s = NULL; + unsigned n, m; + int r; + + assert(ret); + + /* If it has a queue this is good enough for us */ + 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 */ + xsprintf_sys_block_path(p, "/partition", d); + if (access(p, F_OK) < 0) + return -ENOENT; + + /* Get parent dev_t */ + xsprintf_sys_block_path(p, "/../dev", d); + r = read_one_line_file(p, &s); + if (r < 0) + return r; + + r = sscanf(s, "%u:%u", &m, &n); + if (r != 2) + return -EINVAL; + + /* Only return this if it is really good enough for us. */ + xsprintf_sys_block_path(p, "/queue", makedev(m, n)); + if (access(p, F_OK) < 0) + return -ENOENT; + + *ret = makedev(m, n); + return 0; +} + +int get_block_device(const char *path, dev_t *dev) { + struct stat st; + struct statfs sfs; + + assert(path); + assert(dev); + + /* Get's the block device directly backing a file system. If + * the block device is encrypted, returns the device mapper + * block device. */ + + if (lstat(path, &st)) + return -errno; + + if (major(st.st_dev) != 0) { + *dev = st.st_dev; + return 1; + } + + if (statfs(path, &sfs) < 0) + return -errno; + + if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) + return btrfs_get_block_device(path, dev); + + return 0; +} + +int get_block_device_harder(const char *path, dev_t *dev) { + _cleanup_closedir_ DIR *d = NULL; + _cleanup_free_ char *t = NULL; + char p[SYS_BLOCK_PATH_MAX("/slaves")]; + struct dirent *de, *found = NULL; + const char *q; + unsigned maj, min; + dev_t dt; + int r; + + assert(path); + assert(dev); + + /* Gets the backing block device for a file system, and + * handles LUKS encrypted file systems, looking for its + * immediate parent, if there is one. */ + + r = get_block_device(path, &dt); + if (r <= 0) + return r; + + xsprintf_sys_block_path(p, "/slaves", dt); + d = opendir(p); + if (!d) { + if (errno == ENOENT) + goto fallback; + + return -errno; + } + + FOREACH_DIRENT_ALL(de, d, return -errno) { + + if (dot_or_dot_dot(de->d_name)) + continue; + + if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN)) + continue; + + if (found) { + _cleanup_free_ char *u = NULL, *v = NULL, *a = NULL, *b = NULL; + + /* We found a device backed by multiple other devices. We don't really support automatic + * discovery on such setups, with the exception of dm-verity partitions. In this case there are + * two backing devices: the data partition and the hash partition. We are fine with such + * setups, however, only if both partitions are on the same physical device. Hence, let's + * verify this. */ + + u = strjoin(p, "/", de->d_name, "/../dev"); + if (!u) + return -ENOMEM; + + v = strjoin(p, "/", found->d_name, "/../dev"); + if (!v) + return -ENOMEM; + + r = read_one_line_file(u, &a); + if (r < 0) { + log_debug_errno(r, "Failed to read %s: %m", u); + goto fallback; + } + + r = read_one_line_file(v, &b); + if (r < 0) { + log_debug_errno(r, "Failed to read %s: %m", v); + goto fallback; + } + + /* Check if the parent device is the same. If not, then the two backing devices are on + * different physical devices, and we don't support that. */ + if (!streq(a, b)) + goto fallback; + } + + found = de; + } + + if (!found) + goto fallback; + + q = strjoina(p, "/", found->d_name, "/dev"); + + r = read_one_line_file(q, &t); + if (r == -ENOENT) + goto fallback; + if (r < 0) + return r; + + if (sscanf(t, "%u:%u", &maj, &min) != 2) + return -EINVAL; + + if (maj == 0) + goto fallback; + + *dev = makedev(maj, min); + return 1; + +fallback: + *dev = dt; + return 1; +} diff --git a/src/basic/blockdev-util.h b/src/basic/blockdev-util.h new file mode 100644 index 0000000000..642b7ce522 --- /dev/null +++ b/src/basic/blockdev-util.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sys/types.h> + +#include "macro.h" +#include "stdio-util.h" +#include "string-util.h" + +#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)) + +int block_get_whole_disk(dev_t d, dev_t *ret); + +int get_block_device(const char *path, dev_t *dev); + +int get_block_device_harder(const char *path, dev_t *dev); diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index f8d743b407..19d385ab7c 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -38,6 +38,7 @@ #endif #include "alloc-util.h" +#include "blockdev-util.h" #include "btrfs-ctree.h" #include "btrfs-util.h" #include "chattr-util.h" diff --git a/src/basic/device-nodes.h b/src/basic/device-nodes.h index 7dd8a772a5..49f4ccc729 100644 --- a/src/basic/device-nodes.h +++ b/src/basic/device-nodes.h @@ -29,11 +29,6 @@ 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) \ diff --git a/src/basic/meson.build b/src/basic/meson.build index f751ee3215..31a00cee5e 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -35,6 +35,8 @@ basic_sources_plain = files(''' bitmap.c bitmap.h blkid-util.h + blockdev-util.c + blockdev-util.h bpf-program.c bpf-program.h btrfs-ctree.h @@ -203,10 +205,10 @@ basic_sources_plain = files(''' time-util.h umask-util.h unaligned.h - unit-name.c - unit-name.h unit-def.c unit-def.h + unit-name.c + unit-name.h user-util.c user-util.h utf8.c diff --git a/src/basic/util.c b/src/basic/util.c index 53bfb9e0da..5dd3c3014f 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -118,45 +118,6 @@ int socket_from_display(const char *display, char **path) { return 0; } -int block_get_whole_disk(dev_t d, dev_t *ret) { - 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 */ - 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 */ - xsprintf_sys_block_path(p, "/partition", d); - if (access(p, F_OK) < 0) - return -ENOENT; - - /* Get parent dev_t */ - xsprintf_sys_block_path(p, "/../dev", d); - r = read_one_line_file(p, &s); - if (r < 0) - return r; - - r = sscanf(s, "%u:%u", &m, &n); - if (r != 2) - return -EINVAL; - - /* Only return this if it is really good enough for us. */ - xsprintf_sys_block_path(p, "/queue", makedev(m, n)); - if (access(p, F_OK) < 0) - return -ENOENT; - - *ret = makedev(m, n); - return 0; -} - bool kexec_loaded(void) { _cleanup_free_ char *s = NULL; @@ -592,132 +553,3 @@ int version(void) { SYSTEMD_FEATURES); return 0; } - -int get_block_device(const char *path, dev_t *dev) { - struct stat st; - struct statfs sfs; - - assert(path); - assert(dev); - - /* Get's the block device directly backing a file system. If - * the block device is encrypted, returns the device mapper - * block device. */ - - if (lstat(path, &st)) - return -errno; - - if (major(st.st_dev) != 0) { - *dev = st.st_dev; - return 1; - } - - if (statfs(path, &sfs) < 0) - return -errno; - - if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) - return btrfs_get_block_device(path, dev); - - return 0; -} - -int get_block_device_harder(const char *path, dev_t *dev) { - _cleanup_closedir_ DIR *d = NULL; - _cleanup_free_ char *t = NULL; - char p[SYS_BLOCK_PATH_MAX("/slaves")]; - struct dirent *de, *found = NULL; - const char *q; - unsigned maj, min; - dev_t dt; - int r; - - assert(path); - assert(dev); - - /* Gets the backing block device for a file system, and - * handles LUKS encrypted file systems, looking for its - * immediate parent, if there is one. */ - - r = get_block_device(path, &dt); - if (r <= 0) - return r; - - xsprintf_sys_block_path(p, "/slaves", dt); - d = opendir(p); - if (!d) { - if (errno == ENOENT) - goto fallback; - - return -errno; - } - - FOREACH_DIRENT_ALL(de, d, return -errno) { - - if (dot_or_dot_dot(de->d_name)) - continue; - - if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN)) - continue; - - if (found) { - _cleanup_free_ char *u = NULL, *v = NULL, *a = NULL, *b = NULL; - - /* We found a device backed by multiple other devices. We don't really support automatic - * discovery on such setups, with the exception of dm-verity partitions. In this case there are - * two backing devices: the data partition and the hash partition. We are fine with such - * setups, however, only if both partitions are on the same physical device. Hence, let's - * verify this. */ - - u = strjoin(p, "/", de->d_name, "/../dev"); - if (!u) - return -ENOMEM; - - v = strjoin(p, "/", found->d_name, "/../dev"); - if (!v) - return -ENOMEM; - - r = read_one_line_file(u, &a); - if (r < 0) { - log_debug_errno(r, "Failed to read %s: %m", u); - goto fallback; - } - - r = read_one_line_file(v, &b); - if (r < 0) { - log_debug_errno(r, "Failed to read %s: %m", v); - goto fallback; - } - - /* Check if the parent device is the same. If not, then the two backing devices are on - * different physical devices, and we don't support that. */ - if (!streq(a, b)) - goto fallback; - } - - found = de; - } - - if (!found) - goto fallback; - - q = strjoina(p, "/", found->d_name, "/dev"); - - r = read_one_line_file(q, &t); - if (r == -ENOENT) - goto fallback; - if (r < 0) - return r; - - if (sscanf(t, "%u:%u", &maj, &min) != 2) - return -EINVAL; - - if (maj == 0) - goto fallback; - - *dev = makedev(maj, min); - return 1; - -fallback: - *dev = dt; - return 1; -} diff --git a/src/basic/util.h b/src/basic/util.h index 62bf1a6961..8cd78171bc 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -71,8 +71,6 @@ bool plymouth_running(void); bool display_is_local(const char *display) _pure_; int socket_from_display(const char *display, char **path); -int block_get_whole_disk(dev_t d, dev_t *ret); - #define NULSTR_FOREACH(i, l) \ for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) @@ -191,6 +189,3 @@ uint64_t system_tasks_max_scale(uint64_t v, uint64_t max); int update_reboot_parameter_and_warn(const char *param); int version(void); - -int get_block_device(const char *path, dev_t *dev); -int get_block_device_harder(const char *path, dev_t *dev); diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 78ef885b06..d08b4a0787 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -22,6 +22,7 @@ #include <fnmatch.h> #include "alloc-util.h" +#include "blockdev-util.h" #include "bpf-firewall.h" #include "cgroup-util.h" #include "cgroup.h" @@ -307,7 +308,7 @@ static int lookup_block_device(const char *p, dev_t *dev) { /* If this is a partition, try to get the originating * block device */ - block_get_whole_disk(*dev, dev); + (void) block_get_whole_disk(*dev, dev); } else { log_warning("%s is not a block device and file system block device cannot be determined or is not local.", p); return -ENODEV; diff --git a/src/core/umount.c b/src/core/umount.c index d8ccdfd6c2..b39181639a 100644 --- a/src/core/umount.c +++ b/src/core/umount.c @@ -28,6 +28,7 @@ #include "libudev.h" #include "alloc-util.h" +#include "blockdev-util.h" #include "def.h" #include "escape.h" #include "fd-util.h" @@ -35,12 +36,12 @@ #include "linux-3.13/dm-ioctl.h" #include "list.h" #include "mount-setup.h" +#include "mount-util.h" #include "path-util.h" #include "signal-util.h" #include "string-util.h" #include "udev-util.h" #include "umount.h" -#include "mount-util.h" #include "util.h" #include "virt.h" diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index 9e8b956d5c..85899ab301 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -28,6 +28,7 @@ #include "alloc-util.h" #include "blkid-util.h" +#include "blockdev-util.h" #include "btrfs-util.h" #include "dirent-util.h" #include "dissect-image.h" diff --git a/src/partition/growfs.c b/src/partition/growfs.c index 901b33e39e..41b4e872be 100644 --- a/src/partition/growfs.c +++ b/src/partition/growfs.c @@ -28,6 +28,7 @@ #include <sys/types.h> #include <sys/vfs.h> +#include "blockdev-util.h" #include "crypt-util.h" #include "device-nodes.h" #include "dissect-image.h" diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index a11d4849bb..8fc9e97bbd 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -25,6 +25,7 @@ #include "architecture.h" #include "ask-password-api.h" #include "blkid-util.h" +#include "blockdev-util.h" #include "copy.h" #include "crypt-util.h" #include "def.h" |