diff options
Diffstat (limited to 'editdisklbl/editdisklbl.c')
-rw-r--r-- | editdisklbl/editdisklbl.c | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/editdisklbl/editdisklbl.c b/editdisklbl/editdisklbl.c new file mode 100644 index 0000000..6a0c31c --- /dev/null +++ b/editdisklbl/editdisklbl.c @@ -0,0 +1,201 @@ +/* tools/editdisklbl/editdisklbl.c + * + * Copyright 2008, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define __USE_LARGEFILE64 +#define __USE_FILE_OFFSET64 +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "diskconfig.h" + +/* give us some room */ +#define EXTRA_LBAS 100 + +static struct pf_map { + struct part_info *pinfo; + const char *filename; +} part_file_map[MAX_NUM_PARTS] = { {0, 0} }; + +static int +usage(void) +{ + fprintf(stderr, + "\nusage: editdisklbl <options> part1=file1 [part2=file2,...]\n" + "Where options can be one of:\n" + "\t\t-l <layout conf> -- The image layout config file.\n" + "\t\t-i <image file> -- The image file to edit.\n" + "\t\t-t -- Test mode (optional)\n" + "\t\t-v -- Be verbose\n" + "\t\t-h -- This message (optional)\n" + ); + return 1; +} + +static int +parse_args(int argc, char *argv[], struct disk_info **dinfo, int *test, + int *verbose) +{ + char *layout_conf = NULL; + char *img_file = NULL; + struct stat filestat; + int x; + int update_lba = 0; + + while ((x = getopt (argc, argv, "thl:i:")) != EOF) { + switch (x) { + case 'h': + return usage(); + case 'l': + layout_conf = optarg; + break; + case 't': + *test = 1; + break; + case 'i': + img_file = optarg; + break; + case 'v': + *verbose = 1; + break; + default: + fprintf(stderr, "Unknown argument: %c\n", (char)optopt); + return usage(); + } + } + + if (!img_file || !layout_conf) { + fprintf(stderr, "Image filename and configuration file are required\n"); + return usage(); + } + + /* we'll need to parse the command line later for partition-file + * mappings, so make sure there's at least something there */ + if (optind >= argc) { + fprintf(stderr, "Must provide partition -> file mappings\n"); + return usage(); + } + + if (stat(img_file, &filestat)) { + perror("Cannot stat image file"); + return 1; + } + + /* make sure we don't screw up and write to a block device on the host + * and wedge things. I just don't trust myself. */ + if (!S_ISREG(filestat.st_mode)) { + fprintf(stderr, "This program should only be used on regular files."); + return 1; + } + + /* load the disk layout file */ + if (!(*dinfo = load_diskconfig(layout_conf, img_file))) { + fprintf(stderr, "Errors encountered while loading disk conf file %s", + layout_conf); + return 1; + } + + if ((*dinfo)->num_lba == 0) { + (*dinfo)->num_lba = (*dinfo)->skip_lba + EXTRA_LBAS; + update_lba = 1; + } + + /* parse the filename->partition mappings from the command line and patch + * up a loaded config file's partition table entries to have + * length == filesize */ + x = 0; + while (optind < argc) { + char *pair = argv[optind++]; + char *part_name; + struct part_info *pinfo; + struct stat tmp_stat; + + if (x >= MAX_NUM_PARTS) { + fprintf(stderr, "Error: Too many partitions specified (%d)!\n", x); + return 1; + } + + if (!(part_name = strsep(&pair, "=")) || !pair || !(*pair)) { + fprintf(stderr, "Error parsing partition mappings\n"); + return usage(); + } + + if (!(pinfo = find_part(*dinfo, part_name))) { + fprintf(stderr, "Partition '%s' not found.\n", part_name); + return 1; + } + + /* here pair points to the filename (after the '=') */ + part_file_map[x].pinfo = pinfo; + part_file_map[x++].filename = pair; + + if (stat(pair, &tmp_stat) < 0) { + fprintf(stderr, "Could not stat file: %s\n", pair); + return 1; + } + + pinfo->len_kb = (uint32_t) ((tmp_stat.st_size + 1023) >> 10); + if (update_lba) + (*dinfo)->num_lba += + ((uint64_t)pinfo->len_kb * 1024) / (*dinfo)->sect_size; + printf("Updated %s length to be %uKB\n", pinfo->name, pinfo->len_kb); + } + + return 0; +} + +int +main(int argc, char *argv[]) +{ + struct disk_info *dinfo = NULL; + int test = 0; + int verbose = 0; + int cnt; + + if (parse_args(argc, argv, &dinfo, &test, &verbose)) + return 1; + + if (verbose) + dump_disk_config(dinfo); + + if (test) + printf("Test mode enabled. Actions will not be committed to disk!\n"); + + if (apply_disk_config(dinfo, test)) { + fprintf(stderr, "Could not apply disk configuration!\n"); + return 1; + } + + printf("Copying images to specified partition offsets\n"); + /* now copy the images to their appropriate locations on disk */ + for (cnt = 0; cnt < MAX_NUM_PARTS && part_file_map[cnt].pinfo; ++cnt) { + loff_t offs = part_file_map[cnt].pinfo->start_lba * dinfo->sect_size; + const char *dest_fn = dinfo->device; + if (write_raw_image(dest_fn, part_file_map[cnt].filename, offs, test)) { + fprintf(stderr, "Could not write images after editing label.\n"); + return 1; + } + } + printf("File edit complete. Wrote %d images.\n", cnt); + + return 0; +} |