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.h>
22 #include <errno.h>
23 #include <getopt.h>
24 
25 #include "config.h"
26 #ifdef HAVE_LIBBLKID
27 #  include <blkid.h>
28 #endif
29 
30 #include "f2fs_fs.h"
31 #include "f2fs_format_utils.h"
32 
33 #ifdef WITH_ANDROID
34 #include <sparse/sparse.h>
35 extern struct sparse_file *f2fs_sparse_file;
36 #endif
37 
38 extern struct f2fs_configuration c;
39 static int force_overwrite = 0;
40 
41 INIT_FEATURE_TABLE;
42 
mkfs_usage()43 static void mkfs_usage()
44 {
45 	MSG(0, "\nUsage: mkfs.f2fs [options] device [sectors]\n");
46 	MSG(0, "[options]:\n");
47 	MSG(0, "  -a heap-based allocation [default:0]\n");
48 	MSG(0, "  -c device1[,device2,...] up to 7 additional devices, except meta device\n");
49 	MSG(0, "  -d debug level [default:0]\n");
50 	MSG(0, "  -e [cold file ext list] e.g. \"mp3,gif,mov\"\n");
51 	MSG(0, "  -E [hot file ext list] e.g. \"db\"\n");
52 	MSG(0, "  -f force overwrite of the existing filesystem\n");
53 	MSG(0, "  -g add default options\n");
54 	MSG(0, "  -i extended node bitmap, node ratio is 20%% by default\n");
55 	MSG(0, "  -l label\n");
56 	MSG(0, "  -U uuid\n");
57 	MSG(0, "  -m support zoned block device [default:0]\n");
58 	MSG(0, "  -o overprovision percentage [default:auto]\n");
59 	MSG(0, "  -O feature1[,feature2,...] e.g. \"encrypt\"\n");
60 	MSG(0, "  -C [encoding[:flag1,...]] Support casefolding with optional flags\n");
61 	MSG(0, "  -q quiet mode\n");
62 	MSG(0, "  -r set checkpointing seed (srand()) to 0\n");
63 	MSG(0, "  -R root_owner [default: 0:0]\n");
64 	MSG(0, "  -s # of segments per section [default:1]\n");
65 	MSG(0, "  -S sparse mode\n");
66 	MSG(0, "  -t 0: nodiscard, 1: discard [default:1]\n");
67 	MSG(0, "  -T timestamps\n");
68 	MSG(0, "  -w wanted sector size\n");
69 	MSG(0, "  -z # of sections per zone [default:1]\n");
70 	MSG(0, "  -V print the version number and exit\n");
71 	MSG(0, "sectors: number of sectors [default: determined by device size]\n");
72 	exit(1);
73 }
74 
f2fs_show_info()75 static void f2fs_show_info()
76 {
77 	MSG(0, "\n\tF2FS-tools: mkfs.f2fs Ver: %s (%s)\n\n",
78 				F2FS_TOOLS_VERSION,
79 				F2FS_TOOLS_DATE);
80 	if (c.heap == 0)
81 		MSG(0, "Info: Disable heap-based policy\n");
82 
83 	MSG(0, "Info: Debug level = %d\n", c.dbg_lv);
84 	if (c.extension_list[0])
85 		MSG(0, "Info: Add new cold file extension list\n");
86 	if (c.extension_list[1])
87 		MSG(0, "Info: Add new hot file extension list\n");
88 
89 	if (strlen(c.vol_label))
90 		MSG(0, "Info: Label = %s\n", c.vol_label);
91 	MSG(0, "Info: Trim is %s\n", c.trim ? "enabled": "disabled");
92 
93 	if (c.defset == CONF_ANDROID)
94 		MSG(0, "Info: Set conf for android\n");
95 
96 	if (c.feature & le32_to_cpu(F2FS_FEATURE_CASEFOLD))
97 		MSG(0, "Info: Enable %s with casefolding\n",
98 					f2fs_encoding2str(c.s_encoding));
99 	if (c.feature & le32_to_cpu(F2FS_FEATURE_PRJQUOTA))
100 		MSG(0, "Info: Enable Project quota\n");
101 
102 	if (c.feature & le32_to_cpu(F2FS_FEATURE_COMPRESSION))
103 		MSG(0, "Info: Enable Compression\n");
104 }
105 
add_default_options(void)106 static void add_default_options(void)
107 {
108 	switch (c.defset) {
109 	case CONF_ANDROID:
110 		/* -d1 -f -O encrypt -O quota -O verity -w 4096 -R 0:0 */
111 		c.dbg_lv = 1;
112 		force_overwrite = 1;
113 		c.feature |= cpu_to_le32(F2FS_FEATURE_ENCRYPT);
114 		c.feature |= cpu_to_le32(F2FS_FEATURE_QUOTA_INO);
115 		c.feature |= cpu_to_le32(F2FS_FEATURE_VERITY);
116 		c.wanted_sector_size = 4096;
117 		c.root_uid = c.root_gid = 0;
118 		break;
119 	}
120 #ifdef CONF_CASEFOLD
121 	c.s_encoding = F2FS_ENC_UTF8_12_1;
122 	c.feature |= cpu_to_le32(F2FS_FEATURE_CASEFOLD);
123 #endif
124 #ifdef CONF_PROJID
125 	c.feature |= cpu_to_le32(F2FS_FEATURE_PRJQUOTA);
126 	c.feature |= cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR);
127 #endif
128 }
129 
f2fs_parse_options(int argc,char * argv[])130 static void f2fs_parse_options(int argc, char *argv[])
131 {
132 	static const char *option_string = "qa:c:C:d:e:E:g:hil:mo:O:rR:s:S:z:t:T:U:Vfw:";
133 	static const struct option long_opts[] = {
134 		{ .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
135 		{ .name = NULL, .has_arg = 0, .flag = NULL, .val = 0 }
136 	};
137 	int32_t option=0;
138 	int val;
139 	char *token;
140 
141 	while ((option = getopt_long(argc,argv,option_string,long_opts,NULL)) != EOF) {
142 		switch (option) {
143 		case 'q':
144 			c.dbg_lv = -1;
145 			break;
146 		case 'a':
147 			c.heap = atoi(optarg);
148 			break;
149 		case 'c':
150 			if (c.ndevs >= MAX_DEVICES) {
151 				MSG(0, "Error: Too many devices\n");
152 				mkfs_usage();
153 			}
154 
155 			if (strlen(optarg) > MAX_PATH_LEN) {
156 				MSG(0, "Error: device path should be less than "
157 					"%d characters\n", MAX_PATH_LEN);
158 				mkfs_usage();
159 			}
160 			c.devices[c.ndevs++].path = strdup(optarg);
161 			break;
162 		case 'd':
163 			c.dbg_lv = atoi(optarg);
164 			break;
165 		case 'e':
166 			c.extension_list[0] = strdup(optarg);
167 			break;
168 		case 'E':
169 			c.extension_list[1] = strdup(optarg);
170 			break;
171 		case 'g':
172 			if (!strcmp(optarg, "android"))
173 				c.defset = CONF_ANDROID;
174 			break;
175 		case 'h':
176 			mkfs_usage();
177 			break;
178 		case 'i':
179 			c.large_nat_bitmap = 1;
180 			break;
181 		case 'l':		/*v: volume label */
182 			if (strlen(optarg) > 512) {
183 				MSG(0, "Error: Volume Label should be less than "
184 						"512 characters\n");
185 				mkfs_usage();
186 			}
187 			c.vol_label = optarg;
188 			break;
189 		case 'm':
190 			c.zoned_mode = 1;
191 			break;
192 		case 'o':
193 			c.overprovision = atof(optarg);
194 			break;
195 		case 'O':
196 			if (parse_feature(feature_table, optarg))
197 				mkfs_usage();
198 			break;
199 		case 'r':
200 			c.fake_seed = 1;
201 			break;
202 		case 'R':
203 			if (parse_root_owner(optarg, &c.root_uid, &c.root_gid))
204 				mkfs_usage();
205 			break;
206 		case 's':
207 			c.segs_per_sec = atoi(optarg);
208 			break;
209 		case 'S':
210 			c.device_size = atoll(optarg);
211 			c.device_size &= (~((u_int64_t)(F2FS_BLKSIZE - 1)));
212 			c.sparse_mode = 1;
213 			break;
214 		case 'z':
215 			c.secs_per_zone = atoi(optarg);
216 			break;
217 		case 't':
218 			c.trim = atoi(optarg);
219 			break;
220 		case 'T':
221 			c.fixed_time = strtoul(optarg, NULL, 0);
222 			break;
223 		case 'U':
224 			c.vol_uuid = strdup(optarg);
225 			break;
226 		case 'f':
227 			force_overwrite = 1;
228 			break;
229 		case 'w':
230 			c.wanted_sector_size = atoi(optarg);
231 			break;
232 		case 'V':
233 			show_version("mkfs.f2fs");
234 			exit(0);
235 		case 'C':
236 			token = strtok(optarg, ":");
237 			val = f2fs_str2encoding(token);
238 			if (val < 0) {
239 				MSG(0, "\tError: Unknown encoding %s\n", token);
240 				mkfs_usage();
241 			}
242 			c.s_encoding = val;
243 			token = strtok(NULL, "");
244 			val = f2fs_str2encoding_flags(&token, &c.s_encoding_flags);
245 			if (val) {
246 				MSG(0, "\tError: Unknown flag %s\n",token);
247 				mkfs_usage();
248 			}
249 			c.feature |= cpu_to_le32(F2FS_FEATURE_CASEFOLD);
250 			break;
251 		default:
252 			MSG(0, "\tError: Unknown option %c\n",option);
253 			mkfs_usage();
254 			break;
255 		}
256 	}
257 
258 	add_default_options();
259 
260 	if (!(c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR))) {
261 		if (c.feature & cpu_to_le32(F2FS_FEATURE_PRJQUOTA)) {
262 			MSG(0, "\tInfo: project quota feature should always be "
263 				"enabled with extra attr feature\n");
264 			exit(1);
265 		}
266 		if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM)) {
267 			MSG(0, "\tInfo: inode checksum feature should always be "
268 				"enabled with extra attr feature\n");
269 			exit(1);
270 		}
271 		if (c.feature & cpu_to_le32(F2FS_FEATURE_FLEXIBLE_INLINE_XATTR)) {
272 			MSG(0, "\tInfo: flexible inline xattr feature should always be "
273 				"enabled with extra attr feature\n");
274 			exit(1);
275 		}
276 		if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CRTIME)) {
277 			MSG(0, "\tInfo: inode crtime feature should always be "
278 				"enabled with extra attr feature\n");
279 			exit(1);
280 		}
281 		if (c.feature & cpu_to_le32(F2FS_FEATURE_COMPRESSION)) {
282 			MSG(0, "\tInfo: compression feature should always be "
283 				"enabled with extra attr feature\n");
284 			exit(1);
285 		}
286 	}
287 
288 	if (optind >= argc) {
289 		MSG(0, "\tError: Device not specified\n");
290 		mkfs_usage();
291 	}
292 
293 	/* [0] : META, [1 to MAX_DEVICES - 1] : NODE/DATA */
294 	c.devices[0].path = strdup(argv[optind]);
295 
296 	if ((optind + 1) < argc) {
297 		if (c.ndevs > 1) {
298 			MSG(0, "\tError: Not support custom size on multi-devs.\n");
299 			mkfs_usage();
300 		}
301 		c.wanted_total_sectors = atoll(argv[optind+1]);
302 	}
303 
304 	if (c.sparse_mode)
305 		c.trim = 0;
306 
307 	if (c.zoned_mode)
308 		c.feature |= cpu_to_le32(F2FS_FEATURE_BLKZONED);
309 }
310 
311 #ifdef HAVE_LIBBLKID
f2fs_dev_is_overwrite(const char * device)312 static int f2fs_dev_is_overwrite(const char *device)
313 {
314 	const char	*type;
315 	blkid_probe	pr = NULL;
316 	int		ret = -1;
317 
318 	if (!device || !*device)
319 		return 0;
320 
321 	pr = blkid_new_probe_from_filename(device);
322 	if (!pr)
323 		goto out;
324 
325 	ret = blkid_probe_enable_partitions(pr, 1);
326 	if (ret < 0)
327 		goto out;
328 
329 	ret = blkid_do_fullprobe(pr);
330 	if (ret < 0)
331 		goto out;
332 
333 	/*
334 	 * Blkid returns 1 for nothing found and 0 when it finds a signature,
335 	 * but we want the exact opposite, so reverse the return value here.
336 	 *
337 	 * In addition print some useful diagnostics about what actually is
338 	 * on the device.
339 	 */
340 	if (ret) {
341 		ret = 0;
342 		goto out;
343 	}
344 
345 	if (!blkid_probe_lookup_value(pr, "TYPE", &type, NULL)) {
346 		MSG(0, "\t%s appears to contain an existing filesystem (%s).\n",
347 			device, type);
348 	} else if (!blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL)) {
349 		MSG(0, "\t%s appears to contain a partition table (%s).\n",
350 			device, type);
351 	} else {
352 		MSG(0, "\t%s appears to contain something weird according to blkid\n",
353 			device);
354 	}
355 	ret = 1;
356 out:
357 	if (pr)
358 		blkid_free_probe(pr);
359 	if (ret == -1)
360 		MSG(0, "\tprobe of %s failed, cannot detect existing filesystem.\n",
361 			device);
362 	return ret;
363 }
364 
f2fs_check_overwrite(void)365 static int f2fs_check_overwrite(void)
366 {
367 	int i;
368 
369 	for (i = 0; i < c.ndevs; i++)
370 		if (f2fs_dev_is_overwrite((char *)c.devices[i].path))
371 			return -1;
372 	return 0;
373 }
374 
375 #else
376 
f2fs_check_overwrite(void)377 static int f2fs_check_overwrite(void)
378 {
379 	return 0;
380 }
381 
382 #endif /* HAVE_LIBBLKID */
383 
main(int argc,char * argv[])384 int main(int argc, char *argv[])
385 {
386 	f2fs_init_configuration();
387 
388 	f2fs_parse_options(argc, argv);
389 
390 	f2fs_show_info();
391 
392 	c.func = MKFS;
393 
394 	if (!force_overwrite && f2fs_check_overwrite()) {
395 		MSG(0, "\tUse the -f option to force overwrite.\n");
396 		return -1;
397 	}
398 
399 	if (f2fs_devs_are_umounted() < 0) {
400 		if (errno != EBUSY)
401 			MSG(0, "\tError: Not available on mounted device!\n");
402 		return -1;
403 	}
404 
405 	if (f2fs_get_device_info() < 0)
406 		goto err_format;
407 
408 	/*
409 	 * Some options are mandatory for host-managed
410 	 * zoned block devices.
411 	 */
412 	if (c.zoned_model == F2FS_ZONED_HM && !c.zoned_mode) {
413 		MSG(0, "\tError: zoned block device feature is required\n");
414 		goto err_format;
415 	}
416 
417 	if (c.zoned_mode && !c.trim) {
418 		MSG(0, "\tError: Trim is required for zoned block devices\n");
419 		goto err_format;
420 	}
421 
422 	if (f2fs_format_device() < 0)
423 		goto err_format;
424 
425 	if (f2fs_finalize_device() < 0)
426 		goto err_format;
427 
428 	MSG(0, "Info: format successful\n");
429 
430 	return 0;
431 
432 err_format:
433 	f2fs_release_sparse_resource();
434 	return -1;
435 }
436