diff mbox series

[2/2] handler: handler for operation on BTRFS

Message ID 20230512125211.160912-2-sbabic@denx.de
State Accepted
Delegated to: Stefano Babic
Headers show
Series [1/2] diskpart: add support for btrfs filesystem | expand

Commit Message

Stefano Babic May 12, 2023, 12:52 p.m. UTC
Add an handler that works as wrapper for libbtrfsutil and add support to
sw-description. Creation / deletion of subvolumes are supported.

Signed-off-by: Stefano Babic <sbabic@denx.de>
---
 doc/source/handlers.rst  |  27 +++++++++-
 handlers/Makefile        |   1 +
 handlers/btrfs_handler.c | 105 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 132 insertions(+), 1 deletion(-)
 create mode 100644 handlers/btrfs_handler.c
diff mbox series

Patch

diff --git a/doc/source/handlers.rst b/doc/source/handlers.rst
index 1ee09e0..06999e6 100644
--- a/doc/source/handlers.rst
+++ b/doc/source/handlers.rst
@@ -985,7 +985,8 @@  supported:
    | fstype      | string   | Optional filesystem type to be created on the      |
    |             |          | partition. If no fstype key is given, no file      |
    |             |          | will be created on the corresponding partition.    |
-   |             |          | vfat / ext2 / ext3 /ext4 file system is supported  |
+   |             |          | vfat / ext2 / ext3 /ext4 / btrfs                   | 
+   |             |          | file system is supported                           | 
    +-------------+----------+----------------------------------------------------+
    | partuuid    | string   | The partition UUID (GPT only). If omitted, a UUID  |
    |             |          | will be generated automatically.			 |
@@ -1152,6 +1153,30 @@  found on the device. It is a partition handler and it runs before any image is i
 		}
 	});
 
+BTRFS Handler
+-------------
+
+This handler is activated if support for BTRFS is on. It allows to created and delete subvolumes
+during an update.
+
+::
+
+	partitions: (
+	{
+		type = "btrfs";
+		device = "/dev/loop0p1";
+
+		properties: {
+			command = < one of create" or "delete" >
+			path = <path for the subvolume>;
+                        mount = "true" or missing;
+		}
+	})
+
+
+If `mount` is set, SWUpdate will mount the device and the path is appenden to the
+mountpoint used with mount. If device is already mounted, path is the absolute path.
+
 Delta Update Handler
 --------------------
 
diff --git a/handlers/Makefile b/handlers/Makefile
index 847d59f..b5203f9 100644
--- a/handlers/Makefile
+++ b/handlers/Makefile
@@ -10,6 +10,7 @@ 
 obj-y	+= dummy_handler.o chain_handler.o
 obj-$(CONFIG_ARCHIVE) += archive_handler.o
 obj-$(CONFIG_BOOTLOADERHANDLER) += boot_handler.o
+obj-$(CONFIG_BTRFS_FILESYSTEM) += btrfs_handler.o
 obj-$(CONFIG_COPY) += copy_handler.o
 obj-$(CONFIG_CFI)	+= flash_handler.o
 obj-$(CONFIG_DELTA)	+= delta_handler.o delta_downloader.o zchunk_range.o
diff --git a/handlers/btrfs_handler.c b/handlers/btrfs_handler.c
new file mode 100644
index 0000000..517f753
--- /dev/null
+++ b/handlers/btrfs_handler.c
@@ -0,0 +1,105 @@ 
+/*
+ * Copyright (C) 2023
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
+ *
+ * SPDX-License-Identifier:     GPL-2.0-only
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <util.h>
+#include <blkid/blkid.h>
+#include <btrfsutil.h>
+#include "fs_interface.h"
+#include "progress.h"
+#include "swupdate_image.h"
+#include "handler.h"
+
+typedef enum {
+	BTRFS_UNKNOWN,
+	BTRFS_CREATE_SUBVOLUME,
+	BTRFS_DELETE_SUBVOLUME
+} btrfs_op_t;
+
+void btrfs_handler(void);
+
+static int btrfs(struct img_type *img,
+		      void __attribute__ ((__unused__)) *data)
+{
+	int ret = 0;
+	btrfs_op_t op;
+	enum btrfs_util_error btrfs_error;
+
+	char *subvol_path = dict_get_value(&img->properties, "path");
+	char *cmd = dict_get_value(&img->properties, "command");
+	char *globalpath;
+	char *mountpoint;
+
+	op = IS_STR_EQUAL(cmd, "create") ? BTRFS_CREATE_SUBVOLUME :
+		IS_STR_EQUAL(cmd, "delete") ? BTRFS_DELETE_SUBVOLUME : BTRFS_UNKNOWN;
+
+	if (op == BTRFS_UNKNOWN) {
+		ERROR("Wrong operation of btrfs filesystem: %s", cmd);
+		return -EINVAL;
+	}
+	bool tomount = IS_STR_EQUAL(dict_get_value(&img->properties, "mount"), "true");
+	if (tomount) {
+		if (!strlen(img->device)) {
+			ERROR("btrfs must be mounted, no device set");
+			return -EINVAL;
+		}
+		globalpath = alloca(strlen(get_tmpdir()) +
+				strlen(DATADST_DIR_SUFFIX) + strlen(subvol_path) + 2);
+		sprintf(globalpath, "%s%s", get_tmpdir(), DATADST_DIR_SUFFIX);
+		mountpoint = strdupa(globalpath);
+		DEBUG("Try to mount %s as BTRFS", mountpoint);
+		ret = swupdate_mount(img->device, mountpoint, "btrfs");
+		if (ret) {
+			ERROR("%s cannot be mounted with btrfs", img->device);
+			return -1;
+		}
+		globalpath = strcat(globalpath, subvol_path);
+	} else
+		globalpath = subvol_path;
+
+	DEBUG("%s subvolume %s...", (op == BTRFS_CREATE_SUBVOLUME) ? "Creating" : "Deleting", subvol_path);
+	switch (op) {
+	case BTRFS_CREATE_SUBVOLUME:
+		btrfs_error = btrfs_util_create_subvolume(globalpath, 0, NULL, NULL);
+		break;
+	case BTRFS_DELETE_SUBVOLUME:
+		btrfs_error = btrfs_util_delete_subvolume(globalpath, BTRFS_UTIL_DELETE_SUBVOLUME_RECURSIVE);
+		break;
+	default:
+		btrfs_error = BTRFS_UTIL_ERROR_FS_INFO_FAILED;
+		break;
+	}
+
+	if (btrfs_error != BTRFS_UTIL_OK) {
+		ERROR("BTRFS %s failed with btrfs error : %s", cmd,
+			btrfs_util_strerror(btrfs_error));
+		ret = -1;
+	}
+
+	if (tomount) {
+		/*
+		 * btrfs needs some time after creating a subvolume,
+		 * so just delay here
+		 */
+		sleep(1);
+		swupdate_umount(mountpoint);
+	}
+	/*
+	 * Declare that handler has finished
+	 */
+	swupdate_progress_update(100);
+
+	return ret;
+}
+
+__attribute__((constructor))
+void btrfs_handler(void)
+{
+	register_handler("btrfs", btrfs,
+			 PARTITION_HANDLER | NO_DATA_HANDLER, NULL);
+}