Skip to content

Commit 23bcdbf

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. Tested with debian-13 with root hashes. I guess it should still work with PureOS. Signed-off-by: Thierry Laurion <insurgo@riseup.net>
1 parent 5d20cb3 commit 23bcdbf

File tree

6 files changed

+119
-36
lines changed

6 files changed

+119
-36
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-factory-reset

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ select_thumb_drive_for_key_material() {
503503
if [ $(cat /tmp/usb_disk_list | wc -l) -gt 0 ] &&
504504
file_selector --show-size "/tmp/usb_disk_list" "Select USB device to partition" &&
505505
[ -n "$FILE" ]; then
506-
# Obtain size of thumb drive to be wiped with fdisk
506+
# Obtain size of selected thumb drive in bytes
507507
disk_size_bytes="$(blockdev --getsize64 "$FILE")"
508508
if [ "$disk_size_bytes" -lt "$((128 * 1024 * 1024))" ]; then
509509
warn "Thumb drive size is less than 128MB!"

initrd/bin/oem-system-info-xx30

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ 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
# make sure we know the EC version too, populate if not already set
5458
if [ -z "$EC_VER" ]; then
5559
EC_VER=$(ec_version)
@@ -60,4 +64,4 @@ ec_ver_line=""
6064
[ -n "$EC_VER" ] && ec_ver_line="\nEC_VER: ${EC_VER}"
6165

6266
whiptail_type $BG_COLOR_MAIN_MENU $FB_OPTIONS --title 'System Info' \
63-
--msgbox "${BOARD_NAME}\nFW_VER: ${FW_VER}${ec_ver_line}\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
67+
--msgbox "${BOARD_NAME}\nFW_VER: ${FW_VER}${ec_ver_line}\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: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -164,21 +164,29 @@ check_root_checksums() {
164164
open_block_device_lvm() {
165165
TRACE_FUNC
166166
local VG="$1"
167+
local LV
168+
local MAPPER_VG
167169

168170
if ! lvm vgchange -ay "$VG"; then
169171
DEBUG "Can't open LVM VG: $VG"
170172
return 1
171173
fi
172174

173-
# Use the LV 'root'. This is the default name used by Qubes. There's no
174-
# way to configure this at the moment.
175-
if ! [ -e "/dev/mapper/$VG-root" ]; then
175+
# Use the LV 'root'. This is the default name used by Qubes. Try both the
176+
# canonical /dev/<vg>/<lv> path and mapper path (with dash escaping).
177+
LV="/dev/$VG/root"
178+
if ! [ -e "$LV" ]; then
179+
MAPPER_VG="${VG//-/--}"
180+
LV="/dev/mapper/$MAPPER_VG-root"
181+
fi
182+
183+
if ! [ -e "$LV" ]; then
176184
DEBUG "LVM volume group does not have 'root' logical volume"
177185
return 1
178186
fi
179187

180188
# Use the root LV now
181-
open_block_device_layers "/dev/mapper/$VG-root"
189+
open_block_device_layers "$LV"
182190
}
183191

184192
# Open a LUKS device, then continue looking for more layers.
@@ -269,9 +277,16 @@ open_root_device_no_clean_up() {
269277
close_block_device_lvm() {
270278
TRACE_FUNC
271279
local VG="$1"
280+
local LV
281+
local MAPPER_VG
282+
283+
# We always use the LV 'root' currently. Try canonical and mapper paths.
284+
LV="/dev/$VG/root"
285+
if ! [ -e "$LV" ]; then
286+
MAPPER_VG="${VG//-/--}"
287+
LV="/dev/mapper/$MAPPER_VG-root"
288+
fi
272289

273-
# We always use the LV 'root' currently
274-
local LV="/dev/mapper/$VG-root"
275290
if [ -e "$LV" ]; then
276291
close_block_device_layers "$LV"
277292
fi
@@ -367,7 +382,7 @@ detect_root_device()
367382
fi
368383

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

372387
# filter out extraneous options
373388
> /tmp_root_device_list

initrd/etc/functions

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

803803
device_has_partitions() {
804804
local DEVICE="$1"
805-
# fdisk normally says "doesn't contain a valid partition table" for
806-
# devices that lack a partition table - except for FAT32.
807-
#
808-
# FAT32 devices have a volume boot record that looks enough like an MBR
809-
# to satisfy fdisk. In that case, fdisk prints a partition table header
810-
# but no partitions.
811-
#
812-
# This check covers that: [ $(fdisk -l "$b" | wc -l) -eq 5 ]
813-
# In both cases the output is 5 lines: 3 about device info, 1 empty line
814-
# and the 5th will be the table header or the invalid message.
815-
local DISK_DATA=$(fdisk -l "$DEVICE" 2>/dev/null)
816-
if echo "$DISK_DATA" | grep -q "doesn't contain a valid partition table" ||
817-
[ "$(echo "$DISK_DATA" | wc -l)" -eq 5 ]; then
818-
# No partition table
805+
# Check if device has any partitions by checking sysfs
806+
# A device with partitions will have entries like /sys/block/sda/sda1, /sys/block/vda/vda1, etc
807+
local device_name=$(basename "$DEVICE")
808+
809+
if [ ! -e "/sys/block/$device_name" ]; then
810+
# Device doesn't exist
819811
return 1
820812
fi
821-
# There is a partition table
822-
return 0
813+
814+
# Count partitions - handle nvme partition naming (nvme0n1p1) and traditional (sda1, vda1, hda1)
815+
if [ -n "$(ls -1 /sys/block/$device_name/ 2>/dev/null | grep -E "^${device_name}(p)?[0-9]")" ]; then
816+
# There is a partition table
817+
return 0
818+
fi
819+
# No partition table
820+
return 1
821+
}
822+
823+
# List all block devices using sysfs
824+
# Outputs one device path per line (e.g., /dev/sda, /dev/vda, /dev/nvme0n1)
825+
list_block_devices() {
826+
TRACE_FUNC
827+
for dev in /sys/block/sd* /sys/block/nvme* /sys/block/vd* /sys/block/hd*; do
828+
if [ -e "$dev" ]; then
829+
echo "/dev/$(basename "$dev")"
830+
fi
831+
done | sort
832+
}
833+
834+
# Build displayable disk information using sysfs (vs current busybox's 2tb limit per https://bugs.busybox.net/show_bug.cgi?id=16276)
835+
# Output format: "Disk /dev/<name>: <GB> GB" per line
836+
disk_info_sysfs() {
837+
TRACE_FUNC
838+
local disk_info=""
839+
DEBUG "disk_info_sysfs: Starting disk enumeration"
840+
for dev in /sys/block/sd* /sys/block/nvme* /sys/block/vd* /sys/block/hd*; do
841+
if [ -e "$dev" ]; then
842+
local devname=$(basename "$dev")
843+
DEBUG "disk_info_sysfs: Found device $dev (devname=$devname)"
844+
local size_bytes=$(cat "$dev/size" 2>/dev/null)
845+
DEBUG "disk_info_sysfs: /dev/${devname} reports size_bytes=$size_bytes sectors from $dev/size"
846+
if [ -n "$size_bytes" ] && [ "$size_bytes" -gt 0 ]; then
847+
# Determine sector size for this device from sysfs; prefer hw_sector_size
848+
local sector_size=512
849+
if [ -r "$dev/queue/hw_sector_size" ]; then
850+
sector_size=$(cat "$dev/queue/hw_sector_size" 2>/dev/null || echo 512)
851+
DEBUG "disk_info_sysfs: /dev/${devname} using hw_sector_size=$sector_size from $dev/queue/hw_sector_size"
852+
elif [ -r "$dev/queue/logical_block_size" ]; then
853+
sector_size=$(cat "$dev/queue/logical_block_size" 2>/dev/null || echo 512)
854+
DEBUG "disk_info_sysfs: /dev/${devname} using logical_block_size=$sector_size from $dev/queue/logical_block_size"
855+
else
856+
DEBUG "disk_info_sysfs: /dev/${devname} using default sector_size=$sector_size (no queue info available)"
857+
fi
858+
# Convert from sectors * sector_size to bytes, then to decimal GB.
859+
#
860+
# Explanation of the constants:
861+
# - We divide by 1,000,000,000 (1000000000) to report decimal GB (10^9 bytes),
862+
# which matches the historical output used elsewhere in Heads.
863+
# - Shell arithmetic is integer-only, so to round to the nearest GB we add
864+
# half the divisor (500,000,000) before dividing. This implements
865+
# rounding instead of truncation.
866+
# If you prefer binary GiB (1024^3), replace the divisor and half-divisor
867+
# with 1073741824 and 536870912 respectively, or use `awk`/`printf`
868+
# for fractional output.
869+
local size_gb=$(((size_bytes * sector_size + 500000000) / 1000000000))
870+
disk_info="${disk_info}Disk /dev/${devname}: ${size_gb} GB\n"
871+
DEBUG "disk_info_sysfs: /dev/${devname} calculated as ${size_gb} GB (${size_bytes} sectors * ${sector_size} bytes/sector = $((size_bytes * sector_size)) bytes)"
872+
fi
873+
fi
874+
done
875+
echo -n "$disk_info"
823876
}
824877

825878
list_usb_storage() {
@@ -1278,12 +1331,19 @@ is_gpt_bios_grub() {
12781331

12791332
NUMBER="${BASH_REMATCH[1]}"
12801333

1281-
# Now we know the device and partition number, get the type. This is
1282-
# specific to GPT disks, MBR disks are shown differently by fdisk.
1283-
TRACE "$PART_DEV is partition $NUMBER of $DEVICE"
1284-
if [ "$(fdisk -l "/dev/$DEVICE" 2>/dev/null | awk '$1 == '"$NUMBER"' {print $5}')" == grub ]; then
1285-
return 0
1334+
# Check partition type using sysfs if available, otherwise check for grub type
1335+
# For GPT disks, check /sys/class/block/<dev>/<partition>/uevent for PARTTYPENAME
1336+
local part_sys="/sys/class/block/$DEVICE/$(basename "$PART_DEV")"
1337+
if [ -e "$part_sys/uevent" ]; then
1338+
if grep -q "PARTTYPENAME=BIOS boot" "$part_sys/uevent"; then
1339+
TRACE "$PART_DEV is a GPT BIOS grub partition"
1340+
return 0
1341+
fi
12861342
fi
1343+
1344+
# Fallback: try to detect using other sysfs attributes if available
1345+
# For MBR disks, we would need to check partition type differently
1346+
DEBUG "$PART_DEV - unable to confirm it's a bios-grub partition via sysfs"
12871347
return 1
12881348
}
12891349

@@ -1354,7 +1414,7 @@ detect_boot_device() {
13541414
fi
13551415

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

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

initrd/etc/gui_functions

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ display_block_device_size() {
9393
local block_dev disk_size_bytes
9494
block_dev="$1"
9595

96-
# Obtain size of thumb drive to be wiped with fdisk
96+
# Obtain size of the selected block device in bytes
9797
if ! disk_size_bytes="$(blockdev --getsize64 "$block_dev")"; then
9898
exit 1
9999
fi
@@ -178,6 +178,9 @@ show_system_info() {
178178
cpustr=$(cat /proc/cpuinfo | grep 'model name' | uniq | sed -r 's/\(R\)//;s/\(TM\)//;s/CPU //;s/model name.*: //')
179179
kernel=$(uname -s -r)
180180

181+
# Get disk information using the shared sysfs helper from functions
182+
local disk_info="$(disk_info_sysfs)"
183+
181184
local ec_ver_line=""
182185
[ -n "$EC_VER" ] && ec_ver_line="
183186
EC_VER: ${EC_VER}"
@@ -191,8 +194,7 @@ show_system_info() {
191194
Microcode: $(cat /proc/cpuinfo | grep microcode | uniq | cut -d':' -f2 | tr -d ' ')
192195
RAM: ${memtotal} GB
193196
$battery_status
194-
$(fdisk -l 2>/dev/null | grep -e '/dev/sd.:' -e '/dev/nvme.*:' | sed 's/B,.*/B/')
195-
"
197+
${disk_info}"
196198

197199
local msgbox_rm_tabs=$(echo "$msgbox" | tr -d "\t")
198200

0 commit comments

Comments
 (0)