diff mbox series

[4/5] diskpart handler: add support for fslabels

Message ID 20240826064006.41623-5-michael.adler@siemens.com
State Accepted
Headers show
Series Introduce FAT Filesystem Labeling | expand

Commit Message

Michael Adler Aug. 26, 2024, 6:40 a.m. UTC
In addition to creating filesystems, diskpart handler now supports
setting (FAT) filesystem labels.
Labels can be set using the fslabel field of a partition in the
sw-description file.
Previously, external programs would have to be called instead.

Co-authored-by: Oleksandr Makhmudov <oleksandr.makhmudov@siemens.com>
Signed-off-by: Oleksandr Makhmudov <oleksandr.makhmudov@siemens.com>
Signed-off-by: Michael Adler <michael.adler@siemens.com>
Signed-off-by: Christian Storm <christian.storm@siemens.com>
---
 fs/diskformat.c             | 21 +++++++++++++++++++
 fs/fat_fs.c                 | 41 +++++++++++++++++++++++++++++++++++++
 fs/ffconf.h                 |  3 +--
 handlers/diskpart_handler.c | 37 +++++++++++++++++++++++++--------
 include/fs_interface.h      |  2 ++
 5 files changed, 93 insertions(+), 11 deletions(-)
diff mbox series

Patch

diff --git a/fs/diskformat.c b/fs/diskformat.c
index 86e8c59f..643be482 100644
--- a/fs/diskformat.c
+++ b/fs/diskformat.c
@@ -66,11 +66,16 @@  char *diskformat_fs_detect(char *device)
 
 		if (len > 0) {
 			s = strndup(value, len);
+			TRACE("Found %s file system on %s", s, device);
 			break;
 		}
 	}
 	blkid_free_probe(pr);
 
+	if (!s) {
+		TRACE("Found no file system on %s", device);
+	}
+
 	return s;
 }
 
@@ -117,3 +122,19 @@  int diskformat_mkfs(char *device, char *fstype)
 
 	return ret;
 }
+
+int diskformat_set_fslabel(char *device, char *fstype, const char *label)
+{
+#ifdef CONFIG_FAT_FILESYSTEM
+	if (!strcmp(fstype, "vfat")) {
+		if (fat_set_label(device, label)) {
+			ERROR("%s: failed to set FAT label", device);
+			return 1;
+		}
+		return 0;
+	}
+#endif
+	/* failure by default */
+	ERROR("%s: fslabel feature not supported", fstype);
+	return 1;
+}
diff --git a/fs/fat_fs.c b/fs/fat_fs.c
index f560a795..f575e334 100644
--- a/fs/fat_fs.c
+++ b/fs/fat_fs.c
@@ -45,3 +45,44 @@  int fat_mkfs(const char *device_name, const char __attribute__ ((__unused__)) *f
 	fatfs_release();
 	return 0;
 }
+
+int fat_set_label(const char *device_name, const char *label)
+{
+	int ret = 0;
+
+	if (fatfs_init(device_name)) {
+		return -1;
+	}
+
+	FATFS fs;
+	/* initialize the library (without mounting anything!) */
+	FRESULT result = f_mount(&fs, "", 0);
+	if (result != FR_OK) {
+		ERROR("Failed to initialize fatfs library (reason: %d)", result);
+		ret = -1;
+		goto finish;
+	}
+
+	/* try to read existing label and do nothing if it matches our label */
+	char current[12]; /* 11 is the maximum length of a FAT label, +1 for null-termination */
+	if (f_getlabel(device_name, &current[0], NULL) == FR_OK) {
+		current[sizeof(current) - 1] = '\0'; /* make sure it's null-terminated */
+		DEBUG("%s has fslabel '%s'", device_name, current);
+		if (!strcasecmp(label, current)) {
+			TRACE("Current fslabel '%s' matches new label, skipping setlabel", current);
+			goto finish;
+		}
+	} else {
+		DEBUG("Failed to read existing fslabel");
+	}
+	TRACE("Setting FAT fslabel '%s' on %s", label, device_name);
+	if (f_setlabel(label) != FR_OK) {
+		ERROR("%s: failed to set fslabel", device_name);
+		ret = -1;
+	}
+
+finish:
+	f_unmount("");
+	fatfs_release();
+	return ret;
+}
diff --git a/fs/ffconf.h b/fs/ffconf.h
index b85bbb08..c0ec53db 100644
--- a/fs/ffconf.h
+++ b/fs/ffconf.h
@@ -73,8 +73,7 @@ 
 /* This option switches attribute manipulation functions, f_chmod() and f_utime().
 /  (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
 
-
-#define FF_USE_LABEL	0
+#define FF_USE_LABEL	1
 /* This option switches volume label functions, f_getlabel() and f_setlabel().
 /  (0:Disable or 1:Enable) */
 
diff --git a/handlers/diskpart_handler.c b/handlers/diskpart_handler.c
index e33a4517..06b4578e 100644
--- a/handlers/diskpart_handler.c
+++ b/handlers/diskpart_handler.c
@@ -61,7 +61,8 @@  enum partfield {
 	PART_DOSTYPE,
 	PART_UUID,
 	PART_FLAG,
-	PART_FORCE
+	PART_FORCE,
+	PART_FSLABEL
 };
 
 const char *fields[] = {
@@ -74,6 +75,7 @@  const char *fields[] = {
 	[PART_UUID] = "partuuid",
 	[PART_FLAG] = "flag",
 	[PART_FORCE] = "force",
+	[PART_FSLABEL] = "fslabel"
 };
 
 struct partition_data {
@@ -83,6 +85,7 @@  struct partition_data {
 	char type[SWUPDATE_GENERAL_STRING_SIZE];
 	char name[SWUPDATE_GENERAL_STRING_SIZE];
 	char fstype[SWUPDATE_GENERAL_STRING_SIZE];
+	char fslabel[SWUPDATE_GENERAL_STRING_SIZE];
 	char dostype[SWUPDATE_GENERAL_STRING_SIZE];
 	char partuuid[UUID_STR_LEN];
 	int explicit_size;
@@ -1163,6 +1166,7 @@  static int format_parts(struct hnd_priv priv, struct img_type *img, struct creat
 	struct partition_data *part;
 	LIST_FOREACH(part, &priv.listparts, next)
 	{
+		ret = 0; /* reset result */
 		/*
 		 * priv.listparts counts partitions starting with 0,
 		 * but fdisk_partname expects the first partition having
@@ -1175,17 +1179,22 @@  static int format_parts(struct hnd_priv priv, struct img_type *img, struct creat
 
 		char *device = fdisk_partname(path, partno);
 
+		bool do_mkfs = true;
 		if (!createtable->parent && !part->force) {
-			/* Check if file system exists and if so, skip mkfs */
-			if (diskformat_fs_exists(device, part->fstype)) {
-				TRACE("Found %s file system on %s, skip mkfs", part->fstype, device);
-				ret = 0;
-				free(device);
-				continue;
-			}
+			/* only create fs if it does not exist */
+			do_mkfs = !diskformat_fs_exists(device, part->fstype);
+		}
+
+		if (do_mkfs) {
+			ret = diskformat_mkfs(device, part->fstype);
+		} else {
+			TRACE("Skipping mkfs on %s", device);
+		}
+
+		if (!ret && part->fslabel[0] != '\0') {
+			ret = diskformat_set_fslabel(device, part->fstype, part->fslabel);
 		}
 
-		ret = diskformat_mkfs(device, part->fstype);
 		free(device);
 		if (ret)
 			break;
@@ -1323,6 +1332,16 @@  static int diskpart(struct img_type *img,
 						part->force = strtobool(equal);
 						TRACE("Force flag explicitly mentioned, value %d", part->force);
 						break;
+					case PART_FSLABEL:
+#ifdef CONFIG_DISKPART_FORMAT
+						strncpy(part->fslabel, equal, sizeof(part->fslabel));
+						break;
+#else
+						ERROR("Partitions have fslabel entries but diskpart format is "
+						      "missing!");
+						ret = -EINVAL;
+						goto handler_exit;
+#endif
 					}
 				}
 			}
diff --git a/include/fs_interface.h b/include/fs_interface.h
index ccfea6bd..3012f349 100644
--- a/include/fs_interface.h
+++ b/include/fs_interface.h
@@ -12,9 +12,11 @@  char *diskformat_fs_detect(char *device);
 bool diskformat_fs_exists(char *device, char *fstype);
 
 int diskformat_mkfs(char *device, char *fstype);
+int diskformat_set_fslabel(char *device, char *fstype, const char *label);
 
 #if defined(CONFIG_FAT_FILESYSTEM)
 extern int fat_mkfs(const char *device_name, const char *fstype);
+extern int fat_set_label(const char *device_name, const char *label);
 #endif
 
 #if defined (CONFIG_EXT_FILESYSTEM)