Inspecting disk image partitions and contents on Linux

Understanding the internal structure of disk images is essential for debugging conversions, verifying configurations, and troubleshooting boot issues. This tutorial demonstrates systematic approaches to analyze partition layouts and manually inspect file system contents within any disk image. While the techniques apply universally to disk images, the examples focus on Raspberry Pi images processed through mender-convert.

The Challenge

Converting disk images with mender-convert creates complex partition structures with multiple file systems. Quick verification commands often rely on hardcoded offsets that break when image layouts change, making systematic inspection techniques necessary for reliable analysis.

Understanding Partition Structure

Start by examining the overall partition layout using fdisk:

# Display partition table with sector information
fdisk -l deploy/raspberrypi4-mender.img

# Show partition boundaries in human-readable format
parted deploy/raspberrypi4-mender.img unit MB print

The fdisk output reveals crucial information:

  • Start sectors: Where each partition begins on the disk
  • Size: Number of sectors per partition
  • Type: Partition type codes (83 for Linux, c for FAT32)
  • Sector size: Usually 512 bytes, but verify in the header

For Raspberry Pi conversions, expect to see:

  1. Boot partition (FAT32, typically 256MB-512MB)
  2. Root filesystem A (ext4, variable size)
  3. Root filesystem B (ext4, same size as A)
  4. Data partition (ext4, remaining space)

Calculating Mount Offsets

Rather than guessing offsets, calculate them systematically:

#!/bin/bash
# Save this as calculate-offsets.sh and run it
DISK_IMAGE="deploy/raspberrypi4-mender.img"

# Get sector size (usually 512 bytes)
SECTOR_SIZE=$(fdisk -l "$DISK_IMAGE" | grep "Sector size" | awk '{print $7}')

# Extract start sectors for each partition (handle boot flag * in field 2)
BOOT_START=$(fdisk -l "$DISK_IMAGE" | awk '$1 ~ /1$/ {if ($2 == "*") print $3; else print $2}')
ROOTFS_A_START=$(fdisk -l "$DISK_IMAGE" | awk '$1 ~ /2$/ {print $2}')
ROOTFS_B_START=$(fdisk -l "$DISK_IMAGE" | awk '$1 ~ /3$/ {print $2}')
DATA_START=$(fdisk -l "$DISK_IMAGE" | awk '$1 ~ /4$/ {print $2}')

# Calculate byte offsets
BOOT_OFFSET=$((BOOT_START * SECTOR_SIZE))
ROOTFS_A_OFFSET=$((ROOTFS_A_START * SECTOR_SIZE))
ROOTFS_B_OFFSET=$((ROOTFS_B_START * SECTOR_SIZE))
DATA_OFFSET=$((DATA_START * SECTOR_SIZE))

echo "Boot partition offset: $BOOT_OFFSET bytes"
echo "Root A partition offset: $ROOTFS_A_OFFSET bytes"
echo "Root B partition offset: $ROOTFS_B_OFFSET bytes"
echo "Data partition offset: $DATA_OFFSET bytes"

Loop Device Approach

For more convenient access to multiple partitions, use loop devices with the -P flag to automatically create partition devices:

# Create loop device for the entire image
# Use --show -f to automatically find free loop device
sudo losetup -P --show -f $DISK_IMAGE

# Verify partition detection (replace loop0 with actual device from previous command)
ls -la /dev/loop0p*

# Mount individual partitions
sudo mkdir -p /mnt/{boot,rootfs-a,rootfs-b,data}
sudo mount /dev/loop0p1 /mnt/boot
sudo mount /dev/loop0p2 /mnt/rootfs-a
sudo mount /dev/loop0p3 /mnt/rootfs-b
sudo mount /dev/loop0p4 /mnt/data

# Inspect contents
ls -la /mnt/boot/
ls -la /mnt/rootfs-a/etc/
df -h /mnt/*

# Cleanup when finished
sudo umount /mnt/{boot,rootfs-a,rootfs-b,data}
sudo losetup -d /dev/loop0

File System Analysis

Once partitions are mounted, analyze their contents systematically:

Boot Partition Inspection

The boot partition contains the bootloader configuration and kernel files. Raspberry Pi systems use specific configuration files that control hardware initialization and boot parameters. Understanding these files helps diagnose boot failures and verify correct hardware configuration.

# Create mount point and mount boot partition (adjust loop device number as needed)
sudo mkdir -p /mnt/boot
sudo mount /dev/loop0p1 /mnt/boot

# Check bootloader configuration
cat /mnt/boot/config.txt
cat /mnt/boot/cmdline.txt

# Verify kernel and device tree presence
find /mnt/boot -name "*.dtb" | head -5
find /mnt/boot -name "kernel*"

# Check for U-Boot files (if using U-Boot)
find /mnt/boot -name "u-boot*"
find /mnt/boot -name "boot.scr"

Root Filesystem Analysis

The root filesystem contains the complete operating system installation. After conversion, mender-convert creates two identical root partitions for A/B updates. Examining the filesystem structure verifies that the conversion preserved the original system correctly and that required directories and services remain intact.

# Create mount point and mount root filesystem A (adjust loop device as needed)
sudo mkdir -p /mnt/rootfs-a
sudo mount /dev/loop0p2 /mnt/rootfs-a

# Verify essential system directories
ls -la /mnt/rootfs-a/
du -sh /mnt/rootfs-a/{bin,etc,lib,usr,var}

# Check system configuration
cat /mnt/rootfs-a/etc/fstab
cat /mnt/rootfs-a/etc/hostname
ls -la /mnt/rootfs-a/etc/systemd/system/

# Inspect installed packages (Debian/Ubuntu systems)
dpkg --admindir=/mnt/rootfs-a/var/lib/dpkg --get-selections | head -20

Alternative Inspection Methods

Using Offset Mounting

When loop devices are unavailable, use direct offset mounting:

# Create mount points and mount using calculated offsets (use literal values)
# For example, if BOOT_OFFSET=12582912:
sudo mkdir -p /mnt/{boot,rootfs-a}
sudo mount -o loop,offset=12582912 deploy/raspberrypi4-mender.img /mnt/boot
sudo mount -o loop,offset=549453824 deploy/raspberrypi4-mender.img /mnt/rootfs-a

# Inspect and unmount
ls -la /mnt/boot/
sudo umount /mnt/boot /mnt/rootfs-a

File System Type Detection

Before attempting to mount partitions, identify their filesystem types to select appropriate mount commands and avoid errors. The file command analyzes filesystem signatures, while blkid provides additional metadata like UUIDs and labels when available.

# Identify file system types without mounting
sudo file -sL /dev/loop0p1
sudo file -sL /dev/loop0p2

# Or using blkid if available
sudo blkid /dev/loop0p1
sudo blkid /dev/loop0p2

Debugging Common Issues

Boot Problems

Boot failures often stem from missing files, incorrect configuration, or corrupted boot partition contents. Raspberry Pi systems require specific firmware files and properly formatted configuration files. These commands verify the essential boot components are present and correctly configured.

# Create mount point and mount boot partition if not already mounted
sudo mkdir -p /mnt/boot
sudo mount /dev/loop0p1 /mnt/boot 2>/dev/null
cat /mnt/boot/config.txt | grep -v "^#" | grep -v "^$"

# Verify kernel command line
cat /mnt/boot/cmdline.txt

# Check for required boot files
ls -la /mnt/boot/bootcode.bin /mnt/boot/start*.elf 2>/dev/null || echo "Missing Pi boot files"

Root Filesystem Issues

Root filesystem problems prevent successful system initialization. Common issues include filesystem corruption, missing system binaries, or incorrect directory structures. These checks verify filesystem integrity and ensure critical system components exist in expected locations.

# Check file system integrity (read-only check)
sudo fsck.ext4 -n /dev/loop0p2

# Create mount point and mount rootfs if not already mounted
sudo mkdir -p /mnt/rootfs-a
sudo mount /dev/loop0p2 /mnt/rootfs-a 2>/dev/null
test -x /mnt/rootfs-a/sbin/init && echo "Init found" || echo "Init missing"
ls -la /mnt/rootfs-a/lib/systemd/systemd 2>/dev/null || echo "Systemd missing"

Space Usage Analysis

Understanding partition space utilization helps identify oversized images, locate bloated components, or diagnose insufficient space issues. Converted images should have similar content across both root partitions, making space analysis useful for detecting unexpected differences or problematic content.

# Analyze partition space usage
df -h /mnt/boot /mnt/rootfs-a /mnt/rootfs-b /mnt/data

# Find largest directories in root filesystem
sudo find /mnt/rootfs-a -maxdepth 1 -type d -exec du -sh {} \; | sort -hr | head -10

# Check for unexpected large files
sudo find /mnt/rootfs-a -size +100M -type f -exec ls -lh {} \;

Automation Script

Create a helper script for systematic image inspection:

#!/bin/bash
# image-inspect.sh - Systematic disk image inspection
IMAGE="$1"
if [ -z "$IMAGE" ]; then
echo "Usage: $0 <disk-image>"
exit 1
fi

echo "=== Partition Layout ==="
fdisk -l "$IMAGE"

echo
echo "=== File System Types ==="
LOOP_DEV=$(sudo losetup -P --show -f "$IMAGE")
for part in ${LOOP_DEV}p*; do
echo -n "$(basename $part): "
sudo blkid -o value -s TYPE "$part" 2>/dev/null || echo "unknown"
done

echo
echo "=== Mounting and Basic Inspection ==="
sudo mkdir -p /tmp/img-inspect/{boot,rootfs-a,rootfs-b,data}

# Mount partitions (adapt numbering as needed)
sudo mount ${LOOP_DEV}p1 /tmp/img-inspect/boot 2>/dev/null
sudo mount ${LOOP_DEV}p2 /tmp/img-inspect/rootfs-a 2>/dev/null
sudo mount ${LOOP_DEV}p3 /tmp/img-inspect/rootfs-b 2>/dev/null
sudo mount ${LOOP_DEV}p4 /tmp/img-inspect/data 2>/dev/null

# Show space usage
df -h /tmp/img-inspect/*

# Cleanup
sudo umount /tmp/img-inspect/* 2>/dev/null
sudo rmdir /tmp/img-inspect/* /tmp/img-inspect
sudo losetup -d "$LOOP_DEV"

Security Considerations

When inspecting images from untrusted sources:

  • Use read-only mounts: sudo mkdir -p /mnt/boot && sudo mount -o ro /dev/loop0p1 /mnt/boot or sudo mkdir -p /mnt/boot && sudo mount -o loop,ro,offset=12582912 image.img /mnt/boot
  • Avoid executing binaries from mounted filesystems
  • Be cautious with symbolic links that might escape the mount point
  • Consider using containerized inspection environments

Performance Notes

Image inspection operations can be I/O intensive:

  • Loop device setup is faster than repeated offset calculations
  • Loop devices with -P flag provide more reliable partition detection than manual offset calculation
  • For large images, consider working on faster storage (SSD vs HDD)
  • Multiple concurrent mounts of the same image file are supported

This systematic approach to image inspection eliminates guesswork and provides reliable methods for understanding disk image structure, making debugging and verification more efficient and accurate.

1 Like