blob: 77a7a3077d48e0992acf7f96364e2e34dc6d71ba [file] [log] [blame]
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);