Home | History | Annotate | Download | only in editdisklbl
      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