JessiBaughman

DreamPi Read-Only Boot Setup

Mar 7th, 2019
156
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 9.29 KB | None | 0 0
  1. #!/usr/bin/env bash
  2.  
  3. # Adapted from Adafruit read-only script:
  4. # https://learn.adafruit.com/read-only-raspberry-pi/
  5. #
  6. # Make DreamPi run read-only
  7. #
  8. # Tested with DreamPi 1.7
  9. #
  10.  
  11. if [ $(id -u) -ne 0 ]; then
  12.     echo "Installer must be run as root."
  13.     echo "Try 'sudo bash $0'"
  14.     exit 1
  15. fi
  16.  
  17. clear
  18.  
  19. echo "This script configures a Raspberry Pi"
  20. echo "SD card to boot into read-only mode,"
  21. echo "obviating need for clean shutdown."
  22. echo "NO FILES ON THE CARD CAN BE CHANGED"
  23. echo "WHEN PI IS BOOTED IN THIS STATE. Either"
  24. echo "the filesystems must be remounted in"
  25. echo "read/write mode, card must be mounted"
  26. echo "R/W on another system, or an optional"
  27. echo "jumper can be used to enable read/write"
  28. echo "on boot."
  29. echo
  30. echo "Links to original tutorials are in"
  31. echo "script source. This script doesn't offer"
  32. echo "an uninstall option. ALL other system"
  33. echo "config should be complete before using"
  34. echo "this script. (Setup wifi, enable SSH, etc)."
  35. echo
  36. echo "Run time ~3.5 minutes. Reboot required."
  37. echo
  38. echo -n "CONTINUE? [y/N] "
  39. read
  40. if [[ ! "$REPLY" =~ ^(yes|y|Y)$ ]]; then
  41.     echo "Canceled."
  42.     exit 0
  43. fi
  44.  
  45. # FEATURE PROMPTS ----------------------------------------------------------
  46. # Installation doesn't begin until after all user input is taken.
  47.  
  48. INSTALL_RW_JUMPER=0
  49. INSTALL_HALT=0
  50.  
  51. SYS_TYPES=(Pi\ 3\ /\ Pi\ Zero\ W All\ other\ models)
  52. OPTION_NAMES=(NO YES)
  53.  
  54. # Display pinout
  55. echo -e "\
  56. \033[1;36m   3V3\033[0m  (1)\033[0m (2) \033[0m \033[1;31m5V    \033[0m\n\
  57. \033[1;32m GPIO2\033[0m  (3)\033[0m (4) \033[0m \033[1;31m5V    \033[0m\n\
  58. \033[1;32m GPIO3\033[0m  (5)\033[0m (6) \033[0m \033[1;30mGND   \033[0m\n\
  59. \033[1;32m GPIO4\033[0m  (7)\033[0m (8) \033[0m \033[1;32mGPIO14\033[0m\n\
  60. \033[1;30m   GND\033[0m  (9)\033[0m (10)\033[0m \033[1;32mGPIO15\033[0m\n\
  61. \033[1;32mGPIO17\033[0m (11)\033[0m (12)\033[0m \033[1;32mGPIO18\033[0m\n\
  62. \033[1;32mGPIO27\033[0m (13)\033[0m (14)\033[0m \033[1;30mGND   \033[0m\n\
  63. \033[1;32mGPIO22\033[0m (15)\033[0m (16)\033[0m \033[1;32mGPIO23\033[0m\n\
  64. \033[1;36m   3V3\033[0m (17)\033[0m (18)\033[0m \033[1;32mGPIO24\033[0m\n\
  65. \033[1;32mGPIO10\033[0m (19)\033[0m (20)\033[0m \033[1;30mGND   \033[0m\n\
  66. \033[1;32m GPIO9\033[0m (21)\033[0m (22)\033[0m \033[1;32mGPIO25\033[0m\n\
  67. \033[1;32mGPIO11\033[0m (23)\033[0m (24)\033[0m \033[1;32mGPIO8 \033[0m\n\
  68. \033[1;30m   GND\033[0m (25)\033[0m (26)\033[0m \033[1;32mGPIO7 \033[0m\n\
  69. \033[1;32m GPIO0\033[0m (27)\033[0m (28)\033[0m \033[1;32mGPIO1 \033[0m\n\
  70. \033[1;32m GPIO5\033[0m (29)\033[0m (30)\033[0m \033[1;30mGND   \033[0m\n\
  71. \033[1;32m GPIO6\033[0m (31)\033[0m (32)\033[0m \033[1;32mGPIO12\033[0m\n\
  72. \033[1;32mGPIO13\033[0m (33)\033[0m (34)\033[0m \033[1;30mGND   \033[0m\n\
  73. \033[1;32mGPIO19\033[0m (35)\033[0m (36)\033[0m \033[1;32mGPIO16\033[0m\n\
  74. \033[1;32mGPIO26\033[0m (37)\033[0m (38)\033[0m \033[1;32mGPIO20\033[0m\n\
  75. \033[1;30m   GND\033[0m (39)\033[0m (40)\033[0m \033[1;32mGPIO21\033[0m\n"
  76.  
  77. echo -n "Enable boot-time read/write jumper? [y/N] "
  78. read
  79. if [[ "$REPLY" =~ (yes|y|Y)$ ]]; then
  80.     INSTALL_RW_JUMPER=1
  81.     echo -n "GPIO pin for R/W jumper [Suggested: 21]: "
  82.     read
  83.     RW_PIN=$REPLY
  84. fi
  85.  
  86. echo -n "Install GPIO-halt utility? [y/N] "
  87. read
  88. if [[ "$REPLY" =~ (yes|y|Y)$ ]]; then
  89.     INSTALL_HALT=1
  90.     echo -n "GPIO pin for halt button [Suggested: 16]: "
  91.     read
  92.     HALT_PIN=$REPLY
  93. fi
  94.  
  95. # VERIFY SELECTIONS BEFORE CONTINUING --------------------------------------
  96.  
  97. echo
  98. if [ $INSTALL_RW_JUMPER -eq 1 ]; then
  99.     echo "Boot-time R/W jumper: YES (GPIO$RW_PIN)"
  100. else
  101.     echo "Boot-time R/W jumper: NO"
  102. fi
  103. if [ $INSTALL_HALT -eq 1 ]; then
  104.     echo "Install GPIO-halt: YES (GPIO$HALT_PIN)"
  105. else
  106.     echo "Install GPIO-halt: NO"
  107. fi
  108. echo
  109. echo -n "CONTINUE? [y/N] "
  110. read
  111. if [[ ! "$REPLY" =~ ^(yes|y|Y)$ ]]; then
  112.     echo "Canceled."
  113.     exit 0
  114. fi
  115.  
  116. # START INSTALL ------------------------------------------------------------
  117. # All selections have been validated at this point...
  118.  
  119. # Given a filename, a regex pattern to match and a replacement string:
  120. # Replace string if found, else no change.
  121. # (# $1 = filename, $2 = pattern to match, $3 = replacement)
  122. replace() {
  123.     grep $2 $1 >/dev/null
  124.     if [ $? -eq 0 ]; then
  125.         # Pattern found; replace in file
  126.         sed -i "s/$2/$3/g" $1 >/dev/null
  127.     fi
  128. }
  129.  
  130. # Given a filename, a regex pattern to match and a string:
  131. # If found, no change, else append file with string on new line.
  132. append1() {
  133.     grep $2 $1 >/dev/null
  134.     if [ $? -ne 0 ]; then
  135.         # Not found; append on new line (silently)
  136.         echo $3 | sudo tee -a $1 >/dev/null
  137.     fi
  138. }
  139.  
  140. # Given a filename, a regex pattern to match and a string:
  141. # If found, no change, else append space + string to last line --
  142. # this is used for the single-line /boot/cmdline.txt file.
  143. append2() {
  144.     grep $2 $1 >/dev/null
  145.     if [ $? -ne 0 ]; then
  146.         # Not found; insert in file before EOF
  147.         sed -i "s/\'/ $3/g" $1 >/dev/null
  148.     fi
  149. }
  150.  
  151. echo
  152. echo "Starting installation..."
  153. echo "Updating package index files..."
  154. apt-get update
  155.  
  156. echo "Removing packages no longer required..."
  157. apt-get -y autoremove --purge
  158.  
  159. echo "Configuring system..."
  160.  
  161. # START readonlyboot
  162. # Create rc.local replacement, /home/pi/dreampi/readonlyboot
  163. echo "#!/bin/bash" > /home/pi/dreampi/readonlyboot
  164. echo "" >> /home/pi/dreampi/readonlyboot
  165. echo "exit 0" >> /home/pi/dreampi/readonlyboot
  166. chown pi:pi /home/pi/dreampi/readonlyboot
  167. chmod 755 /home/pi/dreampi/readonlyboot
  168.  
  169. # Install boot-time R/W jumper test if requested
  170. GPIOTEST="echo 'Checking GPIO $RW_PIN'\n\
  171. gpio -g mode $RW_PIN up\n\
  172. if [ \`gpio -g read $RW_PIN\` -eq 0 ] ; then\n\
  173. \techo 'GPIO $RW_PIN grounded. Remounting system RW.'\n\
  174. \tmount -o remount,rw \/\n\
  175. \tmount -o remount,rw \/boot\n\
  176. \tumount \/var\/log\n\
  177. \tumount \/var\/tmp\n\
  178. \tumount \/tmp\n\
  179. \tumount \/etc\/ppp\n\
  180. else\n\
  181. \techo 'GPIO $RW_PIN open. Leaving system RO.'\n\
  182. fi\n"
  183.  
  184. if [ $INSTALL_RW_JUMPER -ne 0 ]; then
  185.     apt-get install -y wiringpi
  186.     # Insert before final 'exit 0'
  187.     echo "Setting up boot-time R/W jumper..."
  188.     sed -i "s/^exit\ 0/$GPIOTEST\\nexit\ 0/g" /home/pi/dreampi/readonlyboot >/dev/null
  189. fi
  190.  
  191. # Install gpio-halt if requested
  192. if [ $INSTALL_HALT -ne 0 ]; then
  193.     if [ $INSTALL_RW_JUMPER -eq 0 ]; then
  194.         apt-get install -y wiringpi
  195.     fi
  196.     echo "Installing gpio-halt in /usr/local/bin..."
  197.     cd /tmp
  198.     curl -LO https://github.com/adafruit/Adafruit-GPIO-Halt/archive/master.zip
  199.     unzip master.zip
  200.     cd Adafruit-GPIO-Halt-master
  201.     make
  202.     mv gpio-halt /usr/local/bin/
  203.     cd ..
  204.     rm -rf Adafruit-GPIO-Halt-master
  205.     rm -rf /tmp/master.zip
  206.  
  207.     # Add and enable gpio-halt.service to systemd/system/dreampi
  208.     echo "Adding gpio-halt.service to systemd..."
  209.     echo -ne "[Unit]\n\
  210. Description=Short GPIO $HALT_PIN to ground to shutdown the Pi\n\
  211. After=multi-user.target\n\
  212. \n\
  213. [Service]\n\
  214. Type=idle\n\
  215. ExecStart=/usr/local/bin/gpio-halt $HALT_PIN &\n\
  216. \n\
  217. [Install]\n\
  218. WantedBy=multi-user.target" > /etc/systemd/system/gpio-halt.service
  219.     systemctl enable gpio-halt.service
  220. fi
  221.  
  222. # Add tmpfs /etc/ppp population
  223. mkdir /etc/ppp_ro
  224. cp -R /etc/ppp/* /etc/ppp_ro/
  225. ETCPPP="if [ ! -f \/etc\/ppp\/options ]; then \n\
  226. \techo 'Populating tmpfs \/etc\/ppp'\n\
  227. \tcp -R \/etc\/ppp_ro\/\* \/etc\/ppp\/ \n\
  228. fi\n"
  229. sed -i "s/^exit\ 0/$ETCPPP\\nexit\ 0/g" /home/pi/dreampi/readonlyboot >/dev/null
  230.  
  231. # Create readonlyboot.service and enable
  232. echo -ne "[Unit]\n\
  233. Description=ReadOnly-Boot Service\n\
  234. After=network.target etc-ppp.mount var-log.mount var-tmp.mount tmp.mount\n\
  235. \n\
  236. [Service]\n\
  237. Type=simple\n\
  238. ExecStart=/usr/local/bin/readonlyboot\n\
  239. \n\
  240. [Install]\n\
  241. WantedBy=multi-user.target\n" > /home/pi/dreampi/etc/systemd/system/readonlyboot.service
  242. ln -s /home/pi/dreampi/readonlyboot /usr/local/bin/readonlyboot
  243. ln -s /home/pi/dreampi/etc/systemd/system/readonlyboot.service /etc/systemd/system/readonlyboot.service
  244. systemctl enable readonlyboot.service
  245. # END readonlyboot
  246.  
  247. # Update dreampi.service to run after readonlyboot
  248. sed -i "s/^After=network.*$/After=network.target\ readonlyboot.service/g" /home/pi/dreampi/etc/systemd/system/dreampi.service >/dev/null
  249.  
  250. # Add fastboot, noswap and/or ro to end of /boot/cmdline.txt
  251. append2 /boot/cmdline.txt fastboot fastboot
  252. append2 /boot/cmdline.txt noswap noswap
  253. append2 /boot/cmdline.txt ro^o^t ro
  254.  
  255. # Move /var/spool to /tmp
  256. rm -rf /var/spool
  257. ln -s /tmp /var/spool
  258.  
  259. # Change spool permissions in var.conf (rondie/Margaret fix)
  260. replace /usr/lib/tmpfiles.d/var.conf "spool\s*0755" "spool 1777"
  261.  
  262. # Move dhcpd.resolv.conf to tmpfs
  263. touch /tmp/dhcpcd.resolv.conf
  264. rm /etc/resolv.conf
  265. ln -s /tmp/dhcpcd.resolv.conf /etc/resolv.conf
  266.  
  267. # Make edits to fstab
  268. # make / and /boot ro
  269. # mount /var/log, /var/tmp, /tmp, /etc/ppp to RAM
  270. replace /etc/fstab "vfat\s*defaults\s" "vfat    defaults,ro "
  271. replace /etc/fstab "ext4\s*defaults,noatime\s" "ext4    defaults,noatime,ro "
  272. append1 /etc/fstab "/var/log" "tmpfs /var/log tmpfs nodev,nosuid,noatime,size=100m 0 0"
  273. append1 /etc/fstab "/var/tmp" "tmpfs /var/tmp tmpfs nodev,nosuid,noatime,size=30m 0 0"
  274. append1 /etc/fstab "\s/tmp"   "tmpfs /tmp    tmpfs nodev,nosuid,noatime,size=100m 0 0"
  275. append1 /etc/fstab "/etc/ppp" "tmpfs /etc/ppp tmpfs nodev,nosuid,noatime,size=120k 0 0"
  276.  
  277. # PROMPT FOR REBOOT --------------------------------------------------------
  278.  
  279. echo "Done."
  280. echo
  281. echo "Settings take effect on next boot."
  282. echo
  283. echo -n "REBOOT NOW? [y/N] "
  284. read
  285. if [[ ! "$REPLY" =~ ^(yes|y|Y)$ ]]; then
  286.     echo "Exiting without reboot."
  287.     exit 0
  288. fi
  289. echo "Reboot started..."
  290. reboot
  291. exit 0
Add Comment
Please, Sign In to add comment