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