From: Lennart Poettering Date: Mon, 20 Oct 2025 10:36:05 +0000 (+0200) Subject: blockdev-util: split out partition device node generation from dissect-util.c X-Git-Tag: v259-rc1~259^2~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=524ebfe28ac979171bc683d7148b55e0daa4ec0f;p=thirdparty%2Fsystemd.git blockdev-util: split out partition device node generation from dissect-util.c --- diff --git a/src/shared/blockdev-util.c b/src/shared/blockdev-util.c index 4db38374beb..4a9567ce514 100644 --- a/src/shared/blockdev-util.c +++ b/src/shared/blockdev-util.c @@ -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; +} diff --git a/src/shared/blockdev-util.h b/src/shared/blockdev-util.h index 3c3153bacce..6c60c89e0cd 100644 --- a/src/shared/blockdev-util.h +++ b/src/shared/blockdev-util.h @@ -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); diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 0cbb7d02cff..f00e1cf3559 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -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? */ diff --git a/src/test/test-blockdev-util.c b/src/test/test-blockdev-util.c index 5e5eee0e60e..5e67487fccc 100644 --- a/src/test/test-blockdev-util.c +++ b/src/test/test-blockdev-util.c @@ -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);