]> git.sesse.net Git - bcachefs-tools-debian/blob - bcache-format.c
Rework option handling
[bcachefs-tools-debian] / bcache-format.c
1 /*
2  * Authors: Kent Overstreet <kent.overstreet@gmail.com>
3  *          Gabriel de Perthuis <g2p.code@gmail.com>
4  *          Jacob Malevich <jam@datera.io>
5  *
6  * GPLv2
7  */
8 #define _GNU_SOURCE
9
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <getopt.h>
13 #include <stdbool.h>
14 #include <stdint.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21
22 #include <blkid.h>
23 #include <uuid/uuid.h>
24
25 #include "ccan/darray/darray.h"
26
27 #include "bcache.h"
28 #include "libbcache.h"
29 #include "crypto.h"
30
31 /* Open a block device, do magic blkid stuff: */
32 static int open_for_format(const char *dev, bool force)
33 {
34         blkid_probe pr;
35         const char *fs_type = NULL, *fs_label = NULL;
36         size_t fs_type_len, fs_label_len;
37         int fd;
38
39         if ((fd = open(dev, O_RDWR|O_EXCL)) == -1)
40                 die("Can't open dev %s: %s\n", dev, strerror(errno));
41
42         if (force)
43                 return fd;
44
45         if (!(pr = blkid_new_probe()))
46                 die("blkid error 1");
47         if (blkid_probe_set_device(pr, fd, 0, 0))
48                 die("blkid error 2");
49         if (blkid_probe_enable_partitions(pr, true))
50                 die("blkid error 3");
51         if (blkid_do_fullprobe(pr) < 0)
52                 die("blkid error 4");
53
54         blkid_probe_lookup_value(pr, "TYPE", &fs_type, &fs_type_len);
55         blkid_probe_lookup_value(pr, "LABEL", &fs_label, &fs_label_len);
56
57         if (fs_type) {
58                 if (fs_label)
59                         printf("%s contains a %s filesystem labelled '%s'\n",
60                                dev, fs_type, fs_label);
61                 else
62                         printf("%s contains a %s filesystem\n",
63                                dev, fs_type);
64                 if (!ask_proceed())
65                         exit(EXIT_FAILURE);
66         }
67
68         blkid_free_probe(pr);
69         return fd;
70 }
71
72 static void usage(void)
73 {
74         puts("bcache format - create a new bcache filesystem on one or more devices\n"
75              "Usage: bcache format [OPTION]... <devices>\n"
76              "\n"
77              "Options:\n"
78              "  -b, --block=size\n"
79              "      --btree_node=size       Btree node size, default 256k\n"
80              "      --metadata_checksum_type=(none|crc32c|crc64)\n"
81              "      --data_checksum_type=(none|crc32c|crc64)\n"
82              "      --compression_type=(none|lz4|gzip)\n"
83              "      --encrypted\n"
84              "      --error_action=(continue|readonly|panic)\n"
85              "                              Action to take on filesystem error\n"
86              "  -l, --label=label\n"
87              "      --uuid=uuid\n"
88              "  -f, --force\n"
89              "\n"
90              "Device specific options:\n"
91              "      --fs_size=size          Size of filesystem on device\n"
92              "      --bucket=size           bucket size\n"
93              "      --discard               Enable discards\n"
94              "  -t, --tier=#                tier of subsequent devices\n"
95              "\n"
96              "  -h, --help                  display this help and exit\n"
97              "\n"
98              "Device specific options must come before corresponding devices, e.g.\n"
99              "  bcache format --tier 0 /dev/sdb --tier 1 /dev/sdc\n"
100              "\n"
101              "Report bugs to <linux-bcache@vger.kernel.org>");
102         exit(EXIT_SUCCESS);
103 }
104
105 #define OPTS                                                            \
106         OPT('b',        block_size,             required_argument)      \
107         OPT(0,          btree_node_size,        required_argument)      \
108         OPT(0,          metadata_checksum_type, required_argument)      \
109         OPT(0,          data_checksum_type,     required_argument)      \
110         OPT(0,          compression_type,       required_argument)      \
111         OPT(0,          encrypted,              no_argument)            \
112         OPT('e',        error_action,           required_argument)      \
113         OPT('L',        label,                  required_argument)      \
114         OPT('U',        uuid,                   required_argument)      \
115         OPT('f',        force,                  no_argument)            \
116         OPT(0,          fs_size,                required_argument)      \
117         OPT(0,          bucket_size,            required_argument)      \
118         OPT('t',        tier,                   required_argument)      \
119         OPT(0,          discard,                no_argument)            \
120         OPT('h',        help,                   no_argument)
121
122 enum {
123         Opt_no_opt = 1,
124 #define OPT(shortopt, longopt, has_arg) Opt_##longopt,
125         OPTS
126 #undef OPT
127 };
128
129 static const struct option format_opts[] = {
130 #define OPT(shortopt, longopt, has_arg) {                               \
131                 #longopt,  has_arg, NULL, Opt_##longopt                 \
132         },
133         OPTS
134 #undef OPT
135         { NULL }
136 };
137
138 int cmd_format(int argc, char *argv[])
139 {
140         darray(struct dev_opts) devices;
141         struct dev_opts *dev;
142         unsigned block_size = 0;
143         unsigned btree_node_size = 0;
144         unsigned meta_csum_type = BCH_CSUM_CRC32C;
145         unsigned data_csum_type = BCH_CSUM_CRC32C;
146         unsigned compression_type = BCH_COMPRESSION_NONE;
147         bool encrypted = false;
148         unsigned on_error_action = BCH_ON_ERROR_RO;
149         char *label = NULL;
150         uuid_le uuid;
151         bool force = false;
152
153         /* Device specific options: */
154         u64 filesystem_size = 0;
155         unsigned bucket_size = 0;
156         unsigned tier = 0;
157         bool discard = false;
158         char *passphrase = NULL;
159         int opt;
160
161         darray_init(devices);
162         uuid_clear(uuid.b);
163
164         while ((opt = getopt_long(argc, argv,
165                                   "-b:e:L:U:ft:h",
166                                   format_opts,
167                                   NULL)) != -1)
168                 switch (opt) {
169                 case Opt_block_size:
170                 case 'b':
171                         block_size = hatoi_validate(optarg,
172                                                 "block size");
173                         break;
174                 case Opt_btree_node_size:
175                         btree_node_size = hatoi_validate(optarg,
176                                                 "btree node size");
177                         break;
178                 case Opt_metadata_checksum_type:
179                         meta_csum_type = read_string_list_or_die(optarg,
180                                                 csum_types, "checksum type");
181                         break;
182                 case Opt_data_checksum_type:
183                         data_csum_type = read_string_list_or_die(optarg,
184                                                 csum_types, "checksum type");
185                         break;
186                 case Opt_compression_type:
187                         compression_type = read_string_list_or_die(optarg,
188                                                 compression_types, "compression type");
189                         break;
190                 case Opt_encrypted:
191                         encrypted = true;
192                         break;
193                 case Opt_error_action:
194                 case 'e':
195                         on_error_action = read_string_list_or_die(optarg,
196                                                 error_actions, "error action");
197                         break;
198                 case Opt_label:
199                 case 'L':
200                         label = strdup(optarg);
201                         break;
202                 case Opt_uuid:
203                 case 'U':
204                         if (uuid_parse(optarg, uuid.b))
205                                 die("Bad uuid");
206                         break;
207                 case Opt_force:
208                 case 'f':
209                         force = true;
210                         break;
211                 case Opt_fs_size:
212                         filesystem_size = hatoi(optarg) >> 9;
213                         break;
214                 case Opt_bucket_size:
215                         bucket_size = hatoi_validate(optarg, "bucket size");
216                         break;
217                 case Opt_tier:
218                 case 't':
219                         tier = strtoul_or_die(optarg, CACHE_TIERS, "tier");
220                         break;
221                 case Opt_discard:
222                         discard = true;
223                         break;
224                 case Opt_no_opt:
225                         darray_append(devices, (struct dev_opts) {
226                                 .path                   = strdup(optarg),
227                                 .size                   = filesystem_size,
228                                 .bucket_size            = bucket_size,
229                                 .tier                   = tier,
230                                 .discard                = discard,
231                         });
232                         break;
233                 case Opt_help:
234                 case 'h':
235                         usage();
236                         break;
237                 }
238
239         if (!darray_size(devices))
240                 die("Please supply a device");
241
242         if (uuid_is_null(uuid.b))
243                 uuid_generate(uuid.b);
244
245         if (encrypted) {
246                 char *pass2;
247
248                 passphrase = read_passphrase("Enter passphrase: ");
249                 pass2 = read_passphrase("Enter same passphrase again: ");
250
251                 if (strcmp(passphrase, pass2)) {
252                         memzero_explicit(passphrase, strlen(passphrase));
253                         memzero_explicit(pass2, strlen(pass2));
254                         die("Passphrases do not match");
255                 }
256
257                 memzero_explicit(pass2, strlen(pass2));
258                 free(pass2);
259         }
260
261         darray_foreach(dev, devices)
262                 dev->fd = open_for_format(dev->path, force);
263
264         bcache_format(devices.item, darray_size(devices),
265                       block_size,
266                       btree_node_size,
267                       meta_csum_type,
268                       data_csum_type,
269                       compression_type,
270                       passphrase,
271                       1,
272                       1,
273                       on_error_action,
274                       label,
275                       uuid);
276
277         if (passphrase) {
278                 memzero_explicit(passphrase, strlen(passphrase));
279                 free(passphrase);
280         }
281
282         return 0;
283 }