]> git.sven.stormbind.net Git - sven/exfatprogs.git/blob - mkfs/mkfs.c
18376692791b60acd584f05f0f84ad428cf7451e
[sven/exfatprogs.git] / mkfs / mkfs.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *   Copyright (C) 2019 Namjae Jeon <linkinjeon@kernel.org>
4  */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <stdbool.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <sys/ioctl.h>
14 #include <fcntl.h>
15 #include <getopt.h>
16 #include <inttypes.h>
17 #include <limits.h>
18 #include <errno.h>
19 #include <locale.h>
20 #include <time.h>
21
22 #include "exfat_ondisk.h"
23 #include "libexfat.h"
24 #include "mkfs.h"
25
26 struct exfat_mkfs_info finfo;
27
28 /* random serial generator based on current time */
29 static unsigned int get_new_serial(void)
30 {
31         struct timespec ts;
32
33         if (clock_gettime(CLOCK_REALTIME, &ts)) {
34                 /* set 0000-0000 on error */
35                 ts.tv_sec = 0;
36                 ts.tv_nsec = 0;
37         }
38
39         return (unsigned int)(ts.tv_nsec << 12 | ts.tv_sec);
40 }
41
42 static void exfat_setup_boot_sector(struct pbr *ppbr,
43                 struct exfat_blk_dev *bd, struct exfat_user_input *ui)
44 {
45         struct bpb64 *pbpb = &ppbr->bpb;
46         struct bsx64 *pbsx = &ppbr->bsx;
47         unsigned int i;
48
49         /* Fill exfat BIOS paramemter block */
50         pbpb->jmp_boot[0] = 0xeb;
51         pbpb->jmp_boot[1] = 0x76;
52         pbpb->jmp_boot[2] = 0x90;
53         memcpy(pbpb->oem_name, "EXFAT   ", 8);
54         memset(pbpb->res_zero, 0, 53);
55
56         /* Fill exfat extend BIOS paramemter block */
57         pbsx->vol_offset = cpu_to_le64(bd->offset / bd->sector_size);
58         pbsx->vol_length = cpu_to_le64(bd->size / bd->sector_size);
59         pbsx->fat_offset = cpu_to_le32(finfo.fat_byte_off / bd->sector_size);
60         pbsx->fat_length = cpu_to_le32(finfo.fat_byte_len / bd->sector_size);
61         pbsx->clu_offset = cpu_to_le32(finfo.clu_byte_off / bd->sector_size);
62         pbsx->clu_count = cpu_to_le32(finfo.total_clu_cnt);
63         pbsx->root_cluster = cpu_to_le32(finfo.root_start_clu);
64         pbsx->vol_serial = cpu_to_le32(finfo.volume_serial);
65         pbsx->vol_flags = 0;
66         pbsx->sect_size_bits = bd->sector_size_bits;
67         pbsx->sect_per_clus_bits = 0;
68         /* Compute base 2 logarithm of ui->cluster_size / bd->sector_size */
69         for (i = ui->cluster_size / bd->sector_size; i > 1; i /= 2)
70                 pbsx->sect_per_clus_bits++;
71         pbsx->num_fats = 1;
72         /* fs_version[0] : minor and fs_version[1] : major */
73         pbsx->fs_version[0] = 0;
74         pbsx->fs_version[1] = 1;
75         memset(pbsx->reserved2, 0, 7);
76
77         memset(ppbr->boot_code, 0, 390);
78         ppbr->signature = cpu_to_le16(PBR_SIGNATURE);
79
80         exfat_debug("Volume Offset(sectors) : %" PRIu64 "\n",
81                 le64_to_cpu(pbsx->vol_offset));
82         exfat_debug("Volume Length(sectors) : %" PRIu64 "\n",
83                 le64_to_cpu(pbsx->vol_length));
84         exfat_debug("FAT Offset(sector offset) : %u\n",
85                 le32_to_cpu(pbsx->fat_offset));
86         exfat_debug("FAT Length(sectors) : %u\n",
87                 le32_to_cpu(pbsx->fat_length));
88         exfat_debug("Cluster Heap Offset (sector offset) : %u\n",
89                 le32_to_cpu(pbsx->clu_offset));
90         exfat_debug("Cluster Count : %u\n",
91                 le32_to_cpu(pbsx->clu_count));
92         exfat_debug("Root Cluster (cluster offset) : %u\n",
93                 le32_to_cpu(pbsx->root_cluster));
94         exfat_debug("Volume Serial : 0x%x\n", le32_to_cpu(pbsx->vol_serial));
95         exfat_debug("Sector Size Bits : %u\n",
96                 pbsx->sect_size_bits);
97         exfat_debug("Sector per Cluster bits : %u\n",
98                 pbsx->sect_per_clus_bits);
99 }
100
101 static int exfat_write_boot_sector(struct exfat_blk_dev *bd,
102                 struct exfat_user_input *ui, unsigned int *checksum,
103                 bool is_backup)
104 {
105         struct pbr *ppbr;
106         unsigned int sec_idx = BOOT_SEC_IDX;
107         int ret = 0;
108
109         if (is_backup)
110                 sec_idx += BACKUP_BOOT_SEC_IDX;
111
112         ppbr = malloc(sizeof(struct pbr));
113         if (!ppbr) {
114                 exfat_err("Cannot allocate pbr: out of memory\n");
115                 return -1;
116         }
117         memset(ppbr, 0, sizeof(struct pbr));
118
119         exfat_setup_boot_sector(ppbr, bd, ui);
120
121         /* write main boot sector */
122         ret = exfat_write_sector(bd, ppbr, sec_idx);
123         if (ret < 0) {
124                 exfat_err("main boot sector write failed\n");
125                 ret = -1;
126                 goto free_ppbr;
127         }
128
129         boot_calc_checksum((unsigned char *)ppbr, sizeof(struct pbr),
130                 true, checksum);
131
132 free_ppbr:
133         free(ppbr);
134         return ret;
135 }
136
137 static int exfat_write_extended_boot_sectors(struct exfat_blk_dev *bd,
138                 unsigned int *checksum, bool is_backup)
139 {
140         struct exbs eb;
141         int i;
142         unsigned int sec_idx = EXBOOT_SEC_IDX;
143
144         if (is_backup)
145                 sec_idx += BACKUP_BOOT_SEC_IDX;
146
147         memset(&eb, 0, sizeof(struct exbs));
148         eb.signature = cpu_to_le16(PBR_SIGNATURE);
149         for (i = 0; i < EXBOOT_SEC_NUM; i++) {
150                 if (exfat_write_sector(bd, &eb, sec_idx++)) {
151                         exfat_err("extended boot sector write failed\n");
152                         return -1;
153                 }
154
155                 boot_calc_checksum((unsigned char *) &eb, sizeof(struct exbs),
156                         false, checksum);
157         }
158
159         return 0;
160 }
161
162 static int exfat_write_oem_sector(struct exfat_blk_dev *bd,
163                 unsigned int *checksum, bool is_backup)
164 {
165         char *oem;
166         int ret = 0;
167         unsigned int sec_idx = OEM_SEC_IDX;
168
169         oem = malloc(bd->sector_size);
170         if (!oem)
171                 return -1;
172
173         if (is_backup)
174                 sec_idx += BACKUP_BOOT_SEC_IDX;
175
176         memset(oem, 0xFF, bd->sector_size);
177         ret = exfat_write_sector(bd, oem, sec_idx);
178         if (ret) {
179                 exfat_err("oem sector write failed\n");
180                 ret = -1;
181                 goto free_oem;
182         }
183
184         boot_calc_checksum((unsigned char *)oem, bd->sector_size, false,
185                 checksum);
186
187         /* Zero out reserved sector */
188         memset(oem, 0, bd->sector_size);
189         ret = exfat_write_sector(bd, oem, sec_idx + 1);
190         if (ret) {
191                 exfat_err("reserved sector write failed\n");
192                 ret = -1;
193                 goto free_oem;
194         }
195
196         boot_calc_checksum((unsigned char *)oem, bd->sector_size, false,
197                 checksum);
198
199 free_oem:
200         free(oem);
201         return ret;
202 }
203
204 static int exfat_create_volume_boot_record(struct exfat_blk_dev *bd,
205                 struct exfat_user_input *ui, bool is_backup)
206 {
207         unsigned int checksum = 0;
208         int ret;
209
210         ret = exfat_write_boot_sector(bd, ui, &checksum, is_backup);
211         if (ret)
212                 return ret;
213         ret = exfat_write_extended_boot_sectors(bd, &checksum, is_backup);
214         if (ret)
215                 return ret;
216         ret = exfat_write_oem_sector(bd, &checksum, is_backup);
217         if (ret)
218                 return ret;
219
220         return exfat_write_checksum_sector(bd, checksum, is_backup);
221 }
222
223 static int write_fat_entry(int fd, __le32 clu,
224                 unsigned long long offset)
225 {
226         int nbyte;
227
228         lseek(fd, finfo.fat_byte_off + (offset * sizeof(__le32)), SEEK_SET);
229         nbyte = write(fd, (__u8 *) &clu, sizeof(__le32));
230         if (nbyte != sizeof(int)) {
231                 exfat_err("write failed, offset : %llu, clu : %x\n",
232                         offset, clu);
233                 return -1;
234         }
235
236         return 0;
237 }
238
239 static int write_fat_entries(struct exfat_user_input *ui, int fd,
240                 unsigned int clu, unsigned int length)
241 {
242         int ret;
243         unsigned int count;
244
245         count = clu + round_up(length, ui->cluster_size) / ui->cluster_size;
246
247         for (; clu < count - 1; clu++) {
248                 ret = write_fat_entry(fd, cpu_to_le32(clu + 1), clu);
249                 if (ret)
250                         return ret;
251         }
252
253         ret = write_fat_entry(fd, cpu_to_le32(EXFAT_EOF_CLUSTER), clu);
254         if (ret)
255                 return ret;
256
257         return clu;
258 }
259
260 static int exfat_create_fat_table(struct exfat_blk_dev *bd,
261                 struct exfat_user_input *ui)
262 {
263         int ret, clu;
264
265         /* fat entry 0 should be media type field(0xF8) */
266         ret = write_fat_entry(bd->dev_fd, cpu_to_le32(0xfffffff8), 0);
267         if (ret) {
268                 exfat_err("fat 0 entry write failed\n");
269                 return ret;
270         }
271
272         /* fat entry 1 is historical precedence(0xFFFFFFFF) */
273         ret = write_fat_entry(bd->dev_fd, cpu_to_le32(0xffffffff), 1);
274         if (ret) {
275                 exfat_err("fat 1 entry write failed\n");
276                 return ret;
277         }
278
279         /* write bitmap entries */
280         clu = write_fat_entries(ui, bd->dev_fd, EXFAT_FIRST_CLUSTER,
281                 finfo.bitmap_byte_len);
282         if (clu < 0)
283                 return ret;
284
285         /* write upcase table entries */
286         clu = write_fat_entries(ui, bd->dev_fd, clu + 1, finfo.ut_byte_len);
287         if (clu < 0)
288                 return ret;
289
290         /* write root directory entries */
291         clu = write_fat_entries(ui, bd->dev_fd, clu + 1, finfo.root_byte_len);
292         if (clu < 0)
293                 return ret;
294
295         finfo.used_clu_cnt = clu + 1;
296         exfat_debug("Total used cluster count : %d\n", finfo.used_clu_cnt);
297
298         return ret;
299 }
300
301 static int exfat_create_bitmap(struct exfat_blk_dev *bd)
302 {
303         char *bitmap;
304         unsigned int i, nbytes;
305
306         bitmap = calloc(finfo.bitmap_byte_len, sizeof(*bitmap));
307         if (!bitmap)
308                 return -1;
309
310         for (i = 0; i < finfo.used_clu_cnt - EXFAT_FIRST_CLUSTER; i++)
311                 exfat_set_bit(bd, bitmap, i);
312
313         lseek(bd->dev_fd, finfo.bitmap_byte_off, SEEK_SET);
314         nbytes = write(bd->dev_fd, bitmap, finfo.bitmap_byte_len);
315         if (nbytes != finfo.bitmap_byte_len) {
316                 exfat_err("write failed, nbytes : %d, bitmap_len : %d\n",
317                         nbytes, finfo.bitmap_byte_len);
318                 free(bitmap);
319                 return -1;
320         }
321
322         free(bitmap);
323         return 0;
324 }
325
326 static int exfat_create_root_dir(struct exfat_blk_dev *bd,
327                 struct exfat_user_input *ui)
328 {
329         struct exfat_dentry ed[3];
330         int dentries_len = sizeof(struct exfat_dentry) * 3;
331         int nbytes;
332
333         /* Set volume label entry */
334         ed[0].type = EXFAT_VOLUME;
335         memset(ed[0].vol_label, 0, 22);
336         memcpy(ed[0].vol_label, ui->volume_label, ui->volume_label_len);
337         ed[0].vol_char_cnt = ui->volume_label_len/2;
338
339         /* Set bitmap entry */
340         ed[1].type = EXFAT_BITMAP;
341         ed[1].bitmap_flags = 0;
342         ed[1].bitmap_start_clu = cpu_to_le32(EXFAT_FIRST_CLUSTER);
343         ed[1].bitmap_size = cpu_to_le64(finfo.bitmap_byte_len);
344
345         /* Set upcase table entry */
346         ed[2].type = EXFAT_UPCASE;
347         ed[2].upcase_checksum = cpu_to_le32(0xe619d30d);
348         ed[2].upcase_start_clu = cpu_to_le32(finfo.ut_start_clu);
349         ed[2].upcase_size = cpu_to_le64(EXFAT_UPCASE_TABLE_SIZE);
350
351         lseek(bd->dev_fd, finfo.root_byte_off, SEEK_SET);
352         nbytes = write(bd->dev_fd, ed, dentries_len);
353         if (nbytes != dentries_len) {
354                 exfat_err("write failed, nbytes : %d, dentries_len : %d\n",
355                         nbytes, dentries_len);
356                 return -1;
357         }
358
359         return 0;
360 }
361
362 static void usage(void)
363 {
364         fputs("Usage: mkfs.exfat\n"
365                 "\t-L | --volume-label=label                              Set volume label\n"
366                 "\t-c | --cluster-size=size(or suffixed by 'K' or 'M')    Specify cluster size\n"
367                 "\t-b | --boundary-align=size(or suffixed by 'K' or 'M')  Specify boundary alignment\n"
368                 "\t     --pack-bitmap                                     Move bitmap into FAT segment\n"
369                 "\t-f | --full-format                                     Full format\n"
370                 "\t-V | --version                                         Show version\n"
371                 "\t-v | --verbose                                         Print debug\n"
372                 "\t-h | --help                                            Show help\n",
373                 stderr);
374
375         exit(EXIT_FAILURE);
376 }
377
378 #define PACK_BITMAP (CHAR_MAX + 1)
379
380 static const struct option opts[] = {
381         {"volume-label",        required_argument,      NULL,   'L' },
382         {"cluster-size",        required_argument,      NULL,   'c' },
383         {"boundary-align",      required_argument,      NULL,   'b' },
384         {"pack-bitmap",         no_argument,            NULL,   PACK_BITMAP },
385         {"full-format",         no_argument,            NULL,   'f' },
386         {"version",             no_argument,            NULL,   'V' },
387         {"verbose",             no_argument,            NULL,   'v' },
388         {"help",                no_argument,            NULL,   'h' },
389         {"?",                   no_argument,            NULL,   '?' },
390         {NULL,                  0,                      NULL,    0  }
391 };
392
393 /*
394  * Moves the bitmap to just before the alignment boundary if there is space
395  * between the boundary and the end of the FAT. This may allow the FAT and the
396  * bitmap to share the same allocation unit on flash media, thereby improving
397  * performance and endurance.
398  */
399 static int exfat_pack_bitmap(const struct exfat_user_input *ui)
400 {
401         unsigned int fat_byte_end = finfo.fat_byte_off + finfo.fat_byte_len,
402                 bitmap_byte_len = finfo.bitmap_byte_len,
403                 bitmap_clu_len = round_up(bitmap_byte_len, ui->cluster_size),
404                 bitmap_clu_cnt, total_clu_cnt, new_bitmap_clu_len;
405
406         for (;;) {
407                 bitmap_clu_cnt = bitmap_clu_len / ui->cluster_size;
408                 if (finfo.clu_byte_off - bitmap_clu_len < fat_byte_end ||
409                                 finfo.total_clu_cnt > EXFAT_MAX_NUM_CLUSTER -
410                                         bitmap_clu_cnt)
411                         return -1;
412                 total_clu_cnt = finfo.total_clu_cnt + bitmap_clu_cnt;
413                 bitmap_byte_len = round_up(total_clu_cnt, 8) / 8;
414                 new_bitmap_clu_len = round_up(bitmap_byte_len, ui->cluster_size);
415                 if (new_bitmap_clu_len == bitmap_clu_len) {
416                         finfo.clu_byte_off -= bitmap_clu_len;
417                         finfo.total_clu_cnt = total_clu_cnt;
418                         finfo.bitmap_byte_off -= bitmap_clu_len;
419                         finfo.bitmap_byte_len = bitmap_byte_len;
420                         return 0;
421                 }
422                 bitmap_clu_len = new_bitmap_clu_len;
423         }
424 }
425
426 static int exfat_build_mkfs_info(struct exfat_blk_dev *bd,
427                 struct exfat_user_input *ui)
428 {
429         unsigned long long total_clu_cnt;
430         int clu_len;
431
432         if (ui->boundary_align < bd->sector_size) {
433                 exfat_err("boundary alignment is too small (min %d)\n",
434                                 bd->sector_size);
435                 return -1;
436         }
437         finfo.fat_byte_off = round_up(bd->offset + 24 * bd->sector_size,
438                         ui->boundary_align) - bd->offset;
439         finfo.fat_byte_len = round_up((bd->num_clusters * sizeof(int)),
440                 ui->cluster_size);
441         finfo.clu_byte_off = round_up(bd->offset + finfo.fat_byte_off +
442                 finfo.fat_byte_len, ui->boundary_align) - bd->offset;
443         if (bd->size <= finfo.clu_byte_off) {
444                 exfat_err("boundary alignment is too big\n");
445                 return -1;
446         }
447         total_clu_cnt = (bd->size - finfo.clu_byte_off) / ui->cluster_size;
448         if (total_clu_cnt > EXFAT_MAX_NUM_CLUSTER) {
449                 exfat_err("cluster size is too small\n");
450                 return -1;
451         }
452         finfo.total_clu_cnt = (unsigned int) total_clu_cnt;
453
454         finfo.bitmap_byte_off = finfo.clu_byte_off;
455         finfo.bitmap_byte_len = round_up(finfo.total_clu_cnt, 8) / 8;
456         if (ui->pack_bitmap)
457                 exfat_pack_bitmap(ui);
458         clu_len = round_up(finfo.bitmap_byte_len, ui->cluster_size);
459
460         finfo.ut_start_clu = EXFAT_FIRST_CLUSTER + clu_len / ui->cluster_size;
461         finfo.ut_byte_off = finfo.bitmap_byte_off + clu_len;
462         finfo.ut_byte_len = EXFAT_UPCASE_TABLE_SIZE;
463         clu_len = round_up(finfo.ut_byte_len, ui->cluster_size);
464
465         finfo.root_start_clu = finfo.ut_start_clu + clu_len / ui->cluster_size;
466         finfo.root_byte_off = finfo.ut_byte_off + clu_len;
467         finfo.root_byte_len = sizeof(struct exfat_dentry) * 3;
468         finfo.volume_serial = get_new_serial();
469
470         return 0;
471 }
472
473 static int exfat_zero_out_disk(struct exfat_blk_dev *bd,
474                 struct exfat_user_input *ui)
475 {
476         int nbytes;
477         unsigned long long total_written = 0;
478         char *buf;
479         unsigned int chunk_size = ui->cluster_size;
480         unsigned long long size;
481
482         if (ui->quick)
483                 size = finfo.root_byte_off + chunk_size;
484         else
485                 size = bd->size;
486
487         buf = malloc(chunk_size);
488         if (!buf)
489                 return -1;
490
491         memset(buf, 0, chunk_size);
492         lseek(bd->dev_fd, 0, SEEK_SET);
493         do {
494
495                 nbytes = write(bd->dev_fd, buf, chunk_size);
496                 if (nbytes <= 0) {
497                         if (nbytes < 0)
498                                 exfat_err("write failed(errno : %d)\n", errno);
499                         break;
500                 }
501                 total_written += nbytes;
502         } while (total_written < size);
503
504         free(buf);
505         exfat_debug("zero out written size : %llu, disk size : %llu\n",
506                 total_written, bd->size);
507         return 0;
508 }
509
510 static int make_exfat(struct exfat_blk_dev *bd, struct exfat_user_input *ui)
511 {
512         int ret;
513
514         exfat_info("Creating exFAT filesystem(%s, cluster size=%u)\n\n",
515                 ui->dev_name, ui->cluster_size);
516
517         exfat_info("Writing volume boot record: ");
518         ret = exfat_create_volume_boot_record(bd, ui, 0);
519         exfat_info("%s\n", ret ? "failed" : "done");
520         if (ret)
521                 return ret;
522
523         exfat_info("Writing backup volume boot record: ");
524         /* backup sector */
525         ret = exfat_create_volume_boot_record(bd, ui, 1);
526         exfat_info("%s\n", ret ? "failed" : "done");
527         if (ret)
528                 return ret;
529
530         exfat_info("Fat table creation: ");
531         ret = exfat_create_fat_table(bd, ui);
532         exfat_info("%s\n", ret ? "failed" : "done");
533         if (ret)
534                 return ret;
535
536         exfat_info("Allocation bitmap creation: ");
537         ret = exfat_create_bitmap(bd);
538         exfat_info("%s\n", ret ? "failed" : "done");
539         if (ret)
540                 return ret;
541
542         exfat_info("Upcase table creation: ");
543         ret = exfat_create_upcase_table(bd);
544         exfat_info("%s\n", ret ? "failed" : "done");
545         if (ret)
546                 return ret;
547
548         exfat_info("Writing root directory entry: ");
549         ret = exfat_create_root_dir(bd, ui);
550         exfat_info("%s\n", ret ? "failed" : "done");
551         if (ret)
552                 return ret;
553
554         return 0;
555 }
556
557 static long long parse_size(const char *size)
558 {
559         char *data_unit;
560         unsigned long long byte_size = strtoull(size, &data_unit, 0);
561
562         switch (*data_unit) {
563         case 'M':
564         case 'm':
565                 byte_size <<= 20;
566                 break;
567         case 'K':
568         case 'k':
569                 byte_size <<= 10;
570                 break;
571         case '\0':
572                 break;
573         default:
574                 exfat_err("Wrong unit input('%c') for size\n",
575                                 *data_unit);
576                 return -EINVAL;
577         }
578
579         return byte_size;
580 }
581
582 int main(int argc, char *argv[])
583 {
584         int c;
585         int ret = EXIT_FAILURE;
586         struct exfat_blk_dev bd;
587         struct exfat_user_input ui;
588         bool version_only = false;
589
590         init_user_input(&ui);
591
592         if (!setlocale(LC_CTYPE, ""))
593                 exfat_err("failed to init locale/codeset\n");
594
595         opterr = 0;
596         while ((c = getopt_long(argc, argv, "n:L:c:b:fVvh", opts, NULL)) != EOF)
597                 switch (c) {
598                 /*
599                  * Make 'n' option fallthrough to 'L' option for for backward
600                  * compatibility with old utils.
601                  */
602                 case 'n':
603                 case 'L':
604                 {
605                         ret = exfat_utf16_enc(optarg,
606                                 ui.volume_label, sizeof(ui.volume_label));
607                         if (ret < 0)
608                                 goto out;
609
610                         ui.volume_label_len = ret;
611                         break;
612                 }
613                 case 'c':
614                         ret = parse_size(optarg);
615                         if (ret < 0)
616                                 goto out;
617                         else if (ret & (ret - 1)) {
618                                 exfat_err("cluster size(%d) is not a power of 2)\n",
619                                         ret);
620                                 goto out;
621                         } else if (ret > EXFAT_MAX_CLUSTER_SIZE) {
622                                 exfat_err("cluster size(%d) exceeds max cluster size(%d)\n",
623                                         ui.cluster_size, EXFAT_MAX_CLUSTER_SIZE);
624                                 goto out;
625                         }
626                         ui.cluster_size = ret;
627                         break;
628                 case 'b':
629                         ret = parse_size(optarg);
630                         if (ret < 0)
631                                 goto out;
632                         else if (ret & (ret - 1)) {
633                                 exfat_err("boundary align(%d) is not a power of 2)\n",
634                                         ret);
635                                 goto out;
636                         }
637                         ui.boundary_align = ret;
638                         break;
639                 case PACK_BITMAP:
640                         ui.pack_bitmap = true;
641                         break;
642                 case 'f':
643                         ui.quick = false;
644                         break;
645                 case 'V':
646                         version_only = true;
647                         break;
648                 case 'v':
649                         print_level = EXFAT_DEBUG;
650                         break;
651                 case '?':
652                 case 'h':
653                 default:
654                         usage();
655         }
656
657         show_version();
658         if (version_only)
659                 exit(EXIT_FAILURE);
660
661         if (argc - optind != 1) {
662                 usage();
663         }
664
665         memset(ui.dev_name, 0, sizeof(ui.dev_name));
666         snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[optind]);
667
668         ret = exfat_get_blk_dev_info(&ui, &bd);
669         if (ret < 0)
670                 goto out;
671
672         ret = exfat_build_mkfs_info(&bd, &ui);
673         if (ret)
674                 goto close;
675
676         ret = exfat_zero_out_disk(&bd, &ui);
677         if (ret)
678                 goto close;
679
680         ret = make_exfat(&bd, &ui);
681         if (ret)
682                 goto close;
683
684         exfat_info("Synchronizing...\n");
685         ret = fsync(bd.dev_fd);
686 close:
687         close(bd.dev_fd);
688 out:
689         if (!ret)
690                 exfat_info("\nexFAT format complete!\n");
691         else
692                 exfat_info("\nexFAT format fail!\n");
693         return ret;
694 }