Last active
July 24, 2021 16:53
-
-
Save vladbabii/f6e734cd0aea1288064ece504addc8d6 to your computer and use it in GitHub Desktop.
pi_readonly_auto.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# based on | |
# https://learn.adafruit.com/read-only-raspberry-pi/ | |
if [ $(id -u) -ne 0 ]; then | |
echo "Installer must be run as root." | |
echo "Try 'sudo bash $0'" | |
exit 1 | |
fi | |
echo "____________ 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 "Enable boot-time read/write jumper? on 21 " | |
INSTALL_RW_JUMPER=1 | |
RW_PIN=21 | |
echo "Install GPIO-halt utility on gpio 33 " | |
INSTALL_HALT=1 | |
HALT_PIN=33 | |
echo "Enable kernel panic watchdog" | |
INSTALL_WATCHDOG=1 | |
WD_TARGET=1 | |
# 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 cron 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 avahi-daemon \ | |
dphys-swapfile fake-hwclock | |
apt-get -y --force-yes autoremove --purge | |
# Replace log management with (use logread if needed) | |
#echo "Installing busybox-syslogd..." | |
#apt-get -y --force-yes install 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment