Home | History | Annotate | Download | only in android
      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