diff options
Diffstat (limited to 'utils.c')
-rw-r--r-- | utils.c | 127 |
1 files changed, 93 insertions, 34 deletions
@@ -37,6 +37,7 @@ #include <sys/vfs.h> #include <sys/statfs.h> #include <linux/magic.h> +#include <getopt.h> #include "kerncompat.h" #include "radix-tree.h" @@ -47,6 +48,7 @@ #include "utils.h" #include "volumes.h" #include "ioctl.h" +#include "commands.h" #ifndef BLKDISCARD #define BLKDISCARD _IO(0x12,119) @@ -154,7 +156,7 @@ int test_uuid_unique(char *fs_uuid) blkid_dev dev = NULL; blkid_cache cache = NULL; - if (blkid_get_cache(&cache, 0) < 0) { + if (blkid_get_cache(&cache, NULL) < 0) { printf("ERROR: lblkid cache get failed\n"); return 1; } @@ -182,7 +184,7 @@ int test_uuid_unique(char *fs_uuid) int make_btrfs(int fd, struct btrfs_mkfs_config *cfg) { struct btrfs_super_block super; - struct extent_buffer *buf = NULL; + struct extent_buffer *buf; struct btrfs_root_item root_item; struct btrfs_disk_key disk_key; struct btrfs_extent_item *extent_item; @@ -204,6 +206,10 @@ int make_btrfs(int fd, struct btrfs_mkfs_config *cfg) BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA); u64 num_bytes; + buf = malloc(sizeof(*buf) + max(cfg->sectorsize, cfg->nodesize)); + if (!buf) + return -ENOMEM; + first_free = BTRFS_SUPER_INFO_OFFSET + cfg->sectorsize * 2 - 1; first_free &= ~((u64)cfg->sectorsize - 1); @@ -249,8 +255,6 @@ int make_btrfs(int fd, struct btrfs_mkfs_config *cfg) if (cfg->label) strncpy(super.label, cfg->label, BTRFS_LABEL_SIZE - 1); - buf = malloc(sizeof(*buf) + max(cfg->sectorsize, cfg->nodesize)); - /* create the tree of root objects */ memset(buf->data, 0, cfg->nodesize); buf->len = cfg->nodesize; @@ -550,12 +554,12 @@ int make_btrfs(int fd, struct btrfs_mkfs_config *cfg) /* and write out the super block */ BUG_ON(sizeof(super) > cfg->sectorsize); - memset(buf->data, 0, cfg->sectorsize); + memset(buf->data, 0, BTRFS_SUPER_INFO_SIZE); memcpy(buf->data, &super, sizeof(super)); - buf->len = cfg->sectorsize; + buf->len = BTRFS_SUPER_INFO_SIZE; csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); - ret = pwrite(fd, buf->data, cfg->sectorsize, cfg->blocks[0]); - if (ret != cfg->sectorsize) { + ret = pwrite(fd, buf->data, BTRFS_SUPER_INFO_SIZE, cfg->blocks[0]); + if (ret != BTRFS_SUPER_INFO_SIZE) { ret = (ret < 0 ? -errno : -EIO); goto out; } @@ -1170,6 +1174,34 @@ static int is_loop_device (const char* device) { MAJOR(statbuf.st_rdev) == LOOP_MAJOR); } +/* + * Takes a loop device path (e.g. /dev/loop0) and returns + * the associated file (e.g. /images/my_btrfs.img) using + * loopdev API + */ +static int resolve_loop_device_with_loopdev(const char* loop_dev, char* loop_file) +{ + int fd; + int ret; + struct loop_info64 lo64; + + fd = open(loop_dev, O_RDONLY | O_NONBLOCK); + if (fd < 0) + return -errno; + ret = ioctl(fd, LOOP_GET_STATUS64, &lo64); + if (ret < 0) { + ret = -errno; + goto out; + } + + memcpy(loop_file, lo64.lo_file_name, sizeof(lo64.lo_file_name)); + loop_file[sizeof(lo64.lo_file_name)] = 0; + +out: + close(fd); + + return ret; +} /* Takes a loop device path (e.g. /dev/loop0) and returns * the associated file (e.g. /images/my_btrfs.img) */ @@ -1185,8 +1217,15 @@ static int resolve_loop_device(const char* loop_dev, char* loop_file, if (!realpath(loop_dev, real_loop_dev)) return -errno; snprintf(p, PATH_MAX, "/sys/block/%s/loop/backing_file", strrchr(real_loop_dev, '/')); - if (!(f = fopen(p, "r"))) + if (!(f = fopen(p, "r"))) { + if (errno == ENOENT) + /* + * It's possibly a partitioned loop device, which is + * resolvable with loopdev API. + */ + return resolve_loop_device_with_loopdev(loop_dev, loop_file); return -errno; + } snprintf(fmt, 20, "%%%i[^\n]", max_len-1); ret = fscanf(f, fmt, loop_file); @@ -1479,7 +1518,6 @@ int btrfs_register_one_device(const char *fname) struct btrfs_ioctl_vol_args args; int fd; int ret; - int e; fd = open("/dev/btrfs-control", O_RDWR); if (fd < 0) { @@ -1491,11 +1529,10 @@ int btrfs_register_one_device(const char *fname) memset(&args, 0, sizeof(args)); strncpy_null(args.name, fname); ret = ioctl(fd, BTRFS_IOC_SCAN_DEV, &args); - e = errno; if (ret < 0) { fprintf(stderr, "ERROR: device scan failed '%s' - %s\n", - fname, strerror(e)); - ret = -e; + fname, strerror(errno)); + ret = -errno; } close(fd); return ret; @@ -1516,7 +1553,7 @@ int btrfs_register_all_devices(void) list_for_each_entry(fs_devices, all_uuids, list) { list_for_each_entry(device, &fs_devices->devices, dev_list) { - if (strlen(device->name) != 0) { + if (*device->name) { err = btrfs_register_one_device(device->name); if (err < 0) return err; @@ -2042,7 +2079,7 @@ int get_device_info(int fd, u64 devid, memset(&di_args->uuid, '\0', sizeof(di_args->uuid)); ret = ioctl(fd, BTRFS_IOC_DEV_INFO, di_args); - return ret ? -errno : 0; + return ret < 0 ? -errno : 0; } static u64 find_max_device_id(struct btrfs_ioctl_search_args *search_args, @@ -2426,7 +2463,7 @@ static int group_profile_devs_min(u64 flag) } int test_num_disk_vs_raid(u64 metadata_profile, u64 data_profile, - u64 dev_cnt, int mixed) + u64 dev_cnt, int mixed, int ssd) { u64 allowed = 0; @@ -2467,11 +2504,9 @@ int test_num_disk_vs_raid(u64 metadata_profile, u64 data_profile, return 1; } - if (!mixed && (data_profile & BTRFS_BLOCK_GROUP_DUP)) { - fprintf(stderr, - "ERROR: DUP for data is allowed only in mixed mode\n"); - return 1; - } + warning_on(!mixed && (data_profile & BTRFS_BLOCK_GROUP_DUP) && ssd, + "DUP may not actually lead to 2 copies on the device, see manual page"); + return 0; } @@ -2566,7 +2601,7 @@ int btrfs_scan_lblkid(void) if (btrfs_scan_done) return 0; - if (blkid_get_cache(&cache, 0) < 0) { + if (blkid_get_cache(&cache, NULL) < 0) { printf("ERROR: lblkid cache get failed\n"); return 1; } @@ -2661,17 +2696,15 @@ int lookup_ino_rootid(int fd, u64 *rootid) { struct btrfs_ioctl_ino_lookup_args args; int ret; - int e; memset(&args, 0, sizeof(args)); args.treeid = 0; args.objectid = BTRFS_FIRST_FREE_OBJECTID; ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args); - e = errno; - if (ret) { + if (ret < 0) { fprintf(stderr, "ERROR: Failed to lookup root id - %s\n", - strerror(e)); + strerror(errno)); return ret; } @@ -2768,11 +2801,11 @@ int test_issubvolname(const char *name) } /* - * test if path is a directory - * this function return - * 0-> path exists but it is not a directory - * 1-> path exists and it is a directory - * -1 -> path is unaccessible + * Test if path is a directory + * Returns: + * 0 - path exists but it is not a directory + * 1 - path exists and it is a directory + * < 0 - error */ int test_isdir(const char *path) { @@ -2780,10 +2813,10 @@ int test_isdir(const char *path) int ret; ret = stat(path, &st); - if(ret < 0 ) - return -1; + if (ret < 0) + return -errno; - return S_ISDIR(st.st_mode); + return !!S_ISDIR(st.st_mode); } void units_set_mode(unsigned *units, unsigned mode) @@ -3088,3 +3121,29 @@ int string_is_numerical(const char *str) return 0; return 1; } + +/* + * Preprocess @argv with getopt_long to reorder options and consume the "--" + * option separator. + * Unknown short and long options are reported, optionally the @usage is printed + * before exit. + */ +void clean_args_no_options(int argc, char *argv[], const char * const *usagestr) +{ + static const struct option long_options[] = { + {NULL, 0, NULL, 0} + }; + + while (1) { + int c = getopt_long(argc, argv, "", long_options, NULL); + + if (c < 0) + break; + + switch (c) { + default: + if (usagestr) + usage(usagestr); + } + } +} |