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 USE_MINGW 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 "make_ext4fs.h" 44 #include "ext4_utils.h" 45 46 #ifndef USE_MINGW /* 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, " [ -L <label> ] [ -f ] [ -a <android mountpoint> ] [ -u ]\n"); 58 fprintf(stderr, " [ -S file_contexts ] [ -C fs_config ] [ -T timestamp ]\n"); 59 fprintf(stderr, " [ -z | -s ] [ -w ] [ -c ] [ -J ] [ -v ] [ -B <block_list_file> ]\n"); 60 fprintf(stderr, " [ -d <base_alloc_file_in> ] [ -D <base_alloc_file_out> ]\n"); 61 fprintf(stderr, " <filename> [[<directory>] <target_out_directory>]\n"); 62 } 63 64 int main(int argc, char **argv) 65 { 66 int opt; 67 const char *filename = NULL; 68 const char *directory = NULL; 69 const char *target_out_directory = NULL; 70 char *mountpoint = NULL; 71 fs_config_func_t fs_config_func = NULL; 72 const char *fs_config_file = NULL; 73 int gzip = 0; 74 int sparse = 0; 75 int crc = 0; 76 int wipe = 0; 77 int real_uuid = 0; 78 int fd; 79 int exitcode; 80 int verbose = 0; 81 time_t fixed_time = -1; 82 struct selabel_handle *sehnd = NULL; 83 FILE* block_list_file = NULL; 84 FILE* base_alloc_file_in = NULL; 85 FILE* base_alloc_file_out = NULL; 86 #ifndef USE_MINGW 87 struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "" } }; 88 #endif 89 90 while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:S:T:C:B:d:D:fwzJsctvu")) != -1) { 91 switch (opt) { 92 case 'l': 93 info.len = parse_num(optarg); 94 break; 95 case 'j': 96 info.journal_blocks = parse_num(optarg); 97 break; 98 case 'b': 99 info.block_size = parse_num(optarg); 100 break; 101 case 'g': 102 info.blocks_per_group = parse_num(optarg); 103 break; 104 case 'i': 105 info.inodes = parse_num(optarg); 106 break; 107 case 'I': 108 info.inode_size = parse_num(optarg); 109 break; 110 case 'L': 111 info.label = optarg; 112 break; 113 case 'f': 114 force = 1; 115 break; 116 case 'a': 117 #ifdef ANDROID 118 mountpoint = optarg; 119 #else 120 fprintf(stderr, "can't set android permissions - built without android support\n"); 121 usage(argv[0]); 122 exit(EXIT_FAILURE); 123 #endif 124 break; 125 case 'w': 126 wipe = 1; 127 break; 128 case 'u': 129 real_uuid = 1; 130 break; 131 case 'z': 132 gzip = 1; 133 break; 134 case 'J': 135 info.no_journal = 1; 136 break; 137 case 'c': 138 crc = 1; 139 break; 140 case 's': 141 sparse = 1; 142 break; 143 case 't': 144 fprintf(stderr, "Warning: -t (initialize inode tables) is deprecated\n"); 145 break; 146 case 'S': 147 #ifndef USE_MINGW 148 seopts[0].value = optarg; 149 sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1); 150 if (!sehnd) { 151 perror(optarg); 152 exit(EXIT_FAILURE); 153 } 154 #endif 155 break; 156 case 'v': 157 verbose = 1; 158 break; 159 case 'T': 160 fixed_time = strtoll(optarg, NULL, 0); 161 break; 162 case 'C': 163 fs_config_file = optarg; 164 break; 165 case 'B': 166 block_list_file = fopen(optarg, "w"); 167 if (block_list_file == NULL) { 168 fprintf(stderr, "failed to open block_list_file: %s\n", strerror(errno)); 169 exit(EXIT_FAILURE); 170 } 171 break; 172 case 'd': 173 base_alloc_file_in = fopen(optarg, "r"); 174 if (base_alloc_file_in == NULL) { 175 fprintf(stderr, "failed to open base_alloc_file_in: %s\n", strerror(errno)); 176 exit(EXIT_FAILURE); 177 } 178 break; 179 case 'D': 180 base_alloc_file_out = fopen(optarg, "w"); 181 if (base_alloc_file_out == NULL) { 182 fprintf(stderr, "failed to open base_alloc_file_out: %s\n", strerror(errno)); 183 exit(EXIT_FAILURE); 184 } 185 break; 186 default: /* '?' */ 187 usage(argv[0]); 188 exit(EXIT_FAILURE); 189 } 190 } 191 192 #if !defined(HOST) 193 // Use only if -S option not requested 194 if (!sehnd && mountpoint) { 195 sehnd = selinux_android_file_context_handle(); 196 197 if (!sehnd) { 198 perror(optarg); 199 exit(EXIT_FAILURE); 200 } 201 } 202 #endif 203 204 if (fs_config_file) { 205 if (load_canned_fs_config(fs_config_file) < 0) { 206 fprintf(stderr, "failed to load %s\n", fs_config_file); 207 exit(EXIT_FAILURE); 208 } 209 fs_config_func = canned_fs_config; 210 } else if (mountpoint) { 211 fs_config_func = fs_config; 212 } 213 214 if (wipe && sparse) { 215 fprintf(stderr, "Cannot specifiy both wipe and sparse\n"); 216 usage(argv[0]); 217 exit(EXIT_FAILURE); 218 } 219 220 if (wipe && gzip) { 221 fprintf(stderr, "Cannot specifiy both wipe and gzip\n"); 222 usage(argv[0]); 223 exit(EXIT_FAILURE); 224 } 225 226 if (optind >= argc) { 227 fprintf(stderr, "Expected filename after options\n"); 228 usage(argv[0]); 229 exit(EXIT_FAILURE); 230 } 231 232 filename = argv[optind++]; 233 234 if (optind < argc) 235 directory = argv[optind++]; 236 237 if (optind < argc) 238 target_out_directory = argv[optind++]; 239 240 if (optind < argc) { 241 fprintf(stderr, "Unexpected argument: %s\n", argv[optind]); 242 usage(argv[0]); 243 exit(EXIT_FAILURE); 244 } 245 246 if (strcmp(filename, "-")) { 247 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); 248 if (fd < 0) { 249 perror("open"); 250 return EXIT_FAILURE; 251 } 252 } else { 253 fd = STDOUT_FILENO; 254 } 255 256 exitcode = make_ext4fs_internal(fd, directory, target_out_directory, mountpoint, fs_config_func, gzip, 257 sparse, crc, wipe, real_uuid, sehnd, verbose, fixed_time, 258 block_list_file, base_alloc_file_in, base_alloc_file_out); 259 close(fd); 260 if (block_list_file) 261 fclose(block_list_file); 262 if (base_alloc_file_out) 263 fclose(base_alloc_file_out); 264 if (base_alloc_file_in) 265 fclose(base_alloc_file_in); 266 if (exitcode && strcmp(filename, "-")) 267 unlink(filename); 268 return exitcode; 269 } 270