From 6e2630a0fc872d0db34157972f6dc3941f6d66dd Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Mon, 19 May 2014 21:38:01 +0200
Subject: [PATCH] tools/env: add support for env in ubi volume chardev

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
 tools/env/Makefile |  5 ++++
 tools/env/fw_env.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 71 insertions(+), 10 deletions(-)

--- a/tools/env/Makefile
+++ b/tools/env/Makefile
@@ -24,6 +24,13 @@ ifeq ($(MTD_VERSION),old)
 HOST_EXTRACFLAGS += -DMTD_OLD
 endif
 
+ifeq ($(UBI),y)
+HOST_EXTRACFLAGS += -DUBI
+HOST_LOADLIBES = "-Wl,--gc-sections,-lubi-utils"
+else
+HOST_LOADLIBES = "-Wl,--gc-sections"
+endif
+
 always := fw_printenv
 hostprogs-y := fw_printenv
 
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -30,6 +30,9 @@
 # include <mtd/mtd-user.h>
 #endif
 
+#ifdef UBI
+# include <libubi.h>
+#endif
 #include "fw_env.h"
 
 #include <aes.h>
@@ -810,6 +813,11 @@ static int flash_write_buf (int dev, int
 	off_t top_of_range;	/* end of the last block we may use */
 	loff_t blockstart;	/* running start of the current block -
 				   MEMGETBADBLOCK needs 64 bits */
+#ifdef UBI
+	libubi_t *libubi = NULL;/* pointer to libubi struct */
+#else
+	void *libubi = NULL;
+#endif
 	int rc;
 
 	/*
@@ -915,7 +923,30 @@ static int flash_write_buf (int dev, int
 			continue;
 		}
 
-		if (mtd_type != MTD_ABSENT) {
+#ifdef UBI
+		if (mtd_type == MTD_UBIVOLUME) {
+			struct ubi_vol_info volinfo;
+			libubi = libubi_open();
+			if (libubi)
+				rc = ubi_get_vol_info(libubi,
+					DEVNAME(dev_current), &volinfo);
+			if (libubi && !rc) {
+				erasesize = volinfo.leb_size;
+				int leb = blockstart / erasesize;
+				if (volinfo.type != UBI_STATIC_VOLUME)
+					rc = ubi_leb_change_start(libubi, fd,
+						leb, erasesize);
+				else
+					rc = ubi_update_start(libubi, fd,
+						erasesize);
+			}
+			if (libubi && rc) {
+				libubi_close(libubi);
+				libubi = NULL;
+			}
+		}
+#endif
+		if (!libubi && mtd_type != MTD_ABSENT) {
 			erase.start = blockstart;
 			ioctl(fd, MEMUNLOCK, &erase);
 			/* These do not need an explicit erase cycle */
@@ -932,7 +963,8 @@ static int flash_write_buf (int dev, int
 			fprintf (stderr,
 				 "Seek error on %s: %s\n",
 				 DEVNAME (dev), strerror (errno));
-			return -1;
+			processed = -1;
+			goto out;
 		}
 
 #ifdef DEBUG
@@ -942,10 +974,11 @@ static int flash_write_buf (int dev, int
 		if (write (fd, data + processed, erasesize) != erasesize) {
 			fprintf (stderr, "Write error on %s: %s\n",
 				 DEVNAME (dev), strerror (errno));
-			return -1;
+			processed = -1;
+			goto out;
 		}
 
-		if (mtd_type != MTD_ABSENT)
+		if (!libubi && mtd_type != MTD_ABSENT)
 			ioctl(fd, MEMLOCK, &erase);
 
 		processed  += erasesize;
@@ -956,6 +989,11 @@ static int flash_write_buf (int dev, int
 	if (write_total > count)
 		free (data);
 
+out:
+#ifdef UBI
+	if (libubi)
+		libubi_close(libubi);
+#endif
 	return processed;
 }
 
@@ -1067,12 +1105,8 @@ static int flash_read (int fd)
 
 	if (S_ISCHR(st.st_mode)) {
 		rc = ioctl(fd, MEMGETINFO, &mtdinfo);
-		if (rc < 0) {
-			fprintf(stderr, "Cannot get MTD information for %s\n",
-				DEVNAME(dev_current));
-			return -1;
-		}
-		if (mtdinfo.type != MTD_NORFLASH &&
+		if (!rc &&
+		    mtdinfo.type != MTD_NORFLASH &&
 		    mtdinfo.type != MTD_NANDFLASH &&
 		    mtdinfo.type != MTD_DATAFLASH &&
 		    mtdinfo.type != MTD_UBIVOLUME) {
@@ -1080,6 +1114,28 @@ static int flash_read (int fd)
 				 mtdinfo.type, DEVNAME(dev_current));
 			return -1;
 		}
+#ifdef UBI
+		if (rc) {
+			libubi_t *libubi;
+			struct ubi_vol_info volinfo;
+			libubi = libubi_open();
+			if (!libubi)
+				return -ENOMEM;
+
+			rc = ubi_get_vol_info(libubi, DEVNAME(dev_current),
+						&volinfo);
+			if (rc) {
+				libubi_close(libubi);
+				return -ENODEV;
+			}
+			memset(&mtdinfo, 0, sizeof(mtdinfo));
+			mtdinfo.type = MTD_UBIVOLUME;
+			mtdinfo.size = volinfo.data_bytes;
+			mtdinfo.erasesize = volinfo.leb_size;
+			mtdinfo.writesize = volinfo.leb_size;
+			libubi_close(libubi);
+		}
+#endif
 	} else {
 		memset(&mtdinfo, 0, sizeof(mtdinfo));
 		mtdinfo.type = MTD_ABSENT;
