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