├── .gitignore ├── LICENSE.txt ├── Makefile ├── README.md ├── TODO_ro ├── appliance ├── etc │ ├── bash.bashrc │ ├── network │ │ └── interfaces │ ├── rc.local │ ├── ssh │ │ └── sshd_config │ ├── update-motd.d │ │ └── 20welcome │ └── wpa_supplicant │ │ └── wpa_supplicant.conf └── home │ └── pi │ ├── install_packages.sh │ ├── read-only-fs.sh │ └── time_sync.sh ├── cmdline.txt ├── pi-init2 ├── src └── projects.bytemark.co.uk │ └── pi-init2 │ └── init.go └── ssh /.gitignore: -------------------------------------------------------------------------------- 1 | src/golang.org 2 | pkg/ 3 | *.zip 4 | *~ 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Bytemark Ltd. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Files to copy to sd: cmdline.txt pi-init2 appliance 2 | 3 | SHELL = /bin/bash 4 | GOPATH=$(shell pwd) 5 | GOOS=linux 6 | GOARCH=arm 7 | GOARM=6 8 | 9 | all : src/projects.bytemark.co.uk/pi-init2 10 | @GOPATH=$(GOPATH) GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM) go build -o pi-init2 projects.bytemark.co.uk/pi-init2 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RPI-Setup (WIP) 2 | ======== 3 | 4 | Purpose 5 | ------- 6 | This repository allows you to set up a Raspberry Pi solely by writing to the /boot partition (i.e. the one you can write from most computers!) in a repeatable manner. This allows you to distribute a small .zip file to set up a Raspberry Pi to do anything. You tell the user to unzip it over the top of the Pi's boot partition - the system can set itself up perfectly on the first boot, and once everything is ready to go reboot. 7 | 8 | This is done using [pi-init2](src/projects.bytemark.co.uk/pi-init2/init.go). You can read more about how it works behind the scenes [here](https://blog.bytemark.co.uk/2016/01/04/setting-up-a-raspberry-pi-perfectly-on-the-first-boot). Additionaly pi-init2 various system files are symlinked back to the /boot, allowing you to reliably edit those "user-serviceable" files from the computer in future. 9 | 10 | Another thing this repository will do is automated setting up the SD card in read-only mode as described [here](https://learn.adafruit.com/read-only-raspberry-pi). This is especially important for cases where the pi can get its power cut off without propper shutdown (for example in robotics) as it will prevent SD card corruption. This adds an `(ro)` (read-only) indicator to the bash prompt indicating that the file system can't be changed. To make changes you can use the `rw` and `ro` bash commands to transision between read-write and read-only modes respectivaly. A number of directories (including `/tmp`, `/var/log` and `/var/tmp`) are remapped to a [tmpfs](https://en.wikipedia.org/wiki/Tmpfs) to ensure programs that expect them to be writable contiune to work. 11 | 12 | Setting up the SD card for the PI 13 | ------------- 14 | From your desktop / laptop: 15 | 16 | * Download and write a standard Raspbian Buster Lite SD card. Use [this version](https://slack-files.com/T0RAWRCGY-FQG7WTSBH-eb9549ed22) so everyone is using the same version. We recomend using [etcher](https://www.balena.io/etcher/) to flash the card 17 | * Download the latest release of this repository into the /boot partition. Unzip and move all the files into the /boot folder (replace any files that conflict so the repository's version overwrites the original version). Delete the zip file and now empty folder. 18 | * Remove the SD card and put it into your Pi. 19 | 20 | The Raspberry Pi should now boot and set everything up for development. 21 | 22 | Getting internet access at Stanford 23 | ------------- 24 | This script will make so the RPi automatically wants to connect the Stanford network. Initially it won't be able to do that as it is not yet authenticated to do it. To set that up: 25 | 26 | - Plug your Pi in to power (over the onboard micro USB port). Either plug a monitor and keyboard into the Pi or SSH into it using your laptop over Ethernet. Log in to the Pi. In the welcome message that comes after the login line, look for the Pi's **MAC address**, which will appear under the line that says "wireless Hardware MAC address". Note that address down. 27 | - Use another computer to navigate to [iprequest.stanford.edu](http://iprequest.stanford.edu). 28 | - Log in using your Stanford credentials. 29 | - Follow the on-screen instructions to add another device: 30 | - **First page:** Device Type: Other, Operating System: Linux, Hardware Address: put Pi's MAC address 31 | - **Second page:** Make and model: Other PC, Hardware Addresses Wired: delete what's there, Hardware Addresses Wireless: put Pi's MAC address 32 | - Confirm that the Pi is connected to the network: 33 | - Wait for an email (to your Stanford email) that the device has been accepted 34 | - `sudo reboot` on the Pi 35 | - After it's done rebooting, type `ping www.google.com` and make sure you are receiving packets over the network 36 | 37 | Getting internet access elsewhere 38 | ------------- 39 | There are two methods for getting internet access elsewhere: using the raspi-config tool on the Pi or changing the wpa_supplicant file in the SD card file system. Using the raspi-config tool is simpler and recommended for beginners, but the benefits of modifying the wpa_supplicant file is that you can set the proper internet settings before starting up the Pi, which may help in scenarios where you'd like to do as little setup on the Pi as possible. 40 | 41 | 1. Raspi-config method 42 | 43 | Once SSH'd into the Pi, run: 44 | ```bash 45 | sudo raspi-config 46 | ``` 47 | Then go to Network Options and follow the prompts to connect to Wifi. 48 | 2. Wpa_supplicant method 49 | 50 | Edit `/etc/wpa_supplicant/wpa_supplicant.conf` as documented [here](https://linux.die.net/man/5/wpa_supplicant.conf) and reboot. Thanks to pi-init2 magic that file can be edited before the pi is ever turned on from `/boot/appliance/etc/wpa_supplicant/wpa_supplicant.conf` 51 | 52 | 53 | Getting started with the Pi 54 | ------------- 55 | - Configure your computer to access the robot network: 56 | - Go to your network settings for the interface you wish to use (ethernet/wifi) 57 | - Change your Configure IPv4: Manually 58 | - Change your IP Address to something in range 10.0.0.X (If you ar part of Stanford Student Robotics pick something that doesn't colide with other systems from this [document](https://docs.google.com/spreadsheets/d/1pqduUwYa1_sWiObJDrvCCz4Al3pl588ytE4u-Dwa6Pw/edit?usp=sharing)) 59 | - Change your Subnet Mask: 255.255.255.0 60 | - Leave the Router blank 61 | - After disconnecting from the robot network remember to return those settings to what they orignially were, otherwise your internet on that interface won't work 62 | - Ssh into the pi using `ssh pi@10.0.0.10` from your computer 63 | - Type `rw` to enter read-write mode. Confirm that the terminal prompt ends with `(rw)` instead of `(ro)` 64 | - Run `sudo ./install_packages.sh` to install packages 65 | - If the IP is still 10.0.0.10 you will be prompted to change it 66 | - If the hostname is still raspberry you will be prompted to change it 67 | - You will be asked to enter the current time and date. This is needed so that certificates don't get marked as expired. There is a `time_sync.sh` script that updates the current time from google 68 | 69 | What this repo does 70 | ------------- 71 | - Enables ssh. Because the password is kept unchanged (raspberry) ssh is only enabled on the ethernet interface. Comment out the ListenAddress lines from `/boot/appliance/etc/ssh/sshd_config` to enable it on all interfaces. 72 | - Sets the Pi to connect to the robot network (10.0.0.X) over ethernet 73 | - Expands the SD card file system 74 | - Sets the file system up as read-only 75 | - Prepares to connect to Stanford WiFi (see above for details) 76 | - Gives the script to install tools and repos needed for development 77 | 78 | 79 | Building pi-init2 80 | ----------------- 81 | This repo inculdes the pi-init2 binary and there shouldn't be any reason to recompile it. If you need to there is a included Makefile 82 | -------------------------------------------------------------------------------- /TODO_ro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanfordroboticsclub/RPI-Setup/7aa9d60ab173a085cbc52e6d2adec6086109a2ff/TODO_ro -------------------------------------------------------------------------------- /appliance/etc/bash.bashrc: -------------------------------------------------------------------------------- 1 | # System-wide .bashrc file for interactive bash(1) shells. 2 | 3 | # To enable the settings / commands in this file for login shells as well, 4 | # this file has to be sourced in /etc/profile. 5 | 6 | # If not running interactively, don't do anything 7 | [ -z "$PS1" ] && return 8 | 9 | # check the window size after each command and, if necessary, 10 | # update the values of LINES and COLUMNS. 11 | shopt -s checkwinsize 12 | 13 | # set variable identifying the chroot you work in (used in the prompt below) 14 | if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then 15 | debian_chroot=$(cat /etc/debian_chroot) 16 | fi 17 | 18 | # set a fancy prompt (non-color, overwrite the one in /etc/profile) 19 | PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' 20 | 21 | # Commented out, don't overwrite xterm -T "title" -n "icontitle" by default. 22 | # If this is an xterm set the title to user@host:dir 23 | #case "$TERM" in 24 | #xterm*|rxvt*) 25 | # PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"' 26 | # ;; 27 | #*) 28 | # ;; 29 | #esac 30 | 31 | # enable bash completion in interactive shells 32 | #if ! shopt -oq posix; then 33 | # if [ -f /usr/share/bash-completion/bash_completion ]; then 34 | # . /usr/share/bash-completion/bash_completion 35 | # elif [ -f /etc/bash_completion ]; then 36 | # . /etc/bash_completion 37 | # fi 38 | #fi 39 | 40 | # if the command-not-found package is installed, use it 41 | if [ -x /usr/lib/command-not-found -o -x /usr/share/command-not-found/command-not-found ]; then 42 | function command_not_found_handle { 43 | # check because c-n-f could've been removed in the meantime 44 | if [ -x /usr/lib/command-not-found ]; then 45 | /usr/lib/command-not-found -- "$1" 46 | return $? 47 | elif [ -x /usr/share/command-not-found/command-not-found ]; then 48 | /usr/share/command-not-found/command-not-found -- "$1" 49 | return $? 50 | else 51 | printf "%s: command not found\n" "$1" >&2 52 | return 127 53 | fi 54 | } 55 | fi 56 | 57 | # set variable identifying the filesystem you work in (used in the prompt below) 58 | set_bash_prompt(){ 59 | fs_mode=$(mount | grep mmcblk0p2 | grep -o 'rw' || echo ro) 60 | PS1='\[\033[01;32m\]\u@\h${fs_mode:+($fs_mode)}\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' 61 | } 62 | 63 | alias ro='sudo mount -o remount,ro / ; sudo mount -o remount,ro /boot' 64 | alias rw='sudo mount -o remount,rw / ; sudo mount -o remount,rw /boot' 65 | 66 | # setup fancy prompt" 67 | PROMPT_COMMAND=set_bash_prompt 68 | -------------------------------------------------------------------------------- /appliance/etc/network/interfaces: -------------------------------------------------------------------------------- 1 | # interfaces(5) file used by ifup(8) and ifdown(8) 2 | 3 | # Please note that this file is written to be used with dhcpcd 4 | # For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf' 5 | 6 | # Include files from /etc/network/interfaces.d: 7 | source-directory /etc/network/interfaces.d 8 | 9 | auto lo 10 | iface lo inet loopback 11 | 12 | allow-hotplug wlan0 13 | iface wlan0 inet manual 14 | wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf 15 | iface default inet dhcp 16 | 17 | allow-hotplug eth0 18 | iface eth0 inet static 19 | address 10.0.0.10 20 | netmask 255.255.255.0 21 | 22 | 23 | -------------------------------------------------------------------------------- /appliance/etc/rc.local: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | # 3 | # rc.local 4 | # 5 | # This script is executed at the end of each multiuser runlevel. 6 | # Make sure that the script will "exit 0" on success or any other 7 | # value on error. 8 | # 9 | # In order to enable or disable this script just change the execution 10 | # bits. 11 | # 12 | # By default this script does nothing. 13 | 14 | # Print the IP address 15 | _IP=$(hostname -I) || true 16 | if [ "$_IP" ]; then 17 | printf "My IP address is %s\n" "$_IP" 18 | fi 19 | 20 | if [ -f /boot/TODO_ro ]; then 21 | sudo bash /home/pi/read-only-fs.sh 22 | fi 23 | 24 | exit 0 25 | -------------------------------------------------------------------------------- /appliance/etc/ssh/sshd_config: -------------------------------------------------------------------------------- 1 | 2 | # This is the sshd server system-wide configuration file. See 3 | # sshd_config(5) for more information. 4 | 5 | # This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin 6 | 7 | # The strategy used for options in the default sshd_config shipped with 8 | # OpenSSH is to specify options with their default value where 9 | # possible, but leave them commented. Uncommented options override the 10 | # default value. 11 | # $OpenBSD: sshd_config,v 1.100 2016/08/15 12:32:04 naddy Exp $ 12 | 13 | # This is the sshd server system-wide configuration file. See 14 | # sshd_config(5) for more information. 15 | 16 | # This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin 17 | 18 | # The strategy used for options in the default sshd_config shipped with 19 | # OpenSSH is to specify options with their default value where 20 | # possible, but leave them commented. Uncommented options override the 21 | # default value. 22 | 23 | #Port 22 24 | #AddressFamily any 25 | #ListenAddress 0.0.0.0 26 | #ListenAddress :: 27 | 28 | #HostKey /etc/ssh/ssh_host_rsa_key 29 | #HostKey /etc/ssh/ssh_host_ecdsa_key 30 | #HostKey /etc/ssh/ssh_host_ed25519_key 31 | 32 | # Ciphers and keying 33 | #RekeyLimit default none 34 | 35 | # Logging 36 | #SyslogFacility AUTH 37 | #LogLevel INFO 38 | 39 | # Authentication: 40 | 41 | #LoginGraceTime 2m 42 | #PermitRootLogin prohibit-password 43 | #StrictModes yes 44 | #MaxAuthTries 6 45 | #MaxSessions 10 46 | 47 | #PubkeyAuthentication yes 48 | 49 | # Expect .ssh/authorized_keys2 to be disregarded by default in future. 50 | #AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2 51 | 52 | #AuthorizedPrincipalsFile none 53 | 54 | #AuthorizedKeysCommand none 55 | #AuthorizedKeysCommandUser nobody 56 | 57 | # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts 58 | #HostbasedAuthentication no 59 | # Change to yes if you don't trust ~/.ssh/known_hosts for 60 | # HostbasedAuthentication 61 | #IgnoreUserKnownHosts no 62 | # Don't read the user's ~/.rhosts and ~/.shosts files 63 | #IgnoreRhosts yes 64 | 65 | # To disable tunneled clear text passwords, change to no here! 66 | #PasswordAuthentication yes 67 | #PermitEmptyPasswords no 68 | 69 | # Change to yes to enable challenge-response passwords (beware issues with 70 | # some PAM modules and threads) 71 | ChallengeResponseAuthentication no 72 | 73 | # Kerberos options 74 | #KerberosAuthentication no 75 | #KerberosOrLocalPasswd yes 76 | #KerberosTicketCleanup yes 77 | #KerberosGetAFSToken no 78 | 79 | # GSSAPI options 80 | #GSSAPIAuthentication no 81 | #GSSAPICleanupCredentials yes 82 | #GSSAPIStrictAcceptorCheck yes 83 | #GSSAPIKeyExchange no 84 | 85 | # Set this to 'yes' to enable PAM authentication, account processing, 86 | # and session processing. If this is enabled, PAM authentication will 87 | # be allowed through the ChallengeResponseAuthentication and 88 | # PasswordAuthentication. Depending on your PAM configuration, 89 | # PAM authentication via ChallengeResponseAuthentication may bypass 90 | # the setting of "PermitRootLogin without-password". 91 | # If you just want the PAM account and session checks to run without 92 | # PAM authentication, then enable this but set PasswordAuthentication 93 | # and ChallengeResponseAuthentication to 'no'. 94 | UsePAM yes 95 | 96 | #AllowAgentForwarding yes 97 | #AllowTcpForwarding yes 98 | #GatewayPorts no 99 | X11Forwarding yes 100 | #X11DisplayOffset 10 101 | #X11UseLocalhost yes 102 | #PermitTTY yes 103 | PrintMotd no 104 | #PrintLastLog yes 105 | #TCPKeepAlive yes 106 | #UseLogin no 107 | UsePrivilegeSeparation no 108 | #PermitUserEnvironment no 109 | #Compression delayed 110 | #ClientAliveInterval 0 111 | #ClientAliveCountMax 3 112 | #UseDNS no 113 | #PidFile /var/run/sshd.pid 114 | #MaxStartups 10:30:100 115 | #PermitTunnel no 116 | #ChrootDirectory none 117 | #VersionAddendum none 118 | 119 | # no default banner path 120 | #Banner none 121 | 122 | # Allow client to pass locale environment variables 123 | AcceptEnv LANG LC_* 124 | 125 | # override default of no subsystems 126 | Subsystem sftp /usr/lib/openssh/sftp-server 127 | 128 | # Example of overriding settings on a per-user basis 129 | #Match User anoncvs 130 | # X11Forwarding no 131 | # AllowTcpForwarding no 132 | # PermitTTY no 133 | # ForceCommand cvs server 134 | 135 | ListenAddress 10.0.0.1 136 | ListenAddress 10.0.0.2 137 | ListenAddress 10.0.0.3 138 | ListenAddress 10.0.0.4 139 | ListenAddress 10.0.0.5 140 | ListenAddress 10.0.0.6 141 | ListenAddress 10.0.0.7 142 | ListenAddress 10.0.0.8 143 | ListenAddress 10.0.0.9 144 | 145 | ListenAddress 10.0.0.10 146 | ListenAddress 10.0.0.11 147 | ListenAddress 10.0.0.12 148 | ListenAddress 10.0.0.13 149 | ListenAddress 10.0.0.14 150 | ListenAddress 10.0.0.15 151 | ListenAddress 10.0.0.16 152 | ListenAddress 10.0.0.17 153 | ListenAddress 10.0.0.18 154 | ListenAddress 10.0.0.19 155 | 156 | ListenAddress 10.0.0.20 157 | ListenAddress 10.0.0.21 158 | ListenAddress 10.0.0.22 159 | ListenAddress 10.0.0.23 160 | ListenAddress 10.0.0.24 161 | ListenAddress 10.0.0.25 162 | ListenAddress 10.0.0.26 163 | ListenAddress 10.0.0.27 164 | ListenAddress 10.0.0.28 165 | ListenAddress 10.0.0.29 166 | 167 | ListenAddress 10.0.0.30 168 | ListenAddress 10.0.0.31 169 | ListenAddress 10.0.0.32 170 | ListenAddress 10.0.0.33 171 | ListenAddress 10.0.0.34 172 | ListenAddress 10.0.0.35 173 | ListenAddress 10.0.0.36 174 | ListenAddress 10.0.0.37 175 | ListenAddress 10.0.0.38 176 | ListenAddress 10.0.0.39 177 | 178 | ListenAddress 10.0.0.40 179 | ListenAddress 10.0.0.41 180 | ListenAddress 10.0.0.42 181 | ListenAddress 10.0.0.43 182 | ListenAddress 10.0.0.44 183 | ListenAddress 10.0.0.45 184 | ListenAddress 10.0.0.46 185 | ListenAddress 10.0.0.47 186 | ListenAddress 10.0.0.48 187 | ListenAddress 10.0.0.49 188 | 189 | ListenAddress 10.0.0.50 190 | ListenAddress 10.0.0.51 191 | ListenAddress 10.0.0.52 192 | ListenAddress 10.0.0.53 193 | ListenAddress 10.0.0.54 194 | ListenAddress 10.0.0.55 195 | ListenAddress 10.0.0.56 196 | ListenAddress 10.0.0.57 197 | ListenAddress 10.0.0.58 198 | ListenAddress 10.0.0.59 199 | 200 | ListenAddress 10.0.0.60 201 | ListenAddress 10.0.0.61 202 | ListenAddress 10.0.0.62 203 | ListenAddress 10.0.0.63 204 | ListenAddress 10.0.0.64 205 | ListenAddress 10.0.0.65 206 | ListenAddress 10.0.0.66 207 | ListenAddress 10.0.0.67 208 | ListenAddress 10.0.0.68 209 | ListenAddress 10.0.0.69 210 | 211 | ListenAddress 10.0.0.70 212 | ListenAddress 10.0.0.71 213 | ListenAddress 10.0.0.72 214 | ListenAddress 10.0.0.73 215 | ListenAddress 10.0.0.74 216 | ListenAddress 10.0.0.75 217 | ListenAddress 10.0.0.76 218 | ListenAddress 10.0.0.77 219 | ListenAddress 10.0.0.78 220 | ListenAddress 10.0.0.79 221 | 222 | ListenAddress 10.0.0.80 223 | ListenAddress 10.0.0.81 224 | ListenAddress 10.0.0.82 225 | ListenAddress 10.0.0.83 226 | ListenAddress 10.0.0.84 227 | ListenAddress 10.0.0.85 228 | ListenAddress 10.0.0.86 229 | ListenAddress 10.0.0.87 230 | ListenAddress 10.0.0.88 231 | ListenAddress 10.0.0.89 232 | 233 | ListenAddress 10.0.0.90 234 | ListenAddress 10.0.0.91 235 | ListenAddress 10.0.0.92 236 | ListenAddress 10.0.0.93 237 | ListenAddress 10.0.0.94 238 | ListenAddress 10.0.0.95 239 | ListenAddress 10.0.0.96 240 | ListenAddress 10.0.0.97 241 | ListenAddress 10.0.0.98 242 | ListenAddress 10.0.0.99 243 | 244 | 245 | ListenAddress 10.0.0.100 246 | ListenAddress 10.0.0.101 247 | ListenAddress 10.0.0.102 248 | ListenAddress 10.0.0.103 249 | ListenAddress 10.0.0.104 250 | ListenAddress 10.0.0.105 251 | ListenAddress 10.0.0.106 252 | ListenAddress 10.0.0.107 253 | ListenAddress 10.0.0.108 254 | ListenAddress 10.0.0.109 255 | 256 | ListenAddress 10.0.0.110 257 | ListenAddress 10.0.0.111 258 | ListenAddress 10.0.0.112 259 | ListenAddress 10.0.0.113 260 | ListenAddress 10.0.0.114 261 | ListenAddress 10.0.0.115 262 | ListenAddress 10.0.0.116 263 | ListenAddress 10.0.0.117 264 | ListenAddress 10.0.0.118 265 | ListenAddress 10.0.0.119 266 | 267 | ListenAddress 10.0.0.120 268 | ListenAddress 10.0.0.121 269 | ListenAddress 10.0.0.122 270 | ListenAddress 10.0.0.123 271 | ListenAddress 10.0.0.124 272 | ListenAddress 10.0.0.125 273 | ListenAddress 10.0.0.126 274 | ListenAddress 10.0.0.127 275 | ListenAddress 10.0.0.128 276 | ListenAddress 10.0.0.129 277 | 278 | ListenAddress 10.0.0.130 279 | ListenAddress 10.0.0.131 280 | ListenAddress 10.0.0.132 281 | ListenAddress 10.0.0.133 282 | ListenAddress 10.0.0.134 283 | ListenAddress 10.0.0.135 284 | ListenAddress 10.0.0.136 285 | ListenAddress 10.0.0.137 286 | ListenAddress 10.0.0.138 287 | ListenAddress 10.0.0.139 288 | 289 | ListenAddress 10.0.0.140 290 | ListenAddress 10.0.0.141 291 | ListenAddress 10.0.0.142 292 | ListenAddress 10.0.0.143 293 | ListenAddress 10.0.0.144 294 | ListenAddress 10.0.0.145 295 | ListenAddress 10.0.0.146 296 | ListenAddress 10.0.0.147 297 | ListenAddress 10.0.0.148 298 | ListenAddress 10.0.0.149 299 | 300 | ListenAddress 10.0.0.150 301 | ListenAddress 10.0.0.151 302 | ListenAddress 10.0.0.152 303 | ListenAddress 10.0.0.153 304 | ListenAddress 10.0.0.154 305 | ListenAddress 10.0.0.155 306 | ListenAddress 10.0.0.156 307 | ListenAddress 10.0.0.157 308 | ListenAddress 10.0.0.158 309 | ListenAddress 10.0.0.159 310 | 311 | ListenAddress 10.0.0.160 312 | ListenAddress 10.0.0.161 313 | ListenAddress 10.0.0.162 314 | ListenAddress 10.0.0.163 315 | ListenAddress 10.0.0.164 316 | ListenAddress 10.0.0.165 317 | ListenAddress 10.0.0.166 318 | ListenAddress 10.0.0.167 319 | ListenAddress 10.0.0.168 320 | ListenAddress 10.0.0.169 321 | 322 | ListenAddress 10.0.0.170 323 | ListenAddress 10.0.0.171 324 | ListenAddress 10.0.0.172 325 | ListenAddress 10.0.0.173 326 | ListenAddress 10.0.0.174 327 | ListenAddress 10.0.0.175 328 | ListenAddress 10.0.0.176 329 | ListenAddress 10.0.0.177 330 | ListenAddress 10.0.0.178 331 | ListenAddress 10.0.0.179 332 | 333 | ListenAddress 10.0.0.180 334 | ListenAddress 10.0.0.181 335 | ListenAddress 10.0.0.182 336 | ListenAddress 10.0.0.183 337 | ListenAddress 10.0.0.184 338 | ListenAddress 10.0.0.185 339 | ListenAddress 10.0.0.186 340 | ListenAddress 10.0.0.187 341 | ListenAddress 10.0.0.188 342 | ListenAddress 10.0.0.189 343 | 344 | ListenAddress 10.0.0.190 345 | ListenAddress 10.0.0.191 346 | ListenAddress 10.0.0.192 347 | ListenAddress 10.0.0.193 348 | ListenAddress 10.0.0.194 349 | ListenAddress 10.0.0.195 350 | ListenAddress 10.0.0.196 351 | ListenAddress 10.0.0.197 352 | ListenAddress 10.0.0.198 353 | ListenAddress 10.0.0.199 354 | -------------------------------------------------------------------------------- /appliance/etc/update-motd.d/20welcome: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | MAC=$(cat /sys/class/net/wlan0/address) 3 | 4 | if [ -f /boot/TODO_ro ]; then 5 | echo 6 | echo "Welcome to the Stanford Robotics Raspberry Pi distribution" 7 | echo "The Pi is currently setting up the read-only file system" 8 | echo "It should reboot shortly and be ready to use" 9 | exit 0 10 | fi 11 | 12 | echo 13 | echo "Welcome to the Stanford Robotics Raspberry Pi distribution" 14 | echo "The setup process is almost complete. You just need to register" 15 | echo "the Pi with Stanford network to give it internet access. Go to" 16 | echo "iprequest.stanford.edu and follow the onscreen instructions" 17 | echo "As the wireless Hardware MAC address enter:" 18 | echo 19 | echo $MAC 20 | echo 21 | echo "Then reboot the Pi (sudo reboot) and run the following command" 22 | echo 23 | echo "bash install_packages.sh" 24 | -------------------------------------------------------------------------------- /appliance/etc/wpa_supplicant/wpa_supplicant.conf: -------------------------------------------------------------------------------- 1 | ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev 2 | update_config=1 3 | country=US 4 | 5 | network={ 6 | ssid="StanfordRover" 7 | psk=2f04a71982761d778878e9ff07d5b070693fa482b6427fd4785c89e22490392c 8 | } 9 | 10 | network={ 11 | ssid="Stanford Residences" 12 | key_mgmt=NONE 13 | } 14 | 15 | network={ 16 | ssid="Stanford" 17 | key_mgmt=NONE 18 | } 19 | 20 | -------------------------------------------------------------------------------- /appliance/home/pi/install_packages.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ $(mount | grep mmcblk0p2 | grep -o 'rw' || echo ro) = "ro" ]; then 4 | echo "Please make file system read-write and rerun" 5 | exit; 6 | fi 7 | 8 | # Given a filename, a regex pattern to match and a replacement string: 9 | # Replace string if found, else no change. 10 | # (# $1 = filename, $2 = pattern to match, $3 = replacement) 11 | replace() { 12 | grep $2 $1 >/dev/null 13 | if [ $? -eq 0 ]; then 14 | # Pattern found; replace in file 15 | sed -i "s/$2/$3/g" $1 >/dev/null 16 | fi 17 | } 18 | 19 | if grep -q "10.0.0.10" /boot/appliance/etc/network/interfaces; then 20 | read -p 'Current IP: 10.0.0.10 Please change IP to: 10.0.0.' new_ip 21 | replace /boot/appliance/etc/network/interfaces "10.0.0.10" "10.0.0.$new_ip" 22 | echo "Please update the CS System spreadsheet with this new IP" 23 | fi 24 | 25 | if [ $(hostname) = "raspberrypi" ]; then 26 | read -p 'Current hostname: raspberrypi. Please change hostname to: ' new_hostname 27 | [ ! -z "$new_hostname" ] && echo "$new_hostname" | sudo tee -a /etc/hostname 28 | [ ! -z "$new_hostname" ] && echo "127.0.1.1 $new_hostname" | sudo tee -a /etc/hosts 29 | [ ! -z "$new_hostname" ] && sudo hostnamectl set-hostname "$new_hostname" 30 | echo "Please update the CS System spreadsheet with this new hostname" 31 | fi 32 | 33 | read -p 'Enter the current date [YYYY-MM-DD HH:MM] or hit enter to skip: ' datetime 34 | [ ! -z "$datetime" ] && sudo date -s "$datetime" 35 | 36 | sudo apt update 37 | sudo apt install -y git vim screen python3-pip python-pip 38 | 39 | #### Fixes old pip in apt repo 40 | yes | sudo pip3 install --upgrade pip 41 | yes | sudo pip install --upgrade pip 42 | 43 | #### IPython is nice to have 44 | yes | sudo pip3 install ipython 45 | yes | sudo pip install ipython 46 | 47 | #### UDPCOMMS 48 | git clone https://github.com/stanfordroboticsclub/UDPComms.git 49 | sudo bash UDPComms/install.sh 50 | 51 | #### uDHCPd 52 | git clone https://github.com/stanfordroboticsclub/uDHCPd.git 53 | sudo bash uDHCPd/install.sh 54 | 55 | #### ODRIVE 56 | #git clone https://github.com/stanfordroboticsclub/RoverODrive.git 57 | #sudo bash RoverODrive/install.sh 58 | 59 | #### COMMAND 60 | #git clone https://github.com/stanfordroboticsclub/RoverCommand.git 61 | #sudo bash RoverCommand/install.sh 62 | 63 | #### GPS 64 | #git clone https://github.com/stanfordroboticsclub/RoverGPS.git 65 | #sudo bash RoverGPS/install.sh 66 | -------------------------------------------------------------------------------- /appliance/home/pi/read-only-fs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ensure script isn't being run by accident 4 | if [ ! -f /boot/TODO_ro ]; then 5 | exit 0 6 | fi 7 | 8 | # CREDIT TO THESE TUTORIALS: 9 | # petr.io/en/blog/2015/11/09/read-only-raspberry-pi-with-jessie 10 | # hallard.me/raspberry-pi-read-only 11 | # k3a.me/how-to-make-raspberrypi-truly-read-only-reliable-and-trouble-free 12 | 13 | if [ $(id -u) -ne 0 ]; then 14 | echo "Installer must be run as root." 15 | echo "Try 'sudo bash $0'" 16 | exit 1 17 | fi 18 | 19 | clear 20 | 21 | echo "This script configures a Raspberry Pi" 22 | echo "SD card to boot into read-only mode," 23 | echo "obviating need for clean shutdown." 24 | echo "NO FILES ON THE CARD CAN BE CHANGED" 25 | echo "WHEN PI IS BOOTED IN THIS STATE. Either" 26 | echo "the filesystems must be remounted in" 27 | echo "read/write mode, card must be mounted" 28 | echo "R/W on another system, or an optional" 29 | echo "jumper can be used to enable read/write" 30 | echo "on boot." 31 | echo 32 | echo "Links to original tutorials are in" 33 | echo "script source. THIS IS A ONE-WAY" 34 | echo "OPERATION. THERE IS NO SCRIPT TO" 35 | echo "REVERSE THIS SETUP! ALL other system" 36 | echo "config should be complete before using" 37 | echo "this script. MAKE A BACKUP FIRST." 38 | echo 39 | echo "Run time ~5 minutes. Reboot required." 40 | echo 41 | # echo -n "CONTINUE? [y/N] " 42 | # read 43 | # if [[ ! "$REPLY" =~ ^(yes|y|Y)$ ]]; then 44 | # echo "Canceled." 45 | # exit 0 46 | # fi 47 | 48 | # FEATURE PROMPTS ---------------------------------------------------------- 49 | # Installation doesn't begin until after all user input is taken. 50 | 51 | INSTALL_RW_JUMPER=0 52 | INSTALL_HALT=0 53 | INSTALL_WATCHDOG=0 54 | 55 | # Given a list of strings representing options, display each option 56 | # preceded by a number (1 to N), display a prompt, check input until 57 | # a valid number within the selection range is entered. 58 | selectN() { 59 | for ((i=1; i<=$#; i++)); do 60 | echo $i. ${!i} 61 | done 62 | echo 63 | REPLY="" 64 | while : 65 | do 66 | echo -n "SELECT 1-$#: " 67 | read 68 | if [[ $REPLY -ge 1 ]] && [[ $REPLY -le $# ]]; then 69 | return $REPLY 70 | fi 71 | done 72 | } 73 | 74 | SYS_TYPES=(Pi\ 3\ /\ Pi\ Zero\ W All\ other\ models) 75 | WATCHDOG_MODULES=(bcm2835_wdog bcm2708_wdog) 76 | OPTION_NAMES=(NO YES) 77 | 78 | # echo -n "Enable boot-time read/write jumper? [y/N] " 79 | # read 80 | # if [[ "$REPLY" =~ (yes|y|Y)$ ]]; then 81 | # INSTALL_RW_JUMPER=1 82 | # echo -n "GPIO pin for R/W jumper: " 83 | # read 84 | # RW_PIN=$REPLY 85 | # fi 86 | 87 | # echo -n "Install GPIO-halt utility? [y/N] " 88 | # read 89 | # if [[ "$REPLY" =~ (yes|y|Y)$ ]]; then 90 | # INSTALL_HALT=1 91 | # echo -n "GPIO pin for halt button: " 92 | # read 93 | # HALT_PIN=$REPLY 94 | # fi 95 | 96 | # echo -n "Enable kernel panic watchdog? [y/N] " 97 | # read 98 | # if [[ "$REPLY" =~ (yes|y|Y)$ ]]; then 99 | # INSTALL_WATCHDOG=1 100 | # echo "Target system type:" 101 | # selectN "${SYS_TYPES[0]}" \ 102 | # "${SYS_TYPES[1]}" 103 | # WD_TARGET=$? 104 | # fi 105 | 106 | # VERIFY SELECTIONS BEFORE CONTINUING -------------------------------------- 107 | 108 | echo 109 | if [ $INSTALL_RW_JUMPER -eq 1 ]; then 110 | echo "Boot-time R/W jumper: YES (GPIO$RW_PIN)" 111 | else 112 | echo "Boot-time R/W jumper: NO" 113 | fi 114 | if [ $INSTALL_HALT -eq 1 ]; then 115 | echo "Install GPIO-halt: YES (GPIO$HALT_PIN)" 116 | else 117 | echo "Install GPIO-halt: NO" 118 | fi 119 | if [ $INSTALL_WATCHDOG -eq 1 ]; then 120 | echo "Enable watchdog: YES (${SYS_TYPES[WD_TARGET-1]})" 121 | else 122 | echo "Enable watchdog: NO" 123 | fi 124 | echo 125 | # echo -n "CONTINUE? [y/N] " 126 | # read 127 | # if [[ ! "$REPLY" =~ ^(yes|y|Y)$ ]]; then 128 | # echo "Canceled." 129 | # exit 0 130 | # fi 131 | 132 | # START INSTALL ------------------------------------------------------------ 133 | # All selections have been validated at this point... 134 | 135 | # Given a filename, a regex pattern to match and a replacement string: 136 | # Replace string if found, else no change. 137 | # (# $1 = filename, $2 = pattern to match, $3 = replacement) 138 | replace() { 139 | grep $2 $1 >/dev/null 140 | if [ $? -eq 0 ]; then 141 | # Pattern found; replace in file 142 | sed -i "s/$2/$3/g" $1 >/dev/null 143 | fi 144 | } 145 | 146 | # Given a filename, a regex pattern to match and a replacement string: 147 | # If found, perform replacement, else append file w/replacement on new line. 148 | replaceAppend() { 149 | grep $2 $1 >/dev/null 150 | if [ $? -eq 0 ]; then 151 | # Pattern found; replace in file 152 | sed -i "s/$2/$3/g" $1 >/dev/null 153 | else 154 | # Not found; append on new line (silently) 155 | echo $3 | sudo tee -a $1 >/dev/null 156 | fi 157 | } 158 | 159 | # Given a filename, a regex pattern to match and a string: 160 | # If found, no change, else append file with string on new line. 161 | append1() { 162 | grep $2 $1 >/dev/null 163 | if [ $? -ne 0 ]; then 164 | # Not found; append on new line (silently) 165 | echo $3 | sudo tee -a $1 >/dev/null 166 | fi 167 | } 168 | 169 | # Given a filename, a regex pattern to match and a string: 170 | # If found, no change, else append space + string to last line -- 171 | # this is used for the single-line /boot/cmdline.txt file. 172 | append2() { 173 | grep $2 $1 >/dev/null 174 | if [ $? -ne 0 ]; then 175 | # Not found; insert in file before EOF 176 | sed -i "s/\'/ $3/g" $1 >/dev/null 177 | fi 178 | } 179 | 180 | echo "Expanding file system" 181 | # expands the root partition as we won't be able to do it after making it ro 182 | sudo parted /dev/mmcblk0 resizepart 2 100% 183 | # expands the file system 184 | sudo resize2fs /dev/mmcblk0p2 185 | # change fstab to not use PARTUUIDs (as they change when we resized the partition) 186 | replace /etc/fstab "PARTUUID=........-01" "\/dev\/mmcblk0p1" 187 | replace /etc/fstab "PARTUUID=........-02" "\/dev\/mmcblk0p2" 188 | 189 | echo 190 | echo "Starting installation..." 191 | echo "Updating package index files..." 192 | apt-get update 193 | 194 | echo "Removing unwanted packages..." 195 | #apt-get remove -y --force-yes --purge triggerhappy logrotate dbus \ 196 | # dphys-swapfile xserver-common lightdm fake-hwclock 197 | # Let's keep dbus...that includes avahi-daemon, a la 'raspberrypi.local', 198 | # also keeping xserver & lightdm for GUI login (WIP, not working yet) 199 | apt-get remove -y --force-yes --purge triggerhappy logrotate \ 200 | dphys-swapfile fake-hwclock 201 | apt-get -y --force-yes autoremove --purge 202 | 203 | # Replace log management with busybox (use logread if needed) 204 | echo "Installing ntp and busybox-syslogd..." 205 | apt-get -y --force-yes install ntp busybox-syslogd; dpkg --purge rsyslog 206 | 207 | echo "Configuring system..." 208 | 209 | # Install boot-time R/W jumper test if requested 210 | GPIOTEST="gpio -g mode $RW_PIN up\n\ 211 | if [ \`gpio -g read $RW_PIN\` -eq 0 ] ; then\n\ 212 | \tmount -o remount,rw \/\n\ 213 | \tmount -o remount,rw \/boot\n\ 214 | fi\n" 215 | if [ $INSTALL_RW_JUMPER -ne 0 ]; then 216 | apt-get install -y --force-yes wiringpi 217 | # Check if already present in rc.local: 218 | grep "gpio -g read" /etc/rc.local >/dev/null 219 | if [ $? -eq 0 ]; then 220 | # Already there, but make sure pin is correct: 221 | sed -i "s/^.*gpio\ -g\ read.*$/$GPIOTEST/g" /etc/rc.local >/dev/null 222 | 223 | else 224 | # Not there, insert before final 'exit 0' 225 | sed -i "s/^exit 0/$GPIOTEST\\nexit 0/g" /etc/rc.local >/dev/null 226 | fi 227 | fi 228 | 229 | # Install watchdog if requested 230 | if [ $INSTALL_WATCHDOG -ne 0 ]; then 231 | apt-get install -y --force-yes watchdog 232 | # $MODULE is specific watchdog module name 233 | MODULE=${WATCHDOG_MODULES[($WD_TARGET-1)]} 234 | # Add to /etc/modules, update watchdog config file 235 | append1 /etc/modules $MODULE $MODULE 236 | replace /etc/watchdog.conf "#watchdog-device" "watchdog-device" 237 | replace /etc/watchdog.conf "#max-load-1" "max-load-1" 238 | # Start watchdog at system start and start right away 239 | # Raspbian Stretch needs this package installed first 240 | apt-get install -y --force-yes insserv 241 | insserv watchdog; /etc/init.d/watchdog start 242 | # Additional settings needed on Jessie 243 | append1 /lib/systemd/system/watchdog.service "WantedBy" "WantedBy=multi-user.target" 244 | systemctl enable watchdog 245 | # Set up automatic reboot in sysctl.conf 246 | replaceAppend /etc/sysctl.conf "^.*kernel.panic.*$" "kernel.panic = 10" 247 | fi 248 | 249 | # Install gpio-halt if requested 250 | if [ $INSTALL_HALT -ne 0 ]; then 251 | apt-get install -y --force-yes wiringpi 252 | echo "Installing gpio-halt in /usr/local/bin..." 253 | cd /tmp 254 | curl -LO https://github.com/adafruit/Adafruit-GPIO-Halt/archive/master.zip 255 | unzip master.zip 256 | cd Adafruit-GPIO-Halt-master 257 | make 258 | mv gpio-halt /usr/local/bin 259 | cd .. 260 | rm -rf Adafruit-GPIO-Halt-master 261 | 262 | # Add gpio-halt to /rc.local: 263 | grep gpio-halt /etc/rc.local >/dev/null 264 | if [ $? -eq 0 ]; then 265 | # gpio-halt already in rc.local, but make sure correct: 266 | sed -i "s/^.*gpio-halt.*$/\/usr\/local\/bin\/gpio-halt $HALT_PIN \&/g" /etc/rc.local >/dev/null 267 | else 268 | # Insert gpio-halt into rc.local before final 'exit 0' 269 | sed -i "s/^exit 0/\/usr\/local\/bin\/gpio-halt $HALT_PIN \&\\nexit 0/g" /etc/rc.local >/dev/null 270 | fi 271 | fi 272 | 273 | # Add fastboot, noswap and/or ro to end of /boot/cmdline.txt 274 | append2 /boot/cmdline.txt fastboot fastboot 275 | append2 /boot/cmdline.txt noswap noswap 276 | append2 /boot/cmdline.txt ro^o^t ro 277 | 278 | # Move /var/spool to /tmp 279 | rm -rf /var/spool 280 | ln -s /tmp /var/spool 281 | 282 | # Move /var/lib/lightdm and /var/cache/lightdm to /tmp 283 | rm -rf /var/lib/lightdm 284 | rm -rf /var/cache/lightdm 285 | ln -s /tmp /var/lib/lightdm 286 | ln -s /tmp /var/cache/lightdm 287 | 288 | # Make SSH work 289 | replaceAppend /etc/ssh/sshd_config "^.*UsePrivilegeSeparation.*$" "UsePrivilegeSeparation no" 290 | # bbro method (not working in Jessie?): 291 | #rmdir /var/run/sshd 292 | #ln -s /tmp /var/run/sshd 293 | 294 | # Change spool permissions in var.conf (rondie/Margaret fix) 295 | replace /usr/lib/tmpfiles.d/var.conf "spool\s*0755" "spool 1777" 296 | 297 | # Move dhcpd.resolv.conf to tmpfs 298 | touch /tmp/dhcpcd.resolv.conf 299 | rm /etc/resolv.conf 300 | ln -s /tmp/dhcpcd.resolv.conf /etc/resolv.conf 301 | 302 | # Make edits to fstab 303 | # make / ro 304 | # tmpfs /var/log tmpfs nodev,nosuid 0 0 305 | # tmpfs /var/tmp tmpfs nodev,nosuid 0 0 306 | # tmpfs /tmp tmpfs nodev,nosuid 0 0 307 | replace /etc/fstab "vfat\s*defaults\s" "vfat defaults,ro " 308 | replace /etc/fstab "ext4\s*defaults,noatime\s" "ext4 defaults,noatime,ro " 309 | append1 /etc/fstab "/var/log" "tmpfs /var/log tmpfs nodev,nosuid 0 0" 310 | append1 /etc/fstab "/var/tmp" "tmpfs /var/tmp tmpfs nodev,nosuid 0 0" 311 | append1 /etc/fstab "\s/tmp" "tmpfs /tmp tmpfs nodev,nosuid 0 0" 312 | 313 | # PROMPT FOR REBOOT -------------------------------------------------------- 314 | 315 | echo "Done." 316 | echo 317 | echo "Settings take effect on next boot." 318 | echo 319 | # echo -n "REBOOT NOW? [y/N] " 320 | # read 321 | # if [[ ! "$REPLY" =~ ^(yes|y|Y)$ ]]; then 322 | # echo "Exiting without reboot." 323 | # exit 0 324 | # fi 325 | 326 | echo "Turning script off" 327 | rm /boot/TODO_ro 328 | rm /home/pi/read-only-fs.sh 329 | 330 | echo "Reboot started..." 331 | reboot 332 | exit 0 333 | -------------------------------------------------------------------------------- /appliance/home/pi/time_sync.sh: -------------------------------------------------------------------------------- 1 | sudo date -s "$(curl -s --head http://google.com | grep ^Date: | sed 's/Date: //g')" 2 | -------------------------------------------------------------------------------- /cmdline.txt: -------------------------------------------------------------------------------- 1 | dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p1 rootfstype=vfat rootflags=umask=000 elevator=deadline fsck.repair=yes rootwait init=/pi-init2 2 | -------------------------------------------------------------------------------- /pi-init2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanfordroboticsclub/RPI-Setup/7aa9d60ab173a085cbc52e6d2adec6086109a2ff/pi-init2 -------------------------------------------------------------------------------- /src/projects.bytemark.co.uk/pi-init2/init.go: -------------------------------------------------------------------------------- 1 | /* pi-init2 2 | * 3 | * A shim to drop onto a Raspberry Pi to write some files to its root 4 | * filesystem before giving way to the real /sbin/init. Its goal is simply 5 | * to allow you to customise a RPi by dropping files into that FAT32 /boot 6 | * partition, as opposed to either 1) booting it and manually setting it up, or 7 | * 2) having to mount the root partition, which Windows & Mac users can't easily 8 | * do. 9 | * 10 | * Cross-compile on Mac/Linux: 11 | * GOOS=linux GOARCH=arm go get golang.org/x/sys/unix 12 | * GOOS=linux GOARCH=arm go build projects.bytemark.co.uk/pi-init2 13 | * 14 | * Cross-compile on Windows: 15 | * set GOOS=linux 16 | * set GOARCH=arm 17 | * go build packages projects.bytemark.co.uk/pi-init2 18 | */ 19 | 20 | package main 21 | 22 | import "os" 23 | import "fmt" 24 | import "path/filepath" 25 | import "golang.org/x/sys/unix" 26 | import "syscall" // for Exec only 27 | 28 | func checkFatalAllowed(desc string, err error, allowedErrnos []syscall.Errno) { 29 | if (err != nil) { 30 | errno, ok := err.(syscall.Errno) 31 | if ok { 32 | for _, b := range allowedErrnos { 33 | if b == errno { 34 | return 35 | } 36 | } 37 | } 38 | fmt.Println("error " + desc + ":" +err.Error()) 39 | unix.Exit(1); 40 | } 41 | } 42 | 43 | func checkFatal(desc string, err error) { 44 | checkFatalAllowed(desc, err, []syscall.Errno{}) 45 | } 46 | 47 | func copyAppliance(path string, info os.FileInfo, err error) error { 48 | info, err = os.Stat(path) 49 | if err != nil { 50 | // should only be called with real directories 51 | return err 52 | } 53 | 54 | // for now we don't care about permissions 55 | 56 | if (info.IsDir()) { 57 | if (os.Mkdir("/" + path, os.FileMode(int(0755))) != nil) { 58 | return err 59 | } 60 | } else { 61 | // remove any existing file in place, ignore error, but let's 62 | // not use RemoveAll to delete directories, not sure anything 63 | // useful can come of that 64 | os.Remove("/" + path) 65 | 66 | if (os.Symlink("/boot/appliance/"+path, "/"+path) != nil) { 67 | return err 68 | } 69 | 70 | fmt.Println("Symlinked "+path+" to /boot/appliance") 71 | } 72 | 73 | return nil 74 | } 75 | 76 | func main() { 77 | 78 | exists := []syscall.Errno{syscall.EEXIST}; 79 | 80 | checkFatal("changing directory", 81 | unix.Chdir("/")) 82 | checkFatal("remount rw", 83 | unix.Mount("/","/","vfat", syscall.MS_REMOUNT, ""), ) 84 | checkFatalAllowed( 85 | "making tmp", 86 | unix.Mkdir("tmp", 0770), 87 | exists) 88 | checkFatalAllowed( 89 | "making new_root", unix.Mkdir("new_root", 0770), exists) 90 | checkFatal("mounting tmp", 91 | unix.Mount("", "tmp", "tmpfs", 0, "")) 92 | checkFatal("create device node", 93 | unix.Mknod("tmp/mmcblk0p2", 0660 | syscall.S_IFBLK, 179<<8 | 2)) 94 | checkFatal("mounting real root", 95 | unix.Mount("tmp/mmcblk0p2", "new_root", "ext4", 0, "")) 96 | checkFatal("pivoting", 97 | unix.PivotRoot("new_root", "new_root/boot")) 98 | checkFatal("unmounting /boot/tmp", 99 | unix.Unmount("/boot/tmp", 0)) 100 | checkFatal("Removing /boot/tmp", 101 | os.Remove("/boot/new_root")) 102 | checkFatal("Removing /boot/new_root", 103 | os.Remove("/boot/tmp")) 104 | checkFatal("changing into appliance directory", 105 | unix.Chdir("/boot/appliance")) 106 | checkFatal("copying appliance to root", 107 | filepath.Walk(".", copyAppliance)) 108 | /*checkFatalAllowed( 109 | "remove wpa_supplicant.conf", 110 | unix.Unlink("/etc/wpa_supplicant/wpa_supplicant.conf"), noent) 111 | checkFatalAllowed( 112 | "remove rc.local", 113 | unix.Unlink("/etc/rc.local"), noent) 114 | checkFatal("symlink wpa_supplicant.conf", 115 | unix.Symlink( 116 | "/boot/setup/wpa_supplicant.conf", 117 | "/etc/wpa_supplicant/wpa_supplicant.conf")) 118 | checkFatal("symlink rc.local", 119 | unix.Symlink("/boot/setup/rc.local", "/etc/rc.local"))*/ 120 | 121 | // use deprecated API because Exec has been removed from rebuild syscall 122 | // stuff :-O Hopefully we will get a hook in Raspbian before this becomes 123 | // useless. 124 | checkFatal("exec real init", 125 | syscall.Exec("/sbin/init", os.Args, nil)) 126 | } 127 | -------------------------------------------------------------------------------- /ssh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanfordroboticsclub/RPI-Setup/7aa9d60ab173a085cbc52e6d2adec6086109a2ff/ssh --------------------------------------------------------------------------------