Replace fdisk -l with sysfs-based disk enumeration (2tb+ drive support) #2035
Replace fdisk -l with sysfs-based disk enumeration (2tb+ drive support) #2035tlaurion wants to merge 1 commit intolinuxboot:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR replaces fdisk -l commands with sysfs-based disk enumeration to overcome fdisk's 2TB drive size limitation and improve busybox compatibility. The changes enable proper detection and display of large storage devices (e.g., 8TB drives).
Key changes:
- Introduces
list_block_devices()function that reads from/sys/block/*instead of parsingfdisk -loutput - Replaces fdisk-based disk information gathering with sysfs-based size calculation
- Updates partition detection logic to use sysfs directory structure
Reviewed changes
Copilot reviewed 2 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| initrd/etc/gui_functions | Adds list_block_devices() function and updates show_system_info() to read disk sizes from sysfs |
| initrd/etc/functions | Adds list_block_devices() function, updates device_has_partitions() to check sysfs for partitions, updates is_gpt_bios_grub() to read partition types from sysfs, and updates detect_boot_device() to use new function |
| initrd/bin/root-hashes-gui.sh | Updates detect_root_device() to use list_block_devices() instead of fdisk |
| initrd/bin/oem-system-info-xx30 | Updates disk information gathering to read from sysfs instead of fdisk |
| initrd/bin/config-gui.sh | Updates device listing to use list_block_devices() instead of fdisk |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
b0bdb67 to
879fb3c
Compare
b3c8e82 to
d296082
Compare
12bbb04 to
23bcdbf
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 6 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
initrd/etc/functions:875
- disk_info_sysfs() builds disk_info lines using "\n" and then echoes with echo -n, which produces literal backslash-n sequences unless the consumer interprets escapes. To make output consistent across callers, prefer emitting real newlines via printf (e.g., printf 'Disk /dev/%s: %s GB\n' ...) or use printf '%b' when printing an escape-containing buffer.
local size_gb=$(((size_bytes * sector_size + 500000000) / 1000000000))
disk_info="${disk_info}Disk /dev/${devname}: ${size_gb} GB\n"
DEBUG "disk_info_sysfs: /dev/${devname} calculated as ${size_gb} GB (${size_bytes} sectors * ${sector_size} bytes/sector = $((size_bytes * sector_size)) bytes)"
fi
fi
done
echo -n "$disk_info"
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Check partition type using sysfs if available, otherwise check for grub type | ||
| # For GPT disks, check /sys/class/block/<dev>/<partition>/uevent for PARTTYPENAME | ||
| local part_sys="/sys/class/block/$DEVICE/$(basename "$PART_DEV")" | ||
| if [ -e "$part_sys/uevent" ]; then | ||
| if grep -q "PARTTYPENAME=BIOS boot" "$part_sys/uevent"; then | ||
| TRACE "$PART_DEV is a GPT BIOS grub partition" | ||
| return 0 | ||
| fi | ||
| fi | ||
|
|
||
| # Fallback: try to detect using other sysfs attributes if available | ||
| # For MBR disks, we would need to check partition type differently |
There was a problem hiding this comment.
is_gpt_bios_grub() checks for "PARTTYPENAME=BIOS boot" in sysfs uevent, but the kernel typically exports PARTTYPE (the type GUID) rather than a human-readable PARTTYPENAME (usually provided by udev). In initrd this will likely never match, so BIOS-boot partitions may no longer be filtered reliably. Suggest checking PARTTYPE against the BIOS boot GUID (21686148-6449-6E6F-744E-656564454649) and/or keeping the previous fdisk-based fallback; also update the comment that mentions a fallback that no longer exists.
| # Check partition type using sysfs if available, otherwise check for grub type | |
| # For GPT disks, check /sys/class/block/<dev>/<partition>/uevent for PARTTYPENAME | |
| local part_sys="/sys/class/block/$DEVICE/$(basename "$PART_DEV")" | |
| if [ -e "$part_sys/uevent" ]; then | |
| if grep -q "PARTTYPENAME=BIOS boot" "$part_sys/uevent"; then | |
| TRACE "$PART_DEV is a GPT BIOS grub partition" | |
| return 0 | |
| fi | |
| fi | |
| # Fallback: try to detect using other sysfs attributes if available | |
| # For MBR disks, we would need to check partition type differently | |
| # Check partition type using sysfs if available. | |
| # For GPT disks, check /sys/class/block/<dev>/<partition>/uevent for PARTTYPE | |
| # matching the BIOS boot GUID (21686148-6449-6E6F-744E-656564454649). Some | |
| # environments may also expose PARTTYPENAME=BIOS boot via udev. | |
| local part_sys="/sys/class/block/$DEVICE/$(basename "$PART_DEV")" | |
| if [ -e "$part_sys/uevent" ]; then | |
| # Legacy/udev-based check: human-readable type name | |
| if grep -q "PARTTYPENAME=BIOS boot" "$part_sys/uevent"; then | |
| TRACE "$PART_DEV is a GPT BIOS grub partition (PARTTYPENAME)" | |
| return 0 | |
| fi | |
| # Preferred check: kernel-exported type GUID | |
| if grep -qi "PARTTYPE=21686148-6449-6E6F-744E-656564454649" "$part_sys/uevent"; then | |
| TRACE "$PART_DEV is a GPT BIOS grub partition (PARTTYPE GUID)" | |
| return 0 | |
| fi | |
| fi |
| local size_bytes=$(cat "$dev/size" 2>/dev/null) | ||
| DEBUG "disk_info_sysfs: /dev/${devname} reports size_bytes=$size_bytes sectors from $dev/size" | ||
| if [ -n "$size_bytes" ] && [ "$size_bytes" -gt 0 ]; then | ||
| # Determine sector size for this device from sysfs; prefer hw_sector_size | ||
| local sector_size=512 | ||
| if [ -r "$dev/queue/hw_sector_size" ]; then | ||
| sector_size=$(cat "$dev/queue/hw_sector_size" 2>/dev/null || echo 512) | ||
| DEBUG "disk_info_sysfs: /dev/${devname} using hw_sector_size=$sector_size from $dev/queue/hw_sector_size" | ||
| elif [ -r "$dev/queue/logical_block_size" ]; then | ||
| sector_size=$(cat "$dev/queue/logical_block_size" 2>/dev/null || echo 512) | ||
| DEBUG "disk_info_sysfs: /dev/${devname} using logical_block_size=$sector_size from $dev/queue/logical_block_size" | ||
| else | ||
| DEBUG "disk_info_sysfs: /dev/${devname} using default sector_size=$sector_size (no queue info available)" | ||
| fi | ||
| # Convert from sectors * sector_size to bytes, then to decimal GB. | ||
| # | ||
| # Explanation of the constants: | ||
| # - We divide by 1,000,000,000 (1000000000) to report decimal GB (10^9 bytes), | ||
| # which matches the historical output used elsewhere in Heads. | ||
| # - Shell arithmetic is integer-only, so to round to the nearest GB we add | ||
| # half the divisor (500,000,000) before dividing. This implements | ||
| # rounding instead of truncation. | ||
| # If you prefer binary GiB (1024^3), replace the divisor and half-divisor | ||
| # with 1073741824 and 536870912 respectively, or use `awk`/`printf` | ||
| # for fractional output. | ||
| local size_gb=$(((size_bytes * sector_size + 500000000) / 1000000000)) | ||
| disk_info="${disk_info}Disk /dev/${devname}: ${size_gb} GB\n" | ||
| DEBUG "disk_info_sysfs: /dev/${devname} calculated as ${size_gb} GB (${size_bytes} sectors * ${sector_size} bytes/sector = $((size_bytes * sector_size)) bytes)" |
There was a problem hiding this comment.
In disk_info_sysfs(), /sys/block//size is a count of 512-byte sectors (same units as blockdev --getsz), not “sectors of hw_sector_size”. Multiplying it by hw_sector_size/logical_block_size will over-report sizes (e.g., 4Kn devices) and can overflow sooner. Consider using bytes from blockdev --getsize64 "/dev/$devname" (still avoids busybox fdisk), or treat size as 512-byte sectors and multiply by 512 unconditionally.
… compatibility fdisk -l is unreliable in busybox environments due to 2TB max size based on max sector assumption. Changes: - Add list_block_devices() helper function to initrd/etc/functions and initrd/etc/gui_functions that uses sysfs to enumerate all block devices (SATA, NVMe, VirtIO, IDE) - Update show_system_info() in initrd/etc/gui_functions to use sysfs for disk size reporting instead of parsing fdisk output - Update show_system_info() in initrd/bin/oem-system-info-xx30 to use sysfs for disk size reporting - Replace device_has_partitions() in initrd/etc/functions to check for partition entries in sysfs instead of parsing fdisk output - Replace is_gpt_bios_grub() in initrd/etc/functions to use sysfs partition attributes (PARTTYPENAME) instead of fdisk parsing. Improves reliability for GPT disk detection while maintaining backward compatibility. - Update detect_boot_device() in initrd/etc/functions to use list_block_devices() - Update boot device selection in initrd/bin/config-gui.sh to use list_block_devices() - Update root device selection in initrd/bin/config-gui.sh to use list_block_devices() - Update root device detection in initrd/bin/root-hashes-gui.sh to use list_block_devices() Benefits: - Fixes disk detection failures with virtio block devices (qcow2 disks) - Works reliably in busybox environments - More robust than fdisk output parsing - Supports all block device types (sd*, nvme*, vd*, hd*) - Improves debuggability with explicit logging Note: Interactive partitioning in initrd/etc/luks-functions still uses fdisk for actually writing partition tables, which is its legitimate use case. Tested with debian-13 and PureOS with root hashes. Signed-off-by: Thierry Laurion <insurgo@riseup.net>
23bcdbf to
2f37ee0
Compare
fdisk -l can deal with 2TB max size drives. Use linux sysfs instead.
Tested:
Fixes #2034 (should have been the fix for #1884)