From 834b8de7fe061d9b0e1917d8ceb0c876ddf47a69 Mon Sep 17 00:00:00 2001 From: kinatli jayanth Date: Fri, 5 Sep 2025 12:23:06 +0530 Subject: [PATCH 1/3] Refactor: Enhance diskutils.go for EMT ISO installer boot exclusion - Refactored SystemBlockDevices to build the device list incrementally instead of pre-allocating with fixed size. - Added isBootDevice to detect and exclude active boot devices using /proc/cmdline and /proc/mounts. This improves safety for EMT ISO installer by preventing accidental selection of boot or ISO devices as installation targets. Signed-off-by: kinatli jayanth --- toolkit/tools/imagegen/diskutils/diskutils.go | 87 +++++++++++++++++-- 1 file changed, 79 insertions(+), 8 deletions(-) diff --git a/toolkit/tools/imagegen/diskutils/diskutils.go b/toolkit/tools/imagegen/diskutils/diskutils.go index 00e2e6f542..7053cadc79 100644 --- a/toolkit/tools/imagegen/diskutils/diskutils.go +++ b/toolkit/tools/imagegen/diskutils/diskutils.go @@ -902,20 +902,91 @@ func SystemBlockDevices() (systemDevices []SystemBlockDevice, err error) { return } - systemDevices = make([]SystemBlockDevice, len(blockDevices.Devices)) + // Process each device to build the filtered list + systemDevices = make([]SystemBlockDevice, 0, len(blockDevices.Devices)) + for _, device := range blockDevices.Devices { + devicePath := fmt.Sprintf("/dev/%s", device.Name) + rawSize, err := strconv.ParseUint(device.Size.String(), 10, 64) + if err != nil { + return nil, fmt.Errorf("failed to parse size for %s: %v", devicePath, err) + } - for i, disk := range blockDevices.Devices { - systemDevices[i].DevicePath = fmt.Sprintf("/dev/%s", disk.Name) + isBoot := isBootDevice(devicePath) - systemDevices[i].RawDiskSize, err = strconv.ParseUint(disk.Size.String(), 10, 64) - if err != nil { - return + logger.Log.Debugf("Device: %s, Size: %d, Model: %s, IsBoot: %v", + devicePath, rawSize, strings.TrimSpace(device.Model), isBoot) + + if !isBoot { + systemDevices = append(systemDevices, SystemBlockDevice{ + DevicePath: devicePath, + RawDiskSize: rawSize, + Model: strings.TrimSpace(device.Model), + }) + } else { + logger.Log.Debugf("Excluded boot device: %s", devicePath) } + } - systemDevices[i].Model = strings.TrimSpace(disk.Model) + logger.Log.Debugf("Final device list: %v", systemDevices) + return systemDevices, nil +} + +// isBootDevice determines if a device is the boot device by detecting the system boot path and checking for removable devices. +// It uses /proc/cmdline and /proc/mounts for detection. +func isBootDevice(devicePath string) bool { + // Detect the system boot path once + var bootPath string + cmdline, err := os.ReadFile("/proc/cmdline") + if err == nil { + for _, field := range strings.Fields(string(cmdline)) { + if strings.HasPrefix(field, "root=") { + bootPath = strings.TrimPrefix(field, "root=") + break + } + if strings.HasPrefix(field, "inst.repo=") { + bootPath = strings.TrimPrefix(field, "inst.repo=") + break + } + } } - return + // Fallback: Check /proc/mounts for a boot device if cmdline fails + if bootPath == "" { + mounts, err := os.ReadFile("/proc/mounts") + if err == nil { + for _, line := range strings.Split(string(mounts), "\n") { + fields := strings.Fields(line) + if len(fields) >= 2 && (strings.HasPrefix(fields[0], "/dev/sr") || strings.HasPrefix(fields[0], "/dev/loop")) && + strings.Contains(fields[1], "iso") { + bootPath = fields[0] + break + } + } + } + } + + if bootPath != "" { + logger.Log.Debugf("Detected boot device: %s", bootPath) + } + + // Exclude the boot device itself + if bootPath != "" && devicePath == bootPath { + return true + } + + // Check if the device is removable (e.g., USB or similar boot media) + deviceName := devicePath[5:] // Extract 'sda', 'sdb', 'nvme0n1', etc. from '/dev/' + removableFile := fmt.Sprintf("/sys/block/%s/removable", deviceName) + if exists, err := file.PathExists(removableFile); err == nil && exists { + if content, err := os.ReadFile(removableFile); err == nil { + if strings.TrimSpace(string(content)) == "1" { + logger.Log.Debugf("Excluded %s as removable boot device", devicePath) + return true + } + } + } + + return false } func GetDiskPartitions(diskDevPath string) ([]PartitionInfo, error) { From 89eb2a89d65fd91e7f3b14898da622ca65669f35 Mon Sep 17 00:00:00 2001 From: kinatli jayanth Date: Fri, 5 Sep 2025 12:23:06 +0530 Subject: [PATCH 2/3] Refactor: Enhance diskutils.go for EMT ISO installer boot exclusion - Refactored SystemBlockDevices to build the device list incrementally instead of pre-allocating with fixed size. - Added isBootDevice to detect and exclude active boot devices using /proc/cmdline and /proc/mounts. This improves safety for EMT ISO installer by preventing accidental selection of boot or ISO devices as installation targets. Signed-off-by: kinatli jayanth --- toolkit/tools/imagegen/diskutils/diskutils.go | 87 +++++++++++++++++-- 1 file changed, 79 insertions(+), 8 deletions(-) diff --git a/toolkit/tools/imagegen/diskutils/diskutils.go b/toolkit/tools/imagegen/diskutils/diskutils.go index 00e2e6f542..7053cadc79 100644 --- a/toolkit/tools/imagegen/diskutils/diskutils.go +++ b/toolkit/tools/imagegen/diskutils/diskutils.go @@ -902,20 +902,91 @@ func SystemBlockDevices() (systemDevices []SystemBlockDevice, err error) { return } - systemDevices = make([]SystemBlockDevice, len(blockDevices.Devices)) + // Process each device to build the filtered list + systemDevices = make([]SystemBlockDevice, 0, len(blockDevices.Devices)) + for _, device := range blockDevices.Devices { + devicePath := fmt.Sprintf("/dev/%s", device.Name) + rawSize, err := strconv.ParseUint(device.Size.String(), 10, 64) + if err != nil { + return nil, fmt.Errorf("failed to parse size for %s: %v", devicePath, err) + } - for i, disk := range blockDevices.Devices { - systemDevices[i].DevicePath = fmt.Sprintf("/dev/%s", disk.Name) + isBoot := isBootDevice(devicePath) - systemDevices[i].RawDiskSize, err = strconv.ParseUint(disk.Size.String(), 10, 64) - if err != nil { - return + logger.Log.Debugf("Device: %s, Size: %d, Model: %s, IsBoot: %v", + devicePath, rawSize, strings.TrimSpace(device.Model), isBoot) + + if !isBoot { + systemDevices = append(systemDevices, SystemBlockDevice{ + DevicePath: devicePath, + RawDiskSize: rawSize, + Model: strings.TrimSpace(device.Model), + }) + } else { + logger.Log.Debugf("Excluded boot device: %s", devicePath) } + } - systemDevices[i].Model = strings.TrimSpace(disk.Model) + logger.Log.Debugf("Final device list: %v", systemDevices) + return systemDevices, nil +} + +// isBootDevice determines if a device is the boot device by detecting the system boot path and checking for removable devices. +// It uses /proc/cmdline and /proc/mounts for detection. +func isBootDevice(devicePath string) bool { + // Detect the system boot path once + var bootPath string + cmdline, err := os.ReadFile("/proc/cmdline") + if err == nil { + for _, field := range strings.Fields(string(cmdline)) { + if strings.HasPrefix(field, "root=") { + bootPath = strings.TrimPrefix(field, "root=") + break + } + if strings.HasPrefix(field, "inst.repo=") { + bootPath = strings.TrimPrefix(field, "inst.repo=") + break + } + } } - return + // Fallback: Check /proc/mounts for a boot device if cmdline fails + if bootPath == "" { + mounts, err := os.ReadFile("/proc/mounts") + if err == nil { + for _, line := range strings.Split(string(mounts), "\n") { + fields := strings.Fields(line) + if len(fields) >= 2 && (strings.HasPrefix(fields[0], "/dev/sr") || strings.HasPrefix(fields[0], "/dev/loop")) && + strings.Contains(fields[1], "iso") { + bootPath = fields[0] + break + } + } + } + } + + if bootPath != "" { + logger.Log.Debugf("Detected boot device: %s", bootPath) + } + + // Exclude the boot device itself + if bootPath != "" && devicePath == bootPath { + return true + } + + // Check if the device is removable (e.g., USB or similar boot media) + deviceName := devicePath[5:] // Extract 'sda', 'sdb', 'nvme0n1', etc. from '/dev/' + removableFile := fmt.Sprintf("/sys/block/%s/removable", deviceName) + if exists, err := file.PathExists(removableFile); err == nil && exists { + if content, err := os.ReadFile(removableFile); err == nil { + if strings.TrimSpace(string(content)) == "1" { + logger.Log.Debugf("Excluded %s as removable boot device", devicePath) + return true + } + } + } + + return false } func GetDiskPartitions(diskDevPath string) ([]PartitionInfo, error) { From 6c26d0e862cd3bebc3798d033a60b0493cb382e3 Mon Sep 17 00:00:00 2001 From: kinatli jayanth Date: Fri, 5 Sep 2025 12:23:06 +0530 Subject: [PATCH 3/3] Refactor: Enhance diskutils.go for EMT ISO installer boot exclusion - Refactored SystemBlockDevices to build the device list incrementally instead of pre-allocating with fixed size. - Added isBootDevice to detect and exclude active boot devices using /proc/cmdline and /proc/mounts. This improves safety for EMT ISO installer by preventing accidental selection of boot or ISO devices as installation targets. Signed-off-by: kinatli jayanth --- toolkit/tools/imagegen/diskutils/diskutils.go | 87 +++++++++++++++++-- 1 file changed, 79 insertions(+), 8 deletions(-) diff --git a/toolkit/tools/imagegen/diskutils/diskutils.go b/toolkit/tools/imagegen/diskutils/diskutils.go index 00e2e6f542..7053cadc79 100644 --- a/toolkit/tools/imagegen/diskutils/diskutils.go +++ b/toolkit/tools/imagegen/diskutils/diskutils.go @@ -902,20 +902,91 @@ func SystemBlockDevices() (systemDevices []SystemBlockDevice, err error) { return } - systemDevices = make([]SystemBlockDevice, len(blockDevices.Devices)) + // Process each device to build the filtered list + systemDevices = make([]SystemBlockDevice, 0, len(blockDevices.Devices)) + for _, device := range blockDevices.Devices { + devicePath := fmt.Sprintf("/dev/%s", device.Name) + rawSize, err := strconv.ParseUint(device.Size.String(), 10, 64) + if err != nil { + return nil, fmt.Errorf("failed to parse size for %s: %v", devicePath, err) + } - for i, disk := range blockDevices.Devices { - systemDevices[i].DevicePath = fmt.Sprintf("/dev/%s", disk.Name) + isBoot := isBootDevice(devicePath) - systemDevices[i].RawDiskSize, err = strconv.ParseUint(disk.Size.String(), 10, 64) - if err != nil { - return + logger.Log.Debugf("Device: %s, Size: %d, Model: %s, IsBoot: %v", + devicePath, rawSize, strings.TrimSpace(device.Model), isBoot) + + if !isBoot { + systemDevices = append(systemDevices, SystemBlockDevice{ + DevicePath: devicePath, + RawDiskSize: rawSize, + Model: strings.TrimSpace(device.Model), + }) + } else { + logger.Log.Debugf("Excluded boot device: %s", devicePath) } + } - systemDevices[i].Model = strings.TrimSpace(disk.Model) + logger.Log.Debugf("Final device list: %v", systemDevices) + return systemDevices, nil +} + +// isBootDevice determines if a device is the boot device by detecting the system boot path and checking for removable devices. +// It uses /proc/cmdline and /proc/mounts for detection. +func isBootDevice(devicePath string) bool { + // Detect the system boot path once + var bootPath string + cmdline, err := os.ReadFile("/proc/cmdline") + if err == nil { + for _, field := range strings.Fields(string(cmdline)) { + if strings.HasPrefix(field, "root=") { + bootPath = strings.TrimPrefix(field, "root=") + break + } + if strings.HasPrefix(field, "inst.repo=") { + bootPath = strings.TrimPrefix(field, "inst.repo=") + break + } + } } - return + // Fallback: Check /proc/mounts for a boot device if cmdline fails + if bootPath == "" { + mounts, err := os.ReadFile("/proc/mounts") + if err == nil { + for _, line := range strings.Split(string(mounts), "\n") { + fields := strings.Fields(line) + if len(fields) >= 2 && (strings.HasPrefix(fields[0], "/dev/sr") || strings.HasPrefix(fields[0], "/dev/loop")) && + strings.Contains(fields[1], "iso") { + bootPath = fields[0] + break + } + } + } + } + + if bootPath != "" { + logger.Log.Debugf("Detected boot device: %s", bootPath) + } + + // Exclude the boot device itself + if bootPath != "" && devicePath == bootPath { + return true + } + + // Check if the device is removable (e.g., USB or similar boot media) + deviceName := devicePath[5:] // Extract 'sda', 'sdb', 'nvme0n1', etc. from '/dev/' + removableFile := fmt.Sprintf("/sys/block/%s/removable", deviceName) + if exists, err := file.PathExists(removableFile); err == nil && exists { + if content, err := os.ReadFile(removableFile); err == nil { + if strings.TrimSpace(string(content)) == "1" { + logger.Log.Debugf("Excluded %s as removable boot device", devicePath) + return true + } + } + } + + return false } func GetDiskPartitions(diskDevPath string) ([]PartitionInfo, error) {