1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <fcntl.h> 18 #include <libgen.h> 19 #include <stdio.h> 20 #include <unistd.h> 21 22 #if defined(__linux__) 23 #include <linux/fs.h> 24 #elif defined(__APPLE__) && defined(__MACH__) 25 #include <sys/disk.h> 26 #endif 27 28 #ifdef ANDROID 29 #include <private/android_filesystem_config.h> 30 #include <private/canned_fs_config.h> 31 #endif 32 33 #ifndef _WIN32 34 #include <selinux/selinux.h> 35 #include <selinux/label.h> 36 #if !defined(HOST) 37 #include <selinux/android.h> 38 #endif 39 #else 40 struct selabel_handle; 41 #endif 42 43 #include "ext4_utils/ext4_utils.h" 44 #include "ext4_utils/make_ext4fs.h" 45 46 #ifndef _WIN32 /* O_BINARY is windows-specific flag */ 47 #define O_BINARY 0 48 #endif 49 50 extern struct fs_info info; 51 52 53 static void usage(char *path) 54 { 55 fprintf(stderr, "%s [ -l <len> ] [ -j <journal size> ] [ -b <block_size> ]\n", basename(path)); 56 fprintf(stderr, " [ -g <blocks per group> ] [ -i <inodes> ] [ -I <inode size> ]\n"); 57 fprintf(stderr, " [ -e <flash erase block size> ] [ -o <flash logical block size> ]\n"); 58 fprintf(stderr, " [ -L <label> ] [ -f ] [ -a <android mountpoint> ] [ -u ]\n"); 59 fprintf(stderr, " [ -S file_contexts ] [ -C fs_config ] [ -T timestamp ]\n"); 60 fprintf(stderr, " [ -z | -s ] [ -w ] [ -c ] [ -J ] [ -v ] [ -B <block_list_file> ]\n"); 61 fprintf(stderr, " [ -d <base_alloc_file_in> ] [ -D <base_alloc_file_out> ]\n"); 62 fprintf(stderr, " <filename> [[<directory>] <target_out_directory>]\n"); 63 } 64 65 int main(int argc, char **argv) 66 { 67 int opt; 68 const char *filename = NULL; 69 const char *directory = NULL; 70 const char *target_out_directory = NULL; 71 char *mountpoint = NULL; 72 fs_config_func_t fs_config_func = NULL; 73 const char *fs_config_file = NULL; 74 int gzip = 0; 75 int sparse = 0; 76 int crc = 0; 77 int wipe = 0; 78 int real_uuid = 0; 79 int fd; 80 int exitcode; 81 int verbose = 0; 82 time_t fixed_time = -1; 83 struct selabel_handle *sehnd = NULL; 84 FILE* block_list_file = NULL; 85 FILE* base_alloc_file_in = NULL; 86 FILE* base_alloc_file_out = NULL; 87 #ifndef _WIN32 88 struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "" } }; 89 #endif 90 91 while ((opt = getopt(argc, argv, "l:j:b:g:i:I:e:o:L:a:S:T:C:B:d:D:fwzJsctvu")) != -1) { 92 switch (opt) { 93 case 'l': 94 info.len = parse_num(optarg); 95 break; 96 case 'j': 97 info.journal_blocks = parse_num(optarg); 98 break; 99 case 'b': 100 info.block_size = parse_num(optarg); 101 break; 102 case 'g': 103 info.blocks_per_group = parse_num(optarg); 104 break; 105 case 'i': 106 info.inodes = parse_num(optarg); 107 break; 108 case 'I': 109 info.inode_size = parse_num(optarg); 110 break; 111 case 'e': 112 info.flash_erase_block_size = parse_num(optarg); 113 break; 114 case 'o': 115 info.flash_logical_block_size = parse_num(optarg); 116 break; 117 case 'L': 118 info.label = optarg; 119 break; 120 case 'f': 121 force = 1; 122 break; 123 case 'a': 124 #ifdef ANDROID 125 mountpoint = optarg; 126 #else 127 fprintf(stderr, "can't set android permissions - built without android support\n"); 128 usage(argv[0]); 129 exit(EXIT_FAILURE); 130 #endif 131 break; 132 case 'w': 133 wipe = 1; 134 break; 135 case 'u': 136 real_uuid = 1; 137 break; 138 case 'z': 139 gzip = 1; 140 break; 141 case 'J': 142 info.no_journal = 1; 143 break; 144 case 'c': 145 crc = 1; 146 break; 147 case 's': 148 sparse = 1; 149 break; 150 case 't': 151 fprintf(stderr, "Warning: -t (initialize inode tables) is deprecated\n"); 152 break; 153 case 'S': 154 #ifndef _WIN32 155 seopts[0].value = optarg; 156 sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1); 157 if (!sehnd) { 158 perror(optarg); 159 exit(EXIT_FAILURE); 160 } 161 #endif 162 break; 163 case 'v': 164 verbose = 1; 165 break; 166 case 'T': 167 fixed_time = strtoll(optarg, NULL, 0); 168 break; 169 case 'C': 170 fs_config_file = optarg; 171 break; 172 case 'B': 173 block_list_file = fopen(optarg, "w"); 174 if (block_list_file == NULL) { 175 fprintf(stderr, "failed to open block_list_file: %s\n", strerror(errno)); 176 exit(EXIT_FAILURE); 177 } 178 break; 179 case 'd': 180 base_alloc_file_in = fopen(optarg, "r"); 181 if (base_alloc_file_in == NULL) { 182 fprintf(stderr, "failed to open base_alloc_file_in: %s\n", strerror(errno)); 183 exit(EXIT_FAILURE); 184 } 185 break; 186 case 'D': 187 base_alloc_file_out = fopen(optarg, "w"); 188 if (base_alloc_file_out == NULL) { 189 fprintf(stderr, "failed to open base_alloc_file_out: %s\n", strerror(errno)); 190 exit(EXIT_FAILURE); 191 } 192 break; 193 default: /* '?' */ 194 usage(argv[0]); 195 exit(EXIT_FAILURE); 196 } 197 } 198 199 #if !defined(HOST) 200 // Use only if -S option not requested 201 if (!sehnd && mountpoint) { 202 sehnd = selinux_android_file_context_handle(); 203 204 if (!sehnd) { 205 perror(optarg); 206 exit(EXIT_FAILURE); 207 } 208 } 209 #endif 210 211 if (fs_config_file) { 212 if (load_canned_fs_config(fs_config_file) < 0) { 213 fprintf(stderr, "failed to load %s\n", fs_config_file); 214 exit(EXIT_FAILURE); 215 } 216 fs_config_func = canned_fs_config; 217 } else if (mountpoint) { 218 fs_config_func = fs_config; 219 } 220 221 if (wipe && sparse) { 222 fprintf(stderr, "Cannot specifiy both wipe and sparse\n"); 223 usage(argv[0]); 224 exit(EXIT_FAILURE); 225 } 226 227 if (wipe && gzip) { 228 fprintf(stderr, "Cannot specifiy both wipe and gzip\n"); 229 usage(argv[0]); 230 exit(EXIT_FAILURE); 231 } 232 233 if (optind >= argc) { 234 fprintf(stderr, "Expected filename after options\n"); 235 usage(argv[0]); 236 exit(EXIT_FAILURE); 237 } 238 239 filename = argv[optind++]; 240 241 if (optind < argc) 242 directory = argv[optind++]; 243 244 if (optind < argc) 245 target_out_directory = argv[optind++]; 246 247 if (optind < argc) { 248 fprintf(stderr, "Unexpected argument: %s\n", argv[optind]); 249 usage(argv[0]); 250 exit(EXIT_FAILURE); 251 } 252 253 if (strcmp(filename, "-")) { 254 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); 255 if (fd < 0) { 256 perror("open"); 257 return EXIT_FAILURE; 258 } 259 } else { 260 fd = STDOUT_FILENO; 261 } 262 263 exitcode = make_ext4fs_internal(fd, directory, target_out_directory, mountpoint, fs_config_func, gzip, 264 sparse, crc, wipe, real_uuid, sehnd, verbose, fixed_time, 265 block_list_file, base_alloc_file_in, base_alloc_file_out); 266 close(fd); 267 if (block_list_file) 268 fclose(block_list_file); 269 if (base_alloc_file_out) 270 fclose(base_alloc_file_out); 271 if (base_alloc_file_in) 272 fclose(base_alloc_file_in); 273 if (exitcode && strcmp(filename, "-")) 274 unlink(filename); 275 return exitcode; 276 } 277