| diff -Naur a/ubi-utils/Makefile b/ubi-utils/Makefile |
| --- a/ubi-utils/Makefile 2014-12-19 15:27:10.990583444 -0800 |
| +++ b/ubi-utils/Makefile 2014-12-19 14:52:57.462133419 -0800 |
| @@ -8,7 +8,7 @@ |
| CPPFLAGS += -Iinclude -Isrc -I$(KERNELHDR) |
| |
| LIBS = libubi libmtd libubigen libiniparser libscan |
| -TARGETS = ubiupdatevol ubimkvol ubirmvol ubicrc32 ubinfo ubiattach \ |
| +TARGETS = ubicpvol ubiupdatevol ubimkvol ubirmvol ubicrc32 ubinfo ubiattach \ |
| ubidetach ubinize ubiformat ubirename mtdinfo ubirsvol |
| |
| VPATH = src |
| diff -Naur a/ubi-utils/src/ubicpvol.c b/ubi-utils/src/ubicpvol.c |
| --- a/ubi-utils/src/ubicpvol.c 1969-12-31 16:00:00.000000000 -0800 |
| +++ b/ubi-utils/src/ubicpvol.c 2014-12-19 15:24:59.765776184 -0800 |
| @@ -0,0 +1,291 @@ |
| +/* |
| + * Based originally on the ubiupdatevol utility |
| + * Copyright (c) International Business Machines Corp., 2006 |
| + * Copyright (c) Google, Inc, 2014 |
| + * |
| + * 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. |
| + */ |
| + |
| +/* |
| + * A utility to replicate/copy UBI volumes. |
| + * |
| + * Authors: Frank Haverkamp |
| + * Joshua W. Boyer |
| + * Artem Bityutskiy |
| + * Peter van Vugt |
| + */ |
| + |
| +#include <fcntl.h> |
| +#include <stdio.h> |
| +#include <stdint.h> |
| +#include <getopt.h> |
| +#include <stdarg.h> |
| +#include <stdlib.h> |
| +#include <string.h> |
| +#include <unistd.h> |
| + |
| +#include <libubi.h> |
| +#include "common.h" |
| + |
| +#define PROGRAM_VERSION "1.0" |
| +#define PROGRAM_NAME "ubicpvol" |
| + |
| +struct args { |
| + const char *destNode; |
| + const char *srcNode; |
| +}; |
| + |
| +static struct args args; |
| + |
| +static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION |
| + " - a tool to replicate/copy UBI volumes.\n"; |
| + |
| +static const char *optionsstr = |
| +"Options:\n" |
| +"-h, --help print help message\n" |
| +"-V, --version print program version\n"; |
| + |
| +static const char *usage = |
| +"Usage: " PROGRAM_NAME " [OPTIONS] <UBI source volume node> <UBI destination volume node>\n\n" |
| +"Example: " PROGRAM_NAME " /dev/ubi0_1 /dev/ubi0_2 - copy UBI volume \"/dev/ubi0_1\" to \"/dev/ubi0_2\"\n"; |
| + |
| +static const char *notes = |
| +"Note that both volumes must have the same LEB size and the data in the source\n" |
| +"volume must fit into the destination volume.\n"; |
| + |
| +struct option long_options[] = { |
| + { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, |
| + { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, |
| + { NULL, 0, NULL, 0} |
| +}; |
| + |
| +static int parse_opt(int argc, char * const argv[]) |
| +{ |
| + while (1) { |
| + int key; |
| + |
| + key = getopt_long(argc, argv, "h?V", long_options, NULL); |
| + if (key == -1) |
| + break; |
| + |
| + switch (key) { |
| + case 'h': |
| + case '?': |
| + fprintf(stderr, "%s\n", doc); |
| + fprintf(stderr, "%s\n", usage); |
| + fprintf(stderr, "%s\n", optionsstr); |
| + fprintf(stderr, "%s\n", notes); |
| + exit(EXIT_SUCCESS); |
| + |
| + case 'V': |
| + fprintf(stderr, "%s\n", PROGRAM_VERSION); |
| + exit(EXIT_SUCCESS); |
| + |
| + case ':': |
| + return errmsg("parameter is missing"); |
| + |
| + default: |
| + fprintf(stderr, "Use -h for help\n"); |
| + return -1; |
| + } |
| + } |
| + |
| + if (optind != argc - 2) |
| + return errmsg("specify source and destination UBI device names as first 2 " |
| + "parameters (use -h for help)"); |
| + |
| + args.srcNode = argv[optind]; |
| + args.destNode = argv[optind + 1]; |
| + |
| + return 0; |
| +} |
| + |
| +static int ubi_write(int fd, const void *buf, int len) |
| +{ |
| + int ret; |
| + |
| + while (len) { |
| + ret = write(fd, buf, len); |
| + if (ret <= 0) { |
| + if (errno == EINTR) { |
| + warnmsg("do not interrupt me!"); |
| + continue; |
| + } |
| + return errmsg("error %d: cannot write %d bytes to volume \"%s\"", |
| + errno, len, args.destNode); |
| + } |
| + |
| + len -= ret; |
| + buf += ret; |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +static int copy_volume(libubi_t libubi, struct ubi_vol_info *src_vol_info, struct ubi_vol_info *dest_vol_info) |
| +{ |
| + int err, dest_fd, src_fd; |
| + long long bytes; |
| + char *buf; |
| + int ret = -1; |
| + |
| + if (src_vol_info->leb_size != dest_vol_info->leb_size) { |
| + return errmsg("source and destination volumes have different LEB sizes"); |
| + } else if (src_vol_info->data_bytes > dest_vol_info->rsvd_bytes) { |
| + return errmsg("source volume \"%s\" too large for destination volume \"%s\" (%lld > %lld)", args.srcNode, args.destNode, src_vol_info->data_bytes, dest_vol_info->rsvd_bytes); |
| + } |
| + |
| + buf = malloc(dest_vol_info->leb_size); |
| + if (!buf) |
| + return errmsg("cannot allocate %d bytes of memory", dest_vol_info->leb_size); |
| + |
| + bytes = src_vol_info->data_bytes; |
| + |
| + src_fd = open(args.srcNode, O_RDONLY); |
| + if (src_fd == -1) { |
| + errmsg("cannot open source UBI volume \"%s\"", args.srcNode); |
| + goto out_free; |
| + } |
| + |
| + dest_fd = open(args.destNode, O_RDWR); |
| + if (dest_fd == -1) { |
| + errmsg("cannot open destination UBI volume \"%s\"", args.destNode); |
| + goto out_close1; |
| + } |
| + |
| + err = ubi_update_start(libubi, dest_fd, bytes); |
| + if (err) { |
| + errmsg("cannot start volume \"%s\" update", args.destNode); |
| + goto out_close; |
| + } |
| + |
| + while (bytes) { |
| + int ret, to_copy = dest_vol_info->leb_size; |
| + |
| + if (to_copy > bytes) |
| + to_copy = bytes; |
| + |
| + ret = read(src_fd, buf, to_copy); |
| + if (ret <= 0) { |
| + if (errno == EINTR) { |
| + warnmsg("do not interrupt me!"); |
| + continue; |
| + } else { |
| + errmsg("cannot read %d bytes from \"%s\"", |
| + to_copy, args.srcNode); |
| + goto out_close; |
| + } |
| + } |
| + |
| + err = ubi_write(dest_fd, buf, ret); |
| + if (err) |
| + { |
| + errmsg("cannot write %d bytes to \"%s\"", ret, args.destNode); |
| + goto out_close; |
| + } |
| + bytes -= ret; |
| + |
| + fprintf(stdout, "\r" PROGRAM_NAME ": copied %lli%%", (100 - (100 * bytes / src_vol_info->data_bytes))); |
| + fflush(stdout); |
| + } |
| + fprintf(stdout, "\r" PROGRAM_NAME ": finished copying ubi%d:%s to ubi%d:%s\n", src_vol_info->dev_num, src_vol_info->name, dest_vol_info->dev_num, dest_vol_info->name); |
| + ret = 0; |
| + |
| +out_close: |
| + close(dest_fd); |
| +out_close1: |
| + close(src_fd); |
| +out_free: |
| + free(buf); |
| + return ret; |
| +} |
| + |
| +int main(int argc, char * const argv[]) |
| +{ |
| + int err; |
| + libubi_t libubi; |
| + struct ubi_vol_info src_vol_info, dest_vol_info; |
| + int ret = -1; |
| + |
| + err = parse_opt(argc, argv); |
| + if (err) |
| + return -1; |
| + |
| + libubi = libubi_open(); |
| + if (!libubi) { |
| + if (errno == 0) |
| + return errmsg("UBI is not present in the system"); |
| + else |
| + return errmsg("cannot open libubi"); |
| + } |
| + |
| + err = ubi_probe_node(libubi, args.srcNode); |
| + if (err == 1) { |
| + errmsg("Source node \"%s\" is a UBI device node, not a UBI volume node", |
| + args.srcNode); |
| + goto out_libubi; |
| + } else if (err < 0) { |
| + if (errno == ENODEV) |
| + errmsg("Source node \"%s\" is not a UBI volume node", args.srcNode); |
| + else |
| + errmsg("error while probing source node \"%s\"", args.srcNode); |
| + goto out_libubi; |
| + } |
| + |
| + err = ubi_probe_node(libubi, args.destNode); |
| + if (err == 1) { |
| + errmsg("Destination node \"%s\" is a UBI device node, not a UBI volume node", |
| + args.destNode); |
| + goto out_libubi; |
| + } else if (err < 0) { |
| + if (errno == ENODEV) |
| + errmsg("Destination node \"%s\" is not a UBI volume node", args.destNode); |
| + else |
| + errmsg("error while probing destination node \"%s\"", args.destNode); |
| + goto out_libubi; |
| + } |
| + |
| + err = ubi_get_vol_info(libubi, args.srcNode, &src_vol_info); |
| + if (err) { |
| + errmsg("cannot get information about source UBI volume \"%s\"", |
| + args.srcNode); |
| + goto out_libubi; |
| + } |
| + |
| + err = ubi_get_vol_info(libubi, args.destNode, &dest_vol_info); |
| + if (err) { |
| + errmsg("cannot get information about destination UBI volume \"%s\"", |
| + args.destNode); |
| + goto out_libubi; |
| + } |
| + |
| + if ((src_vol_info.dev_num == dest_vol_info.dev_num) && (src_vol_info.vol_id == dest_vol_info.vol_id)) { |
| + errmsg("Source and destination nodes \"%s\" and \"%s\" point to same volume", args.srcNode, args.destNode); |
| + goto out_libubi; |
| + } |
| + |
| + err = copy_volume(libubi, &src_vol_info, &dest_vol_info); |
| + if (err) |
| + { |
| + errmsg("copy failed, err=%d", args.srcNode, args.destNode, err); |
| + goto out_libubi; |
| + } |
| + |
| + ret = 0; |
| + |
| +out_libubi: |
| + libubi_close(libubi); |
| + return ret; |
| +} |
| diff -Naur a/ubi-utils/src/ubiupdatevol.c b/ubi-utils/src/ubiupdatevol.c |
| --- a/ubi-utils/src/ubiupdatevol.c 2010-01-15 09:12:24.000000000 -0800 |
| +++ b/ubi-utils/src/ubiupdatevol.c 2014-12-19 15:12:23.549163250 -0800 |
| @@ -283,10 +283,9 @@ |
| libubi = libubi_open(); |
| if (!libubi) { |
| if (errno == 0) |
| - errmsg("UBI is not present in the system"); |
| + return errmsg("UBI is not present in the system"); |
| else |
| - sys_errmsg("cannot open libubi"); |
| - goto out_libubi; |
| + return errmsg("cannot open libubi"); |
| } |
| |
| err = ubi_probe_node(libubi, args.node); |