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