Close

Booting Crankshaft-NG from USB

wjcarpenterWJCarpenter wrote 09/01/2024 at 22:04 • 6 min read • Like

https://getcrankshaft.com/ Is a software bundle for using a Raspberry Pi and attached touchscreen display as a DIY Android Auto head unit. The project has been dormant for a couple of years, but that hasn't stopped me from poking around at it. One of the clever things they do is mount the boot and root filesystem read-only to minimize the chance of SD card corruption, which is one of the banes of SD cards with Linux. The selectively make the filesystems writable when they need to store some persistent thing, like a config update. The usual reason for wanting to operate from a USB thumb drive is minimized. However, because of the physical geometry of my screen and the case I printed for it, it's a tremendous amount of trouble to get the SD card out and back in once things are assembled. 

So, I want to skip the SD card and operate directly from a USB thumb drive. I'm using a Raspberry Pi 3B+, which can boot from USB out of the box. Some things in the Crankshaft layer assume you are using an SD card and prevent booting and operating from USB. I've worked through the changes needed to get it working, and here are the details.


There are the usual two Linux filesystems involved: the boot filesystem and the root filesystem. Crankshaft assumes those are /dev/mmcblk0p1 and /dev/mmcblk0p2 (SD card partitions), respectively. The USB drive will typically have those same filesystems on /dev/sda1 and /dev/sda2, respectively. That's not guaranteed if you have other things involved, so it's better to identify them by the partition UUID. I assume you're doing your image-making on some Linux machine. With the USB drive plugged into that machine, you can get the partition UUIDs via the blkid command:

$ blkid
/dev/sda1: LABEL_FATBOOT="boot" LABEL="boot" UUID="BBBB-AAAA" TYPE="vfat" PARTUUID="abcdefab-01"
/dev/sda2: LABEL="rootfs" UUID="ffffffff-eeee-dddd-cccc-bbbbbbbbbbbb" TYPE="ext4" PARTUUID="abcdefab-02"

 The thing we're interested in is the PARTUUID. The following steps assume you have the partitions of your thumb drive actually mounted on some Linux machine. You may need to be root to do some of the steps, depending on your local configuration of that Linux machine.

Caution: It's possible to end up with partitions on different devices having the same partition UUID. Using both devices on the same host can result in a lot of confusion and chaos. The smart thing to do for that case is to change the partition UUIDs on at least one of them. This thread has some good information about how to do that: https://askubuntu.com/questions/1250224/how-to-change-partuuid


In the root directory of the "boot" filesystem (/dev/sda1 in my example), there is a text file cmdline.txt that supplies command line parameters to the kernel at boot time. It's quite long but looks something like this:

console=tty3 root=/dev/mmcblk0p2 ro rootfstype=ext4 ....

With a text editor, change the "root=" part to reference your root filesystem partition (/dev/sda2 in my example). Instead of a device name, use the partition UUID. For example,

console=tty3 root=PARTUUID=abcdefab-02 ro rootfstype=ext4 ....

With no SD card inserted, the RPi's boot sequence stuff will find the boot partition on your thumb drive, and the above change will tell it where to find the root partition. But more tricks are needed.


In the "etc" directory of the root filesystem is the standard fstab file that tells Linux what filesystems to mount where. For the Crankshaft image, it will look something like this:

proc        /proc        proc            defaults,noatime,nodiratime        0    0
/dev/mmcblk0p1    /boot        vfat            ro,defaults,noatime,nodiratime        0    2
/dev/mmcblk0p2    /        ext4            defaults,noatime,nodiratime    0    1
ramfs        /tmp            ramfs            size=128m,nodev,nosuid,noatime,nodiratime        0    0
ramfs        /var/tmp        ramfs            size=16m,nodev,nosuid,noatime,nodiratime        0    0
ramfs        /var/log        ramfs            size=16m,nodev,nosuid,noatime,nodiratime        0    0

(followed by several more "ramfs"  mounts, which are irrelevant for this discussion). The second and third lines are our old friends, the boot and root partitions. You want to change those to reference the partition UUIDs of your USB drive:

proc        /proc        proc            defaults,noatime,nodiratime        0    0
#/dev/mmcblk0p1    /boot        vfat            ro,defaults,noatime,nodiratime        0    2
#/dev/mmcblk0p2    /        ext4            defaults,noatime,nodiratime    0    1
PARTUUID=abcdefab-01    /boot        vfat            ro,defaults,noatime,nodiratime        0    2
#PARTUUID=abcdefab-02    /        ext4            defaults,noatime,nodiratime    0    1
ramfs        /tmp            ramfs            size=128m,nodev,nosuid,noatime,nodiratime        0    0
ramfs        /var/tmp        ramfs            size=16m,nodev,nosuid,noatime,nodiratime        0    0
ramfs        /var/log        ramfs            size=16m,nodev,nosuid,noatime,nodiratime        0    0

It's not necessary to change the line for "/", but I did it and left it there as a comment for consistency.


If you have used other RPi images, you know that one of the things they do during the first boot is expand the root filesystem to use the rest of the space on the physical device. The Crankshaft image tries to do that, too, but it hardcodes the root partition device name instead of detecting it. On the root filesystem partition, the file usr/local/bin/crankshaft is a lengthy shell script (over 3700 lines). The partition resize logic is in an area that starts like this:

    #resize partition and fs
    if [ $1 == "resize" ]; then
    cs_systemrw
    currentsize=$(sudo parted /dev/mmcblk0p2 print | tail -n2 | head -n1 | awk {'print $4'})
    cs_echo "Current partition size: $currentsize"

 Of course, one could fix up that logic to use the correct USB root partition. I find it easier to do the resize myself, manually, and get Crankshaft to skip that step. You can do that by creating a file "etc/cs_resize_done" so that Crankshaft thinks it's already done it. The file can be empty, but I put a short note into it to remind me that I created it manually.

There are various tools for manipulating partitions on Linux. I like to use gparted because its graphical interface helps me avoid blunders. The Crankshaft root partition starts out with a size under 3 GB. I don't know how much extra space it might need under all possible circumstances (though I suspect it's not much). I resized mine to about 10 GB.


Crankshaft can use additional partitions for whatever you want to put there. I don't currently have a use for this, but while I have the USB drive open in gparted, I created an additional partition to use the rest of the space. I formatted it for ext4 and used the label CSSTORAGE so that Crankshaft would recognize it.


If I discover more fix-ups needed, I'll update this page.

Like

Discussions