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