The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

The New Hotness

  • Making and Mounting SD Card Backup Images

    The process of creating, configuring, and backing up a Raspberry Pi goes a little something like this:

    unzip /mnt/diskimages/ISOs/Raspberry\ Pi/2016-11-25-raspbian-jessie-lite.zip
    sudo dcfldd statusinterval=16 bs=4M if=2016-11-25-raspbian-jessie-lite.img of=/dev/sdb
    ... Micro SD card to Pi, boot, perform various configuration tweaks ...
    ... card back to PC ...
    sudo dcfldd statusinterval=16 bs=4M if=/dev/sdb of=Streamer5-2017-01-02.img
    zip -1 Streamer5-2017-01-02.zip Streamer5-2017-01-02.img
    rsync -ahuv --progress Streamer5-2017-01-02.zip /mnt/diskimages/ISOs/Raspberry\ Pi/
    

    The ZIP operation crushes an 8 GB image down to 1.6 GB, obviously depending on most of the image being filled with binary zeros or foxes or something trivial like that. You could work around that with fsarchiver, at the cost of handling each partition separately.

    You can pipe the incoming image through GZIP when you don’t need the image right away:

    sudo dcfldd statusinterval=16 bs=4M if=/dev/sdb | gzip -1c > Streamer5-2017-01-02.gz
    

    There’s an obvious gotcha when you try to write an image to a (slightly) smaller card than the one it came from. Writing a smaller image on a larger card works just fine.

    With a raw image in hand, you must know the disk partition offsets within the image to mount them in loopback mode:

    fdisk -l Streamer5-2017-01-02.img
    Disk Streamer5-2017-01-02.img: 7.4 GiB, 7892631552 bytes, 15415296 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: dos
    Disk identifier: 0xc280d360
    
    Device                    Boot  Start      End  Sectors  Size Id Type
    Streamer5-2017-01-02.img1        8192   137215   129024   63M  c W95 FAT32 (LBA)
    Streamer5-2017-01-02.img2      137216 15415295 15278080  7.3G 83 Linux
    

    Knowing the offsets, the mounts go like this:

    sudo mount -o loop,offset=$(( 8192*512 )) Streamer5-2017-01-02.img /mnt/loop/
    ... snippage ...
    sudo mount -o loop,offset=$(( 137216*512 )) Streamer5-2017-01-02.img /mnt/loop/
    

    Because a Jessie Lite system will fit neatly into a 2 GB SD Card, you can trim the disk image to eliminate most of the unused space:

    sudo losetup -f
    /dev/loop0
    
    sudo losetup /dev/loop0 Streamer5-2017-01-02.img
    
    sudo partprobe /dev/loop0
    
    sudo gparted /dev/loop0
    ... resize ext4 partition from 7 GB to 1.8 GB
    
    sudo losetup -d /dev/loop0
    
    fdisk -l Streamer5-2017-01-02.img
    Disk Streamer5-2017-01-02.img: 7.4 GiB, 7892631552 bytes, 15415296 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: dos
    Disk identifier: 0xc280d360
    
    Device                    Boot  Start     End Sectors  Size Id Type
    Streamer5-2017-01-02.img1        8192  137215  129024   63M  c W95 FAT32 (LBA)
    Streamer5-2017-01-02.img2      137216 3833855 3696640  1.8G 83 Linux
    
    truncate --size=$(( (3833855+1)*512 )) Streamer5-2017-01-02.img
    ... or, if you don't care about an exact fit, use ...
    truncate --size=2G Streamer5-2017-01-02.img
    

    The partition and filesystem will plump up to fill the SD Card during the first boot on the Raspberry Pi.

    There exist automagic utilities for all that, but practicing simple stuff helps keep it all fresh…