diff mbox series

[3/3] diskpart: add handler to toggle boot flag

Message ID 20220410093518.308218-3-sbabic@denx.de
State Accepted
Headers show
Series [1/3] diskpart: factorize retrieving partition table type | expand

Commit Message

Stefano Babic April 10, 2022, 9:35 a.m. UTC
type = "toggleboot";
	properties {
		partition = <partition number>;
	}

Signed-off-by: Stefano Babic <sbabic@denx.de>
---
 doc/source/handlers.rst     |  18 ++++++
 handlers/diskpart_handler.c | 106 ++++++++++++++++++++++++++++++++++++
 2 files changed, 124 insertions(+)
diff mbox series

Patch

diff --git a/doc/source/handlers.rst b/doc/source/handlers.rst
index 95fb02d..8bf1f43 100644
--- a/doc/source/handlers.rst
+++ b/doc/source/handlers.rst
@@ -946,6 +946,24 @@  MBR Example:
 	   }
 	}
 
+Toggleboot Handler
+------------------
+
+This handler is a script handler. It turns on the bootflag for one of a disk partition
+if the partition table is DOS. It reports an error if the table is GPT.
+
+::
+
+	script: (
+	{
+	   type = "toggleboot";
+	   device = "/dev/sde";
+	   properties: {
+		partition = "1";
+           }
+        }
+
+	
 Diskformat Handler
 ------------------
 
diff --git a/handlers/diskpart_handler.c b/handlers/diskpart_handler.c
index 3cf7f6d..a6fe369 100644
--- a/handlers/diskpart_handler.c
+++ b/handlers/diskpart_handler.c
@@ -23,6 +23,7 @@ 
 #include "util.h"
 
 void diskpart_handler(void);
+void diskpart_toggle_boot(void);
 
 /*
  * This is taken from libfdisk to declare if a field is not set
@@ -1111,9 +1112,114 @@  handler_release:
 	return ret;
 }
 
+static int toggle_boot(struct img_type *img, void  *data)
+{
+
+	struct fdisk_context *cxt;
+	char *path;
+	int ret;
+	unsigned long partno;
+
+	struct script_handler_data *script_data;
+
+	if (!data)
+		return -1;
+
+	script_data = data;
+
+	if (script_data->scriptfn != POSTINSTALL)
+		return 0;
+
+	/*
+	 * Parse properties
+	 */
+	partno = strtoul(dict_get_value(&img->properties, "partition"), NULL, 10);
+
+	/*
+	 * Set is possible only for primary partitions
+	 */
+	if (partno > 4 || partno < 1) {
+		ERROR("Wrong partition number: %ld", partno);
+		return -EINVAL;
+	}
+
+	partno--;
+
+	cxt = fdisk_new_context();
+	if (!cxt) {
+		ERROR("Failed to allocate libfdisk context");
+		return -ENOMEM;
+	}
+	
+	/*
+	 * Resolve device path symlink.
+	 */
+	path = realpath(img->device, NULL);
+	if (!path)
+		path = strdup(img->device);
+
+	/*
+	 * fdisk_new_nested_context requires the device to be assigned.
+	 */
+	ret = fdisk_assign_device(cxt, path, 0);
+	free(path);
+	if (ret < 0) {
+		ERROR("Device %s cannot be opened: %s", img->device, strerror(-ret));
+		return ret;
+	}
+
+	if (!fdisk_is_label(cxt, DOS)) {
+		ERROR("Setting boot flag supported for DOS table only");
+		ret = -EINVAL;
+		goto toggle_boot_exit;
+	}
+
+	int nparts = fdisk_get_npartitions(cxt);
+
+	TRACE("Toggling Boot Flag for partition %ld", partno);
+
+	struct fdisk_partition *pa = NULL;
+	for (int i = 0; i < nparts; i++) {
+
+		if (fdisk_get_partition(cxt, i, &pa) != 0)
+			continue;
+
+		if (i != partno) {
+			if (fdisk_partition_is_bootable(pa))
+				fdisk_toggle_partition_flag(cxt, i, DOS_FLAG_ACTIVE);
+		} else {
+			if (!fdisk_partition_is_bootable(pa)) {
+				ret = fdisk_toggle_partition_flag(cxt, i, DOS_FLAG_ACTIVE);
+				if (ret)
+					ERROR("Setting boot flag for partition %d on %s FAILED", i, img->device);
+			}
+		}
+	}
+	fdisk_unref_partition(pa);
+
+	ret = fdisk_write_disklabel(cxt);
+
+toggle_boot_exit:
+	if (cxt && fdisk_get_devfd(cxt) >= 0) {
+		if (fdisk_deassign_device(cxt, 0))
+			WARN("Error deassign device %s", img->device);
+	}
+	if (cxt)
+		diskpart_unref_context(cxt);
+
+	return ret;
+}
+
 __attribute__((constructor))
 void diskpart_handler(void)
 {
 	register_handler("diskpart", diskpart,
 				PARTITION_HANDLER | NO_DATA_HANDLER, NULL);
 }
+
+__attribute__((constructor))
+void diskpart_toggle_boot(void)
+{
+	register_handler("toggleboot", toggle_boot,
+				SCRIPT_HANDLER | NO_DATA_HANDLER, NULL);
+}