[PATCHv2,06/12] installer: Add code to create a BTRFS subvolume layout

Message ID 20240323105629.371511-6-stefan.schantl@ipfire.org
State Staged
Commit 0465449e42a7c64b0c1e3d3831c199955a522070
Headers
Series [PATCHv2,01/12] btrfs-progs: New package |

Commit Message

Stefan Schantl March 23, 2024, 10:56 a.m. UTC
  Signed-off-by: Stefan Schantl <stefan.schantl@ipfire.org>
---
 src/installer/hw.c | 80 ++++++++++++++++++++++++++++++++++++++++++++--
 src/installer/hw.h | 20 ++++++++++++
 2 files changed, 98 insertions(+), 2 deletions(-)
  

Patch

diff --git a/src/installer/hw.c b/src/installer/hw.c
index 11dbcd96d..8396d83cf 100644
--- a/src/installer/hw.c
+++ b/src/installer/hw.c
@@ -810,6 +810,7 @@  int hw_create_partitions(struct hw_destination* dest, const char* output) {
 
 static int hw_format_filesystem(const char* path, int fs, const char* output) {
 	char cmd[STRING_SIZE] = "\0";
+	int r;
 
 	// Swap
 	if (fs == HW_FS_SWAP) {
@@ -829,7 +830,9 @@  static int hw_format_filesystem(const char* path, int fs, const char* output) {
 
 	// BTRFS
 	} else if (fs == HW_FS_BTRFS) {
-		snprintf(cmd, sizeof(cmd), "/usr/bin/mkfs.btrfs -f %s", path);
+		r = hw_create_btrfs_layout(path, output);
+
+		return r;
 
 	// FAT32
 	} else if (fs == HW_FS_FAT32) {
@@ -838,7 +841,7 @@  static int hw_format_filesystem(const char* path, int fs, const char* output) {
 
 	assert(*cmd);
 
-	int r = mysystem(output, cmd);
+	r = mysystem(output, cmd);
 
 	return r;
 }
@@ -875,6 +878,59 @@  int hw_create_filesystems(struct hw_destination* dest, const char* output) {
 	return 0;
 }
 
+int hw_create_btrfs_layout(const char* path, const char* output) {
+	const struct btrfs_subvolumes* subvolume = NULL;
+	char cmd[STRING_SIZE];
+	char volume[STRING_SIZE];
+	int r;
+
+	r = snprintf(cmd, sizeof(cmd), "/usr/bin/mkfs.btrfs -f %s", path);
+	if (r < 0) {
+		return r;
+	}
+
+	// Create the main BTRFS file system.
+	r = mysystem(output, cmd);
+
+	if (r) {
+		return r;
+	}
+
+
+	// We need to mount the FS in order to create any subvolumes.
+	r = hw_mount(path, DESTINATION_MOUNT_PATH, "btrfs", 0);
+
+	if (r) {
+		return r;
+	}
+
+	// Loop through the list of subvolumes to create.
+	for ( subvolume = btrfs_subvolumes; subvolume->name; subvolume++ ) {
+		r = snprintf(volume, sizeof(volume), "%s", subvolume->name);
+
+		// Abort if snprintf fails.
+		if (r < 0) {
+			return r;
+		}
+
+		// Call function to create the subvolume
+		r = hw_create_btrfs_subvolume(output, volume);
+
+		if (r) {
+			return r;
+		}
+	}
+
+	// Umount the main BTRFS after subvolume creation.
+	r = hw_umount(DESTINATION_MOUNT_PATH, 0);
+
+	if (r) {
+		return r;
+	}
+
+	return 0;
+}
+
 int hw_mount_filesystems(struct hw_destination* dest, const char* prefix) {
 	char target[STRING_SIZE];
 
@@ -1224,3 +1280,23 @@  int hw_restore_backup(const char* output, const char* backup_path, const char* d
 
 	return 0;
 }
+
+int hw_create_btrfs_subvolume(const char* output, const char* subvolume) {
+	char command [STRING_SIZE];
+	int r;
+
+	// Abort if the command could not be assigned.
+	r = snprintf(command, sizeof(command), "/usr/bin/btrfs subvolume create  %s/%s", DESTINATION_MOUNT_PATH, subvolume);
+	if (r < 0) {
+		return r;
+	}
+
+	// Create the subvolume
+	r = mysystem(output, command);
+
+	if (r) {
+		return r;
+	}
+
+	return 0;
+}
diff --git a/src/installer/hw.h b/src/installer/hw.h
index e5ee65a6d..73a5233e2 100644
--- a/src/installer/hw.h
+++ b/src/installer/hw.h
@@ -104,6 +104,26 @@  struct hw_destination {
 	unsigned long long size_root;
 };
 
+// Struct to define the BTRFS subvolumes layout
+static const struct btrfs_subvolumes {
+	const char* name;
+	const char* mount_path;
+} btrfs_subvolumes[] = {
+	{ "@",          "/" },
+	{ "@snapshots", "/.snapshots" },
+	{ "@home",      "/home" },
+	{ "@root",      "/root" },
+	{ "@cache",     "/var/cache" },
+	{ "@backups",   "/var/ipfire/backup" },
+	{ "@lib",       "/var/lib" },
+	{ "@logs",      "/var/log" },
+	{ "@mails",     "/var/mail" },
+	{ "@tmp",       "/var/tmp" },
+
+	// Sentinel
+	{ NULL },
+};
+
 struct hw* hw_init();
 void hw_free(struct hw* hw);