blockdev-util: split out partition device node generation from dissect-util.c

This commit is contained in:
Lennart Poettering
2025-10-20 12:36:05 +02:00
parent bb45a893c2
commit 524ebfe28a
4 changed files with 74 additions and 8 deletions

View 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;
}

View 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);

View 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? */

View 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);