]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
rootfs-handoff: add UUID= and LABEL= support for root= parameter
authorTulio A M Mendes <[email protected]>
Thu, 11 Jun 2026 03:54:56 +0000 (00:54 -0300)
committerTulio A M Mendes <[email protected]>
Thu, 11 Jun 2026 03:54:56 +0000 (00:54 -0300)
- Added ext2_get_uuid_label() function in ext2.c to extract UUID and volume name
- Added format_uuid() helper to format 16-byte UUID to string format
- Added uuid_matches() helper to compare UUID string with binary UUID
- Added resolve_by_uuid_label() function in init.c to scan block devices and partitions
- Modified init_resolve_mount_device() to recognize UUID= and LABEL= prefixes
- Scans all ATA devices (hda-hdd) and their partitions (hda1-hda4)
- Supports ext2 filesystems (UUID and volume name from superblock)
- This implements the 'UUID= and LABEL= support' item from ROOTFS_HANDOFF_PLAN.md

Test Results:
- Smoke test: 131/131 PASS
- Battery test: 157/157 PASS
- Analyzer: PASS
- Zero regressions

include/ext2.h
src/kernel/ext2.c
src/kernel/init.c

index 7df2d244e9e48f029e77bbcb8c1d4599c9c002b1..c4802cc6fc43d8279ecbbd903d42f2bee2e960c9 100644 (file)
@@ -48,6 +48,11 @@ vfs_mount_result_t ext2_mount_partition(struct partition* part);
  * Returns -EINVAL if filesystem has errors that prevent mount */
 int ext2_verify_state(block_device_t* bdev, uint32_t partition_lba);
 
+/* Get ext2 filesystem UUID (16 bytes) and volume name
+ * Returns 0 on success, -errno on failure */
+int ext2_get_uuid_label(block_device_t* bdev, uint32_t partition_lba,
+                        uint8_t uuid[16], char label[16]);
+
 /* Unmount an ext2 filesystem and free its resources */
 void ext2_umount(struct ext2_mount* em);
 
index 5fc0ee541c9f40a664a4c06177cdbb9d398ae4d1..53e66d9f650dac5056b81059b9dae14124e69955 100644 (file)
@@ -246,6 +246,42 @@ int ext2_verify_state(block_device_t* bdev, uint32_t partition_lba) {
     return 0;
 }
 
+/* Get ext2 filesystem UUID (16 bytes) and volume name
+ * Returns 0 on success, -errno on failure */
+int ext2_get_uuid_label(block_device_t* bdev, uint32_t partition_lba,
+                        uint8_t uuid[16], char label[16]) {
+    if (!bdev) return -ENODEV;
+
+    /* Read superblock to get UUID and label */
+    uint8_t sec[EXT2_SECTOR_SIZE];
+    uint32_t sb_lba = partition_lba + EXT2_SUPER_OFFSET / EXT2_SECTOR_SIZE;
+
+    uint8_t raw[1024];
+    for (uint32_t i = 0; i < 1024 / EXT2_SECTOR_SIZE; i++) {
+        if (blockdev_read(bdev, sb_lba + i, sec) < 0) return -EIO;
+        memcpy(raw + i * EXT2_SECTOR_SIZE, sec, EXT2_SECTOR_SIZE);
+    }
+
+    struct ext2_superblock sb;
+    memcpy(&sb, raw, sizeof(sb));
+
+    /* Check magic */
+    if (sb.s_magic != EXT2_SUPER_MAGIC) {
+        return -EINVAL;  /* Not an ext2 filesystem */
+    }
+
+    /* Copy UUID and label */
+    if (uuid) {
+        memcpy(uuid, sb.s_uuid, 16);
+    }
+    if (label) {
+        memcpy(label, sb.s_volume_name, 16);
+        label[15] = '\0';  /* Ensure null-termination */
+    }
+
+    return 0;
+}
+
 static int ext2_read_superblock(struct ext2_mount* em, struct ext2_superblock* sb) {
     if (!em || !em->bdev) return -ENODEV;
     /* Superblock is at byte offset 1024, which is LBA 2-3 relative to partition */
index a3c121da101cb2c3551697188b3b0820b36fafe2..bfeedbb37ab76cae7ae6f1dc7672fac6f08cf07a 100644 (file)
@@ -28,6 +28,7 @@
 #include "socket.h"
 #include "vbe.h"
 #include "keyboard.h"
+#include "blockdev.h"
 #include "console.h"
 #include "errno.h"
 #include "utils.h"
@@ -84,9 +85,112 @@ static void init_build_mount_source_name(const char* source_name, block_device_t
     *dp = '\0';
 }
 
+/* Format UUID (16 bytes) to string "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */
+static void format_uuid(const uint8_t uuid[16], char* out, size_t out_size) {
+    if (out_size < 37) return;  /* Need 36 chars + null terminator */
+
+    const char hex[] = "0123456789abcdef";
+    int pos = 0;
+
+    /* Format: 8-4-4-4-12 */
+    for (int i = 0; i < 16; i++) {
+        if (i == 4 || i == 6 || i == 8 || i == 10) {
+            out[pos++] = '-';
+        }
+        out[pos++] = hex[uuid[i] >> 4];
+        out[pos++] = hex[uuid[i] & 0x0F];
+    }
+    out[pos] = '\0';
+}
+
+/* Compare UUID string with binary UUID */
+static int uuid_matches(const char* uuid_str, const uint8_t uuid[16]) {
+    char formatted[37];
+    format_uuid(uuid, formatted, sizeof(formatted));
+    return strcmp(uuid_str, formatted) == 0;
+}
+
+/* Resolve device by UUID or LABEL
+ * Scans all block devices and partitions to find matching UUID or LABEL
+ * Returns 0 on success, -errno on failure */
+static int resolve_by_uuid_label(const char* prefix, const char* value,
+                                 block_device_t** bdev, uint32_t* lba) {
+    /* Scan all block devices */
+    for (int i = 0; i < 8; i++) {  /* ATA devices: hda-hdd */
+        char devname[8];
+        devname[0] = 'h';
+        devname[1] = 'd';
+        devname[2] = 'a' + i;
+        devname[3] = '\0';
+        block_device_t* dev = blockdev_find(devname);
+        if (!dev) continue;
+
+        /* Check whole device (ext2 on raw disk) */
+        uint8_t uuid[16];
+        char label[16];
+        if (ext2_get_uuid_label(dev, 0, uuid, label) == 0) {
+            if (strcmp(prefix, "UUID") == 0) {
+                if (uuid_matches(value, uuid)) {
+                    *bdev = dev;
+                    *lba = 0;
+                    return 0;
+                }
+            } else if (strcmp(prefix, "LABEL") == 0) {
+                if (strcmp(value, label) == 0) {
+                    *bdev = dev;
+                    *lba = 0;
+                    return 0;
+                }
+            }
+        }
+
+        /* Check partitions */
+        for (int part_num = 1; part_num <= 4; part_num++) {
+            char partname[16];
+            partname[0] = 'h';
+            partname[1] = 'd';
+            partname[2] = 'a' + i;
+            partname[3] = '0' + part_num;
+            partname[4] = '\0';
+            partition_t* part = partition_find(partname);
+            if (!part || !part->parent) continue;
+
+            if (ext2_get_uuid_label(part->parent, part->start_lba, uuid, label) == 0) {
+                if (strcmp(prefix, "UUID") == 0) {
+                    if (uuid_matches(value, uuid)) {
+                        *bdev = part->parent;
+                        *lba = part->start_lba;
+                        return 0;
+                    }
+                } else if (strcmp(prefix, "LABEL") == 0) {
+                    if (strcmp(value, label) == 0) {
+                        *bdev = part->parent;
+                        *lba = part->start_lba;
+                        return 0;
+                    }
+                }
+            }
+        }
+    }
+
+    return -ENODEV;
+}
+
 int init_resolve_mount_device(const char* device, block_device_t** bdev, uint32_t* lba) {
     if (!device || !bdev || !lba) return -EINVAL;
 
+    /* Check for UUID= or LABEL= prefix */
+    if (strncmp(device, "UUID=", 5) == 0) {
+        const char* uuid_str = device + 5;
+        return resolve_by_uuid_label("UUID", uuid_str, bdev, lba);
+    }
+
+    if (strncmp(device, "LABEL=", 6) == 0) {
+        const char* label_str = device + 6;
+        return resolve_by_uuid_label("LABEL", label_str, bdev, lba);
+    }
+
+    /* Regular device path */
     const char* devname = device;
     if (strncmp(devname, "/dev/", 5) == 0) devname += 5;