Running Linux on a Readonly Root Filesystem
To increase flash lifetime and avoid problems with unexpected power cuts, I run all of my embedded Linux systems from a readonly root filesystem. This is a moving target: Depending on the software in use as well as the version and configuration of systemd and userland software, different adjustments may be needed.
I have created a readonly linux reference page containing all tweaks I
know of at the moment, which are mostly tmpfs mounts and /etc/tmpfiles.d
entries. I'll update it when I run by something new.
Debian Installer Preseeding for USB sticks (with UEFI)
Preseeding is a handy way of automating Debian installations. With a proper preseed.cfg, a Debian installation can run completely unattended in about 10 minutes, including setup of users, sudo and SSH keys.
For future reference, here are the things I found helpful
custom post-installation commands
d-i preseed/late_command
executes arbitrary commands after the installation
is completed. I use this to set up SSH keys and sudo, like so:
in-target mkdir -p /root/.ssh /home/derf/.ssh; \
in-target wget -O /root/.ssh/authorized_keys https://.../keys-root; \
in-target wget -O /home/derf/.ssh/authorized_keys https://.../keys; \
in-target chmod 700 /root/.ssh /home/derf/.ssh; \
in-target chmod 600 /root/.ssh/authorized_keys /home/derf/.ssh/authorized_keys; \
in-target chown -R derf:derf /home/derf/.ssh; \
apt-install sudo; in-target adduser derf sudo
Adding preseed.cfg to virt-install images
--initrd-inject
embeds arbitrary files into the root of the installation
image. So, for preseeding, just add --initrd-inject .../preseed.cfg
to your
virt-install
invocation.
Adding preseed.cfg to USB images (with UEFI support)
This is a bit more tricky. Basically: Download and unpack ISO, inject preseed.cfg into initrd, refresh md5sums, rebuild ISO and add UEFI support.
The following script should do the job for most amd64 systems.
Usage: ./mkpreseediso debian-x.y.z-amd64-netinst.iso
#!/bin/sh
set -e
ISO="$1"
WD="$(mktemp -d)"
7z x -o$WD $ISO
cd $WD
gunzip install.amd/initrd.gz
cp /tmp/preseed.cfg .
echo preseed.cfg | cpio -o -H newc -A -F install.amd/initrd
rm preseed.cfg
gzip install.amd/initrd
find -follow -type f -print0 | xargs --null md5sum > md5sum.txt
cd
xorriso -as mkisofs -o $ISO -isohybrid-mbr /usr/lib/ISOLINUX/isohdpfx.bin \
-c isolinux/boot.cat -b isolinux/isolinux.bin -no-emul-boot -boot-load-size 4 \
-boot-info-table -eltorito-alt-boot -e boot/grub/efi.img -no-emul-boot \
-isohybrid-gpt-basdat $WD
Check if a filesystem is mounted readonly
findmnt --raw --noheadings --output options --target SOME_DIRECTORY | grep -qE '(^|,)ro($|,)'
findmnt
is a handy alternative tomount
when writing scripts- SOME_DIRECTORY does not have to correspond to a mountpoint. If it doesn't, findmnt will traverse its parent directories until it finds the corresponding filesystem / mountpoint.
- a simple
grep ro
would also match options likeerrors=remount-ro
, so we make sure to only match the singlero
option. It must be delimited by commas or the start/end of the option string.
Checking Maildirs on the Commandline
I have a set of maildirs (one for each mailing list / other context) and want to know which of them contains unread mail without firing up my MUA.
Luckily, this is easy to do on the commandline without even looking at mail contents, as there's (mostly?) two kinds of unread mail:
- new and unprocessed mail. These messages are stored in
Maildir/new
, so if there's anything in there, it's an unread mail - new but no longer "Recent" mail. These messages have not been read yet, but
have already been transferred to a MUA using a Read-Write operation, causing
them to be marked as no longer new on the server side. They are stored in
Maildir/cur
alongside read mail, but do not have the "Seen" (S) flag set.
This is easy to check with zsh globbing: new/*(N)
expands to a non-empty
list if new and unprocessed mail is present, and cur/*~*,*S*(N)
expands to
a non-empty list if old but unread mail is present. Note that it requires
the extended_glob
zsh option to be set.