]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
blockdev-util: split out partition device node generation from dissect-util.c
authorLennart Poettering <lennart@poettering.net>
Mon, 20 Oct 2025 10:36:05 +0000 (12:36 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 22 Oct 2025 20:56:01 +0000 (22:56 +0200)
src/shared/blockdev-util.c
src/shared/blockdev-util.h
src/shared/dissect-image.c
src/test/test-blockdev-util.c

index 4db38374beb0f18b63d4401ec8591b64069886b8..4a9567ce5144eeea4af286f8beebe4be21d87c2f 100644 (file)
@@ -904,3 +904,46 @@ int blockdev_get_root(int level, dev_t *ret) {
 
         return 1;
 }
+
+int partition_node_of(const char *node, unsigned nr, char **ret) {
+        int r;
+
+        assert(node);
+        assert(nr > 0);
+        assert(ret);
+
+        /* Given a device node path to a block device returns the device node path to the partition block
+         * device of the specified partition */
+
+        _cleanup_free_ char *fn = NULL;
+        r = path_extract_filename(node, &fn);
+        if (r < 0)
+                return r;
+        if (r == O_DIRECTORY)
+                return -EISDIR;
+
+        _cleanup_free_ char *dn = NULL;
+        r = path_extract_directory(node, &dn);
+        if (r < 0 && r != -EDESTADDRREQ) /* allow if only filename is specified */
+                return r;
+
+        size_t l = strlen(fn);
+        assert(l > 0); /* underflow check for the subtraction below */
+
+        bool need_p = ascii_isdigit(fn[l-1]); /* Last char a digit? */
+
+        _cleanup_free_ char *subnode = NULL;
+        if (asprintf(&subnode, "%s%s%u", fn, need_p ? "p" : "", nr) < 0)
+                return -ENOMEM;
+
+        if (dn) {
+                _cleanup_free_ char *j = path_join(dn, subnode);
+                if (!j)
+                        return -ENOMEM;
+
+                *ret = TAKE_PTR(j);
+        } else
+                *ret = TAKE_PTR(subnode);
+
+        return 0;
+}
index 3c3153bacce5d9ff4ff2c64f35ce81b36c84370d..6c60c89e0cdb4c79b0b9ebc344b5cd64d156b644 100644 (file)
@@ -57,3 +57,5 @@ int blockdev_get_sector_size(int fd, uint32_t *ret);
 int blockdev_get_device_size(int fd, uint64_t *ret);
 
 int blockdev_get_root(int level, dev_t *ret);
+
+int partition_node_of(const char *node, unsigned nr, char **ret);
index 0cbb7d02cff2f7e8ba6ae61c97559546e2ee6a76..f00e1cf355978631a439897942ae99a44d71d564 100644 (file)
@@ -627,14 +627,9 @@ static int make_partition_devname(
                         if (!s)
                                 return -ENOMEM;
                 } else {
-                        size_t l = strlen(whole_devname);
-                        if (l < 1) /* underflow check for the subtraction below */
-                                return -EINVAL;
-
-                        bool need_p = ascii_isdigit(whole_devname[l-1]); /* Last char a digit? */
-
-                        if (asprintf(&s, "%s%s%i", whole_devname, need_p ? "p" : "", nr) < 0)
-                                return -ENOMEM;
+                        r = partition_node_of(whole_devname, nr, &s);
+                        if (r < 0)
+                                return r;
                 }
         } else {
                 if (nr < 0) /* whole disk? */
index 5e5eee0e60eb89847560fa0c362e69ebd9fb244b..5e67487fccc0e7888e04aabe6a1aeec441e512bb 100644 (file)
@@ -77,4 +77,30 @@ TEST(partscan_enabled) {
         }
 }
 
+static void test_partition_node_of_one(const char *main, unsigned partition, const char *result, int retval) {
+        _cleanup_free_ char *s = NULL;
+        int r;
+
+        r = partition_node_of(main, partition, &s);
+        ASSERT_EQ(r, retval);
+        if (r < 0)
+                return;
+        ASSERT_STREQ(s, result);
+
+        log_info("%s with %u → %s", main, partition, result);
+}
+
+TEST(partition_node_of) {
+        test_partition_node_of_one("/dev/sda", 2, "/dev/sda2", 0);
+        test_partition_node_of_one("sda", 3, "sda3", 0);
+        test_partition_node_of_one("/dev/nvme0n1", 7, "/dev/nvme0n1p7", 0);
+        test_partition_node_of_one("nvme0n1", 8, "nvme0n1p8", 0);
+        test_partition_node_of_one("/dev/loop1", 3, "/dev/loop1p3", 0);
+        test_partition_node_of_one("", 1, NULL, -EINVAL);
+        test_partition_node_of_one("/", 1, NULL, -EADDRNOTAVAIL);
+        test_partition_node_of_one("/dev/", 1, NULL, -EISDIR);
+        test_partition_node_of_one("/sda", 1, "/sda1", 0);
+        test_partition_node_of_one(".", 1, NULL, -EADDRNOTAVAIL);
+}
+
 DEFINE_TEST_MAIN(LOG_INFO);