Wachalarm-Monitor/docs/image-setup.sh

307 lines
12 KiB
Bash
Executable File

#!/bin/bash
# exit on error; treat unset variables as errors; exit on errors in piped commands
set -euo pipefail
# Ensure we operate from consistent pwd for the rest of the script
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" # Figure out the ABSOLUTE PATH of this script without relying on the realpath command, which may not always be available
cd "$DIR"
if [ "$OSTYPE" == "linux-gnu" ]; then
MOUNTED_BOOT_VOLUME="/media/$(whoami)/boot" # i.e. under which name is the SD card mounted under /media in Linux (Ubuntu)
SD_DD_BS="1M"
SD_DD_PROGRESS="status=progress"
elif [ "$OSTYPE" == "darwin" ]; then
MOUNTED_BOOT_VOLUME="/Volumes/boot" # i.e. under which name is the SD card mounted under /Volumes on macOS
SD_DD_BS="1m"
SD_DD_PROGRESS=""
else
echo "Error: Unsupported platform $OSTYPE, sorry"
exit 1
fi
BOOT_CMDLINE_TXT="$MOUNTED_BOOT_VOLUME/cmdline.txt"
BOOT_CONFIG_TXT="$MOUNTED_BOOT_VOLUME/config.txt"
SD_SIZE_REAL=2500 # this is in MB
SD_SIZE_SAFE=2800 # this is in MB
SD_SIZE_ZERO=3200 # this is in MB
SSH_PUBKEY="$(cat ~/.ssh/id_rsa.pub)"
SSH_CONNECT_TIMEOUT=30
LOCALE="en_US.UTF-8 UTF-8" # or e.g. "fi_FI.UTF-8 UTF-8" for Finland
LANGUAGE="en_US.UTF-8" # should match above
KEYBOARD="us" # or e.g. "fi" for Finnish
TIMEZONE="Etc/UTC" # or e.g. "Europe/Helsinki"; see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
function echo-bold {
echo -e "$(tput -Txterm-256color bold)$1$(tput -Txterm-256color sgr 0)" # https://unix.stackexchange.com/a/269085; the -T arg accounts for $ENV not being set
}
function working {
echo-bold "\n[WORKING] $1"
}
function question {
echo-bold "\n[QUESTION] $1"
}
function ssh {
/usr/bin/ssh -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout="$SSH_CONNECT_TIMEOUT" "pi@$IP" "$1"
}
function scp {
/usr/bin/scp -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$@" "pi@$IP:/home/pi"
}
function figureOutSdCard {
if [ "$OSTYPE" == "linux-gnu" ]; then
lsblk --fs
DISK="/dev/$(lsblk -l | grep "$MOUNTED_BOOT_VOLUME" | sed 's/[0-9].*//')"
DISK_SAMPLE="/dev/sda"
elif [ "$OSTYPE" == "darwin" ]; then
diskutil list
DISK="$(diskutil list | grep /dev/ | grep external | grep physical | cut -d ' ' -f 1 | head -n 1)"
DISK_SAMPLE="/dev/disk2"
else
echo "Error: Unsupported platform $OSTYPE, sorry"
exit 1
fi
}
function unmountSdCard {
if [ "$OSTYPE" == "linux-gnu" ]; then
for part in $(lsblk --list "$DISK" | grep part | sed 's/ .*//'); do
udisksctl unmount -b "/dev/$part"
done
elif [ "$OSTYPE" == "darwin" ]; then
diskutil unmountDisk "$DISK"
else
echo "Error: Unsupported platform $OSTYPE, sorry"
exit 1
fi
}
question "Enter version (e.g. \"1.2.3\") being built"
echo "Omit the \"v\" prefix, it'll be added where needed"
echo "For alpha/beta builds, use a \"-betaN\" suffic"
echo "For RC builds, DO NOT use any suffix, as then the same image can't be promoted to stable without rebuilding"
echo "Enter version:"
read TAG
working "Updating version file"
echo -e "$TAG\n\nhttps://github.com/futurice/chilipie-kiosk" > ../home/.chilipie-kiosk-version
working "Generating first-boot.html"
if [ ! -d "node_modules" ]; then
npm install markdown-styles@3.1.10 html-inline@1.2.0
fi
rm -rf md-input md-output
mkdir md-input md-output
cp ../docs/first-boot.md md-input
./node_modules/.bin/generate-md --layout github --input md-input/ --output md-output/
./node_modules/.bin/html-inline -i md-output/first-boot.html > ../home/first-boot.html
rm -rf md-input md-output
question "Physically mount the SD card to this machine "
echo "(press enter when ready)"
read
working "Figuring out SD card device"
figureOutSdCard
question "Based on the above, SD card determined to be \"$DISK\" (should be e.g. \"$DISK_SAMPLE\"), press enter to continue"
read
working "Safely unmounting the card"
unmountSdCard
working "Writing the card full of zeros (for security and compressibility reasons)"
echo "This may take a long time"
echo "You may be prompted for your password by sudo"
sudo dd bs="$SD_DD_BS" count="$SD_SIZE_ZERO" if=/dev/zero of="$DISK" "$SD_DD_PROGRESS"
question "Prepare baseline Raspbian:"
echo "* Flash Raspbian Lite with Etcher"
echo "* Eject the SD card"
echo "* Mount the card back"
echo "* Wait for your OS to mount it"
echo "(press enter when ready)"
read
working "Backing up original boot files"
cp -v "$BOOT_CMDLINE_TXT" "$BOOT_CMDLINE_TXT.backup"
cp -v "$BOOT_CONFIG_TXT" "$BOOT_CONFIG_TXT.backup"
working "Disabling automatic root filesystem expansion"
echo "Updating: $BOOT_CMDLINE_TXT"
cat "$BOOT_CMDLINE_TXT" | sed "s#init=/usr/lib/raspi-config/init_resize.sh##" > temp
mv temp "$BOOT_CMDLINE_TXT"
working "Enabling SSH for first boot"
# https://www.raspberrypi.org/documentation/remote-access/ssh/
touch "$MOUNTED_BOOT_VOLUME/ssh"
working "Safely unmounting the card"
unmountSdCard
question "Do initial Pi setup:"
echo "* Eject the card"
echo "* Connect your Pi to Ethernet"
echo "* Boot the Pi from your card"
echo "* Make note of the \"My IP address is\" message at the end of boot"
echo "Enter the IP address:"
read IP
working "Installing temporary SSH pubkey"
echo -e "Password hint: \"raspberry\""
ssh "mkdir .ssh && echo '$SSH_PUBKEY' > .ssh/authorized_keys"
working "Figuring out partition start"
ssh "echo -e 'p\nq\n' | sudo fdisk /dev/mmcblk0 | grep /dev/mmcblk0p2 | tr -s ' ' | cut -d ' ' -f 2" > temp
START="$(cat temp)"
rm temp
question "Partition start determined to be \"$START\" (should be e.g. \"98304\"), press enter to continue"
read
working "Resizing the root partition on the Pi"
ssh "echo -e 'd\n2\nn\np\n2\n$START\n+${SD_SIZE_REAL}M\ny\nw\n' | sudo fdisk /dev/mmcblk0"
working "Setting locale"
# We want to do this as early as possible, so perl et al won't complain about misconfigured locales for the rest of the image prep
ssh "echo $LOCALE | sudo tee /etc/locale.gen"
ssh "sudo locale-gen"
ssh "echo -e \"LANGUAGE=$LANGUAGE\nLC_ALL=$LANGUAGE\" | sudo tee /etc/environment"
working "Setting hostname"
# We want to do this right before reboot, so we don't get a lot of unnecessary complaints about "sudo: unable to resolve host chilipie-kiosk" (https://askubuntu.com/a/59517)
ssh "sudo hostnamectl set-hostname chilipie-kiosk"
ssh "sudo perl -i -p0e 's/raspberrypi/chilipie-kiosk/g' /etc/hosts" # "perl" is more cross-platform than "sed -i"
# From now on, some ssh commands will exit non-0, which should be fine
set +e
working "Rebooting the Pi"
ssh "sudo reboot"
echo "Waiting for host to come back up..."
until SSH_CONNECT_TIMEOUT=5 ssh "echo OK"
do
sleep 1
done
working "Finishing the root partition resize"
ssh "df -h . && sudo resize2fs /dev/mmcblk0p2 && df -h ."
# From raspi-config: https://github.com/RPi-Distro/raspi-config/blob/c0ddae8a2e99ecf15759c7cb8f0681cb0e7ce63a/raspi-config#L1141
# See also: https://github.com/futurice/chilipie-kiosk/issues/61#issuecomment-524622522
working "Enabling auto-login to CLI"
ssh "sudo systemctl set-default multi-user.target"
ssh "sudo ln -fs /lib/systemd/system/getty@.service /etc/systemd/system/getty.target.wants/getty@tty1.service"
ssh "sudo ln -fs /lib/systemd/system/getty@.service /etc/systemd/system/getty.target.wants/getty@tty2.service"
ssh "sudo ln -fs /lib/systemd/system/getty@.service /etc/systemd/system/getty.target.wants/getty@tty3.service"
ssh "sudo mkdir -p /etc/systemd/system/getty@tty1.service.d"
ssh "sudo mkdir -p /etc/systemd/system/getty@tty2.service.d"
ssh "sudo mkdir -p /etc/systemd/system/getty@tty3.service.d"
ssh "echo -e '[Service]\nExecStart=\nExecStart=-/sbin/agetty --autologin pi --noclear %I \$TERM\n' | sudo tee /etc/systemd/system/getty@tty1.service.d/autologin.conf"
ssh "echo -e '[Service]\nExecStart=\nExecStart=-/sbin/agetty --autologin pi --noclear %I \$TERM\n' | sudo tee /etc/systemd/system/getty@tty2.service.d/autologin.conf"
ssh "echo -e '[Service]\nExecStart=\nExecStart=-/sbin/agetty --autologin pi --noclear %I \$TERM\n' | sudo tee /etc/systemd/system/getty@tty3.service.d/autologin.conf"
working "Setting timezone"
ssh "(echo '$TIMEZONE' | sudo tee /etc/timezone) && sudo dpkg-reconfigure --frontend noninteractive tzdata"
working "Setting keyboard layout"
ssh "(echo -e 'XKBMODEL="pc105"\nXKBLAYOUT="$KEYBOARD"\nXKBVARIANT=""\nXKBOPTIONS=""\nBACKSPACE="guess"\n' | sudo tee /etc/default/keyboard) && sudo dpkg-reconfigure --frontend noninteractive keyboard-configuration"
working "Silencing console logins" # this is to avoid a brief flash of the console login before X comes up
ssh "sudo rm /etc/profile.d/sshpwd.sh /etc/profile.d/wifi-check.sh" # remove warnings about default password and WiFi country (https://raspberrypi.stackexchange.com/a/105234)
ssh "touch .hushlogin" # https://scribles.net/silent-boot-on-raspbian-stretch-in-console-mode/
ssh "sudo perl -i -p0e 's#--autologin pi#--skip-login --noissue --login-options \"-f pi\"#g' /etc/systemd/system/getty@tty1.service.d/autologin.conf" # "perl" is more cross-platform than "sed -i"
working "Installing packages"
ssh "sudo apt-get update && DEBIAN_FRONTEND=noninteractive sudo apt-get install -y vim matchbox-window-manager unclutter mailutils nitrogen jq chromium-browser xserver-xorg xinit rpd-plym-splash xdotool rng-tools xinput-calibrator"
# We install mailutils just so that you can check "mail" for cronjob output
working "Setting home directory default content"
ssh "rm -rfv /home/pi/*"
scp $(find ../home -type f)
working "Setting splash screen background"
ssh "sudo rm /usr/share/plymouth/themes/pix/splash.png && sudo ln -s /home/pi/background.png /usr/share/plymouth/themes/pix/splash.png"
working "Installing default crontab"
ssh "crontab /home/pi/crontab.example"
working "Rebooting the Pi"
ssh "sudo reboot"
question "Once the Pi has rebooted into Chromium:"
echo "* Tell Chromium we don't want to sign in"
echo "* Configure Chromium to start \"where you left off\""
echo " * F11 to exit full screen"
echo " * Alt + F, then S to go to Settings"
echo " * Type \"continue\" to filter the options"
echo " * Tab to select \"Continue where you left off\""
echo "* Navigate to \"file:///home/pi/first-boot.html\""
echo "(press enter when ready)"
read
working "Figuring out software versions"
ssh "hostnamectl | grep 'Operating System:' | tr -s ' ' | cut -d ' ' -f 4-" > temp
VERSION_LINUX="$(cat temp)"
ssh "hostnamectl | grep 'Kernel:' | tr -s ' ' | cut -d ' ' -f 3-4" > temp
VERSION_KERNEL="$(cat temp)"
ssh "chromium-browser --version | cut -d ' ' -f 1-2" > temp
VERSION_CHROMIUM="$(cat temp)"
rm temp
working "Removing SSH host keys & enable regeneration"
ssh "sudo rm -f -v /etc/ssh/ssh_host_*_key* && sudo systemctl enable regenerate_ssh_host_keys"
working "Removing temporary SSH pubkey & disabling SSH"
ssh "(echo > .ssh/authorized_keys) && sudo systemctl disable ssh"
working "Powering off the Pi"
ssh "sudo poweroff"
question "Eject the SD card from the Pi, and mount it back to this computer"
echo "(press enter when ready)"
read
# We do this again now just to be safe
working "Figuring out SD card device"
figureOutSdCard
question "Based on the above, SD card determined to be \"$DISK\" (should be e.g. \"$DISK_SAMPLE\"), press enter to continue"
read
working "Making boot quieter (part 1)" # https://scribles.net/customizing-boot-up-screen-on-raspberry-pi/
echo "Updating: $BOOT_CONFIG_TXT"
perl -i -p0e "s/#disable_overscan=1/disable_overscan=1/g" "$BOOT_CONFIG_TXT" # "perl" is more cross-platform than "sed -i"
echo -e "\ndisable_splash=1" >> "$BOOT_CONFIG_TXT"
working "Making boot quieter (part 2)" # https://scribles.net/customizing-boot-up-screen-on-raspberry-pi/
echo "You may want to revert these changes if you ever need to debug the startup process"
echo "Updating: $BOOT_CMDLINE_TXT"
cat "$BOOT_CMDLINE_TXT" \
| sed 's/console=tty1/console=tty3/' \
| sed 's/$/ splash plymouth.ignore-serial-consoles logo.nologo vt.global_cursor_default=0/' \
> temp
mv temp "$BOOT_CMDLINE_TXT"
working "Safely unmounting the card"
unmountSdCard
working "Dumping the image from the card"
cd ..
echo "This may take a long time"
echo "You may be prompted for your password by sudo"
sudo dd bs="$SD_DD_BS" count="$SD_SIZE_SAFE" if="$DISK" of="chilipie-kiosk-$TAG.img" "$SD_DD_PROGRESS"
working "Compressing image"
COPYFILE_DISABLE=1 tar -zcvf chilipie-kiosk-$TAG.img.tar.gz chilipie-kiosk-$TAG.img
working "Listing image sizes"
du -hs chilipie-kiosk-$TAG.img*
working "Calculating image hashes"
openssl sha1 chilipie-kiosk-$TAG.img*
working "Software versions are:"
echo "* Linux: \`$VERSION_LINUX\`"
echo "* Kernel: \`$VERSION_KERNEL\`"
echo "* Chromium: \`$VERSION_CHROMIUM\`"