1// Copyright 2016 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <errno.h>
6#include <fcntl.h>
7#include <getopt.h>
8#include <stdarg.h>
9#include <stdbool.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <sys/stat.h>
14#include <unistd.h>
15
16#include <fs-management/mount.h>
17#include <lib/fdio/util.h>
18#include <zircon/compiler.h>
19#include <zircon/processargs.h>
20#include <zircon/syscalls.h>
21
22struct {
23    const char* name;
24    disk_format_t df;
25} FILESYSTEMS[] = {
26    {"blobfs", DISK_FORMAT_BLOBFS},
27    {"minfs", DISK_FORMAT_MINFS},
28    {"fat", DISK_FORMAT_FAT},
29};
30
31int usage(void) {
32    fprintf(stderr, "usage: mkfs [ <option>* ] devicepath filesystem\n");
33    fprintf(stderr, " -h|--help                     Print this message\n");
34    fprintf(stderr, " -v|--verbose                  Verbose mode\n");
35    fprintf(stderr,
36            " -s|--fvm_data_slices SLICES   If block device is on top of a FVM,\n"
37            "                               the filesystem will have at least SLICES slices "
38            "                               allocated for data.\n");
39    fprintf(stderr, " values for 'filesystem' include:\n");
40    for (size_t i = 0; i < countof(FILESYSTEMS); i++) {
41        fprintf(stderr, "  '%s'\n", FILESYSTEMS[i].name);
42    }
43    return -1;
44}
45
46int parse_args(int argc, char** argv, mkfs_options_t* options, disk_format_t* df,
47               char** devicepath) {
48    static const struct option cmds[] = {
49        {"help", no_argument, NULL, 'h'},
50        {"verbose", no_argument, NULL, 'v'},
51        {"fvm_data_slices", required_argument, NULL, 's'},
52        {0, 0, 0, 0},
53    };
54
55    int opt_index = -1;
56    int c = -1;
57
58    while ((c = getopt_long(argc, argv, "hvs:", cmds, &opt_index)) >= 0) {
59        switch (c) {
60        case 'v':
61            options->verbose = true;
62            break;
63        case 's':
64            options->fvm_data_slices = strtoul(optarg, NULL, 0);
65            if (options->fvm_data_slices == 0) {
66                fprintf(stderr, "Invalid Args: %s\n", strerror(errno));
67                return usage();
68            }
69            break;
70        case 'h':
71            return usage();
72        default:
73            break;
74        };
75    };
76
77    if (argc - optind < 1) {
78        fprintf(stderr, "Invalid Args: Missing devicepath.\n");
79        return usage();
80    }
81
82    if (argc - optind < 2) {
83        fprintf(stderr, "Invalid Args: Missing filesystem.\n");
84        return usage();
85    }
86
87    for (size_t i = 0; i < countof(FILESYSTEMS); i++) {
88        if (!strcmp(FILESYSTEMS[i].name, argv[argc - 1])) {
89            *df = FILESYSTEMS[i].df;
90            break;
91        }
92    }
93
94    if (*df == DISK_FORMAT_UNKNOWN) {
95        fprintf(stderr, "fs_mkfs: Cannot format a device with filesystem '%s'\n", argv[2]);
96        return usage();
97    }
98
99    size_t device_arg = argc - 2;
100    *devicepath = argv[device_arg];
101
102    return 0;
103}
104
105int main(int argc, char** argv) {
106    mkfs_options_t options = default_mkfs_options;
107    char* devicepath;
108    disk_format_t df;
109    int r;
110    if ((r = parse_args(argc, argv, &options, &df, &devicepath))) {
111        return r;
112    }
113
114    if (options.verbose) {
115        printf("fs_mkfs: Formatting device [%s]\n", devicepath);
116    }
117
118    if ((r = mkfs(devicepath, df, launch_stdio_sync, &options)) < 0) {
119        fprintf(stderr, "fs_mkfs: Failed to format device: %d\n", r);
120    }
121    return r;
122}
123