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