summaryrefslogtreecommitdiff
path: root/editdisklbl/editdisklbl.c
diff options
context:
space:
mode:
Diffstat (limited to 'editdisklbl/editdisklbl.c')
-rw-r--r--editdisklbl/editdisklbl.c201
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;
+}