diff mbox series

[v2,2/2] handlers: diskpart_handler.c: add install_gpt_partition_image

Message ID 20220616124055.2163867-2-philippe.reynes@softathome.com
State Changes Requested
Headers show
Series [v2,1/2] handlers: diskpart_handler.c: add handler for script gptswap | expand

Commit Message

Philippe REYNES June 16, 2022, 12:40 p.m. UTC
Add a handler to write in a GPT partition.
With the handler raw, the device of the parition is provided
to the raw handler. This handler use a device on the disk that
contains the GPT partition and the name of the GPT partition
to found the device of the partition to write.

For example:
images: (
	{
		filename = "u-boot.bin";
		type = "gptpart";
		device = "/dev/vdb";
		volume = "u-boot-1";
	},
	{
		filename = "kernel.bin";
		type = "gptpart";
		device = "/dev/vdb";
		volume = "kernel-1";
	},
);

Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
---

Changelog:
v2:
- rebase on master
- add a constructor to register the handler install_gpt_partition_image

 doc/source/handlers.rst     |  24 ++++++++
 handlers/diskpart_handler.c | 115 ++++++++++++++++++++++++++++++++++++
 2 files changed, 139 insertions(+)

Comments

Stefano Babic June 18, 2022, 9 a.m. UTC | #1
On 16.06.22 14:40, Philippe Reynes wrote:
> Add a handler to write in a GPT partition.
> With the handler raw, the device of the parition

                                       ^-- partition

  is provided
> to the raw handler. This handler use a device on the disk that
> contains the GPT partition and the name of the GPT partition
> to found the device of the partition to write.
> 
> For example:
> images: (
> 	{
> 		filename = "u-boot.bin";
> 		type = "gptpart";
> 		device = "/dev/vdb";
> 		volume = "u-boot-1";
> 	},
> 	{
> 		filename = "kernel.bin";
> 		type = "gptpart";
> 		device = "/dev/vdb";
> 		volume = "kernel-1";
> 	},
> );
> 
> Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
> ---
> 

IMO I think this can be reached better if you chain the handlers. This 
handler is in fact a frontend for the "raw" handler. It finds which is 
the device and, when this is found, it is convenient to call the raw 
handler.

I am thinking to some use cases that are drop by this implementation, 
for example if there is an offset:

  	{
  		filename = "u-boot.bin";
  		type = "gptpart";
  		device = "/dev/vdb";
  		volume = "u-boot-1";
		offset = "1024";
  	},

This can be reached easy if you:

	/* Find device + partition */
	partno = fdisk_partition_get_partno(pa);
	snprintf(node, sizeof(node), "%s%zu", img->device, partno + 1);

	/* set device for next handler */
	strlcpy(img->device, node, sizeof(img->device));
	strcpy(img->type, "raw");
	// well, we are then not limited to raw

	hnd = find_handler(img);
	if (hnd)
		==> hnd->installer(img,..);


What do you think ?

Best regards,
Stefano


> Changelog:
> v2:
> - rebase on master
> - add a constructor to register the handler install_gpt_partition_image
> 
>   doc/source/handlers.rst     |  24 ++++++++
>   handlers/diskpart_handler.c | 115 ++++++++++++++++++++++++++++++++++++
>   2 files changed, 139 insertions(+)
> 
> diff --git a/doc/source/handlers.rst b/doc/source/handlers.rst
> index 01ec221..029a70c 100644
> --- a/doc/source/handlers.rst
> +++ b/doc/source/handlers.rst
> @@ -963,6 +963,30 @@ if the partition table is DOS. It reports an error if the table is GPT.
>              }
>           }
>   
> +gpt partition installer
> +.......................
> +
> +There is a handler gptpart that allows writing an image into a gpt partition selected by
> +the name. This handler do not modify the gpt partition (type, size, ...), it just writes
> +the image in the GPT partition.
> +
> +::
> +
> +        images: (
> +                {
> +                        filename = "u-boot.bin";
> +                        type = "gptpart";
> +			device = "/dev/vdb";
> +                        volume = "u-boot-1";
> +                },
> +                {
> +                        filename = "kernel.bin";
> +                        type = "gptpart";
> +			device = "/dev/vdb";
> +                        volume = "kernel-1";
> +                },
> +        );
> +
>   gpt partition swap
>   ..................
>   
> diff --git a/handlers/diskpart_handler.c b/handlers/diskpart_handler.c
> index 925976b..7408ee6 100644
> --- a/handlers/diskpart_handler.c
> +++ b/handlers/diskpart_handler.c
> @@ -907,6 +907,114 @@ static int diskpart_reread_partition(char *device)
>   	return ret;
>   }
>   
> +static int install_gpt_partition_image(struct img_type *img,
> +				       void __attribute__ ((__unused__)) *data)
> +{
> +	struct fdisk_context *cxt = NULL;
> +	struct diskpart_table *tb = NULL;
> +	int ret = 0;
> +	unsigned long hybrid = 0;
> +	struct hnd_priv priv =  {
> +		.labeltype = FDISK_DISKLABEL_DOS,
> +	};
> +	struct create_table *createtable = NULL;
> +	struct fdisk_partition *pa;
> +	size_t partno;
> +        char node[64];
> +        int fdout;
> +
> +	LIST_INIT(&priv.listparts);
> +	if (!strlen(img->device)) {
> +		ERROR("Partition handler without setting the device");
> +		return -EINVAL;
> +	}
> +
> +	createtable = calloc(1, sizeof(*createtable));
> +	if (!createtable) {
> +		ERROR("OOM allocating createtable !");
> +		return -ENOMEM;
> +	}
> +
> +	/*
> +	 * Reads flags: nolock and noinuse
> +	 */
> +	priv.nolock = strtobool(dict_get_value(&img->properties, "nolock"));
> +	priv.noinuse = strtobool(dict_get_value(&img->properties, "noinuse"));
> +
> +        /*
> +         * Create context
> +         */
> +	ret = diskpart_assign_context(&cxt, img, priv, hybrid, createtable);
> +	if (ret == -EACCES)
> +		goto handler_release;
> +	else if (ret)
> +		goto handler_exit;
> +
> +	tb = calloc(1, sizeof(*tb));
> +	if (!tb) {
> +		ERROR("OOM loading partitions !");
> +		ret = -ENOMEM;
> +		goto handler_exit;
> +	}
> +
> +	/*
> +	 * Fill the in-memory partition table from the disk.
> +	 */
> +	ret = diskpart_get_partitions(cxt, tb, createtable);
> +	if (ret)
> +		goto handler_exit;
> +
> +	/*
> +	 * Search partition to update
> +	 */
> +	pa = diskpart_get_partition_by_name(tb, img->volname);
> +	if (!pa) {
> +		ERROR("Can't find partition %s", img->volname);
> +		ret = -1;
> +		goto handler_exit;
> +	}
> +
> +	/*
> +	 * Open the node of the partition
> +	 */
> +	partno = fdisk_partition_get_partno(pa);
> +	snprintf(node, sizeof(node), "%s%zu", img->device, partno + 1);
> +	fdout = open(node, O_RDWR);
> +	if (fdout < 0) {
> +		ERROR("Node %s cannot be opened", node);
> +		ret = -1;
> +		goto handler_exit;
> +	}
> +
> +	/*
> +	 * Write image
> +	 */
> +	if (copyimage(&fdout, img, NULL) < 0) {
> +		ERROR("Error copying extracted file");
> +		ret = -1;
> +		goto handler_close;
> +	}
> +
> +handler_close:
> +        close(fdout);
> +
> +handler_exit:
> +	if (tb)
> +		diskpart_unref_table(tb);
> +	if (cxt && fdisk_get_devfd(cxt) >= 0)
> +		if (fdisk_deassign_device(cxt, 0))
> +			WARN("Error deassign device %s", img->device);
> +
> +handler_release:
> +	if (cxt)
> +		diskpart_unref_context(cxt);
> +
> +	if (createtable)
> +		free(createtable);
> +
> +	return ret;
> +}
> +
>   static int diskpart(struct img_type *img,
>   	void __attribute__ ((__unused__)) *data)
>   {
> @@ -1472,3 +1580,10 @@ void diskpart_gpt_swap_partition(void)
>   	register_handler("gptswap", gpt_swap_partition,
>   			 SCRIPT_HANDLER | NO_DATA_HANDLER, NULL);
>   }
> +
> +__attribute__((constructor))
> +void diskpart_install_gpt_partition_image(void)
> +{
> +	register_handler("gptpart", install_gpt_partition_image,
> +			 IMAGE_HANDLER, NULL);
> +}
Philippe REYNES June 21, 2022, 5:47 p.m. UTC | #2
Hi Stefano,


Le 18/06/2022 à 11:00, Stefano Babic a écrit :
>
>
> On 16.06.22 14:40, Philippe Reynes wrote:
>> Add a handler to write in a GPT partition.
>> With the handler raw, the device of the parition
>
>                                       ^-- partition
>
>  is provided
>> to the raw handler. This handler use a device on the disk that
>> contains the GPT partition and the name of the GPT partition
>> to found the device of the partition to write.
>>
>> For example:
>> images: (
>>     {
>>         filename = "u-boot.bin";
>>         type = "gptpart";
>>         device = "/dev/vdb";
>>         volume = "u-boot-1";
>>     },
>>     {
>>         filename = "kernel.bin";
>>         type = "gptpart";
>>         device = "/dev/vdb";
>>         volume = "kernel-1";
>>     },
>> );
>>
>> Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
>> ---
>>
>
> IMO I think this can be reached better if you chain the handlers. This 
> handler is in fact a frontend for the "raw" handler. It finds which is 
> the device and, when this is found, it is convenient to call the raw 
> handler.
>
> I am thinking to some use cases that are drop by this implementation, 
> for example if there is an offset:
>
>      {
>          filename = "u-boot.bin";
>          type = "gptpart";
>          device = "/dev/vdb";
>          volume = "u-boot-1";
>         offset = "1024";
>      },
>
> This can be reached easy if you:
>
>     /* Find device + partition */
>     partno = fdisk_partition_get_partno(pa);
>     snprintf(node, sizeof(node), "%s%zu", img->device, partno + 1);
>
>     /* set device for next handler */
>     strlcpy(img->device, node, sizeof(img->device));
>     strcpy(img->type, "raw");
>     // well, we are then not limited to raw
>
>     hnd = find_handler(img);
>     if (hnd)
>         ==> hnd->installer(img,..);
>
>
> What do you think ?
>

I think that you are right. It is interesting to chain on raw handler.

Thanks for this idea/feedback.

I just sent a v3 of my patches with this change (and some little cleaning).


> Best regards,
> Stefano
>

Best regards,

Philippe



>
>> Changelog:
>> v2:
>> - rebase on master
>> - add a constructor to register the handler install_gpt_partition_image
>>
>>   doc/source/handlers.rst     |  24 ++++++++
>>   handlers/diskpart_handler.c | 115 ++++++++++++++++++++++++++++++++++++
>>   2 files changed, 139 insertions(+)
>>
>> diff --git a/doc/source/handlers.rst b/doc/source/handlers.rst
>> index 01ec221..029a70c 100644
>> --- a/doc/source/handlers.rst
>> +++ b/doc/source/handlers.rst
>> @@ -963,6 +963,30 @@ if the partition table is DOS. It reports an 
>> error if the table is GPT.
>>              }
>>           }
>>   +gpt partition installer
>> +.......................
>> +
>> +There is a handler gptpart that allows writing an image into a gpt 
>> partition selected by
>> +the name. This handler do not modify the gpt partition (type, size, 
>> ...), it just writes
>> +the image in the GPT partition.
>> +
>> +::
>> +
>> +        images: (
>> +                {
>> +                        filename = "u-boot.bin";
>> +                        type = "gptpart";
>> +            device = "/dev/vdb";
>> +                        volume = "u-boot-1";
>> +                },
>> +                {
>> +                        filename = "kernel.bin";
>> +                        type = "gptpart";
>> +            device = "/dev/vdb";
>> +                        volume = "kernel-1";
>> +                },
>> +        );
>> +
>>   gpt partition swap
>>   ..................
>>   diff --git a/handlers/diskpart_handler.c b/handlers/diskpart_handler.c
>> index 925976b..7408ee6 100644
>> --- a/handlers/diskpart_handler.c
>> +++ b/handlers/diskpart_handler.c
>> @@ -907,6 +907,114 @@ static int diskpart_reread_partition(char *device)
>>       return ret;
>>   }
>>   +static int install_gpt_partition_image(struct img_type *img,
>> +                       void __attribute__ ((__unused__)) *data)
>> +{
>> +    struct fdisk_context *cxt = NULL;
>> +    struct diskpart_table *tb = NULL;
>> +    int ret = 0;
>> +    unsigned long hybrid = 0;
>> +    struct hnd_priv priv =  {
>> +        .labeltype = FDISK_DISKLABEL_DOS,
>> +    };
>> +    struct create_table *createtable = NULL;
>> +    struct fdisk_partition *pa;
>> +    size_t partno;
>> +        char node[64];
>> +        int fdout;
>> +
>> +    LIST_INIT(&priv.listparts);
>> +    if (!strlen(img->device)) {
>> +        ERROR("Partition handler without setting the device");
>> +        return -EINVAL;
>> +    }
>> +
>> +    createtable = calloc(1, sizeof(*createtable));
>> +    if (!createtable) {
>> +        ERROR("OOM allocating createtable !");
>> +        return -ENOMEM;
>> +    }
>> +
>> +    /*
>> +     * Reads flags: nolock and noinuse
>> +     */
>> +    priv.nolock = strtobool(dict_get_value(&img->properties, 
>> "nolock"));
>> +    priv.noinuse = strtobool(dict_get_value(&img->properties, 
>> "noinuse"));
>> +
>> +        /*
>> +         * Create context
>> +         */
>> +    ret = diskpart_assign_context(&cxt, img, priv, hybrid, 
>> createtable);
>> +    if (ret == -EACCES)
>> +        goto handler_release;
>> +    else if (ret)
>> +        goto handler_exit;
>> +
>> +    tb = calloc(1, sizeof(*tb));
>> +    if (!tb) {
>> +        ERROR("OOM loading partitions !");
>> +        ret = -ENOMEM;
>> +        goto handler_exit;
>> +    }
>> +
>> +    /*
>> +     * Fill the in-memory partition table from the disk.
>> +     */
>> +    ret = diskpart_get_partitions(cxt, tb, createtable);
>> +    if (ret)
>> +        goto handler_exit;
>> +
>> +    /*
>> +     * Search partition to update
>> +     */
>> +    pa = diskpart_get_partition_by_name(tb, img->volname);
>> +    if (!pa) {
>> +        ERROR("Can't find partition %s", img->volname);
>> +        ret = -1;
>> +        goto handler_exit;
>> +    }
>> +
>> +    /*
>> +     * Open the node of the partition
>> +     */
>> +    partno = fdisk_partition_get_partno(pa);
>> +    snprintf(node, sizeof(node), "%s%zu", img->device, partno + 1);
>> +    fdout = open(node, O_RDWR);
>> +    if (fdout < 0) {
>> +        ERROR("Node %s cannot be opened", node);
>> +        ret = -1;
>> +        goto handler_exit;
>> +    }
>> +
>> +    /*
>> +     * Write image
>> +     */
>> +    if (copyimage(&fdout, img, NULL) < 0) {
>> +        ERROR("Error copying extracted file");
>> +        ret = -1;
>> +        goto handler_close;
>> +    }
>> +
>> +handler_close:
>> +        close(fdout);
>> +
>> +handler_exit:
>> +    if (tb)
>> +        diskpart_unref_table(tb);
>> +    if (cxt && fdisk_get_devfd(cxt) >= 0)
>> +        if (fdisk_deassign_device(cxt, 0))
>> +            WARN("Error deassign device %s", img->device);
>> +
>> +handler_release:
>> +    if (cxt)
>> +        diskpart_unref_context(cxt);
>> +
>> +    if (createtable)
>> +        free(createtable);
>> +
>> +    return ret;
>> +}
>> +
>>   static int diskpart(struct img_type *img,
>>       void __attribute__ ((__unused__)) *data)
>>   {
>> @@ -1472,3 +1580,10 @@ void diskpart_gpt_swap_partition(void)
>>       register_handler("gptswap", gpt_swap_partition,
>>                SCRIPT_HANDLER | NO_DATA_HANDLER, NULL);
>>   }
>> +
>> +__attribute__((constructor))
>> +void diskpart_install_gpt_partition_image(void)
>> +{
>> +    register_handler("gptpart", install_gpt_partition_image,
>> +             IMAGE_HANDLER, NULL);
>> +}
diff mbox series

Patch

diff --git a/doc/source/handlers.rst b/doc/source/handlers.rst
index 01ec221..029a70c 100644
--- a/doc/source/handlers.rst
+++ b/doc/source/handlers.rst
@@ -963,6 +963,30 @@  if the partition table is DOS. It reports an error if the table is GPT.
            }
         }
 
+gpt partition installer
+.......................
+
+There is a handler gptpart that allows writing an image into a gpt partition selected by
+the name. This handler do not modify the gpt partition (type, size, ...), it just writes
+the image in the GPT partition.
+
+::
+
+        images: (
+                {
+                        filename = "u-boot.bin";
+                        type = "gptpart";
+			device = "/dev/vdb";
+                        volume = "u-boot-1";
+                },
+                {
+                        filename = "kernel.bin";
+                        type = "gptpart";
+			device = "/dev/vdb";
+                        volume = "kernel-1";
+                },
+        );
+
 gpt partition swap
 ..................
 
diff --git a/handlers/diskpart_handler.c b/handlers/diskpart_handler.c
index 925976b..7408ee6 100644
--- a/handlers/diskpart_handler.c
+++ b/handlers/diskpart_handler.c
@@ -907,6 +907,114 @@  static int diskpart_reread_partition(char *device)
 	return ret;
 }
 
+static int install_gpt_partition_image(struct img_type *img,
+				       void __attribute__ ((__unused__)) *data)
+{
+	struct fdisk_context *cxt = NULL;
+	struct diskpart_table *tb = NULL;
+	int ret = 0;
+	unsigned long hybrid = 0;
+	struct hnd_priv priv =  {
+		.labeltype = FDISK_DISKLABEL_DOS,
+	};
+	struct create_table *createtable = NULL;
+	struct fdisk_partition *pa;
+	size_t partno;
+        char node[64];
+        int fdout;
+
+	LIST_INIT(&priv.listparts);
+	if (!strlen(img->device)) {
+		ERROR("Partition handler without setting the device");
+		return -EINVAL;
+	}
+
+	createtable = calloc(1, sizeof(*createtable));
+	if (!createtable) {
+		ERROR("OOM allocating createtable !");
+		return -ENOMEM;
+	}
+
+	/*
+	 * Reads flags: nolock and noinuse
+	 */
+	priv.nolock = strtobool(dict_get_value(&img->properties, "nolock"));
+	priv.noinuse = strtobool(dict_get_value(&img->properties, "noinuse"));
+
+        /*
+         * Create context
+         */
+	ret = diskpart_assign_context(&cxt, img, priv, hybrid, createtable);
+	if (ret == -EACCES)
+		goto handler_release;
+	else if (ret)
+		goto handler_exit;
+
+	tb = calloc(1, sizeof(*tb));
+	if (!tb) {
+		ERROR("OOM loading partitions !");
+		ret = -ENOMEM;
+		goto handler_exit;
+	}
+
+	/*
+	 * Fill the in-memory partition table from the disk.
+	 */
+	ret = diskpart_get_partitions(cxt, tb, createtable);
+	if (ret)
+		goto handler_exit;
+
+	/*
+	 * Search partition to update
+	 */
+	pa = diskpart_get_partition_by_name(tb, img->volname);
+	if (!pa) {
+		ERROR("Can't find partition %s", img->volname);
+		ret = -1;
+		goto handler_exit;
+	}
+
+	/*
+	 * Open the node of the partition
+	 */
+	partno = fdisk_partition_get_partno(pa);
+	snprintf(node, sizeof(node), "%s%zu", img->device, partno + 1);
+	fdout = open(node, O_RDWR);
+	if (fdout < 0) {
+		ERROR("Node %s cannot be opened", node);
+		ret = -1;
+		goto handler_exit;
+	}
+
+	/*
+	 * Write image
+	 */
+	if (copyimage(&fdout, img, NULL) < 0) {
+		ERROR("Error copying extracted file");
+		ret = -1;
+		goto handler_close;
+	}
+
+handler_close:
+        close(fdout);
+
+handler_exit:
+	if (tb)
+		diskpart_unref_table(tb);
+	if (cxt && fdisk_get_devfd(cxt) >= 0)
+		if (fdisk_deassign_device(cxt, 0))
+			WARN("Error deassign device %s", img->device);
+
+handler_release:
+	if (cxt)
+		diskpart_unref_context(cxt);
+
+	if (createtable)
+		free(createtable);
+
+	return ret;
+}
+
 static int diskpart(struct img_type *img,
 	void __attribute__ ((__unused__)) *data)
 {
@@ -1472,3 +1580,10 @@  void diskpart_gpt_swap_partition(void)
 	register_handler("gptswap", gpt_swap_partition,
 			 SCRIPT_HANDLER | NO_DATA_HANDLER, NULL);
 }
+
+__attribute__((constructor))
+void diskpart_install_gpt_partition_image(void)
+{
+	register_handler("gptpart", install_gpt_partition_image,
+			 IMAGE_HANDLER, NULL);
+}