Skip to content

Replace fdisk -l with sysfs-based disk enumeration (2tb+ drive support) #2035

Open
tlaurion wants to merge 1 commit intolinuxboot:masterfrom
tlaurion:replace_codebase_fdisk-l
Open

Replace fdisk -l with sysfs-based disk enumeration (2tb+ drive support) #2035
tlaurion wants to merge 1 commit intolinuxboot:masterfrom
tlaurion:replace_codebase_fdisk-l

Conversation

@tlaurion
Copy link
Collaborator

@tlaurion tlaurion commented Dec 8, 2025

fdisk -l can deal with 2TB max size drives. Use linux sysfs instead.

Tested:

  • qemu oem-factory reset with a canokey and public key exported to virt thumb drive's exclusive ext4 public partition
  • qemu oem-facctory-reset with canokey and in-ram key generation and key to card, creating luks+exfat partition on virt thumb drive
  • qemu-img 8tb qcow2 root attached: system information shows 8tb
  • test on v540tu
  • rootfs hash creation/hash checks on ubuntu/pureos/debian

Fixes #2034 (should have been the fix for #1884)

Copilot AI review requested due to automatic review settings December 8, 2025 18:26
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 parsing fdisk -l output
  • 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.

@tlaurion tlaurion marked this pull request as draft December 8, 2025 18:59
@tlaurion tlaurion force-pushed the replace_codebase_fdisk-l branch 2 times, most recently from b0bdb67 to 879fb3c Compare December 8, 2025 19:34
@tlaurion tlaurion changed the title Replace fdisk -l with sysfs-based disk enumeration for better busybox compatibility Replace fdisk -l with sysfs-based disk enumeration (2tb+ drive support) Dec 8, 2025
@tlaurion tlaurion marked this pull request as ready for review December 8, 2025 22:52
@tlaurion tlaurion force-pushed the replace_codebase_fdisk-l branch 3 times, most recently from b3c8e82 to d296082 Compare December 15, 2025 21:15
@tlaurion tlaurion force-pushed the replace_codebase_fdisk-l branch 3 times, most recently from 12bbb04 to 23bcdbf Compare February 28, 2026 00:54
@tlaurion tlaurion requested a review from Copilot February 28, 2026 00:55
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +1334 to +1345
# 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
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
# 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

Copilot uses AI. Check for mistakes.
Comment on lines +844 to +871
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)"
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
… 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>
@tlaurion tlaurion force-pushed the replace_codebase_fdisk-l branch from 23bcdbf to 2f37ee0 Compare February 28, 2026 17:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8tb drives are reported as 4tb drives under System Information menu

2 participants