]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
systemd-growfs: remove dependency on udev symlinks
authorDevendra Tewari <devendra.tewari@gmail.com>
Wed, 24 Aug 2022 10:13:04 +0000 (07:13 -0300)
committerLuca Boccassi <luca.boccassi@gmail.com>
Wed, 24 Aug 2022 20:42:16 +0000 (21:42 +0100)
systemd-growfs currently requires that udev ran first to work (because
/dev/block/ symlinks must exist) but that is not what happens when
we're not using initrd and systemd is PID1.

src/basic/devnum-util.c
src/basic/devnum-util.h
src/partition/growfs.c

index 70c07315c599f6743a11b3d76d171da7b2c36cc2..fbefa2bd69ca40556a5a90fce83473567fc5e440 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "chase-symlinks.h"
 #include "devnum-util.h"
+#include "fs-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "string-util.h"
@@ -57,6 +58,53 @@ int device_path_make_major_minor(mode_t mode, dev_t devnum, char **ret) {
         return 0;
 }
 
+int device_path_make_major_minor_sysfs(mode_t mode, dev_t devnum, char **ret) {
+        _cleanup_free_ char *syspath = NULL, *link = NULL, *fname = NULL;
+        _cleanup_free_ char *devpath = NULL;
+        const char *t;
+        int r;
+
+        /* Generates the /dev/... path given a dev_t. What makes this different
+         * from device_path_make_major_minor is that it works even when udev 
+         * hasn't yet run */
+
+        if (S_ISCHR(mode))
+                t = "char";
+        else if (S_ISBLK(mode))
+                t = "block";
+        else
+                return -ENODEV;
+
+        if (asprintf(&syspath, "/sys/dev/%s/" DEVNUM_FORMAT_STR, t, DEVNUM_FORMAT_VAL(devnum)) < 0)
+                return -ENOMEM;
+
+        r = readlink_malloc(syspath, &link);
+        if (r < 0)
+                return r;
+
+        r = path_extract_filename(link, &fname);
+        if (r < 0)
+                return r;
+
+        devpath = path_join("/dev", fname);
+        if (!devpath)
+                return -ENOMEM;
+
+        struct stat st;
+        if (stat(devpath, &st) < 0)
+                return -errno;
+
+        if (((st.st_mode ^ mode) & S_IFMT) != 0)
+                return S_ISBLK(mode) ? -ENOTBLK : -ENODEV;
+
+        if (st.st_rdev != devnum)
+                return -ENXIO;
+
+        *ret = TAKE_PTR(devpath);
+
+        return 0;
+}
+
 int device_path_make_canonical(mode_t mode, dev_t devnum, char **ret) {
         _cleanup_free_ char *p = NULL;
         int r;
index 3f1894b2fd7875d8e0e54a05fa92446bb0314c1a..7adb6fb249ee36637ccbb28a0ce731ecb8b00366 100644 (file)
@@ -29,6 +29,7 @@ int parse_devnum(const char *s, dev_t *ret);
         })
 
 int device_path_make_major_minor(mode_t mode, dev_t devnum, char **ret);
+int device_path_make_major_minor_sysfs(mode_t mode, dev_t devnum, char **ret);
 int device_path_make_canonical(mode_t mode, dev_t devnum, char **ret);
 int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devnum);
 
index e105c0e151a56ea0f58827c13b407b7f5c913ae2..e940dccd48b96a89f3da15f995e2d54efe6d19a4 100644 (file)
@@ -41,7 +41,7 @@ static int resize_crypt_luks_device(dev_t devno, const char *fstype, dev_t main_
         if (r < 0)
                 return log_error_errno(r, "Cannot resize LUKS device: %m");
 
-        r = device_path_make_major_minor(S_IFBLK, main_devno, &main_devpath);
+        r = device_path_make_major_minor_sysfs(S_IFBLK, main_devno, &main_devpath);
         if (r < 0)
                 return log_error_errno(r, "Failed to format device major/minor path: %m");
 
@@ -54,7 +54,7 @@ static int resize_crypt_luks_device(dev_t devno, const char *fstype, dev_t main_
                                        main_devpath);
 
         log_debug("%s is %"PRIu64" bytes", main_devpath, size);
-        r = device_path_make_major_minor(S_IFBLK, devno, &devpath);
+        r = device_path_make_major_minor_sysfs(S_IFBLK, devno, &devpath);
         if (r < 0)
                 return log_error_errno(r, "Failed to format major/minor path: %m");
 
@@ -115,7 +115,7 @@ static int maybe_resize_underlying_device(
         if (devno == main_devno)
                 return 0;
 
-        r = device_path_make_major_minor(S_IFBLK, devno, &devpath);
+        r = device_path_make_major_minor_sysfs(S_IFBLK, devno, &devpath);
         if (r < 0)
                 return log_error_errno(r, "Failed to format device major/minor path: %m");
 
@@ -237,7 +237,7 @@ static int run(int argc, char *argv[]) {
         if (r < 0)
                 log_warning_errno(r, "Unable to resize underlying device of \"%s\", proceeding anyway: %m", arg_target);
 
-        r = device_path_make_major_minor(S_IFBLK, devno, &devpath);
+        r = device_path_make_major_minor_sysfs(S_IFBLK, devno, &devpath);
         if (r < 0)
                 return log_error_errno(r, "Failed to format device major/minor path: %m");