summaryrefslogtreecommitdiff
path: root/libubi/libubi-tiny.c
diff options
context:
space:
mode:
Diffstat (limited to 'libubi/libubi-tiny.c')
-rw-r--r--libubi/libubi-tiny.c315
1 files changed, 315 insertions, 0 deletions
diff --git a/libubi/libubi-tiny.c b/libubi/libubi-tiny.c
new file mode 100644
index 0000000..d726801
--- /dev/null
+++ b/libubi/libubi-tiny.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * An utility to delete UBI devices (detach MTD devices from UBI).
+ *
+ * Author: Artem Bityutskiy
+ */
+
+#define PROGRAM_NAME "ubidetach"
+#define VERSION "owrt-fstools"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "libubi-tiny.h"
+
+#define DEFAULT_CTRL_DEV "/dev/ubi_ctrl"
+
+static int ubi_write(char *node, int fd, const void *buf, int len)
+{
+ int ret;
+
+ while (len) {
+ ret = write(fd, buf, len);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ fprintf(stderr, "do not interrupt me!");
+ continue;
+ }
+ fprintf(stderr, "cannot write %d bytes to volume \"%s\"", len, node);
+ return -1;
+ }
+
+ if (ret == 0) {
+ fprintf(stderr, "cannot write %d bytes to volume \"%s\"", len, node);
+ return -1;
+ }
+ len -= ret;
+ buf += ret;
+ }
+
+ return 0;
+}
+
+static int update_volume(libubi_t libubi, struct ubi_vol_info *vol_info, char *node, char *img, int skip)
+{
+ int err, fd, ifd;
+ long long bytes;
+ char *buf;
+ struct stat st;
+
+ buf = malloc(vol_info->leb_size);
+ if (!buf) {
+ fprintf(stderr, "cannot allocate %d bytes of memory", vol_info->leb_size);
+ return -1;
+ }
+ err = stat(img, &st);
+ if (err < 0) {
+ fprintf(stderr, "stat failed on \"%s\"", img);
+ goto out_free;
+ }
+
+ bytes = st.st_size - skip;
+
+ if (bytes > vol_info->rsvd_bytes) {
+ fprintf(stderr, "\"%s\" (size %lld) will not fit volume \"%s\" (size %lld)",
+ img, bytes, node, vol_info->rsvd_bytes);
+ goto out_free;
+ }
+
+ fd = open(node, O_RDWR);
+ if (fd == -1) {
+ fprintf(stderr, "cannot open UBI volume \"%s\"", node);
+ goto out_free;
+ }
+
+ ifd = open(img, O_RDONLY);
+ if (ifd == -1) {
+ fprintf(stderr, "cannot open \"%s\"", img);
+ goto out_close1;
+ }
+
+ if (skip && lseek(ifd, skip, SEEK_CUR) == -1) {
+ fprintf(stderr, "lseek input by %d failed", skip);
+ goto out_close;
+ }
+
+ err = ubi_update_start(libubi, fd, bytes);
+ if (err) {
+ fprintf(stderr, "cannot start volume \"%s\" update", node);
+ goto out_close;
+ }
+
+ while (bytes) {
+ ssize_t ret;
+ int to_copy = vol_info->leb_size;
+ if (to_copy > bytes)
+ to_copy = bytes;
+
+ ret = read(ifd, buf, to_copy);
+ if (ret <= 0) {
+ if (errno == EINTR) {
+ fprintf(stderr, "do not interrupt me!");
+ continue;
+ } else {
+ fprintf(stderr, "cannot read %d bytes from \"%s\"",
+ to_copy, img);
+ goto out_close;
+ }
+ }
+
+ err = ubi_write(node, fd, buf, ret);
+ if (err)
+ goto out_close;
+ bytes -= ret;
+ }
+
+ close(ifd);
+ close(fd);
+ free(buf);
+ return 0;
+
+out_close:
+ close(ifd);
+out_close1:
+ close(fd);
+out_free:
+ free(buf);
+ return -1;
+}
+
+int ubiattach(libubi_t libubi, char *mtd)
+{
+ struct ubi_attach_request req = {
+ .dev_num = UBI_DEV_NUM_AUTO,
+ .mtd_num = -1,
+ .vid_hdr_offset = 0,
+ .max_beb_per1024 = 0,
+ .mtd_dev_node = mtd,
+ };
+ int err = ubi_attach(libubi, DEFAULT_CTRL_DEV, &req);
+
+ if (err) {
+ fprintf(stderr, "cannot attach \"%s\"", mtd);
+ return err;
+ }
+
+ return 0;
+}
+
+int ubidetach(libubi_t libubi, char *mtd)
+{
+ return ubi_detach(libubi, DEFAULT_CTRL_DEV, mtd);
+}
+
+int ubirsvol(libubi_t libubi, char *node, char *name, int bytes)
+{
+ struct ubi_dev_info dev_info;
+ struct ubi_vol_info vol_info;
+ int err = ubi_get_dev_info(libubi, node, &dev_info);
+
+ if (err) {
+ fprintf(stderr, "cannot get information about UBI device \"%s\"",
+ node);
+ return -1;
+ }
+ err = ubi_get_vol_info1_nm(libubi, dev_info.dev_num, name, &vol_info);
+ if (err) {
+ fprintf(stderr, "cannot find UBI volume \"%s\"", name);
+ return -1;
+ }
+
+ err = ubi_rsvol(libubi, node, vol_info.vol_id, bytes);
+ if (err) {
+ fprintf(stderr, "cannot UBI resize volume");
+ return -1;
+ }
+
+ return 0;
+}
+
+int ubirmvol(libubi_t libubi, char *node, char *name)
+{
+ struct ubi_dev_info dev_info;
+ struct ubi_vol_info vol_info;
+ int err = ubi_get_dev_info(libubi, node, &dev_info);
+
+ if (err) {
+ fprintf(stderr, "cannot get information about UBI device \"%s\"",
+ node);
+ return -1;
+ }
+
+ err = ubi_get_vol_info1_nm(libubi, dev_info.dev_num, name, &vol_info);
+ if (err) {
+ fprintf(stderr, "cannot find UBI volume \"%s\"", name);
+ return -1;
+ }
+
+ err = ubi_rmvol(libubi, node, vol_info.vol_id);
+ if (err) {
+ fprintf(stderr, "cannot UBI remove volume");
+ return -1;
+ }
+
+ return 0;
+}
+
+int ubimkvol(libubi_t libubi, char *node, char *name, int maxavs)
+{
+ struct ubi_dev_info dev_info;
+ struct ubi_vol_info vol_info;
+ struct ubi_mkvol_request req;
+ int err = ubi_get_dev_info(libubi, node, &dev_info);
+
+ if (err) {
+ fprintf(stderr, "cannot get information about UBI device \"%s\"",
+ node);
+ return -1;
+ }
+
+ if (dev_info.avail_bytes == 0) {
+ fprintf(stderr, "UBI device does not have free logical eraseblocks");
+ return -1;
+ }
+
+ if (maxavs)
+ printf("Set volume size to %lld\n", dev_info.avail_bytes);
+
+ req.vol_id = UBI_VOL_NUM_AUTO;
+ req.alignment = 1;
+ req.bytes = dev_info.avail_bytes;
+ req.vol_type = UBI_DYNAMIC_VOLUME;
+ req.name = name;
+
+ err = ubi_mkvol(libubi, node, &req);
+ if (err < 0) {
+ fprintf(stderr, "cannot UBI create volume");
+ return -1;
+ }
+
+ /* Print information about the created device */
+ err = ubi_get_vol_info1(libubi, dev_info.dev_num, req.vol_id, &vol_info);
+ if (err) {
+ fprintf(stderr, "cannot get information about newly created UBI volume");
+ return -1;
+ }
+
+ printf("Volume ID %d, size %d LEBs (", vol_info.vol_id, vol_info.rsvd_lebs);
+ ubiutils_print_bytes(vol_info.rsvd_bytes, 0);
+ printf("), LEB size ");
+ ubiutils_print_bytes(vol_info.leb_size, 1);
+ printf(", %s, name \"%s\", alignment %d\n",
+ req.vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static",
+ vol_info.name, vol_info.alignment);
+
+ return 0;
+}
+
+int ubiupdatevol(libubi_t libubi, char *node, char *file)
+{
+ struct ubi_vol_info vol_info;
+ int err = ubi_get_vol_info(libubi, node, &vol_info);
+
+ if (err) {
+ fprintf(stderr, "cannot get information about UBI volume \"%s\"",
+ node);
+ return -1;
+ }
+
+ return update_volume(libubi, &vol_info, node, file, 0);
+}
+
+int ubitruncatevol(libubi_t libubi, char *node)
+{
+ int err, fd;
+
+ fd = open(node, O_RDWR);
+ if (fd == -1) {
+ fprintf(stderr, "cannot open \"%s\"", node);
+ return -1;
+ }
+
+ err = ubi_update_start(libubi, fd, 0);
+ if (err) {
+ fprintf(stderr, "cannot truncate volume \"%s\"", node);
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}