Embedded Read-only Root on Raspberry Pi and Odroid

Introduction

My main home automation controller runs on an Odroid U3 (bought from pollin.de).  Additionally I have a number of Raspberry Pi devices performing various duties around the home.

One of the most important features of an embedded system is that it doesn’t fail or need maintenance because of a power failure or an update etc.  This article explains how to run debian wheezy on these
devices with a read-only root filesystem.

Setup

Get SD Card Image

Odroid U3 / Raspberry Pi:

Decompress the image and write to an SD card using dd (eg):

dd if=<image>.img of=/dev/mmcblk0 bs=4M

Now boot the image.  On the odroid the login is root:odroidu2, on the raspberrypi it is root:raspberry

Raspberry Pi 2:

For the Raspberry Pi 2 use a debian Jessie netinstall.

  1. Follow the instructions at https://github.com/debian-pi/raspbian-ua-netinst to perform a netinstall.
  2. Make sure /etc/apt/sources.list contains “contrib non-free” in list

Initial Setup

If desired, modify /etc/apt/sources.list to point to your local mirror (eg. http://ftp.uk.debian.org).

Update and install packages:

apt-get update
apt-get dist-upgrade
apt-get install vim console-data locales

Raspberry Pi:

apt-get install rpi-update && rpi-update

Now reconfigure so that we have a unique and reasonably secure image.  We are going to regenerate the ssh keys and configure timezones/locales:

rm /etc/ssh/ssh_host*
dpkg-reconfigure openssh-server
dpkg-reconfigure tzdata
dpkg-reconfigure locales

Cleanup image:

Odroid:

userdel odroid && rm -rf /home/odroid

Resize the root partition:

  1. Using fdisk delete and re-add the root partition with identical start block and type.  If a swap partition exists delete it.
  2. Reboot and then run: resize2fs /dev/root

Boot Parameters:

Pi: Edit /boot/config.txt:

gpu_mem=16

Read-only Root Filesystem

This was initially based on this post: http://blog.gegg.us/2014/03/a-raspbian-read-only-root-fs-howto/

Add/Remove packages:

apt-get remove --purge cron anacron logrotate dbus rsync
apt-get autoremove --purge
apt-get install busybox-syslogd
dpkg --purge rsyslog

Modify System Files:

  • /etc/init.d/checkroot.sh: Comment out the line containing “do_start”.
  • /etc/init.d/checkfs.sh: Change:
    FSCK_LOGFILE=/tmp/checkfs.log

    Comment:

    #[ "$FSCKFIX" ] || FSCKFIX=no
    Add:
    FSCKFIX=yes
    VERBOSE=no

    Comment first instance of:

    #handle_failed_fsck

    Comment second instance and add log message:

    log_action_end_msg 1 "code $FSCKCODE"
    #handle_failed_fsck
  • /etc/init.d/checkroot-bootclean.sh:
    #rm -f /tmp/.clean /lib/init/rw/.clean /run/.clean /run/lock/.clean
    #clean_all
  • /etc/init.d/mountall.sh: Comment out the line containing “swaponagain ‘swapfile'”
  • /etc/fstab:
    proc /proc proc defaults 0 0
    /dev/mmcblk0p1 /boot vfat defaults,ro 0 0
    /dev/mmcblk0p2 / ext4 defaults,ro 0 0
    tmpfs /tmp tmpfs defaults 0 0
  • Comment out getty (tty2-tty6) instances in /etc/inittab

  • Edit /etc/ssh/sshd_config:

    PrintLastLog no
  • Add /etc/bash.bash_logout:
    /opt/bin/clean-rw
    /opt/bin/mount-ro

Remove startup scripts

insserv -r bootlogs
insserv -r sudo
insserv -r motd
insserv -r alsa-utils
insserv -r console-setup
insserv -r fake-hwclock

Modify boot

Pi: Append ro in /boot/cmdline.txt:

... elevator=deadline rootwait ro

DHCP and DNS

If you are using DHCP for IP addressing you need to make a few changes:

  • Make dhclient write it’s leases file to /tmp instead of /var/lib/dhcp:
    rm -rf /var/lib/dhcp
    ln -s /tmp /var/lib/dhcp
    • Make resolv.conf written to /tmp instead of fixed:
      rm /etc/resolv.conf
      ln -s /tmp/resolv.conf /etc/resolv.conf
    • Use the modified version of /sbin/dhclient-script so that it uses /tmp for it’s leases file.

Helper Scripts

The following helper scripts are available from the repository and should be placed in /opt/bin:

  • clean-rw: Clean up filesystem history etc ready for readonly.
  • mount-rw: Remount filesystems read/write for maintenance.
  • mount-ro: Remount filesystems readonly.
  • shutdown: Init script which executes clean-rw on shutdown if filesystems are read/write.
ln -s /opt/bin/shutdown /etc/init.d/shutdown

insserv -d shutdown

2 thoughts on “Embedded Read-only Root on Raspberry Pi and Odroid”

Leave a Reply

Your e-mail address will not be published. Required fields are marked *