diff --git a/cmd_device.c b/cmd_device.c index fa63e48d..797b958c 100644 --- a/cmd_device.c +++ b/cmd_device.c @@ -95,12 +95,20 @@ int cmd_device_add(int argc, char *argv[]) dev_opts.path = dev_path; dev_opts.fd = open_for_format(dev_opts.path, force); - format_opts.block_size = - read_file_u64(fs.sysfs_fd, "block_size") >> 9; - format_opts.btree_node_size = - read_file_u64(fs.sysfs_fd, "btree_node_size") >> 9; + struct bch_opt_strs fs_opt_strs; + memset(&fs_opt_strs, 0, sizeof(fs_opt_strs)); - struct bch_sb *sb = bch2_format(format_opts, &dev_opts, 1); + struct bch_opts fs_opts = bch2_parse_opts(fs_opt_strs); + + opt_set(fs_opts, block_size, + read_file_u64(fs.sysfs_fd, "block_size") >> 9); + opt_set(fs_opts, btree_node_size, + read_file_u64(fs.sysfs_fd, "btree_node_size") >> 9); + + struct bch_sb *sb = bch2_format(fs_opt_strs, + fs_opts, + format_opts, + &dev_opts, 1); free(sb); fsync(dev_opts.fd); close(dev_opts.fd); diff --git a/cmd_format.c b/cmd_format.c index a4824947..83246a0f 100644 --- a/cmd_format.c +++ b/cmd_format.c @@ -5,6 +5,7 @@ * * GPLv2 */ +#include #include #include #include @@ -28,109 +29,72 @@ #include "libbcachefs/super-io.h" #include "libbcachefs/util.h" -#define OPTS \ -t("bcachefs format - create a new bcachefs filesystem on one or more devices") \ -t("Usage: bcachefs format [OPTION]... ") \ -t("") \ -x('b', block_size, "size", NULL) \ -x(0, btree_node_size, "size", "Default 256k") \ -x(0, metadata_checksum_type, "(none|crc32c|crc64)", NULL) \ -x(0, data_checksum_type, "(none|crc32c|crc64)", NULL) \ -x(0, compression_type, "(none|lz4|gzip)", NULL) \ -x(0, background_compression_type, "(none|lz4|gzip)", NULL) \ -x(0, replicas, "#", NULL) \ -x(0, data_replicas, "#", NULL) \ -x(0, metadata_replicas, "#", NULL) \ -x(0, foreground_target, "target", NULL) \ -x(0, background_target, "target", NULL) \ -x(0, promote_target, "target", NULL) \ -x(0, encrypted, NULL, "Enable whole filesystem encryption (chacha20/poly1305)")\ -x(0, no_passphrase, NULL, "Don't encrypt master encryption key")\ -x('e', error_action, "(continue|remount-ro|panic)", NULL) \ -x('L', label, "label", NULL) \ -x('U', uuid, "uuid", NULL) \ -x('f', force, NULL, NULL) \ -t("") \ -t("Device specific options:") \ -x(0, fs_size, "size", "Size of filesystem on device")\ -x(0, bucket_size, "size", "Bucket size") \ -x('g', group, "label", "Disk group")\ -x(0, discard, NULL, NULL) \ -x(0, data_allowed, "journal,btree,data", "Allowed types of data on this device")\ -x(0, durability, "#", "Number of times data written to this device will have been considered replicated")\ -t("Device specific options must come before corresponding devices, e.g.") \ -t(" bcachefs format --group cache /dev/sdb --tier 1 /dev/sdc") \ -t("") \ -x('q', quiet, NULL, "Only print errors") \ -x('h', help, NULL, "Display this help and exit") +#define OPTS \ +x(0, replicas, required_argument) \ +x(0, encrypted, no_argument) \ +x(0, no_passphrase, no_argument) \ +x('L', label, required_argument) \ +x('U', uuid, required_argument) \ +x(0, fs_size, required_argument) \ +x(0, bucket_size, required_argument) \ +x('g', group, required_argument) \ +x(0, discard, no_argument) \ +x(0, data_allowed, required_argument) \ +x(0, durability, required_argument) \ +x('f', force, no_argument) \ +x('q', quiet, no_argument) \ +x('h', help, no_argument) static void usage(void) { -#define t(text) puts(text "\n") -#define x(shortopt, longopt, arg, help) do { \ - OPTS -#undef x -#undef t - puts("bcachefs format - create a new bcachefs filesystem on one or more devices\n" "Usage: bcachefs format [OPTION]... \n" "\n" - "Options:\n" - " -b, --block=size\n" - " --btree_node=size Btree node size, default 256k\n" - " --metadata_checksum_type=(none|crc32c|crc64)\n" - " --data_checksum_type=(none|crc32c|crc64)\n" - " --compression_type=(none|lz4|gzip|zstd)\n" - " --background_compression_type=(none|lz4|gzip|zstd)\n" - " --data_replicas=# Number of data replicas\n" - " --metadata_replicas=# Number of metadata replicas\n" + "Options:"); + + bch2_opts_usage(OPT_FORMAT); + + puts( " --replicas=# Sets both data and metadata replicas\n" " --encrypted Enable whole filesystem encryption (chacha20/poly1305)\n" " --no_passphrase Don't encrypt master encryption key\n" - " -e, --error_action=(continue|remount-ro|panic)\n" - " Action to take on filesystem error\n" " -L, --label=label\n" " -U, --uuid=uuid\n" + "\n" + "Device specific options:"); + + bch2_opts_usage(OPT_DEVICE); + + puts(" -g, --group=label Disk group\n" + "\n" " -f, --force\n" - "\n" - "Device specific options:\n" - " --fs_size=size Size of filesystem on device\n" - " --bucket=size Bucket size\n" - " --discard Enable discards\n" - " --durability=# Device durability (0-4)\n" - " -g, --group=label Disk group\n" - "\n" " -q, --quiet Only print errors\n" " -h, --help Display this help and exit\n" "\n" "Device specific options must come before corresponding devices, e.g.\n" - " bcachefs format --group cache /dev/sdb --tier 1 /dev/sdc\n" + " bcachefs format --group cache /dev/sdb /dev/sdc\n" "\n" "Report bugs to "); } enum { O_no_opt = 1, -#define t(text) -#define x(shortopt, longopt, arg, help) O_##longopt, +#define x(shortopt, longopt, arg) O_##longopt, OPTS #undef x -#undef t }; -static const struct option format_opts[] = { -#define t(text) -#define x(shortopt, longopt, arg, help) { \ - .name = #longopt, \ - .has_arg = arg ? required_argument : no_argument, \ - .flag = NULL, \ - .val = O_##longopt, \ +#define x(shortopt, longopt, arg) { \ + .name = #longopt, \ + .has_arg = arg, \ + .flag = NULL, \ + .val = O_##longopt, \ }, +static const struct option format_opts[] = { OPTS -#undef x -#undef t { NULL } }; +#undef x u64 read_flag_list_or_die(char *opt, const char * const list[], const char *msg) @@ -148,73 +112,28 @@ int cmd_format(int argc, char *argv[]) struct format_opts opts = format_opts_default(); struct dev_opts dev_opts = dev_opts_default(), *dev; bool force = false, no_passphrase = false, quiet = false; + unsigned v; int opt; darray_init(devices); + struct bch_opt_strs fs_opt_strs = + bch2_cmdline_opts_get(&argc, argv, OPT_FORMAT); + struct bch_opts fs_opts = bch2_parse_opts(fs_opt_strs); + while ((opt = getopt_long(argc, argv, - "-b:e:g:L:U:fqh", + "-L:U:fh", format_opts, NULL)) != -1) switch (opt) { - case O_block_size: - case 'b': - opts.block_size = - hatoi_validate(optarg, "block size"); - break; - case O_btree_node_size: - opts.btree_node_size = - hatoi_validate(optarg, "btree node size"); - break; - case O_metadata_checksum_type: - opts.meta_csum_type = - read_string_list_or_die(optarg, - bch2_csum_types, "checksum type"); - break; - case O_data_checksum_type: - opts.data_csum_type = - read_string_list_or_die(optarg, - bch2_csum_types, "checksum type"); - break; - case O_compression_type: - opts.compression_type = - read_string_list_or_die(optarg, - bch2_compression_types, - "compression type"); - break; - case O_background_compression_type: - opts.background_compression_type = - read_string_list_or_die(optarg, - bch2_compression_types, - "compression type"); - break; - case O_data_replicas: - if (kstrtouint(optarg, 10, &opts.data_replicas) || - !opts.data_replicas || - opts.data_replicas > BCH_REPLICAS_MAX) - die("invalid replicas"); - break; - case O_metadata_replicas: - if (kstrtouint(optarg, 10, &opts.meta_replicas) || - !opts.meta_replicas || - opts.meta_replicas > BCH_REPLICAS_MAX) - die("invalid replicas"); - break; case O_replicas: - if (kstrtouint(optarg, 10, &opts.data_replicas) || - !opts.data_replicas || - opts.data_replicas > BCH_REPLICAS_MAX) + if (kstrtouint(optarg, 10, &v) || + !v || + v > BCH_REPLICAS_MAX) die("invalid replicas"); - opts.meta_replicas = opts.data_replicas; - break; - case O_foreground_target: - opts.foreground_target = optarg; - break; - case O_background_target: - opts.background_target = optarg; - break; - case O_promote_target: - opts.promote_target = optarg; + + opt_set(fs_opts, metadata_replicas, v); + opt_set(fs_opts, data_replicas, v); break; case O_encrypted: opts.encrypted = true; @@ -222,12 +141,6 @@ int cmd_format(int argc, char *argv[]) case O_no_passphrase: no_passphrase = true; break; - case O_error_action: - case 'e': - opts.on_error_action = - read_string_list_or_die(optarg, - bch2_error_actions, "error action"); - break; case O_label: case 'L': opts.label = optarg; @@ -282,6 +195,9 @@ int cmd_format(int argc, char *argv[]) usage(); exit(EXIT_SUCCESS); break; + case '?': + die("unrecognized option %s", optarg); + break; } if (darray_empty(devices)) @@ -294,7 +210,10 @@ int cmd_format(int argc, char *argv[]) dev->fd = open_for_format(dev->path, force); struct bch_sb *sb = - bch2_format(opts, devices.item, darray_size(devices)); + bch2_format(fs_opt_strs, + fs_opts, + opts, + devices.item, darray_size(devices)); if (!quiet) bch2_sb_print(sb, false, 1 << BCH_SB_FIELD_members, HUMAN_READABLE); diff --git a/cmd_migrate.c b/cmd_migrate.c index 8f464858..2d82d157 100644 --- a/cmd_migrate.c +++ b/cmd_migrate.c @@ -185,13 +185,13 @@ static struct bch_inode_unpacked create_file(struct bch_fs *c, (handler) != NULL; \ (handler) = *(handlers)++) -static const struct xattr_handler *xattr_resolve_name(const char **name) +static const struct xattr_handler *xattr_resolve_name(char **name) { const struct xattr_handler **handlers = bch2_xattr_handlers; const struct xattr_handler *handler; for_each_xattr_handler(handlers, handler) { - const char *n; + char *n; n = strcmp_prefix(*name, xattr_prefix(handler)); if (n) { @@ -225,7 +225,7 @@ static void copy_xattrs(struct bch_fs *c, struct bch_inode_unpacked *dst, if (attrs_size < 0) die("listxattr error: %m"); - const char *next, *attr; + char *next, *attr; for (attr = attrs; attr < attrs + attrs_size; attr = next) { @@ -657,8 +657,10 @@ static const struct option migrate_opts[] = { { NULL } }; -static int migrate_fs(const char *fs_path, - struct format_opts format_opts, +static int migrate_fs(const char *fs_path, + struct bch_opt_strs fs_opt_strs, + struct bch_opts fs_opts, + struct format_opts format_opts, bool force) { if (!path_is_fs_root(fs_path)) @@ -675,25 +677,24 @@ static int migrate_fs(const char *fs_path, dev.path = dev_t_to_path(stat.st_dev); dev.fd = xopen(dev.path, O_RDWR); - unsigned block_size = get_blocksize(dev.path, dev.fd) << 9; - BUG_ON(!is_power_of_2(block_size) || block_size < 512); - format_opts.block_size = block_size >> 9; + opt_set(fs_opts, block_size, get_blocksize(dev.path, dev.fd)); char *file_path = mprintf("%s/bcachefs", fs_path); printf("Creating new filesystem on %s in space reserved at %s\n", dev.path, file_path); - bch2_pick_bucket_size(format_opts, &dev); + bch2_pick_bucket_size(fs_opts, &dev); u64 bcachefs_inum; ranges extents = reserve_new_fs_space(file_path, - format_opts.block_size << 9, + fs_opts.block_size << 9, get_size(dev.path, dev.fd) / 5, &bcachefs_inum, stat.st_dev, force); find_superblock_space(extents, &dev); - struct bch_sb *sb = bch2_format(format_opts, &dev, 1); + struct bch_sb *sb = bch2_format(fs_opt_strs, + fs_opts,format_opts, &dev, 1); u64 sb_offset = le64_to_cpu(sb->layout.sb_offset[0]); if (format_opts.passphrase) @@ -757,6 +758,10 @@ int cmd_migrate(int argc, char *argv[]) bool no_passphrase = false, force = false; int opt; + struct bch_opt_strs fs_opt_strs = + bch2_cmdline_opts_get(&argc, argv, OPT_FORMAT); + struct bch_opts fs_opts = bch2_parse_opts(fs_opt_strs); + while ((opt = getopt_long(argc, argv, "f:Fh", migrate_opts, NULL)) != -1) switch (opt) { @@ -783,7 +788,10 @@ int cmd_migrate(int argc, char *argv[]) if (format_opts.encrypted && !no_passphrase) format_opts.passphrase = read_passphrase_twice("Enter passphrase: "); - return migrate_fs(fs_path, format_opts, force); + return migrate_fs(fs_path, + fs_opt_strs, + fs_opts, + format_opts, force); } static void migrate_superblock_usage(void) diff --git a/libbcachefs.c b/libbcachefs.c index b24e7f37..ea52ce48 100644 --- a/libbcachefs.c +++ b/libbcachefs.c @@ -23,6 +23,7 @@ #include "libbcachefs/opts.h" #include "libbcachefs/replicas.h" #include "libbcachefs/super-io.h" +#include "tools-util.h" #define NSEC_PER_SEC 1000000000L @@ -71,7 +72,7 @@ static void init_layout(struct bch_sb_layout *l, unsigned block_size, l->sb_offset[1] = cpu_to_le64(backup); } -void bch2_pick_bucket_size(struct format_opts opts, struct dev_opts *dev) +void bch2_pick_bucket_size(struct bch_opts opts, struct dev_opts *dev) { if (!dev->sb_offset) { dev->sb_offset = BCH_SB_SECTOR; @@ -90,7 +91,9 @@ void bch2_pick_bucket_size(struct format_opts opts, struct dev_opts *dev) dev->bucket_size = opts.block_size; /* Bucket size must be >= btree node size: */ - dev->bucket_size = max(dev->bucket_size, opts.btree_node_size); + if (opt_defined(opts, btree_node_size)) + dev->bucket_size = max_t(unsigned, dev->bucket_size, + opts.btree_node_size); /* Want a bucket size of at least 128k, if possible: */ dev->bucket_size = max(dev->bucket_size, 256U); @@ -115,7 +118,8 @@ void bch2_pick_bucket_size(struct format_opts opts, struct dev_opts *dev) if (dev->bucket_size < opts.block_size) die("Bucket size cannot be smaller than block size"); - if (dev->bucket_size < opts.btree_node_size) + if (opt_defined(opts, btree_node_size) && + dev->bucket_size < opts.btree_node_size) die("Bucket size cannot be smaller than btree node size"); if (dev->nbuckets < BCH_MIN_NR_NBUCKETS) @@ -146,37 +150,48 @@ static unsigned parse_target(struct bch_sb_handle *sb, return 0; } -struct bch_sb *bch2_format(struct format_opts opts, - struct dev_opts *devs, size_t nr_devs) +struct bch_sb *bch2_format(struct bch_opt_strs fs_opt_strs, + struct bch_opts fs_opts, + struct format_opts opts, + struct dev_opts *devs, + size_t nr_devs) { struct bch_sb_handle sb = { NULL }; struct dev_opts *i; struct bch_sb_field_members *mi; + unsigned max_dev_block_size = 0; + unsigned opt_id; + + for (i = devs; i < devs + nr_devs; i++) + max_dev_block_size = max(max_dev_block_size, + get_blocksize(i->path, i->fd)); /* calculate block size: */ - if (!opts.block_size) - for (i = devs; i < devs + nr_devs; i++) - opts.block_size = max(opts.block_size, - get_blocksize(i->path, i->fd)); + if (!opt_defined(fs_opts, block_size)) { + opt_set(fs_opts, block_size, max_dev_block_size); + } else if (fs_opts.block_size < max_dev_block_size) + die("blocksize too small: %u, must be greater than device blocksize %u", + fs_opts.block_size, max_dev_block_size); /* calculate bucket sizes: */ for (i = devs; i < devs + nr_devs; i++) - bch2_pick_bucket_size(opts, i); + bch2_pick_bucket_size(fs_opts, i); /* calculate btree node size: */ - if (!opts.btree_node_size) { + if (!opt_defined(fs_opts, btree_node_size)) { /* 256k default btree node size */ - opts.btree_node_size = 512; + opt_set(fs_opts, btree_node_size, 512); for (i = devs; i < devs + nr_devs; i++) - opts.btree_node_size = - min(opts.btree_node_size, i->bucket_size); + fs_opts.btree_node_size = + min_t(unsigned, fs_opts.btree_node_size, + i->bucket_size); } - if (!is_power_of_2(opts.block_size)) + if (!is_power_of_2(fs_opts.block_size)) die("block size must be power of 2"); - if (!is_power_of_2(opts.btree_node_size)) + if (!is_power_of_2(fs_opts.btree_node_size)) die("btree node size must be power of 2"); if (uuid_is_null(opts.uuid.b)) @@ -188,7 +203,7 @@ struct bch_sb *bch2_format(struct format_opts opts, sb.sb->version = le16_to_cpu(bcachefs_metadata_version_current); sb.sb->version_min = le16_to_cpu(bcachefs_metadata_version_current); sb.sb->magic = BCACHE_MAGIC; - sb.sb->block_size = cpu_to_le16(opts.block_size); + sb.sb->block_size = cpu_to_le16(fs_opts.block_size); sb.sb->user_uuid = opts.uuid; sb.sb->nr_devices = nr_devs; @@ -199,24 +214,24 @@ struct bch_sb *bch2_format(struct format_opts opts, opts.label, min(strlen(opts.label), sizeof(sb.sb->label))); - SET_BCH_SB_CSUM_TYPE(sb.sb, opts.meta_csum_type); - SET_BCH_SB_META_CSUM_TYPE(sb.sb, opts.meta_csum_type); - SET_BCH_SB_DATA_CSUM_TYPE(sb.sb, opts.data_csum_type); - SET_BCH_SB_COMPRESSION_TYPE(sb.sb, opts.compression_type); - SET_BCH_SB_BACKGROUND_COMPRESSION_TYPE(sb.sb, - opts.background_compression_type); + for (opt_id = 0; + opt_id < bch2_opts_nr; + opt_id++) { + const struct bch_option *opt = &bch2_opt_table[opt_id]; + u64 v; - SET_BCH_SB_BTREE_NODE_SIZE(sb.sb, opts.btree_node_size); - SET_BCH_SB_GC_RESERVE(sb.sb, 8); - SET_BCH_SB_META_REPLICAS_WANT(sb.sb, opts.meta_replicas); - SET_BCH_SB_META_REPLICAS_REQ(sb.sb, opts.meta_replicas_required); - SET_BCH_SB_DATA_REPLICAS_WANT(sb.sb, opts.data_replicas); - SET_BCH_SB_DATA_REPLICAS_REQ(sb.sb, opts.data_replicas_required); - SET_BCH_SB_ERROR_ACTION(sb.sb, opts.on_error_action); - SET_BCH_SB_STR_HASH_TYPE(sb.sb, BCH_STR_HASH_SIPHASH); - SET_BCH_SB_ENCODED_EXTENT_MAX_BITS(sb.sb,ilog2(opts.encoded_extent_max)); + if (opt->set_sb == SET_NO_SB_OPT) + continue; - SET_BCH_SB_POSIX_ACL(sb.sb, 1); + v = bch2_opt_defined_by_id(&fs_opts, opt_id) + ? bch2_opt_get_by_id(&fs_opts, opt_id) + : bch2_opt_get_by_id(&bch2_opts_default, opt_id); + + opt->set_sb(sb.sb, v); + } + + SET_BCH_SB_ENCODED_EXTENT_MAX_BITS(sb.sb, + ilog2(opts.encoded_extent_max)); struct timespec now; if (clock_gettime(CLOCK_REALTIME, &now)) @@ -260,11 +275,11 @@ struct bch_sb *bch2_format(struct format_opts opts, } SET_BCH_SB_FOREGROUND_TARGET(sb.sb, - parse_target(&sb, devs, nr_devs, opts.foreground_target)); + parse_target(&sb, devs, nr_devs, fs_opt_strs.foreground_target)); SET_BCH_SB_BACKGROUND_TARGET(sb.sb, - parse_target(&sb, devs, nr_devs, opts.background_target)); + parse_target(&sb, devs, nr_devs, fs_opt_strs.background_target)); SET_BCH_SB_PROMOTE_TARGET(sb.sb, - parse_target(&sb, devs, nr_devs, opts.promote_target)); + parse_target(&sb, devs, nr_devs, fs_opt_strs.promote_target)); /* Crypt: */ if (opts.encrypted) { @@ -278,7 +293,7 @@ struct bch_sb *bch2_format(struct format_opts opts, for (i = devs; i < devs + nr_devs; i++) { sb.sb->dev_idx = i - devs; - init_layout(&sb.sb->layout, opts.block_size, + init_layout(&sb.sb->layout, fs_opts.block_size, i->sb_offset, i->sb_end); if (i->sb_offset == BCH_SB_SECTOR) { @@ -931,3 +946,151 @@ int bchu_data(struct bchfs_handle fs, struct bch_ioctl_data cmd) close(progress_fd); return 0; } + +/* option parsing */ + +struct bch_opt_strs bch2_cmdline_opts_get(int *argc, char *argv[], + unsigned opt_types) +{ + struct bch_opt_strs opts; + unsigned i = 1; + + memset(&opts, 0, sizeof(opts)); + + while (i < *argc) { + char *optstr = strcmp_prefix(argv[i], "--"); + char *valstr = NULL, *p; + int optid, nr_args = 1; + + if (!optstr) { + i++; + continue; + } + + optstr = strdup(optstr); + + p = optstr; + while (isalpha(*p) || *p == '_') + p++; + + if (*p == '=') { + *p = '\0'; + valstr = p + 1; + } + + optid = bch2_opt_lookup(optstr); + if (optid < 0 || + !(bch2_opt_table[optid].mode & opt_types)) { + free(optstr); + i++; + continue; + } + + if (!valstr && + bch2_opt_table[optid].type != BCH_OPT_BOOL) { + nr_args = 2; + valstr = argv[i + 1]; + } + + if (!valstr) + valstr = "1"; + + opts.by_id[optid] = valstr; + + *argc -= nr_args; + memmove(&argv[i], + &argv[i + nr_args], + sizeof(char *) * (*argc - i)); + argv[*argc] = NULL; + } + + return opts; +} + +struct bch_opts bch2_parse_opts(struct bch_opt_strs strs) +{ + struct bch_opts opts = bch2_opts_empty(); + unsigned i; + int ret; + u64 v; + + for (i = 0; i < bch2_opts_nr; i++) { + if (!strs.by_id[i] || + bch2_opt_table[i].type == BCH_OPT_FN) + continue; + + ret = bch2_opt_parse(NULL, &bch2_opt_table[i], + strs.by_id[i], &v); + if (ret < 0) + die("Invalid %s: %s", strs.by_id[i], strerror(-ret)); + + bch2_opt_set_by_id(&opts, i, v); + } + + return opts; +} + +void bch2_opts_usage(unsigned opt_types) +{ + const struct bch_option *opt; + unsigned i, c = 0, helpcol = 30; + + void tabalign() { + while (c < helpcol) { + putchar(' '); + c++; + } + } + + void newline() { + printf("\n"); + c = 0; + } + + for (opt = bch2_opt_table; + opt < bch2_opt_table + bch2_opts_nr; + opt++) { + if (!(opt->mode & opt_types)) + continue; + + c += printf(" --%s", opt->attr.name); + + switch (opt->type) { + case BCH_OPT_BOOL: + break; + case BCH_OPT_STR: + c += printf("=("); + for (i = 0; opt->choices[i]; i++) { + if (i) + c += printf("|"); + c += printf("%s", opt->choices[i]); + } + c += printf(")"); + break; + default: + c += printf("=%s", opt->hint); + break; + } + + if (opt->help) { + const char *l = opt->help; + + if (c >= helpcol) + newline(); + + while (1) { + const char *n = strchrnul(l, '\n'); + + tabalign(); + printf("%.*s", (int) (n - l), l); + newline(); + + if (!*n) + break; + l = n + 1; + } + } else { + newline(); + } + } +} diff --git a/libbcachefs.h b/libbcachefs.h index 7f914d22..b8da35d1 100644 --- a/libbcachefs.h +++ b/libbcachefs.h @@ -6,34 +6,33 @@ #include "libbcachefs/bcachefs_format.h" #include "libbcachefs/bcachefs_ioctl.h" -#include "tools-util.h" +#include "libbcachefs/opts.h" #include "libbcachefs/vstructs.h" +#include "tools-util.h" + +/* option parsing */ + +struct bch_opt_strs { +union { + char *by_id[bch2_opts_nr]; +}; +struct { +#define x(_name, ...) char *_name; + BCH_OPTS() +#undef x +}; +}; + +struct bch_opt_strs bch2_cmdline_opts_get(int *, char *[], unsigned); +struct bch_opts bch2_parse_opts(struct bch_opt_strs); +void bch2_opts_usage(unsigned); struct format_opts { char *label; uuid_le uuid; - unsigned on_error_action; - - unsigned block_size; - unsigned btree_node_size; unsigned encoded_extent_max; - unsigned meta_replicas; - unsigned data_replicas; - - unsigned meta_replicas_required; - unsigned data_replicas_required; - - const char *foreground_target; - const char *background_target; - const char *promote_target; - - unsigned meta_csum_type; - unsigned data_csum_type; - unsigned compression_type; - unsigned background_compression_type; - bool encrypted; char *passphrase; }; @@ -41,14 +40,7 @@ struct format_opts { static inline struct format_opts format_opts_default() { return (struct format_opts) { - .on_error_action = BCH_ON_ERROR_RO, .encoded_extent_max = 128, - .meta_csum_type = BCH_CSUM_OPT_CRC32C, - .data_csum_type = BCH_CSUM_OPT_CRC32C, - .meta_replicas = 1, - .data_replicas = 1, - .meta_replicas_required = 1, - .data_replicas_required = 1, }; } @@ -76,8 +68,10 @@ static inline struct dev_opts dev_opts_default() }; } -void bch2_pick_bucket_size(struct format_opts, struct dev_opts *); -struct bch_sb *bch2_format(struct format_opts, struct dev_opts *, size_t); +void bch2_pick_bucket_size(struct bch_opts, struct dev_opts *); +struct bch_sb *bch2_format(struct bch_opt_strs, + struct bch_opts, + struct format_opts, struct dev_opts *, size_t); void bch2_super_write(int, struct bch_sb *); struct bch_sb *__bch2_super_read(int, u64); diff --git a/tools-util.c b/tools-util.c index b107cc43..486bbacf 100644 --- a/tools-util.c +++ b/tools-util.c @@ -386,7 +386,7 @@ struct fiemap_extent fiemap_iter_next(struct fiemap_iter *iter) return e; } -const char *strcmp_prefix(const char *a, const char *a_prefix) +char *strcmp_prefix(char *a, const char *a_prefix) { while (*a_prefix && *a == *a_prefix) { a++; diff --git a/tools-util.h b/tools-util.h index 57f61e50..ae63f723 100644 --- a/tools-util.h +++ b/tools-util.h @@ -145,7 +145,7 @@ struct fiemap_extent fiemap_iter_next(struct fiemap_iter *); for (fiemap_iter_init(&iter, fd); \ (extent = fiemap_iter_next(&iter)).fe_length;) -const char *strcmp_prefix(const char *, const char *); +char *strcmp_prefix(char *, const char *); unsigned hatoi_validate(const char *, const char *);