1 /* tools/editdisklbl/editdisklbl.c 2 * 3 * Copyright 2008, The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #define __USE_LARGEFILE64 19 #define __USE_FILE_OFFSET64 20 #include <errno.h> 21 #include <fcntl.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <unistd.h> 26 #include <sys/stat.h> 27 #include <sys/types.h> 28 29 #include "diskconfig/diskconfig.h" 30 31 /* give us some room */ 32 #define EXTRA_LBAS 100 33 34 static struct pf_map { 35 struct part_info *pinfo; 36 const char *filename; 37 } part_file_map[MAX_NUM_PARTS] = { {0, 0} }; 38 39 static int 40 usage(void) 41 { 42 fprintf(stderr, 43 "\nusage: editdisklbl <options> part1=file1 [part2=file2,...]\n" 44 "Where options can be one of:\n" 45 "\t\t-l <layout conf> -- The image layout config file.\n" 46 "\t\t-i <image file> -- The image file to edit.\n" 47 "\t\t-t -- Test mode (optional)\n" 48 "\t\t-v -- Be verbose\n" 49 "\t\t-h -- This message (optional)\n" 50 ); 51 return 1; 52 } 53 54 static int 55 parse_args(int argc, char *argv[], struct disk_info **dinfo, int *test, 56 int *verbose) 57 { 58 char *layout_conf = NULL; 59 char *img_file = NULL; 60 struct stat filestat; 61 int x; 62 int update_lba = 0; 63 64 while ((x = getopt (argc, argv, "vthl:i:")) != EOF) { 65 switch (x) { 66 case 'h': 67 return usage(); 68 case 'l': 69 layout_conf = optarg; 70 break; 71 case 't': 72 *test = 1; 73 break; 74 case 'i': 75 img_file = optarg; 76 break; 77 case 'v': 78 *verbose = 1; 79 break; 80 default: 81 fprintf(stderr, "Unknown argument: %c\n", (char)optopt); 82 return usage(); 83 } 84 } 85 86 if (!img_file || !layout_conf) { 87 fprintf(stderr, "Image filename and configuration file are required\n"); 88 return usage(); 89 } 90 91 /* we'll need to parse the command line later for partition-file 92 * mappings, so make sure there's at least something there */ 93 if (optind >= argc) { 94 fprintf(stderr, "Must provide partition -> file mappings\n"); 95 return usage(); 96 } 97 98 if (stat(img_file, &filestat)) { 99 perror("Cannot stat image file"); 100 return 1; 101 } 102 103 /* make sure we don't screw up and write to a block device on the host 104 * and wedge things. I just don't trust myself. */ 105 if (!S_ISREG(filestat.st_mode)) { 106 fprintf(stderr, "This program should only be used on regular files."); 107 return 1; 108 } 109 110 /* load the disk layout file */ 111 if (!(*dinfo = load_diskconfig(layout_conf, img_file))) { 112 fprintf(stderr, "Errors encountered while loading disk conf file %s", 113 layout_conf); 114 return 1; 115 } 116 117 if ((*dinfo)->num_lba == 0) { 118 (*dinfo)->num_lba = (*dinfo)->skip_lba + EXTRA_LBAS; 119 update_lba = 1; 120 } 121 122 /* parse the filename->partition mappings from the command line and patch 123 * up a loaded config file's partition table entries to have 124 * length == filesize */ 125 x = 0; 126 while (optind < argc) { 127 char *pair = argv[optind++]; 128 char *part_name; 129 struct part_info *pinfo; 130 struct stat tmp_stat; 131 132 if (x >= MAX_NUM_PARTS) { 133 fprintf(stderr, "Error: Too many partitions specified (%d)!\n", x); 134 return 1; 135 } 136 137 if (!(part_name = strsep(&pair, "=")) || !pair || !(*pair)) { 138 fprintf(stderr, "Error parsing partition mappings\n"); 139 return usage(); 140 } 141 142 if (!(pinfo = find_part(*dinfo, part_name))) { 143 fprintf(stderr, "Partition '%s' not found.\n", part_name); 144 return 1; 145 } 146 147 /* here pair points to the filename (after the '=') */ 148 part_file_map[x].pinfo = pinfo; 149 part_file_map[x++].filename = pair; 150 151 if (stat(pair, &tmp_stat) < 0) { 152 fprintf(stderr, "Could not stat file: %s\n", pair); 153 return 1; 154 } 155 156 pinfo->len_kb = (uint32_t) ((tmp_stat.st_size + 1023) >> 10); 157 if (update_lba) 158 (*dinfo)->num_lba += 159 ((uint64_t)pinfo->len_kb * 1024) / (*dinfo)->sect_size; 160 printf("Updated %s length to be %uKB\n", pinfo->name, pinfo->len_kb); 161 } 162 163 return 0; 164 } 165 166 int 167 main(int argc, char *argv[]) 168 { 169 struct disk_info *dinfo = NULL; 170 int test = 0; 171 int verbose = 0; 172 int cnt; 173 174 if (parse_args(argc, argv, &dinfo, &test, &verbose)) 175 return 1; 176 177 if (verbose) 178 dump_disk_config(dinfo); 179 180 if (test) 181 printf("Test mode enabled. Actions will not be committed to disk!\n"); 182 183 if (apply_disk_config(dinfo, test)) { 184 fprintf(stderr, "Could not apply disk configuration!\n"); 185 return 1; 186 } 187 188 printf("Copying images to specified partition offsets\n"); 189 /* now copy the images to their appropriate locations on disk */ 190 for (cnt = 0; cnt < MAX_NUM_PARTS && part_file_map[cnt].pinfo; ++cnt) { 191 loff_t offs = part_file_map[cnt].pinfo->start_lba * dinfo->sect_size; 192 const char *dest_fn = dinfo->device; 193 if (write_raw_image(dest_fn, part_file_map[cnt].filename, offs, test)) { 194 fprintf(stderr, "Could not write images after editing label.\n"); 195 return 1; 196 } 197 } 198 printf("File edit complete. Wrote %d images.\n", cnt); 199 200 return 0; 201 } 202