Merge pull request #20 from cimryan/u/cimryan/readonlyrootfs

U/cimryan/readonlyrootfs
This commit is contained in:
cimryan
2018-10-16 07:41:52 -07:00
committed by GitHub
7 changed files with 263 additions and 81 deletions

View File

@@ -14,7 +14,7 @@
1. Run the following commands: 1. Run the following commands:
``` ```
cd ~ cd ~
wget https://raw.githubusercontent.com/cimryan/teslausb/master/windows_archive/setup-piForHeadlessConfig.ps1 -OutFile setup-piForHeadlessConfig.ps1 wget https://raw.githubusercontent.com/cimryan/teslausb/u/cimryan/readonlyrootfs/windows_archive/setup-piForHeadlessConfig.ps1 -OutFile setup-piForHeadlessConfig.ps1
./setup-piForHeadlessConfig.ps1 -Verbose ./setup-piForHeadlessConfig.ps1 -Verbose
``` ```
1. Enter the single letter of the "boot" drive and press Enter. 1. Enter the single letter of the "boot" drive and press Enter.

View File

@@ -130,7 +130,7 @@ Now that you have a shell on the Pi you can turn the Pi into a smart USB drive.
``` ```
1. Run these commands: 1. Run these commands:
``` ```
wget https://raw.githubusercontent.com/cimryan/teslausb/master/windows_archive/setup-teslausb wget https://raw.githubusercontent.com/cimryan/teslausb/u/cimryan/readonlyrootfs/windows_archive/setup-teslausb
chmod +x setup-teslausb chmod +x setup-teslausb
./setup-teslausb ./setup-teslausb
``` ```
@@ -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. Eject the drives.
1. Unplug the Pi from the PC. 1. Unplug the Pi from the PC.
1. Plug the Pi into your Tesla. 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.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -23,7 +23,7 @@ Write-Verbose "Updating $configPath ..."
Write-Verbose "Updating $cmdlinePath ..." Write-Verbose "Updating $cmdlinePath ..."
$cmdlinetxtContent = gc -Raw $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 ..." Write-Verbose "Enabling SSH ..."
[System.IO.File]::CreateText($sshPath).Dispose() [System.IO.File]::CreateText($sshPath).Dispose()

View File

@@ -1,6 +1,8 @@
#!/bin/bash -eu #!/bin/bash -eu
if [ "$(whoami)" != "root" ] BRANCH=u/cimryan/readonlyrootfs
if ! [ $(id -u) = 0 ]
then then
echo "STOP: Run sudo -i." echo "STOP: Run sudo -i."
exit 1 exit 1
@@ -15,74 +17,100 @@ function check_variable () {
fi fi
} }
check_variable "archiveserver" function check_archive_server_reachable () {
check_variable "sharename" echo "Verifying that the archive server $archiveserver is reachable..."
check_variable "shareuser" local serverunreachable=false
check_variable "sharepassword" ping -c 1 -w 1 "$archiveserver" 1>/dev/null 2>&1 || serverunreachable=true
check_variable "campercent"
serverunreachable=false if [ "$serverunreachable" = true ]
ping -c 1 -w 1 "$archiveserver" 1>/dev/null 2>&1 || serverunreachable=true then
if [ "$serverunreachable" = true ]
then
echo "STOP: The archive server $archiveserver is unreachable. Try specifying its IP address instead." echo "STOP: The archive server $archiveserver is unreachable. Try specifying its IP address instead."
exit 1 exit 1
fi fi
archiveserverip="$(getent hosts $archiveserver | cut -d' ' -f1)" echo "The archive server is reachable."
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
} }
pushd ~ function check_available_space () {
echo "Verifying that there is sufficient space available on the MicroSD card..."
cp /boot/cmdline.txt ~ local available_space="$( parted -m /dev/mmcblk0 u b print free | tail -1 | cut -d ":" -f 4 | sed 's/B//g' )"
cat ~/cmdline.txt | sed 's/[[:space:]]\+modules-load=[^ [:space:]]\+//' | sed 's/rootwait/rootwait modules-load=dwc2/' > /boot/cmdline.txt
rm ~/cmdline.txt
mkdir /mnt/archive if [ "$available_space" -lt 4294967296 ]
then
echo "STOP: The MicroSD card is too small."
exit 1
fi
echo "" >> /etc/fstab echo "There is sufficient space available."
echo "//$archiveserverip/$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 function get_ancillary_setup_scripts () {
echo "password=$sharepassword" >> /root/.teslaCamArchiveCredentials 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
}
mkdir /root/bin 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."
}
wget https://raw.githubusercontent.com/cimryan/teslausb/master/windows_archive/archiveloop BACKINGFILES_MOUNTPOINT=/backingfiles
sed s/ARCHIVE_HOST_NAME=archiveserver/ARCHIVE_HOST_NAME=$archiveserver/ ~/archiveloop > /root/bin/archiveloop
rm ~/archiveloop
chmod +x /root/bin/archiveloop
pushd /root/bin function create_usb_drive_backing_files () {
wget https://raw.githubusercontent.com/cimryan/teslausb/master/windows_archive/archive-teslacam-clips mkdir "$BACKINGFILES_MOUNTPOINT"
chmod +x archive-teslacam-clips /tmp/create-backingfiles-partition.sh "$BACKINGFILES_MOUNTPOINT"
popd
echo "#!/bin/bash -eu" > ~/rc.local echo "Mounting the partition for the backing files..."
tail -n +2 /etc/rc.local | sed '$d' >> ~/rc.local mount /backingfiles
echo "Mounted the partition for the backing files."
/tmp/create-backingfiles.sh "$campercent" "$BACKINGFILES_MOUNTPOINT"
}
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."
}
function configure_archive_scripts () {
echo "Configuring the archive scripts..."
mkdir /root/bin
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 cat << 'EOF' >> ~/rc.local
LOGFILE=/tmp/rc.local.log LOGFILE=/tmp/rc.local.log
@@ -97,26 +125,57 @@ log "All done"
exit 0 exit 0
EOF EOF
cat ~/rc.local > /etc/rc.local cat ~/rc.local > /etc/rc.local
rm ~/rc.local rm ~/rc.local
echo "Configured rc.local."
}
cam_disk_size="$(( $available_space * $campercent / 100 ))" function configure_hostname () {
cam_disk_file_name="/cam_disk.bin" echo "Configuring the hostname..."
add_drive "cam" "CAM" "$cam_disk_size" "$cam_disk_file_name"
if [ "$campercent" -lt 100 ] local new_host_name="teslausb"
then cp /etc/hosts ~
musicpercent="$(( 100 - $campercent ))" sed "s/raspberrypi/$new_host_name/g" ~/hosts > /etc/hosts
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
cp /etc/hosts ~ cp /etc/hostname ~
sed s/raspberrypi/teslausb/g ~/hosts > /etc/hosts sed "s/raspberrypi/$new_host_name/g" ~/hostname > /etc/hostname
echo "Configured the hostname."
}
cp /etc/hostname ~ function make_root_fs_readonly () {
sed s/raspberrypi/teslausb/g ~/hostname > /etc/hostname /tmp/make-root-fs-readonly.sh
}
echo "Verifying environment variables..."
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."