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