From b5cb10aa56589ddc4be143a4c0da4c36279265c6 Mon Sep 17 00:00:00 2001 From: Sohan Kunkerkar Date: Fri, 9 Jul 2021 11:31:57 -0400 Subject: [PATCH] exec/util: add blkid API to query block devices based on FSTYPE This change adds a building block to query block devices based on the particular filesystem. --- internal/exec/util/blkid.c | 42 +++++++++++++++++++++++++++++++++++++ internal/exec/util/blkid.go | 21 +++++++++++++++++++ internal/exec/util/blkid.h | 13 +++++++++++- 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/internal/exec/util/blkid.c b/internal/exec/util/blkid.c index 3335cbac18..28a8656d7a 100644 --- a/internal/exec/util/blkid.c +++ b/internal/exec/util/blkid.c @@ -19,6 +19,12 @@ static inline void _free_probe(blkid_probe *pr) { if (pr) blkid_free_probe(*pr); } #define _cleanup_probe_ __attribute__((cleanup(_free_probe))) +static inline void _free_cache(blkid_cache *gcache) { blkid_put_cache(*gcache); } +#define _cleanup_cache_ __attribute__((cleanup(_free_cache))) + +static inline void _free_iterator(blkid_dev_iterate *iter) { blkid_dev_iterate_end(*iter); } +#define _cleanup_iterator_ __attribute__((cleanup(_free_iterator))) + static result_t extract_part_info(blkid_partition part, struct partition_info *info, long sector_divisor); static result_t checked_copy(char *dest, const char *src, size_t len); @@ -248,3 +254,39 @@ static result_t extract_part_info(blkid_partition part, struct partition_info *i return RESULT_OK; } + +// blkid_get_block_devices fetches block devices with the given FSTYPE +result_t blkid_get_block_devices(const char *fstype, struct block_device_list *device) { + blkid_dev_iterate iter _cleanup_iterator_ = NULL; + blkid_dev dev; + blkid_cache cache _cleanup_cache_ = NULL; + int err, count = 0; + const char *ctmp = NULL; + + if (blkid_get_cache(&cache, "/dev/null") != 0) + return RESULT_GET_CACHE_FAILED; + + if (blkid_probe_all(cache) != 0) + return RESULT_PROBE_FAILED; + + iter = blkid_dev_iterate_begin(cache); + + blkid_dev_set_search(iter, "TYPE", fstype); + + while (blkid_dev_next(iter, &dev) == 0) { + dev = blkid_verify(cache, dev); + if (!dev) + continue; + ctmp = blkid_dev_devname(dev); + if (count > MAX_BLOCK_DEVICES) + return RESULT_MAX_BLOCK_DEVICES; + err = checked_copy(device->path[count], ctmp, MAX_BLOCK_DEVICE_PATH_LEN); + if (err) + return err; + count++; + } + blkid_dev_iterate_end(iter); + + device->count = count; + return RESULT_OK; +} diff --git a/internal/exec/util/blkid.go b/internal/exec/util/blkid.go index fbaa609fec..7c8de3ab58 100644 --- a/internal/exec/util/blkid.go +++ b/internal/exec/util/blkid.go @@ -110,6 +110,8 @@ func cResultToErr(res C.result_t) error { return errors.New("bad partition index specified") case C.RESULT_GET_PARTLIST_FAILED: return errors.New("failed to get list of partitions") + case C.RESULT_GET_CACHE_FAILED: + return fmt.Errorf("failed to retrieve cache") case C.RESULT_DISK_HAS_NO_TYPE: return errors.New("disk has no type string, despite having a partition table") case C.RESULT_DISK_NOT_GPT: @@ -118,6 +120,8 @@ func cResultToErr(res C.result_t) error { return errors.New("bad parameters passed") case C.RESULT_OVERFLOW: return errors.New("return value doesn't fit in buffer") + case C.RESULT_MAX_BLOCK_DEVICES: + return fmt.Errorf("found too many filesystems of the specified type") case C.RESULT_NO_TOPO: return errors.New("failed to get topology information") case C.RESULT_NO_SECTOR_SIZE: @@ -190,3 +194,20 @@ func filesystemLookup(device string, allowAmbivalent bool, fieldName string) (st } return string(buf[:bytes.IndexByte(buf[:], 0)]), nil } + +// GetBlockDevices returns a slice of block devices with the given filesystem +func GetBlockDevices(fstype string) ([]string, error) { + var dev C.struct_block_device_list + res := C.blkid_get_block_devices(C.CString(fstype), &dev) + + if res != C.RESULT_OK { + return nil, cResultToErr(res) + } + + length := int(dev.count) + blkDeviceList := make([]string, length) + for i := 0; i < length; i++ { + blkDeviceList[i] = C.GoString(&dev.path[i][0]) + } + return blkDeviceList, nil +} diff --git a/internal/exec/util/blkid.h b/internal/exec/util/blkid.h index 276116437e..ee35d93f89 100644 --- a/internal/exec/util/blkid.h +++ b/internal/exec/util/blkid.h @@ -27,10 +27,12 @@ typedef enum { RESULT_NO_PARTITION_TABLE, RESULT_BAD_INDEX, RESULT_GET_PARTLIST_FAILED, + RESULT_GET_CACHE_FAILED, RESULT_DISK_HAS_NO_TYPE, RESULT_DISK_NOT_GPT, RESULT_BAD_PARAMS, RESULT_OVERFLOW, + RESULT_MAX_BLOCK_DEVICES, RESULT_NO_TOPO, RESULT_NO_SECTOR_SIZE, RESULT_BAD_SECTOR_SIZE, @@ -48,6 +50,14 @@ struct partition_info { int number; }; +#define MAX_BLOCK_DEVICES 10 +#define MAX_BLOCK_DEVICE_PATH_LEN 50 + +struct block_device_list { + char path[MAX_BLOCK_DEVICES][MAX_BLOCK_DEVICE_PATH_LEN]; + int count; +}; + result_t blkid_lookup(const char *device, bool allow_ambivalent, const char *field_name, char buf[], size_t buf_len); result_t blkid_get_num_partitions(const char *device, int *ret); @@ -57,5 +67,6 @@ result_t blkid_get_logical_sector_size(const char *device, int *ret_sector_size) // WARNING part_num may not be what you expect. see the .c file's comment for why result_t blkid_get_partition(const char *device, int part_num, struct partition_info *info); -#endif // _BLKID_H_ +result_t blkid_get_block_devices(const char *fstype, struct block_device_list *device); +#endif // _BLKID_H_