Skip to content

Commit b3c8e82

Browse files
committed
Replace fdisk -l with sysfs-based disk enumeration for better busybox 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. Signed-off-by: Thierry Laurion <insurgo@riseup.net>
1 parent 3b656d0 commit b3c8e82

File tree

5 files changed

+130
-28
lines changed

5 files changed

+130
-28
lines changed

initrd/bin/config-gui.sh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,9 @@ while true; do
119119
exit 0
120120
;;
121121
"b")
122+
#Change /boot device
122123
CURRENT_OPTION="$(load_config_value CONFIG_BOOT_DEV)"
123-
if ! fdisk -l 2>/dev/null | grep "Disk /dev/" | cut -f2 -d " " | cut -f1 -d ":" >/tmp/disklist.txt; then
124+
if ! list_block_devices >/tmp/disklist.txt; then
124125
whiptail_error --title 'ERROR: No bootable devices found' \
125126
--msgbox " $ERROR\n\n" 0 80
126127
exit 1
@@ -214,8 +215,9 @@ while true; do
214215
fi
215216
;;
216217
"R")
218+
#Change the root device for hashing
217219
CURRENT_OPTION="$(load_config_value CONFIG_ROOT_DEV)"
218-
fdisk -l 2>/dev/null | grep "Disk /dev/" | cut -f2 -d " " | cut -f1 -d ":" >/tmp/disklist.txt
220+
list_block_devices >/tmp/disklist.txt
219221
# filter out extraneous options
220222
>/tmp/root_device_list.txt
221223
for i in $(cat /tmp/disklist.txt); do

initrd/bin/oem-system-info-xx30

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,9 @@ kernel=$(uname -s -r)
5050

5151
FB_OPTIONS=""
5252
if whiptail --version | grep "fbwhiptail"; then FB_OPTIONS="--text-size 12"; fi
53+
54+
# Build disk information using shared sysfs helper
55+
disk_info="$(disk_info_sysfs)"
56+
5357
whiptail_type $BG_COLOR_MAIN_MENU $FB_OPTIONS --title 'System Info' \
54-
--msgbox "${BOARD_NAME}\nFW_VER: ${FW_VER}\nKernel: ${kernel}\nCPU: ${cpustr} RAM: ${memtotal} GB $battery_status\n$(fdisk -l | grep -e '/dev/sd.:' -e '/dev/nvme.*:' | sed 's/B,.*/B/')\n\n$(cat /tmp/devices_usb_pci)" 0 80
58+
--msgbox "${BOARD_NAME}\nFW_VER: ${FW_VER}\nKernel: ${kernel}\nCPU: ${cpustr} RAM: ${memtotal} GB $battery_status\n${disk_info}\n$(cat /tmp/devices_usb_pci)" 0 80

initrd/bin/root-hashes-gui.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ detect_root_device()
367367
fi
368368

369369
# generate list of possible boot devices
370-
fdisk -l 2>/dev/null | grep "Disk /dev/" | cut -f2 -d " " | cut -f1 -d ":" > /tmp/disklist
370+
list_block_devices > /tmp/disklist
371371

372372
# filter out extraneous options
373373
> /tmp_root_device_list

initrd/etc/functions

Lines changed: 82 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -659,24 +659,77 @@ enable_usb_storage() {
659659

660660
device_has_partitions() {
661661
local DEVICE="$1"
662-
# fdisk normally says "doesn't contain a valid partition table" for
663-
# devices that lack a partition table - except for FAT32.
664-
#
665-
# FAT32 devices have a volume boot record that looks enough like an MBR
666-
# to satisfy fdisk. In that case, fdisk prints a partition table header
667-
# but no partitions.
668-
#
669-
# This check covers that: [ $(fdisk -l "$b" | wc -l) -eq 5 ]
670-
# In both cases the output is 5 lines: 3 about device info, 1 empty line
671-
# and the 5th will be the table header or the invalid message.
672-
local DISK_DATA=$(fdisk -l "$DEVICE" 2>/dev/null)
673-
if echo "$DISK_DATA" | grep -q "doesn't contain a valid partition table" ||
674-
[ "$(echo "$DISK_DATA" | wc -l)" -eq 5 ]; then
675-
# No partition table
662+
# Check if device has any partitions by checking sysfs
663+
# A device with partitions will have entries like /sys/block/sda/sda1, /sys/block/vda/vda1, etc
664+
local device_name=$(basename "$DEVICE")
665+
666+
if [ ! -e "/sys/block/$device_name" ]; then
667+
# Device doesn't exist
676668
return 1
677669
fi
678-
# There is a partition table
679-
return 0
670+
671+
# Count partitions - handle nvme partition naming (nvme0n1p1) and traditional (sda1, vda1, hda1)
672+
if [ -n "$(ls -1 /sys/block/$device_name/ 2>/dev/null | grep -E "^${device_name}(p)?[0-9]")" ]; then
673+
# There is a partition table
674+
return 0
675+
fi
676+
# No partition table
677+
return 1
678+
}
679+
680+
# List all block devices using sysfs
681+
# Outputs one device path per line (e.g., /dev/sda, /dev/vda, /dev/nvme0n1)
682+
list_block_devices() {
683+
TRACE_FUNC
684+
for dev in /sys/block/sd* /sys/block/nvme* /sys/block/vd* /sys/block/hd*; do
685+
if [ -e "$dev" ]; then
686+
echo "/dev/$(basename "$dev")"
687+
fi
688+
done | sort
689+
}
690+
691+
# Build displayable disk information using sysfs (vs current busybox's 2tb limit per https://bugs.busybox.net/show_bug.cgi?id=16276)
692+
# Output format matches prior fdisk parsing: "Disk /dev/<name>: <GB> GB" per line
693+
disk_info_sysfs() {
694+
TRACE_FUNC
695+
local disk_info=""
696+
DEBUG "disk_info_sysfs: Starting disk enumeration"
697+
for dev in /sys/block/sd* /sys/block/nvme* /sys/block/vd* /sys/block/hd*; do
698+
if [ -e "$dev" ]; then
699+
local devname=$(basename "$dev")
700+
DEBUG "disk_info_sysfs: Found device $dev (devname=$devname)"
701+
local size_bytes=$(cat "$dev/size" 2>/dev/null)
702+
DEBUG "disk_info_sysfs: /dev/${devname} reports size_bytes=$size_bytes sectors from $dev/size"
703+
if [ -n "$size_bytes" ] && [ "$size_bytes" -gt 0 ]; then
704+
# Determine sector size for this device from sysfs; prefer hw_sector_size
705+
local sector_size=512
706+
if [ -r "$dev/queue/hw_sector_size" ]; then
707+
sector_size=$(cat "$dev/queue/hw_sector_size" 2>/dev/null || echo 512)
708+
DEBUG "disk_info_sysfs: /dev/${devname} using hw_sector_size=$sector_size from $dev/queue/hw_sector_size"
709+
elif [ -r "$dev/queue/logical_block_size" ]; then
710+
sector_size=$(cat "$dev/queue/logical_block_size" 2>/dev/null || echo 512)
711+
DEBUG "disk_info_sysfs: /dev/${devname} using logical_block_size=$sector_size from $dev/queue/logical_block_size"
712+
else
713+
DEBUG "disk_info_sysfs: /dev/${devname} using default sector_size=$sector_size (no queue info available)"
714+
fi
715+
# Convert from sectors * sector_size to bytes, then to decimal GB.
716+
#
717+
# Explanation of the constants:
718+
# - We divide by 1,000,000,000 (1000000000) to report decimal GB (10^9 bytes),
719+
# which matches the historical output used elsewhere in Heads.
720+
# - Shell arithmetic is integer-only, so to round to the nearest GB we add
721+
# half the divisor (500,000,000) before dividing. This implements
722+
# rounding instead of truncation.
723+
# If you prefer binary GiB (1024^3), replace the divisor and half-divisor
724+
# with 1073741824 and 536870912 respectively, or use `awk`/`printf`
725+
# for fractional output.
726+
local size_gb=$(((size_bytes * sector_size + 500000000) / 1000000000))
727+
disk_info="${disk_info}Disk /dev/${devname}: ${size_gb} GB\n"
728+
DEBUG "disk_info_sysfs: /dev/${devname} calculated as ${size_gb} GB (${size_bytes} sectors * ${sector_size} bytes/sector = $((size_bytes * sector_size)) bytes)"
729+
fi
730+
fi
731+
done
732+
echo -n "$disk_info"
680733
}
681734

682735
list_usb_storage() {
@@ -1087,12 +1140,19 @@ is_gpt_bios_grub() {
10871140

10881141
NUMBER="${BASH_REMATCH[1]}"
10891142

1090-
# Now we know the device and partition number, get the type. This is
1091-
# specific to GPT disks, MBR disks are shown differently by fdisk.
1092-
TRACE "$PART_DEV is partition $NUMBER of $DEVICE"
1093-
if [ "$(fdisk -l "/dev/$DEVICE" 2>/dev/null | awk '$1 == '"$NUMBER"' {print $5}')" == grub ]; then
1094-
return 0
1143+
# Check partition type using sysfs if available, otherwise check for grub type
1144+
# For GPT disks, check /sys/class/block/<dev>/<partition>/uevent for PARTTYPENAME
1145+
local part_sys="/sys/class/block/$DEVICE/$(basename "$PART_DEV")"
1146+
if [ -e "$part_sys/uevent" ]; then
1147+
if grep -q "PARTTYPENAME=BIOS boot" "$part_sys/uevent"; then
1148+
TRACE "$PART_DEV is a GPT BIOS grub partition"
1149+
return 0
1150+
fi
10951151
fi
1152+
1153+
# Fallback: try to detect using other sysfs attributes if available
1154+
# For MBR disks, we would need to check partition type differently
1155+
DEBUG "$PART_DEV - unable to confirm it's a bios-grub partition via sysfs"
10961156
return 1
10971157
}
10981158

@@ -1163,7 +1223,7 @@ detect_boot_device() {
11631223
fi
11641224

11651225
# generate list of possible boot devices
1166-
fdisk -l 2>/dev/null | grep "Disk /dev/" | cut -f2 -d " " | cut -f1 -d ":" >/tmp/disklist
1226+
list_block_devices >/tmp/disklist
11671227

11681228
# Check each possible boot device
11691229
for i in $(cat /tmp/disklist); do

initrd/etc/gui_functions

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,43 @@ show_system_info() {
172172
cpustr=$(cat /proc/cpuinfo | grep 'model name' | uniq | sed -r 's/\(R\)//;s/\(TM\)//;s/CPU //;s/model name.*: //')
173173
kernel=$(uname -s -r)
174174

175+
# Build disk info using top-level block devices from sysfs (avoid partitions)
176+
disk_info=""
177+
DEBUG "show_system_info: Enumerating disks via list_block_devices"
178+
while IFS= read -r dev; do
179+
devname=$(basename "$dev")
180+
DEBUG "show_system_info: Processing device $dev (devname=$devname)"
181+
size_sectors=$(cat "/sys/block/$devname/size" 2>/dev/null || echo 0)
182+
DEBUG "show_system_info: /dev/${devname} size_sectors=$size_sectors from /sys/block/$devname/size"
183+
if [ -n "$size_sectors" ] && [ "$size_sectors" -gt 0 ]; then
184+
# get per-device sector size if available
185+
sector_size=512
186+
if [ -r "/sys/block/$devname/queue/hw_sector_size" ]; then
187+
sector_size=$(cat "/sys/block/$devname/queue/hw_sector_size" 2>/dev/null || echo 512)
188+
DEBUG "show_system_info: /dev/${devname} hw_sector_size=$sector_size"
189+
elif [ -r "/sys/block/$devname/queue/logical_block_size" ]; then
190+
sector_size=$(cat "/sys/block/$devname/queue/logical_block_size" 2>/dev/null || echo 512)
191+
DEBUG "show_system_info: /dev/${devname} logical_block_size=$sector_size"
192+
else
193+
DEBUG "show_system_info: /dev/${devname} using default sector_size=$sector_size"
194+
fi
195+
# Convert from sectors * sector_size to bytes, then to decimal GB.
196+
#
197+
# Explanation of the constants:
198+
# - We divide by 1,000,000,000 (1000000000) to report decimal GB (10^9 bytes),
199+
# consistent with the previous behavior.
200+
# - Shell arithmetic is integer-only; adding 500,000,000 (half the divisor)
201+
# before dividing implements rounding to the nearest GB instead of truncating.
202+
# For binary GiB use 1073741824 and half 536870912, or use external tools
203+
# for fractional precision.
204+
size_gb=$(((size_sectors * sector_size + 500000000) / 1000000000))
205+
DEBUG "show_system_info: /dev/${devname} calculated as ${size_gb} GB ($size_sectors sectors * $sector_size bytes = $((size_sectors * sector_size)) bytes)"
206+
disk_info="${disk_info}Disk /dev/${devname}: ${size_gb} GB\n"
207+
else
208+
DEBUG "show_system_info: /dev/${devname} skipped (size_sectors=$size_sectors is empty or zero)"
209+
fi
210+
done < <(list_block_devices)
211+
175212
local msgbox="${BOARD_NAME}
176213
177214
FW_VER: ${FW_VER}
@@ -181,8 +218,7 @@ show_system_info() {
181218
Microcode: $(cat /proc/cpuinfo | grep microcode | uniq | cut -d':' -f2 | tr -d ' ')
182219
RAM: ${memtotal} GB
183220
$battery_status
184-
$(fdisk -l 2>/dev/null | grep -e '/dev/sd.:' -e '/dev/nvme.*:' | sed 's/B,.*/B/')
185-
"
221+
${disk_info}"
186222

187223
local msgbox_rm_tabs=$(echo "$msgbox" | tr -d "\t")
188224

0 commit comments

Comments
 (0)