1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <fcntl.h>
18#include <libgen.h>
19#include <unistd.h>
20
21#if defined(__linux__)
22#include <linux/fs.h>
23#elif defined(__APPLE__) && defined(__MACH__)
24#include <sys/disk.h>
25#endif
26
27#ifdef ANDROID
28#include <private/android_filesystem_config.h>
29#endif
30
31#include "make_ext4fs.h"
32
33#ifndef USE_MINGW /* O_BINARY is windows-specific flag */
34#define O_BINARY 0
35#endif
36
37extern struct fs_info info;
38
39
40static void usage(char *path)
41{
42	fprintf(stderr, "%s [ -l <len> ] [ -j <journal size> ] [ -b <block_size> ]\n", basename(path));
43	fprintf(stderr, "    [ -g <blocks per group> ] [ -i <inodes> ] [ -I <inode size> ]\n");
44	fprintf(stderr, "    [ -L <label> ] [ -f ] [ -a <android mountpoint> ]\n");
45	fprintf(stderr, "    [ -S file_contexts ]\n");
46	fprintf(stderr, "    [ -z | -s ] [ -t ] [ -w ] [ -c ] [ -J ]\n");
47	fprintf(stderr, "    <filename> [<directory>]\n");
48}
49
50int main(int argc, char **argv)
51{
52	int opt;
53	const char *filename = NULL;
54	const char *directory = NULL;
55	char *mountpoint = "";
56	fs_config_func_t fs_config_func = NULL;
57	int gzip = 0;
58	int sparse = 0;
59	int crc = 0;
60	int wipe = 0;
61	int init_itabs = 0;
62	int fd;
63	int exitcode;
64	struct selabel_handle *sehnd = NULL;
65#ifdef HAVE_SELINUX
66	struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "" } };
67#endif
68
69	while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:fwzJsctS:")) != -1) {
70		switch (opt) {
71		case 'l':
72			info.len = parse_num(optarg);
73			break;
74		case 'j':
75			info.journal_blocks = parse_num(optarg);
76			break;
77		case 'b':
78			info.block_size = parse_num(optarg);
79			break;
80		case 'g':
81			info.blocks_per_group = parse_num(optarg);
82			break;
83		case 'i':
84			info.inodes = parse_num(optarg);
85			break;
86		case 'I':
87			info.inode_size = parse_num(optarg);
88			break;
89		case 'L':
90			info.label = optarg;
91			break;
92		case 'f':
93			force = 1;
94			break;
95		case 'a':
96#ifdef ANDROID
97			fs_config_func = fs_config;
98			mountpoint = optarg;
99#else
100			fprintf(stderr, "can't set android permissions - built without android support\n");
101			usage(argv[0]);
102			exit(EXIT_FAILURE);
103#endif
104			break;
105		case 'w':
106			wipe = 1;
107			break;
108		case 'z':
109			gzip = 1;
110			break;
111		case 'J':
112			info.no_journal = 1;
113			break;
114		case 'c':
115			crc = 1;
116			break;
117		case 's':
118			sparse = 1;
119			break;
120		case 't':
121			init_itabs = 1;
122			break;
123		case 'S':
124#ifdef HAVE_SELINUX
125			seopts[0].value = optarg;
126			sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
127			if (!sehnd) {
128				perror(optarg);
129				exit(EXIT_FAILURE);
130			}
131#endif
132			   break;
133		default: /* '?' */
134			usage(argv[0]);
135			exit(EXIT_FAILURE);
136		}
137	}
138
139	if (wipe && sparse) {
140		fprintf(stderr, "Cannot specifiy both wipe and sparse\n");
141		usage(argv[0]);
142		exit(EXIT_FAILURE);
143	}
144
145	if (wipe && gzip) {
146		fprintf(stderr, "Cannot specifiy both wipe and gzip\n");
147		usage(argv[0]);
148		exit(EXIT_FAILURE);
149	}
150
151	if (optind >= argc) {
152		fprintf(stderr, "Expected filename after options\n");
153		usage(argv[0]);
154		exit(EXIT_FAILURE);
155	}
156
157	filename = argv[optind++];
158
159	if (optind < argc)
160		directory = argv[optind++];
161
162	if (optind < argc) {
163		fprintf(stderr, "Unexpected argument: %s\n", argv[optind]);
164		usage(argv[0]);
165		exit(EXIT_FAILURE);
166	}
167
168	if (strcmp(filename, "-")) {
169		fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
170		if (fd < 0) {
171			error_errno("open");
172			return EXIT_FAILURE;
173		}
174	} else {
175		fd = STDOUT_FILENO;
176	}
177
178	exitcode = make_ext4fs_internal(fd, directory, mountpoint, fs_config_func, gzip,
179			sparse, crc, wipe, init_itabs, sehnd);
180	close(fd);
181
182	return exitcode;
183}
184