]> git.sesse.net Git - bcachefs-tools-debian/blob - cmd_format.c
cmd_migrate
[bcachefs-tools-debian] / cmd_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 #include <errno.h>
9 #include <fcntl.h>
10 #include <getopt.h>
11 #include <stdbool.h>
12 #include <stdint.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19
20 #include <blkid.h>
21 #include <uuid/uuid.h>
22
23 #include "ccan/darray/darray.h"
24
25 #include "cmds.h"
26 #include "libbcache.h"
27 #include "crypto.h"
28 #include "opts.h"
29 #include "util.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
38         int fd = xopen(dev, O_RDWR|O_EXCL);
39
40         if (force)
41                 return fd;
42
43         if (!(pr = blkid_new_probe()))
44                 die("blkid error 1");
45         if (blkid_probe_set_device(pr, fd, 0, 0))
46                 die("blkid error 2");
47         if (blkid_probe_enable_partitions(pr, true))
48                 die("blkid error 3");
49         if (blkid_do_fullprobe(pr) < 0)
50                 die("blkid error 4");
51
52         blkid_probe_lookup_value(pr, "TYPE", &fs_type, &fs_type_len);
53         blkid_probe_lookup_value(pr, "LABEL", &fs_label, &fs_label_len);
54
55         if (fs_type) {
56                 if (fs_label)
57                         printf("%s contains a %s filesystem labelled '%s'\n",
58                                dev, fs_type, fs_label);
59                 else
60                         printf("%s contains a %s filesystem\n",
61                                dev, fs_type);
62                 fputs("Proceed anyway?", stdout);
63                 if (!ask_yn())
64                         exit(EXIT_FAILURE);
65         }
66
67         blkid_free_probe(pr);
68         return fd;
69 }
70
71 #define OPTS                                                                    \
72 t("bcache format - create a new bcache filesystem on one or more devices")      \
73 t("Usage: bcache format [OPTION]... <devices>")                                 \
74 t("")                                                                           \
75 x('b',  block_size,             "size",                 NULL)                   \
76 x(0,    btree_node_size,        "size",                 "Default 256k")         \
77 x(0,    metadata_checksum_type, "(none|crc32c|crc64)",  NULL)                   \
78 x(0,    data_checksum_type,     "(none|crc32c|crc64)",  NULL)                   \
79 x(0,    compression_type,       "(none|lz4|gzip)",      NULL)                   \
80 x(0,    encrypted,              NULL,                   "Enable whole filesystem encryption (chacha20/poly1305)")\
81 x(0,    no_passphrase,          NULL,                   "Don't encrypt master encryption key")\
82 x('e',  error_action,           "(continue|readonly|panic)", NULL)              \
83 x(0,    max_journal_entry_size, "size",                 NULL)                   \
84 x('L',  label,                  "label",                NULL)                   \
85 x('U',  uuid,                   "uuid",                 NULL)                   \
86 x('f',  force,                  NULL,                   NULL)                   \
87 t("")                                                                           \
88 t("Device specific options:")                                                   \
89 x(0,    fs_size,                "size",                 "Size of filesystem on device")\
90 x(0,    bucket_size,            "size",                 "Bucket size")          \
91 x('t',  tier,                   "#",                    "Higher tier indicates slower devices")\
92 x(0,    discard,                NULL,                   NULL)                   \
93 t("Device specific options must come before corresponding devices, e.g.")       \
94 t("  bcache format --tier 0 /dev/sdb --tier 1 /dev/sdc")                        \
95 t("")                                                                           \
96 x('h',  help,                   NULL,                   "display this help and exit")
97
98 static void usage(void)
99 {
100 #define t(text)                         puts(text "\n")
101 #define x(shortopt, longopt, arg, help) do {                            \
102         OPTS
103 #undef x
104 #undef t
105
106         puts("bcache format - create a new bcache filesystem on one or more devices\n"
107              "Usage: bcache format [OPTION]... <devices>\n"
108              "\n"
109              "Options:\n"
110              "  -b, --block=size\n"
111              "      --btree_node=size       Btree node size, default 256k\n"
112              "      --metadata_checksum_type=(none|crc32c|crc64)\n"
113              "      --data_checksum_type=(none|crc32c|crc64)\n"
114              "      --compression_type=(none|lz4|gzip)\n"
115              "      --encrypted             Enable whole filesystem encryption (chacha20/poly1305)\n"
116              "      --no_passphrase         Don't encrypt master encryption key\n"
117              "      --error_action=(continue|readonly|panic)\n"
118              "                              Action to take on filesystem error\n"
119              "      --max_journal_entry_size=size\n"
120              "  -l, --label=label\n"
121              "      --uuid=uuid\n"
122              "  -f, --force\n"
123              "\n"
124              "Device specific options:\n"
125              "      --fs_size=size          Size of filesystem on device\n"
126              "      --bucket=size           bucket size\n"
127              "      --discard               Enable discards\n"
128              "  -t, --tier=#                tier of subsequent devices\n"
129              "\n"
130              "  -h, --help                  display this help and exit\n"
131              "\n"
132              "Device specific options must come before corresponding devices, e.g.\n"
133              "  bcache format --tier 0 /dev/sdb --tier 1 /dev/sdc\n"
134              "\n"
135              "Report bugs to <linux-bcache@vger.kernel.org>");
136 }
137
138 enum {
139         Opt_no_opt = 1,
140 #define t(text)
141 #define x(shortopt, longopt, arg, help) Opt_##longopt,
142         OPTS
143 #undef x
144 #undef t
145 };
146
147 static const struct option format_opts[] = {
148 #define t(text)
149 #define x(shortopt, longopt, arg, help) {                               \
150         .name           = #longopt,                                     \
151         .has_arg        = arg ? required_argument : no_argument,        \
152         .flag           = NULL,                                         \
153         .val            = Opt_##longopt,                                \
154 },
155         OPTS
156 #undef x
157 #undef t
158         { NULL }
159 };
160
161 static unsigned hatoi_validate(const char *s, const char *msg)
162 {
163         u64 v;
164
165         if (bch_strtoull_h(s, &v))
166                 die("bad %s %s", msg, s);
167
168         if (v & (v - 1))
169                 die("%s must be a power of two", msg);
170
171         v /= 512;
172
173         if (v > USHRT_MAX)
174                 die("%s too large\n", msg);
175
176         if (!v)
177                 die("%s too small\n", msg);
178
179         return v;
180 }
181
182 int cmd_format(int argc, char *argv[])
183 {
184         darray(struct dev_opts) devices;
185         struct format_opts opts = format_opts_default();
186         struct dev_opts dev_opts = { 0 }, *dev;
187         bool force = false, no_passphrase = false;
188         int opt;
189
190         darray_init(devices);
191
192         while ((opt = getopt_long(argc, argv,
193                                   "-b:e:L:U:ft:h",
194                                   format_opts,
195                                   NULL)) != -1)
196                 switch (opt) {
197                 case Opt_block_size:
198                 case 'b':
199                         opts.block_size =
200                                 hatoi_validate(optarg, "block size");
201                         break;
202                 case Opt_btree_node_size:
203                         opts.btree_node_size =
204                                 hatoi_validate(optarg, "btree node size");
205                         break;
206                 case Opt_metadata_checksum_type:
207                         opts.meta_csum_type =
208                                 read_string_list_or_die(optarg,
209                                                 bch_csum_types, "checksum type");
210                         break;
211                 case Opt_data_checksum_type:
212                         opts.data_csum_type =
213                                 read_string_list_or_die(optarg,
214                                                 bch_csum_types, "checksum type");
215                         break;
216                 case Opt_compression_type:
217                         opts.compression_type =
218                                 read_string_list_or_die(optarg,
219                                                 bch_compression_types,
220                                                 "compression type");
221                         break;
222                 case Opt_encrypted:
223                         opts.encrypted = true;
224                         break;
225                 case Opt_no_passphrase:
226                         no_passphrase = true;
227                         break;
228                 case Opt_error_action:
229                 case 'e':
230                         opts.on_error_action =
231                                 read_string_list_or_die(optarg,
232                                                 bch_error_actions, "error action");
233                         break;
234                 case Opt_max_journal_entry_size:
235                         opts.max_journal_entry_size =
236                                 hatoi_validate(optarg, "journal entry size");
237                         break;
238                 case Opt_label:
239                 case 'L':
240                         opts.label = strdup(optarg);
241                         break;
242                 case Opt_uuid:
243                 case 'U':
244                         if (uuid_parse(optarg, opts.uuid.b))
245                                 die("Bad uuid");
246                         break;
247                 case Opt_force:
248                 case 'f':
249                         force = true;
250                         break;
251                 case Opt_fs_size:
252                         if (bch_strtoull_h(optarg, &dev_opts.size))
253                                 die("invalid filesystem size");
254
255                         dev_opts.size >>= 9;
256                         break;
257                 case Opt_bucket_size:
258                         dev_opts.bucket_size =
259                                 hatoi_validate(optarg, "bucket size");
260                         break;
261                 case Opt_tier:
262                 case 't':
263                         if (kstrtouint(optarg, 10, &dev_opts.tier) ||
264                             dev_opts.tier >= BCH_TIER_MAX)
265                                 die("invalid tier");
266                         break;
267                 case Opt_discard:
268                         dev_opts.discard = true;
269                         break;
270                 case Opt_no_opt:
271                         dev_opts.path = strdup(optarg);
272                         darray_append(devices, dev_opts);
273                         dev_opts.size = 0;
274                         break;
275                 case Opt_help:
276                 case 'h':
277                         usage();
278                         exit(EXIT_SUCCESS);
279                         break;
280                 }
281
282         if (!darray_size(devices))
283                 die("Please supply a device");
284
285         if (opts.encrypted && !no_passphrase) {
286                 opts.passphrase = read_passphrase("Enter passphrase: ");
287
288                 if (isatty(STDIN_FILENO)) {
289                         char *pass2 =
290                                 read_passphrase("Enter same passphrase again: ");
291
292                         if (strcmp(opts.passphrase, pass2)) {
293                                 memzero_explicit(opts.passphrase,
294                                                  strlen(opts.passphrase));
295                                 memzero_explicit(pass2, strlen(pass2));
296                                 die("Passphrases do not match");
297                         }
298
299                         memzero_explicit(pass2, strlen(pass2));
300                         free(pass2);
301                 }
302         }
303
304         darray_foreach(dev, devices)
305                 dev->fd = open_for_format(dev->path, force);
306
307         struct bch_sb *sb =
308                 bcache_format(opts, devices.item, darray_size(devices));
309         bcache_super_print(sb, HUMAN_READABLE);
310         free(sb);
311
312         if (opts.passphrase) {
313                 memzero_explicit(opts.passphrase, strlen(opts.passphrase));
314                 free(opts.passphrase);
315         }
316
317         return 0;
318 }