diff mbox series

[[libubootenv] v3 3/3] handle protected mmcblk_boot_ devices

Message ID 20191011134808.5348-4-adrian.freihofer@siemens.com
State Accepted
Headers show
Series [[libubootenv] v3 3/3] handle protected mmcblk_boot_ devices | expand

Commit Message

Freihofer, Adrian Oct. 11, 2019, 1:48 p.m. UTC
Some block devices support physical write protection. The kernel
provides a standard interface to enable or disable protection in
/sys/class/block/*/force_ro.

This patch adds functionality to automatically detect these memory
types. If read-only mode is enabled on the partition on which the
uboot environment must be written, libubootenv temporarily switches
to read/write mode.ease enter the commit message for your changes.

Signed-off-by: Adrian Freihofer <adrian.freihofer@siemens.com>
---
 src/uboot_env.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)
diff mbox series

Patch

diff --git a/src/uboot_env.c b/src/uboot_env.c
index 726c433..b59b140 100644
--- a/src/uboot_env.c
+++ b/src/uboot_env.c
@@ -488,15 +488,92 @@  static int devread(struct uboot_ctx *ctx, unsigned int copy, void *data)
 	return ret;
 }
 
+static int fileprotect(struct uboot_flash_env *dev, bool on)
+{
+	const char c_sys_path_1[] = "/sys/class/block/";
+	const char c_sys_path_2[] = "/force_ro";
+	const char c_dev_name_1[] = "mmcblk";
+	const char c_dev_name_2[] = "boot";
+	const char c_unprot_char = '0';
+	const char c_prot_char = '1';
+	const char *devfile = dev->devname;
+	int ret = 0;  // 0 means OK, negative means error
+	int ret_int = 0;
+	char *sysfs_path = NULL;
+	int fd_force_ro;
+
+	// Devices without ro flag at /sys/class/block/mmcblk?boot?/force_ro are ignored
+	if (strncmp("/dev/", dev->devname, 5) == 0) {
+		devfile = dev->devname + 5;
+	} else {
+		return ret;
+	}
+
+	ret_int = strncmp(devfile, c_dev_name_1, sizeof(c_dev_name_1) - 1);
+	if (ret_int != 0) {
+		return ret;
+	}
+
+	if (strncmp(devfile + sizeof(c_dev_name_1), c_dev_name_2, sizeof(c_dev_name_2) - 1) != 0) {
+		return ret;
+	}
+
+	if (*(devfile + sizeof(c_dev_name_1) - 1) < '0' ||
+	    *(devfile + sizeof(c_dev_name_1) - 1) > '9') {
+		return ret;
+	}
+
+	if (*(devfile + sizeof(c_dev_name_1) + sizeof(c_dev_name_2) - 1) < '0' ||
+	    *(devfile + sizeof(c_dev_name_1) + sizeof(c_dev_name_2) - 1) > '9') {
+		return ret;
+	}
+
+	// There is a ro flag, the device needs to be protected or unprotected
+	ret_int = asprintf(&sysfs_path, "%s%s%s", c_sys_path_1, devfile, c_sys_path_2);
+	if(ret_int < 0) {
+		ret = -ENOMEM;
+		goto fileprotect_out;
+	}
+
+	if (access(sysfs_path, W_OK) == -1) {
+		goto fileprotect_out;
+	}
+
+	fd_force_ro = open(sysfs_path, O_RDWR);
+	if (fd_force_ro == -1) {
+		ret = -EBADF;
+		goto fileprotect_out;
+	}
+
+	if(on == false){
+		write(fd_force_ro, &c_unprot_char, 1);
+	} else {
+		fsync(dev->fd);
+		write(fd_force_ro, &c_prot_char, 1);
+	}
+	close(fd_force_ro);
+
+fileprotect_out:
+	if(sysfs_path)
+		free(sysfs_path);
+	return ret;
+}
+
 static int filewrite(struct uboot_flash_env *dev, void *data)
 {
 	int ret;
 
+	ret = fileprotect(dev, false);
+	if (ret < 0)
+		return ret;
+
 	if (dev->offset)
 		lseek(dev->fd, dev->offset, SEEK_SET);
 
 	ret = write(dev->fd, data, dev->envsize);
 
+	fileprotect(dev, true);  // no error handling, keep ret from write
+
 	return ret;
 }