summaryrefslogtreecommitdiff
path: root/utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils.c')
-rw-r--r--utils.c127
1 files changed, 93 insertions, 34 deletions
diff --git a/utils.c b/utils.c
index d546bea..3df8b42 100644
--- a/utils.c
+++ b/utils.c
@@ -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);
+ }
+ }
+}