123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- #!/bin/bash
-
- # CREDIT TO THESE TUTORIALS:
- # petr.io/en/blog/2015/11/09/read-only-raspberry-pi-with-jessie
- # hallard.me/raspberry-pi-read-only
- # k3a.me/how-to-make-raspberrypi-truly-read-only-reliable-and-trouble-free
-
- if [ $(id -u) -ne 0 ]; then
- echo "Installer must be run as root."
- echo "Try 'sudo bash $0'"
- exit 1
- fi
-
- clear
-
- echo "This script configures a Raspberry Pi"
- echo "SD card to boot into read-only mode,"
- echo "obviating need for clean shutdown."
- echo "NO FILES ON THE CARD CAN BE CHANGED"
- echo "WHEN PI IS BOOTED IN THIS STATE. Either"
- echo "the filesystems must be remounted in"
- echo "read/write mode, card must be mounted"
- echo "R/W on another system, or an optional"
- echo "jumper can be used to enable read/write"
- echo "on boot."
- echo
- echo "Links to original tutorials are in"
- echo "script source. THIS IS A ONE-WAY"
- echo "OPERATION. THERE IS NO SCRIPT TO"
- echo "REVERSE THIS SETUP! ALL other system"
- echo "config should be complete before using"
- echo "this script. MAKE A BACKUP FIRST."
- echo
- echo "Run time ~5 minutes. Reboot required."
- echo
- echo -n "CONTINUE? [y/N] "
- read
- if [[ ! "$REPLY" =~ ^(yes|y|Y)$ ]]; then
- echo "Canceled."
- exit 0
- fi
-
- # FEATURE PROMPTS ----------------------------------------------------------
- # Installation doesn't begin until after all user input is taken.
-
- INSTALL_RW_JUMPER=0
- INSTALL_HALT=0
- INSTALL_WATCHDOG=0
-
- # Given a list of strings representing options, display each option
- # preceded by a number (1 to N), display a prompt, check input until
- # a valid number within the selection range is entered.
- selectN() {
- for ((i=1; i<=$#; i++)); do
- echo $i. ${!i}
- done
- echo
- REPLY=""
- while :
- do
- echo -n "SELECT 1-$#: "
- read
- if [[ $REPLY -ge 1 ]] && [[ $REPLY -le $# ]]; then
- return $REPLY
- fi
- done
- }
-
- SYS_TYPES=(Pi\ 3\ /\ Pi\ Zero\ W All\ other\ models)
- WATCHDOG_MODULES=(bcm2835_wdog bcm2708_wdog)
- OPTION_NAMES=(NO YES)
-
- echo -n "Enable boot-time read/write jumper? [y/N] "
- read
- if [[ "$REPLY" =~ (yes|y|Y)$ ]]; then
- INSTALL_RW_JUMPER=1
- echo -n "GPIO pin for R/W jumper: "
- read
- RW_PIN=$REPLY
- fi
-
- echo -n "Install GPIO-halt utility? [y/N] "
- read
- if [[ "$REPLY" =~ (yes|y|Y)$ ]]; then
- INSTALL_HALT=1
- echo -n "GPIO pin for halt button: "
- read
- HALT_PIN=$REPLY
- fi
-
- echo -n "Enable kernel panic watchdog? [y/N] "
- read
- if [[ "$REPLY" =~ (yes|y|Y)$ ]]; then
- INSTALL_WATCHDOG=1
- echo "Target system type:"
- selectN "${SYS_TYPES[0]}" \
- "${SYS_TYPES[1]}"
- WD_TARGET=$?
- fi
-
- # VERIFY SELECTIONS BEFORE CONTINUING --------------------------------------
-
- echo
- if [ $INSTALL_RW_JUMPER -eq 1 ]; then
- echo "Boot-time R/W jumper: YES (GPIO$RW_PIN)"
- else
- echo "Boot-time R/W jumper: NO"
- fi
- if [ $INSTALL_HALT -eq 1 ]; then
- echo "Install GPIO-halt: YES (GPIO$HALT_PIN)"
- else
- echo "Install GPIO-halt: NO"
- fi
- if [ $INSTALL_WATCHDOG -eq 1 ]; then
- echo "Enable watchdog: YES (${SYS_TYPES[WD_TARGET-1]})"
- else
- echo "Enable watchdog: NO"
- fi
- echo
- echo -n "CONTINUE? [y/N] "
- read
- if [[ ! "$REPLY" =~ ^(yes|y|Y)$ ]]; then
- echo "Canceled."
- exit 0
- fi
-
- # START INSTALL ------------------------------------------------------------
- # All selections have been validated at this point...
-
- # Given a filename, a regex pattern to match and a replacement string:
- # Replace string if found, else no change.
- # (# $1 = filename, $2 = pattern to match, $3 = replacement)
- replace() {
- grep $2 $1 >/dev/null
- if [ $? -eq 0 ]; then
- # Pattern found; replace in file
- sed -i "s/$2/$3/g" $1 >/dev/null
- fi
- }
-
- # Given a filename, a regex pattern to match and a replacement string:
- # If found, perform replacement, else append file w/replacement on new line.
- replaceAppend() {
- grep $2 $1 >/dev/null
- if [ $? -eq 0 ]; then
- # Pattern found; replace in file
- sed -i "s/$2/$3/g" $1 >/dev/null
- else
- # Not found; append on new line (silently)
- echo $3 | sudo tee -a $1 >/dev/null
- fi
- }
-
- # Given a filename, a regex pattern to match and a string:
- # If found, no change, else append file with string on new line.
- append1() {
- grep $2 $1 >/dev/null
- if [ $? -ne 0 ]; then
- # Not found; append on new line (silently)
- echo $3 | sudo tee -a $1 >/dev/null
- fi
- }
-
- # Given a filename, a regex pattern to match and a string:
- # If found, no change, else append space + string to last line --
- # this is used for the single-line /boot/cmdline.txt file.
- append2() {
- grep $2 $1 >/dev/null
- if [ $? -ne 0 ]; then
- # Not found; insert in file before EOF
- sed -i "s/\'/ $3/g" $1 >/dev/null
- fi
- }
-
- echo
- echo "Starting installation..."
- echo "Updating package index files..."
- apt-get update
-
- echo "Removing unwanted packages..."
- #apt-get remove -y --force-yes --purge triggerhappy logrotate dbus \
- # dphys-swapfile xserver-common lightdm fake-hwclock
- # Let's keep dbus...that includes avahi-daemon, a la 'raspberrypi.local',
- # also keeping xserver & lightdm for GUI login (WIP, not working yet)
- apt-get remove -y --force-yes --purge triggerhappy logrotate \
- dphys-swapfile fake-hwclock
- apt-get -y --force-yes autoremove --purge
-
- # Replace log management with busybox (use logread if needed)
- echo "Installing ntp and busybox-syslogd..."
- apt-get -y --force-yes install ntp busybox-syslogd; dpkg --purge rsyslog
-
- echo "Configuring system..."
-
- # Install boot-time R/W jumper test if requested
- GPIOTEST="gpio -g mode $RW_PIN up\n\
- if [ \`gpio -g read $RW_PIN\` -eq 0 ] ; then\n\
- \tmount -o remount,rw \/\n\
- \tmount -o remount,rw \/boot\n\
- fi\n"
- if [ $INSTALL_RW_JUMPER -ne 0 ]; then
- apt-get install -y --force-yes wiringpi
- # Check if already present in rc.local:
- grep "gpio -g read" /etc/rc.local >/dev/null
- if [ $? -eq 0 ]; then
- # Already there, but make sure pin is correct:
- sed -i "s/^.*gpio\ -g\ read.*$/$GPIOTEST/g" /etc/rc.local >/dev/null
-
- else
- # Not there, insert before final 'exit 0'
- sed -i "s/^exit 0/$GPIOTEST\\nexit 0/g" /etc/rc.local >/dev/null
- fi
- fi
-
- # Install watchdog if requested
- if [ $INSTALL_WATCHDOG -ne 0 ]; then
- apt-get install -y --force-yes watchdog
- # $MODULE is specific watchdog module name
- MODULE=${WATCHDOG_MODULES[($WD_TARGET-1)]}
- # Add to /etc/modules, update watchdog config file
- append1 /etc/modules $MODULE $MODULE
- replace /etc/watchdog.conf "#watchdog-device" "watchdog-device"
- replace /etc/watchdog.conf "#max-load-1" "max-load-1"
- # Start watchdog at system start and start right away
- # Raspbian Stretch needs this package installed first
- apt-get install -y --force-yes insserv
- insserv watchdog; /etc/init.d/watchdog start
- # Additional settings needed on Jessie
- append1 /lib/systemd/system/watchdog.service "WantedBy" "WantedBy=multi-user.target"
- systemctl enable watchdog
- # Set up automatic reboot in sysctl.conf
- replaceAppend /etc/sysctl.conf "^.*kernel.panic.*$" "kernel.panic = 10"
- fi
-
- # Install gpio-halt if requested
- if [ $INSTALL_HALT -ne 0 ]; then
- apt-get install -y --force-yes wiringpi
- echo "Installing gpio-halt in /usr/local/bin..."
- cd /tmp
- curl -LO https://github.com/adafruit/Adafruit-GPIO-Halt/archive/master.zip
- unzip master.zip
- cd Adafruit-GPIO-Halt-master
- make
- mv gpio-halt /usr/local/bin
- cd ..
- rm -rf Adafruit-GPIO-Halt-master
-
- # Add gpio-halt to /rc.local:
- grep gpio-halt /etc/rc.local >/dev/null
- if [ $? -eq 0 ]; then
- # gpio-halt already in rc.local, but make sure correct:
- sed -i "s/^.*gpio-halt.*$/\/usr\/local\/bin\/gpio-halt $HALT_PIN \&/g" /etc/rc.local >/dev/null
- else
- # Insert gpio-halt into rc.local before final 'exit 0'
- sed -i "s/^exit 0/\/usr\/local\/bin\/gpio-halt $HALT_PIN \&\\nexit 0/g" /etc/rc.local >/dev/null
- fi
- fi
-
- # Add fastboot, noswap and/or ro to end of /boot/cmdline.txt
- append2 /boot/cmdline.txt fastboot fastboot
- append2 /boot/cmdline.txt noswap noswap
- append2 /boot/cmdline.txt ro^o^t ro
-
- # Move /var/spool to /tmp
- rm -rf /var/spool
- ln -s /tmp /var/spool
-
- # Move /var/lib/lightdm and /var/cache/lightdm to /tmp
- rm -rf /var/lib/lightdm
- rm -rf /var/cache/lightdm
- ln -s /tmp /var/lib/lightdm
- ln -s /tmp /var/cache/lightdm
-
- # Make SSH work
- replaceAppend /etc/ssh/sshd_config "^.*UsePrivilegeSeparation.*$" "UsePrivilegeSeparation no"
- # bbro method (not working in Jessie?):
- #rmdir /var/run/sshd
- #ln -s /tmp /var/run/sshd
-
- # Change spool permissions in var.conf (rondie/Margaret fix)
- replace /usr/lib/tmpfiles.d/var.conf "spool\s*0755" "spool 1777"
-
- # Move dhcpd.resolv.conf to tmpfs
- touch /tmp/dhcpcd.resolv.conf
- rm /etc/resolv.conf
- ln -s /tmp/dhcpcd.resolv.conf /etc/resolv.conf
-
- # Make edits to fstab
- # make / ro
- # tmpfs /var/log tmpfs nodev,nosuid 0 0
- # tmpfs /var/tmp tmpfs nodev,nosuid 0 0
- # tmpfs /tmp tmpfs nodev,nosuid 0 0
- replace /etc/fstab "vfat\s*defaults\s" "vfat defaults,ro "
- replace /etc/fstab "ext4\s*defaults,noatime\s" "ext4 defaults,noatime,ro "
- append1 /etc/fstab "/var/log" "tmpfs /var/log tmpfs nodev,nosuid 0 0"
- append1 /etc/fstab "/var/tmp" "tmpfs /var/tmp tmpfs nodev,nosuid 0 0"
- append1 /etc/fstab "\s/tmp" "tmpfs /tmp tmpfs nodev,nosuid 0 0"
-
- # PROMPT FOR REBOOT --------------------------------------------------------
-
- echo "Done."
- echo
- echo "Settings take effect on next boot."
- echo
- echo -n "REBOOT NOW? [y/N] "
- read
- if [[ ! "$REPLY" =~ ^(yes|y|Y)$ ]]; then
- echo "Exiting without reboot."
- exit 0
- fi
- echo "Reboot started..."
- reboot
- exit 0
|