1 /**
2 * f2fs_format.c
3 *
4 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 * http://www.samsung.com/
6 *
7 * Dual licensed under the GPL or LGPL version 2 licenses.
8 */
9 #define _LARGEFILE64_SOURCE
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <fcntl.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <sys/stat.h>
17 #ifndef ANDROID_WINDOWS_HOST
18 #include <sys/mount.h>
19 #endif
20 #include <time.h>
21 #include <uuid/uuid.h>
22 #include <errno.h>
23
24 #include "config.h"
25 #ifdef HAVE_LIBBLKID
26 # include <blkid/blkid.h>
27 #endif
28
29 #include "f2fs_fs.h"
30 #include "f2fs_format_utils.h"
31
32 #ifdef WITH_ANDROID
33 #include <sparse/sparse.h>
34 extern struct sparse_file *f2fs_sparse_file;
35 #endif
36
37 extern struct f2fs_configuration c;
38 static int force_overwrite = 0;
39
mkfs_usage()40 static void mkfs_usage()
41 {
42 MSG(0, "\nUsage: mkfs.f2fs [options] device [sectors]\n");
43 MSG(0, "[options]:\n");
44 MSG(0, " -a heap-based allocation [default:0]\n");
45 MSG(0, " -c [device path] up to 7 devices excepts meta device\n");
46 MSG(0, " -d debug level [default:0]\n");
47 MSG(0, " -e [extension list] e.g. \"mp3,gif,mov\"\n");
48 MSG(0, " -f force overwrite the exist filesystem\n");
49 MSG(0, " -l label\n");
50 MSG(0, " -m support zoned block device [default:0]\n");
51 MSG(0, " -o overprovision ratio [default:5]\n");
52 MSG(0, " -O [feature list] e.g. \"encrypt\"\n");
53 MSG(0, " -q quiet mode\n");
54 MSG(0, " -s # of segments per section [default:1]\n");
55 MSG(0, " -S sparse mode\n");
56 MSG(0, " -t 0: nodiscard, 1: discard [default:1]\n");
57 MSG(0, " -w wanted sector size\n");
58 MSG(0, " -z # of sections per zone [default:1]\n");
59 MSG(0, "sectors: number of sectors. [default: determined by device size]\n");
60 exit(1);
61 }
62
f2fs_show_info()63 static void f2fs_show_info()
64 {
65 MSG(0, "\n\tF2FS-tools: mkfs.f2fs Ver: %s (%s)\n\n",
66 F2FS_TOOLS_VERSION,
67 F2FS_TOOLS_DATE);
68 if (c.heap == 0)
69 MSG(0, "Info: Disable heap-based policy\n");
70
71 MSG(0, "Info: Debug level = %d\n", c.dbg_lv);
72 if (c.extension_list)
73 MSG(0, "Info: Add new extension list\n");
74
75 if (c.vol_label)
76 MSG(0, "Info: Label = %s\n", c.vol_label);
77 MSG(0, "Info: Trim is %s\n", c.trim ? "enabled": "disabled");
78 }
79
parse_feature(const char * features)80 static void parse_feature(const char *features)
81 {
82 while (*features == ' ')
83 features++;
84 if (!strcmp(features, "encrypt")) {
85 c.feature |= cpu_to_le32(F2FS_FEATURE_ENCRYPT);
86 } else if (!strcmp(features, "verity")) {
87 c.feature |= cpu_to_le32(F2FS_FEATURE_VERITY);
88 } else if (!strcmp(features, "extra_attr")) {
89 c.feature |= cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR);
90 } else if (!strcmp(features, "project_quota")) {
91 c.feature |= cpu_to_le32(F2FS_FEATURE_PRJQUOTA);
92 } else if (!strcmp(features, "inode_checksum")) {
93 c.feature |= cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM);
94 } else if (!strcmp(features, "flexible_inline_xattr")) {
95 c.feature |= cpu_to_le32(F2FS_FEATURE_FLEXIBLE_INLINE_XATTR);
96 } else if (!strcmp(features, "quota")) {
97 c.feature |= cpu_to_le32(F2FS_FEATURE_QUOTA_INO);
98 } else if (!strcmp(features, "inode_crtime")) {
99 c.feature |= cpu_to_le32(F2FS_FEATURE_INODE_CRTIME);
100 } else {
101 MSG(0, "Error: Wrong features\n");
102 mkfs_usage();
103 }
104 }
105
f2fs_parse_options(int argc,char * argv[])106 static void f2fs_parse_options(int argc, char *argv[])
107 {
108 static const char *option_string = "qa:c:d:e:l:mo:O:s:S:z:t:fw:";
109 int32_t option=0;
110
111 while ((option = getopt(argc,argv,option_string)) != EOF) {
112 switch (option) {
113 case 'q':
114 c.dbg_lv = -1;
115 break;
116 case 'a':
117 c.heap = atoi(optarg);
118 break;
119 case 'c':
120 if (c.ndevs >= MAX_DEVICES) {
121 MSG(0, "Error: Too many devices\n");
122 mkfs_usage();
123 }
124
125 if (strlen(optarg) > MAX_PATH_LEN) {
126 MSG(0, "Error: device path should be less than "
127 "%d characters\n", MAX_PATH_LEN);
128 mkfs_usage();
129 }
130 c.devices[c.ndevs++].path = strdup(optarg);
131 break;
132 case 'd':
133 c.dbg_lv = atoi(optarg);
134 break;
135 case 'e':
136 c.extension_list = strdup(optarg);
137 break;
138 case 'l': /*v: volume label */
139 if (strlen(optarg) > 512) {
140 MSG(0, "Error: Volume Label should be less than "
141 "512 characters\n");
142 mkfs_usage();
143 }
144 c.vol_label = optarg;
145 break;
146 case 'm':
147 c.zoned_mode = 1;
148 break;
149 case 'o':
150 c.overprovision = atof(optarg);
151 break;
152 case 'O':
153 parse_feature(optarg);
154 break;
155 case 's':
156 c.segs_per_sec = atoi(optarg);
157 break;
158 case 'S':
159 c.device_size = atoll(optarg);
160 c.device_size &= (~((u_int64_t)(F2FS_BLKSIZE - 1)));
161 c.sparse_mode = 1;
162 break;
163 case 'z':
164 c.secs_per_zone = atoi(optarg);
165 break;
166 case 't':
167 c.trim = atoi(optarg);
168 break;
169 case 'f':
170 force_overwrite = 1;
171 break;
172 case 'w':
173 c.wanted_sector_size = atoi(optarg);
174 break;
175 default:
176 MSG(0, "\tError: Unknown option %c\n",option);
177 mkfs_usage();
178 break;
179 }
180 }
181
182 if (!(c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR))) {
183 if (c.feature & cpu_to_le32(F2FS_FEATURE_PRJQUOTA)) {
184 MSG(0, "\tInfo: project quota feature should always been"
185 "enabled with extra attr feature\n");
186 exit(1);
187 }
188 if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM)) {
189 MSG(0, "\tInfo: inode checksum feature should always been"
190 "enabled with extra attr feature\n");
191 exit(1);
192 }
193 if (c.feature & cpu_to_le32(F2FS_FEATURE_FLEXIBLE_INLINE_XATTR)) {
194 MSG(0, "\tInfo: flexible inline xattr feature should always been"
195 "enabled with extra attr feature\n");
196 exit(1);
197 }
198 if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CRTIME)) {
199 MSG(0, "\tInfo: inode crtime feature should always been"
200 "enabled with extra attr feature\n");
201 exit(1);
202 }
203 }
204
205 if (optind >= argc) {
206 MSG(0, "\tError: Device not specified\n");
207 mkfs_usage();
208 }
209
210 /* [0] : META, [1 to MAX_DEVICES - 1] : NODE/DATA */
211 c.devices[0].path = strdup(argv[optind]);
212
213 if ((optind + 1) < argc) {
214 if (c.ndevs > 1) {
215 MSG(0, "\tError: Not support custom size on multi-devs.\n");
216 mkfs_usage();
217 }
218 c.wanted_total_sectors = atoll(argv[optind+1]);
219 }
220
221 if (c.sparse_mode)
222 c.trim = 0;
223
224 if (c.zoned_mode)
225 c.feature |= cpu_to_le32(F2FS_FEATURE_BLKZONED);
226 }
227
228 #ifdef HAVE_LIBBLKID
f2fs_dev_is_overwrite(const char * device)229 static int f2fs_dev_is_overwrite(const char *device)
230 {
231 const char *type;
232 blkid_probe pr = NULL;
233 int ret = -1;
234
235 if (!device || !*device)
236 return 0;
237
238 pr = blkid_new_probe_from_filename(device);
239 if (!pr)
240 goto out;
241
242 ret = blkid_probe_enable_partitions(pr, 1);
243 if (ret < 0)
244 goto out;
245
246 ret = blkid_do_fullprobe(pr);
247 if (ret < 0)
248 goto out;
249
250 /*
251 * Blkid returns 1 for nothing found and 0 when it finds a signature,
252 * but we want the exact opposite, so reverse the return value here.
253 *
254 * In addition print some useful diagnostics about what actually is
255 * on the device.
256 */
257 if (ret) {
258 ret = 0;
259 goto out;
260 }
261
262 if (!blkid_probe_lookup_value(pr, "TYPE", &type, NULL)) {
263 MSG(0, "\t%s appears to contain an existing filesystem (%s).\n",
264 device, type);
265 } else if (!blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL)) {
266 MSG(0, "\t%s appears to contain a partition table (%s).\n",
267 device, type);
268 } else {
269 MSG(0, "\t%s appears to contain something weird according to blkid\n",
270 device);
271 }
272 ret = 1;
273 out:
274 if (pr)
275 blkid_free_probe(pr);
276 if (ret == -1)
277 MSG(0, "\tprobe of %s failed, cannot detect existing filesystem.\n",
278 device);
279 return ret;
280 }
281
f2fs_check_overwrite(void)282 static int f2fs_check_overwrite(void)
283 {
284 int i;
285
286 for (i = 0; i < c.ndevs; i++)
287 if (f2fs_dev_is_overwrite((char *)c.devices[i].path))
288 return -1;
289 return 0;
290 }
291
292 #else
293
f2fs_check_overwrite(void)294 static int f2fs_check_overwrite(void)
295 {
296 return 0;
297 }
298
299 #endif /* HAVE_LIBBLKID */
300
main(int argc,char * argv[])301 int main(int argc, char *argv[])
302 {
303 f2fs_init_configuration();
304
305 f2fs_parse_options(argc, argv);
306
307 f2fs_show_info();
308
309 c.func = MKFS;
310
311 if (!force_overwrite && f2fs_check_overwrite()) {
312 MSG(0, "\tUse the -f option to force overwrite.\n");
313 return -1;
314 }
315
316 if (f2fs_devs_are_umounted() < 0) {
317 if (errno != EBUSY)
318 MSG(0, "\tError: Not available on mounted device!\n");
319 return -1;
320 }
321
322 if (f2fs_get_device_info() < 0)
323 return -1;
324
325 /*
326 * Some options are mandatory for host-managed
327 * zoned block devices.
328 */
329 if (c.zoned_model == F2FS_ZONED_HM && !c.zoned_mode) {
330 MSG(0, "\tError: zoned block device feature is required\n");
331 return -1;
332 }
333
334 if (c.zoned_mode && !c.trim) {
335 MSG(0, "\tError: Trim is required for zoned block devices\n");
336 return -1;
337 }
338
339 if (c.sparse_mode) {
340 if (f2fs_init_sparse_file())
341 return -1;
342 }
343
344 if (f2fs_format_device() < 0)
345 return -1;
346
347 if (f2fs_finalize_device() < 0)
348 return -1;
349
350 MSG(0, "Info: format successful\n");
351
352 return 0;
353 }
354