• 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 #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