diff --git a/README.md b/README.md index b88d08b..3d14615 100644 --- a/README.md +++ b/README.md @@ -146,3 +146,17 @@ If you set up the Pi with a keyboard and a monitor disconnect it and connect it 1. Eject the drives. 1. Unplug the Pi from the PC. 1. Plug the Pi into your Tesla. + +## Making changes to the system after setup +The setup process configures the Pi with read-only file systems for the operating system but with read-write access through the USB + interface. This means that you'll be able to record dashcam video and add and remove music files but you won't be able to make changes + to files on / or on /boot. This is to protect against corruption of the operating system when the Tesla cuts power to the Pi. + +To make changes to the system partitions: +``` +ssh pi@teslausb. +sudo -i +mount / -o remount,rw +mount /boot -o remount,rw +``` +Then make whatever changes you need to. The next time the system boots the partitions will once again be read-only. \ No newline at end of file diff --git a/windows_archive/create-backingfiles-partition.sh b/windows_archive/create-backingfiles-partition.sh new file mode 100644 index 0000000..e8b7013 --- /dev/null +++ b/windows_archive/create-backingfiles-partition.sh @@ -0,0 +1,22 @@ +#!/bin/bash -eu + +BACKINGFILES_MOUNTPOINT="$1" + +PARTITION_TABLE=$(parted -m /dev/mmcblk0 unit s print) +ROOT_PARTITION_LINE=$(echo "$PARTITION_TABLE" | grep -e "^2:") +LAST_ROOT_PARTITION_SECTOR=$(echo "$ROOT_PARTITION_LINE" | sed 's/s//g' | cut -d ":" -f 3) + +FIRST_BACKINGFILES_PARTITION_SECTOR=$(( $LAST_ROOT_PARTITION_SECTOR + 1 )) + +ORIGINAL_DISK_IDENTIFIER=$( fdisk -l /dev/mmcblk0 | grep -e "^Disk identifier" | sed "s/Disk identifier: 0x//" ) + +parted -m /dev/mmcblk0 u s mkpart primary ext4 "$FIRST_BACKINGFILES_PARTITION_SECTOR" 100% + +NEW_DISK_IDENTIFIER=$( fdisk -l /dev/mmcblk0 | grep -e "^Disk identifier" | sed "s/Disk identifier: 0x//" ) + +sed -i "s/${ORIGINAL_DISK_IDENTIFIER}/${NEW_DISK_IDENTIFIER}/g" /etc/fstab +sed -i "s/${ORIGINAL_DISK_IDENTIFIER}/${NEW_DISK_IDENTIFIER}/" /boot/cmdline.txt + +mkfs.ext4 -F /dev/mmcblk0p3 + +echo "/dev/mmcblk0p3 $BACKINGFILES_MOUNTPOINT ext4 auto,rw,noatime 0 2" >> /etc/fstab diff --git a/windows_archive/create-backingfiles.sh b/windows_archive/create-backingfiles.sh new file mode 100644 index 0000000..a406df4 --- /dev/null +++ b/windows_archive/create-backingfiles.sh @@ -0,0 +1,38 @@ +#!/bin/bash -eu + +CAM_PERCENT="$1" +BACKINGFILES_MOUNTPOINT="$2" + +G_MASS_STORAGE_CONF_FILE_NAME=/etc/modprobe.d/g_mass_storage.conf + +function add_drive () { + local name="$1" + local label="$2" + local size="$3" + + local filename="$4" + echo "Allocating ${size}K for $filename..." + fallocate -l "$size"K "$filename" + mkfs.vfat "$filename" -F 32 -n "$label" + + local mountpoint=/mnt/"$name" + + mkdir "$mountpoint" + echo "$filename $mountpoint vfat noauto,users,umask=000 0 0" >> /etc/fstab +} + +FREE_1K_BLOCKS="$(df --output=avail --block-size=1K /backingfiles/ | tail -n 1)" + +CAM_DISK_SIZE="$(( $FREE_1K_BLOCKS * $CAM_PERCENT / 100 ))" +CAM_DISK_FILE_NAME="$BACKINGFILES_MOUNTPOINT/cam_disk.bin" +add_drive "cam" "CAM" "$CAM_DISK_SIZE" "$CAM_DISK_FILE_NAME" + +if [ "$CAM_PERCENT" -lt 100 ] +then + MUSIC_DISK_SIZE="$(df --output=avail --block-size=1K /backingfiles/ | tail -n 1)" + MUSIC_DISK_FILE_NAME="$BACKINGFILES_MOUNTPOINT/music_disk.bin" + add_drive "music" "MUSIC" "$MUSIC_DISK_SIZE" "$MUSIC_DISK_FILE_NAME" + echo "options g_mass_storage file=$CAM_DISK_FILE_NAME,$MUSIC_DISK_FILE_NAME removable=1,1 ro=0,0 stall=0 iSerialNumber=123456" > "$G_MASS_STORAGE_CONF_FILE_NAME" +else + echo "options g_mass_storage file=$CAM_DISK_FILE_NAME removable=1 ro=0 stall=0 iSerialNumber=123456" > "$G_MASS_STORAGE_CONF_FILE_NAME" +fi diff --git a/windows_archive/make-root-fs-readonly.sh b/windows_archive/make-root-fs-readonly.sh new file mode 100644 index 0000000..1d7882c --- /dev/null +++ b/windows_archive/make-root-fs-readonly.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +# Adapted from https://github.com/adafruit/Raspberry-Pi-Installer-Scripts/blob/master/read-only-fs.sh + +function append_cmdline_txt_param() { + local toAppend="$1" + sed -i "s/\'/ ${toAppend}/g" /boot/cmdline.txt >/dev/null +} + +echo "Updating package index files..." +apt-get update +echo "Removing unwanted packages..." +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..." + +# Add fastboot, noswap and/or ro to end of /boot/cmdline.txt +append_cmdline_txt_param fastboot +append_cmdline_txt_param noswap +append_cmdline_txt_param ro + +# Move /var/spool to /tmp +rm -rf /var/spool +ln -s /tmp /var/spool + +# Change spool permissions in var.conf (rondie/Margaret fix) +sed -i "s/spool\s*0755/spool 1777/g" /usr/lib/tmpfiles.d/var.conf >/dev/null + +# Move dhcpd.resolv.conf to tmpfs +touch /tmp/dhcpcd.resolv.conf +rm /etc/resolv.conf +ln -s /tmp/dhcpcd.resolv.conf /etc/resolv.conf + +# Update /etc/fstab +# make /boot read-only +# make / read-only +# tmpfs /var/log tmpfs nodev,nosuid 0 0 +# tmpfs /var/tmp tmpfs nodev,nosuid 0 0 +# tmpfs /tmp tmpfs nodev,nosuid 0 0 +sed -i -r "s@(/boot\s+vfat\s+\S+)@\1,ro@" /etc/fstab +sed -i -r "s@(/\s+ext4\s+\S+)@\1,ro@" /etc/fstab +echo "" >> /etc/fstab +echo "tmpfs /var/log tmpfs nodev,nosuid 0 0" >> /etc/fstab +echo "tmpfs /var/tmp tmpfs nodev,nosuid 0 0" >> /etc/fstab +echo "tmpfs /tmp tmpfs nodev,nosuid 0 0" >> /etc/fstab + diff --git a/windows_archive/setup-piForHeadlessConfig.ps1 b/windows_archive/setup-piForHeadlessConfig.ps1 index d5c682f..ff951ea 100644 --- a/windows_archive/setup-piForHeadlessConfig.ps1 +++ b/windows_archive/setup-piForHeadlessConfig.ps1 @@ -23,7 +23,7 @@ Write-Verbose "Updating $configPath ..." Write-Verbose "Updating $cmdlinePath ..." $cmdlinetxtContent = gc -Raw $cmdlinePath -$cmdlinetxtContent.Replace("rootwait", "rootwait modules-load=dwc2,g_ether") | Out-File -FilePath $cmdlinePath -Encoding utf8 +$cmdlinetxtContent.Replace("rootwait", "rootwait modules-load=dwc2,g_ether").Replace(" init=/usr/lib/raspi-config/init_resize.sh", "") | Out-File -FilePath $cmdlinePath -Encoding utf8 Write-Verbose "Enabling SSH ..." [System.IO.File]::CreateText($sshPath).Dispose() diff --git a/windows_archive/setup-teslausb b/windows_archive/setup-teslausb index 4e40a1b..25466a2 100644 --- a/windows_archive/setup-teslausb +++ b/windows_archive/setup-teslausb @@ -1,6 +1,8 @@ #!/bin/bash -eu -if [ "$(whoami)" != "root" ] +BRANCH=master + +if ! [ $(id -u) = 0 ] then echo "STOP: Run sudo -i." exit 1 @@ -15,74 +17,100 @@ function check_variable () { fi } -check_variable "archiveserver" -check_variable "sharename" -check_variable "shareuser" -check_variable "sharepassword" -check_variable "campercent" - -serverunreachable=false -ping -c 1 -w 1 "$archiveserver" 1>/dev/null 2>&1 || serverunreachable=true - -if [ "$serverunreachable" = true ] -then - echo "STOP: The archive server $archiveserver is unreachable. Try specifying its IP address instead." - exit 1 -fi - -archiveserverip="$(getent hosts $archiveserver | cut -d' ' -f1)" - -available_space="$(($(df --output=avail / | tail -1) - 1000000))" - -if [ "$available_space" -lt 0 ] -then - echo "STOP: The MicroSD card is too small." - exit 1 -fi - -function add_drive () { - local name="$1" - local label="$2" - local size="$3" - - local filename="$4" - fallocate -l "$size"K "$filename" - mkfs.vfat "$filename" -F 32 -n "$label" - - local mountpoint=/mnt/"$name" - - mkdir "$mountpoint" - echo "$filename $mountpoint vfat noauto,users,umask=000 0 0" >> /etc/fstab +function check_archive_server_reachable () { + echo "Verifying that the archive server $archiveserver is reachable..." + local serverunreachable=false + ping -c 1 -w 1 "$archiveserver" 1>/dev/null 2>&1 || serverunreachable=true + + if [ "$serverunreachable" = true ] + then + echo "STOP: The archive server $archiveserver is unreachable. Try specifying its IP address instead." + exit 1 + fi + + echo "The archive server is reachable." } -pushd ~ +function check_available_space () { + echo "Verifying that there is sufficient space available on the MicroSD card..." + + local available_space="$( parted -m /dev/mmcblk0 u b print free | tail -1 | cut -d ":" -f 4 | sed 's/B//g' )" -cp /boot/cmdline.txt ~ -cat ~/cmdline.txt | sed 's/[[:space:]]\+modules-load=[^ [:space:]]\+//' | sed 's/rootwait/rootwait modules-load=dwc2/' > /boot/cmdline.txt -rm ~/cmdline.txt + if [ "$available_space" -lt 4294967296 ] + then + echo "STOP: The MicroSD card is too small." + exit 1 + fi + + echo "There is sufficient space available." +} -mkdir /mnt/archive +function get_ancillary_setup_scripts () { + pushd /tmp + wget https://raw.githubusercontent.com/cimryan/teslausb/"$BRANCH"/windows_archive/create-backingfiles-partition.sh + chmod +x ./create-backingfiles-partition.sh + wget https://raw.githubusercontent.com/cimryan/teslausb/"$BRANCH"/windows_archive/create-backingfiles.sh + chmod +x ./create-backingfiles.sh + wget https://raw.githubusercontent.com/cimryan/teslausb/"$BRANCH"/windows_archive/make-root-fs-readonly.sh + chmod +x ./make-root-fs-readonly.sh + popd +} -echo "" >> /etc/fstab -echo "//$archiveserverip/$sharename /mnt/archive cifs vers=3,credentials=/root/.teslaCamArchiveCredentials,iocharset=utf8,file_mode=0777,dir_mode=0777 0" >> /etc/fstab +function fix_cmdline_txt_modules_load () +{ + echo "Fixing the modules-load parameter in /boot/cmdline.txt..." + cp /boot/cmdline.txt ~ + cat ~/cmdline.txt | sed 's/[[:space:]]\+modules-load=[^ [:space:]]\+//' | sed 's/rootwait/rootwait modules-load=dwc2/' > /boot/cmdline.txt + rm ~/cmdline.txt + echo "Fixed cmdline.txt." +} -echo "username=$shareuser" > /root/.teslaCamArchiveCredentials -echo "password=$sharepassword" >> /root/.teslaCamArchiveCredentials +BACKINGFILES_MOUNTPOINT=/backingfiles -mkdir /root/bin +function create_usb_drive_backing_files () { + mkdir "$BACKINGFILES_MOUNTPOINT" + /tmp/create-backingfiles-partition.sh "$BACKINGFILES_MOUNTPOINT" + + echo "Mounting the partition for the backing files..." + mount /backingfiles + echo "Mounted the partition for the backing files." + + /tmp/create-backingfiles.sh "$campercent" "$BACKINGFILES_MOUNTPOINT" +} -wget https://raw.githubusercontent.com/cimryan/teslausb/master/windows_archive/archiveloop -sed s/ARCHIVE_HOST_NAME=archiveserver/ARCHIVE_HOST_NAME=$archiveserver/ ~/archiveloop > /root/bin/archiveloop -rm ~/archiveloop -chmod +x /root/bin/archiveloop +function configure_archive () { + echo "Configuring the archive..." + mkdir /mnt/archive + local archive_server_ip_address="$(getent hosts $archiveserver | cut -d' ' -f1)" + echo "//$archive_server_ip_address/$sharename /mnt/archive cifs vers=3,credentials=/root/.teslaCamArchiveCredentials,iocharset=utf8,file_mode=0777,dir_mode=0777 0" >> /etc/fstab + + echo "username=$shareuser" > /root/.teslaCamArchiveCredentials + echo "password=$sharepassword" >> /root/.teslaCamArchiveCredentials + echo "Configured the archive." +} -pushd /root/bin -wget https://raw.githubusercontent.com/cimryan/teslausb/master/windows_archive/archive-teslacam-clips -chmod +x archive-teslacam-clips -popd +function configure_archive_scripts () { + echo "Configuring the archive scripts..." + mkdir /root/bin -echo "#!/bin/bash -eu" > ~/rc.local -tail -n +2 /etc/rc.local | sed '$d' >> ~/rc.local + pushd ~ + wget https://raw.githubusercontent.com/cimryan/teslausb/"$BRANCH"/windows_archive/archiveloop + sed s/ARCHIVE_HOST_NAME=archiveserver/ARCHIVE_HOST_NAME=$archiveserver/ ~/archiveloop > /root/bin/archiveloop + rm ~/archiveloop + chmod +x /root/bin/archiveloop + popd + + pushd /root/bin + wget https://raw.githubusercontent.com/cimryan/teslausb/"$BRANCH"/windows_archive/archive-teslacam-clips + chmod +x archive-teslacam-clips + popd + echo "Configured the archive scripts." +} + +function configure_rc_local () { + echo "Configuring /etc/rc.local to run the archive scripts at startup..." + echo "#!/bin/bash -eu" > ~/rc.local + tail -n +2 /etc/rc.local | sed '$d' >> ~/rc.local cat << 'EOF' >> ~/rc.local LOGFILE=/tmp/rc.local.log @@ -97,26 +125,57 @@ log "All done" exit 0 EOF -cat ~/rc.local > /etc/rc.local -rm ~/rc.local + cat ~/rc.local > /etc/rc.local + rm ~/rc.local + echo "Configured rc.local." +} -cam_disk_size="$(( $available_space * $campercent / 100 ))" -cam_disk_file_name="/cam_disk.bin" -add_drive "cam" "CAM" "$cam_disk_size" "$cam_disk_file_name" +function configure_hostname () { + echo "Configuring the hostname..." + + local new_host_name="teslausb" + cp /etc/hosts ~ + sed "s/raspberrypi/$new_host_name/g" ~/hosts > /etc/hosts + + cp /etc/hostname ~ + sed "s/raspberrypi/$new_host_name/g" ~/hostname > /etc/hostname + echo "Configured the hostname." +} -if [ "$campercent" -lt 100 ] -then - musicpercent="$(( 100 - $campercent ))" - music_disk_size="$(( $available_space * $musicpercent / 100 ))" - music_disk_file_name="/music_disk.bin" - add_drive "music" "MUSIC" "$music_disk_size" "$music_disk_file_name" - echo "options g_mass_storage file=$cam_disk_file_name,$music_disk_file_name removable=1,1 ro=0,0 stall=0 iSerialNumber=123456" > /etc/modprobe.d/g_mass_storage.conf -else - echo "options g_mass_storage file=$cam_disk_file_name removable=1 ro=0 stall=0 iSerialNumber=123456" > /etc/modprobe.d/g_mass_storage.conf -fi +function make_root_fs_readonly () { + /tmp/make-root-fs-readonly.sh +} -cp /etc/hosts ~ -sed s/raspberrypi/teslausb/g ~/hosts > /etc/hosts +echo "Verifying environment variables..." -cp /etc/hostname ~ -sed s/raspberrypi/teslausb/g ~/hostname > /etc/hostname \ No newline at end of file +check_variable "archiveserver" +check_variable "sharename" +check_variable "shareuser" +check_variable "sharepassword" +check_variable "campercent" + +check_archive_server_reachable + +check_available_space + +get_ancillary_setup_scripts + +pushd ~ + +configure_archive_scripts + +fix_cmdline_txt_modules_load + +echo "" >> /etc/fstab + +create_usb_drive_backing_files + +configure_archive + +configure_rc_local + +configure_hostname + +make_root_fs_readonly + +echo "All done."