• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdio.h>
2 #include <getopt.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <limits.h>
6 #include <ext2fs/ext2fs.h>
7 
8 #include "perms.h"
9 #include "base_fs.h"
10 #include "block_list.h"
11 #include "basefs_allocator.h"
12 #include "create_inode.h"
13 
14 static char *prog_name = "e2fsdroid";
15 static char *in_file;
16 static char *block_list;
17 static char *basefs_out;
18 static char *basefs_in;
19 static char *mountpoint = "";
20 static time_t fixed_time = -1;
21 static char *fs_config_file;
22 static struct selinux_opt seopt_file[8];
23 static int max_nr_opt = (int)sizeof(seopt_file) / sizeof(seopt_file[0]);
24 static char *product_out;
25 static char *src_dir;
26 static int android_configure;
27 static int android_sparse_file = 1;
28 
usage(int ret)29 static void usage(int ret)
30 {
31 	fprintf(stderr, "%s [-B block_list] [-D basefs_out] [-T timestamp]\n"
32 			"\t[-C fs_config] [-S file_contexts] [-p product_out]\n"
33 			"\t[-a mountpoint] [-d basefs_in] [-f src_dir] [-e] image\n",
34                 prog_name);
35 	exit(ret);
36 }
37 
absolute_path(const char * file)38 static char *absolute_path(const char *file)
39 {
40 	char *ret;
41 	char cwd[PATH_MAX];
42 
43 	if (file[0] != '/') {
44 		getcwd(cwd, PATH_MAX);
45 		ret = malloc(strlen(cwd) + 1 + strlen(file) + 1);
46 		if (ret)
47 			sprintf(ret, "%s/%s", cwd, file);
48 	} else
49 		ret = strdup(file);
50 	return ret;
51 }
52 
main(int argc,char * argv[])53 int main(int argc, char *argv[])
54 {
55 	int c;
56 	char *p;
57 	int flags = EXT2_FLAG_RW;
58 	errcode_t retval;
59 	io_manager io_mgr;
60 	ext2_filsys fs = NULL;
61 	struct fs_ops_callbacks fs_callbacks = { NULL, NULL };
62 	char *token;
63 	int nr_opt = 0;
64 	ext2_ino_t inodes_count;
65 	ext2_ino_t free_inodes_count;
66 	blk64_t blocks_count;
67 	blk64_t free_blocks_count;
68 
69 	add_error_table(&et_ext2_error_table);
70 
71 	while ((c = getopt (argc, argv, "T:C:S:p:a:D:d:B:f:e")) != EOF) {
72 		switch (c) {
73 		case 'T':
74 			fixed_time = strtoul(optarg, &p, 0);
75 			android_configure = 1;
76 			break;
77 		case 'C':
78 			fs_config_file = absolute_path(optarg);
79 			android_configure = 1;
80 			break;
81 		case 'S':
82 			token = strtok(optarg, ",");
83 			while (token) {
84 				if (nr_opt == max_nr_opt) {
85 					fprintf(stderr, "Expected at most %d selinux opts\n",
86 						max_nr_opt);
87 					exit(EXIT_FAILURE);
88 				}
89 				seopt_file[nr_opt].type = SELABEL_OPT_PATH;
90 				seopt_file[nr_opt].value = absolute_path(token);
91 				nr_opt++;
92 				token = strtok(NULL, ",");
93 			}
94 			android_configure = 1;
95 			break;
96 		case 'p':
97 			product_out = absolute_path(optarg);
98 			break;
99 		case 'a':
100 			mountpoint = strdup(optarg);
101 			break;
102 		case 'D':
103 			basefs_out = absolute_path(optarg);
104 			break;
105 		case 'd':
106 			basefs_in = absolute_path(optarg);
107 			break;
108 		case 'B':
109 			block_list = absolute_path(optarg);
110 			break;
111 		case 'f':
112 			src_dir = absolute_path(optarg);
113 			break;
114 		case 'e':
115 			android_sparse_file = 0;
116 			break;
117 		default:
118 			usage(EXIT_FAILURE);
119 		}
120 	}
121 	if (optind >= argc) {
122 		fprintf(stderr, "Expected filename after options\n");
123 		exit(EXIT_FAILURE);
124 	}
125 
126 	if (android_sparse_file) {
127 		io_mgr = sparse_io_manager;
128 		if (asprintf(&in_file, "(%s)", argv[optind]) == -1) {
129 			fprintf(stderr, "Failed to allocate file name\n");
130 			exit(EXIT_FAILURE);
131 		}
132 	} else {
133 		io_mgr = unix_io_manager;
134 		in_file = strdup(argv[optind]);
135 	}
136 	retval = ext2fs_open(in_file, flags, 0, 0, io_mgr, &fs);
137 	if (retval) {
138 		com_err(prog_name, retval, "while opening file %s\n", in_file);
139 		return retval;
140 	}
141 
142 	if (src_dir) {
143 		ext2fs_read_bitmaps(fs);
144 		if (basefs_in) {
145 			retval = base_fs_alloc_load(fs, basefs_in, mountpoint);
146 			if (retval) {
147 				com_err(prog_name, retval, "%s",
148 				"while reading base_fs file");
149 			    exit(1);
150 			}
151 			fs_callbacks.create_new_inode =
152 				base_fs_alloc_set_target;
153 			fs_callbacks.end_create_new_inode =
154 				base_fs_alloc_unset_target;
155 		}
156 		retval = populate_fs2(fs, EXT2_ROOT_INO, src_dir,
157 				      EXT2_ROOT_INO, &fs_callbacks);
158 		if (retval) {
159 			com_err(prog_name, retval, "%s",
160 			"while populating file system");
161 		    exit(1);
162 		}
163 		if (basefs_in)
164 			base_fs_alloc_cleanup(fs);
165 	}
166 
167 	if (android_configure) {
168 		retval = android_configure_fs(fs, src_dir, product_out, mountpoint,
169 			seopt_file, nr_opt, fs_config_file, fixed_time);
170 		if (retval) {
171 			com_err(prog_name, retval, "%s",
172 				"while configuring the file system");
173 			exit(1);
174 		}
175 	}
176 
177 	if (block_list) {
178 		retval = fsmap_iter_filsys(fs, &block_list_format, block_list,
179 					   mountpoint);
180 		if (retval) {
181 			com_err(prog_name, retval, "%s",
182 				"while creating the block_list");
183 			exit(1);
184 		}
185 	}
186 
187 	if (basefs_out) {
188 		retval = fsmap_iter_filsys(fs, &base_fs_format,
189 					   basefs_out, mountpoint);
190 		if (retval) {
191 			com_err(prog_name, retval, "%s",
192 				"while creating the basefs file");
193 			exit(1);
194 		}
195 	}
196 
197 	inodes_count = fs->super->s_inodes_count;
198 	free_inodes_count = fs->super->s_free_inodes_count;
199 	blocks_count = ext2fs_blocks_count(fs->super);
200 	free_blocks_count = ext2fs_free_blocks_count(fs->super);
201 
202 	retval = ext2fs_close_free(&fs);
203 	if (retval) {
204 		com_err(prog_name, retval, "%s",
205 				"while writing superblocks");
206 		exit(1);
207 	}
208 
209 	printf("Created filesystem with %u/%u inodes and %llu/%llu blocks\n",
210 			inodes_count - free_inodes_count, inodes_count,
211 			blocks_count - free_blocks_count, blocks_count);
212 
213 	remove_error_table(&et_ext2_error_table);
214 	return 0;
215 }
216