| /* |
| * Copyright (c) International Business Machines Corp., 2006 |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
| * the GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| * |
| * Author: Oliver Lohmann |
| * |
| * 1.2 Removed argp because we want to use uClibc. |
| * 1.3 Minor cleanups |
| * 1.4 Migrated to new libubi |
| */ |
| |
| #include <stdio.h> |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <getopt.h> |
| #include <unistd.h> |
| #include <errno.h> |
| #include <mtd/ubi-media.h> |
| |
| #include "config.h" |
| #include "error.h" |
| #include "example_ubi.h" |
| #include "ubimirror.h" |
| |
| #define PROGRAM_VERSION "1.4" |
| |
| typedef enum action_t { |
| ACT_NORMAL = 0, |
| ACT_ARGP_ABORT, |
| ACT_ARGP_ERR, |
| } action_t; |
| |
| #define ABORT_ARGP do { \ |
| args->action = ACT_ARGP_ABORT; \ |
| } while (0) |
| |
| #define ERR_ARGP do { \ |
| args->action = ACT_ARGP_ERR; \ |
| } while (0) |
| |
| #define VOL_ARGS_MAX 2 |
| |
| static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" |
| "ubimirror - mirrors ubi volumes.\n"; |
| |
| static const char *optionsstr = |
| " -c, --copyright Print copyright information.\n" |
| " -s, --side=<seqnum> Use the side <seqnum> as source.\n" |
| " -?, --help Give this help list\n" |
| " --usage Give a short usage message\n" |
| " -V, --version Print program version\n"; |
| |
| static const char *usage = |
| "Usage: ubimirror [-c?V] [-s <seqnum>] [--copyright] [--side=<seqnum>]\n" |
| " [--help] [--usage] [--version] <source> <destination>\n"; |
| |
| static const char copyright [] __attribute__((unused)) = |
| "(C) IBM Coorporation 2007"; |
| |
| struct option long_options[] = { |
| { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, |
| { .name = "side", .has_arg = 1, .flag = NULL, .val = 's' }, |
| { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, |
| { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, |
| { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, |
| { NULL, 0, NULL, 0} |
| }; |
| |
| typedef struct myargs { |
| action_t action; |
| int side; |
| int vol_no; /* index of current volume */ |
| /* @FIXME replace by bootenv_list, makes live easier */ |
| /* @FIXME remove the constraint of two entries in the array */ |
| const char* vol[VOL_ARGS_MAX]; /* comma separated list of src/dst |
| volumes */ |
| char *arg1; |
| char **options; /* [STRING...] */ |
| } myargs; |
| |
| static int |
| get_update_side(const char* str) |
| { |
| uint32_t i = strtoul(str, NULL, 0); |
| |
| if ((i != 0) && (i != 1)) { |
| return -1; |
| } |
| return i; |
| } |
| |
| |
| static int |
| parse_opt(int argc, char **argv, myargs *args) |
| { |
| while (1) { |
| int key; |
| |
| key = getopt_long(argc, argv, "cs:?V", long_options, NULL); |
| if (key == -1) |
| break; |
| |
| switch (key) { |
| case 'c': |
| err_msg("%s", copyright); |
| ABORT_ARGP; |
| break; |
| case 's': |
| args->side = get_update_side(optarg); |
| if (args->side < 0) { |
| err_msg("Unsupported seqnum: %s.\n" |
| "Supported seqnums are '0' " |
| "and '1'\n", optarg); |
| ERR_ARGP; |
| } |
| break; |
| case '?': /* help */ |
| err_msg("Usage: ubimirror [OPTION...] " |
| "<source> <destination>\n"); |
| err_msg("%s", doc); |
| err_msg("%s", optionsstr); |
| err_msg("\nReport bugs to %s\n", |
| PACKAGE_BUGREPORT); |
| exit(0); |
| break; |
| case 'V': |
| err_msg("%s", PROGRAM_VERSION); |
| exit(0); |
| break; |
| default: |
| err_msg("%s", usage); |
| exit(-1); |
| } |
| } |
| |
| while (optind < argc) { |
| /* only two entries allowed */ |
| if (args->vol_no >= VOL_ARGS_MAX) { |
| err_msg("%s", usage); |
| ERR_ARGP; |
| } |
| args->vol[(args->vol_no)++] = argv[optind++]; |
| } |
| |
| return 0; |
| } |
| |
| |
| int |
| main(int argc, char **argv) { |
| int rc = 0; |
| unsigned int ids[VOL_ARGS_MAX]; |
| char err_buf[1024]; |
| |
| myargs args = { |
| .action = ACT_NORMAL, |
| .side = -1, |
| .vol_no = 0, |
| .vol = {"", ""}, |
| .options = NULL, |
| }; |
| |
| parse_opt(argc, argv, &args); |
| if (args.action == ACT_ARGP_ERR) { |
| rc = 127; |
| goto err; |
| } |
| if (args.action == ACT_ARGP_ABORT) { |
| rc = 126; |
| goto out; |
| } |
| if (args.vol_no < VOL_ARGS_MAX) { |
| fprintf(stderr, "missing volume number for %s\n", |
| args.vol_no == 0 ? "source and target" : "target"); |
| rc = 125; |
| goto out; |
| } |
| for( rc = 0; rc < args.vol_no; ++rc){ |
| char *endp; |
| ids[rc] = strtoul(args.vol[rc], &endp, 0); |
| if( *endp != '\0' ){ |
| fprintf(stderr, "invalid volume number %s\n", |
| args.vol[rc]); |
| rc = 125; |
| goto out; |
| } |
| } |
| rc = ubimirror(EXAMPLE_UBI_DEVICE, args.side, ids, args.vol_no, |
| err_buf, sizeof(err_buf)); |
| if( rc ){ |
| err_buf[sizeof err_buf - 1] = '\0'; |
| fprintf(stderr, "%s", err_buf); |
| if( rc < 0 ) |
| rc = -rc; |
| } |
| out: |
| err: |
| return rc; |
| } |