Skip to content

Commit

Permalink
Added ability to run record firstboot scripts with script(1)
Browse files Browse the repository at this point in the history
  • Loading branch information
meeDamian committed May 25, 2020
1 parent ead93f8 commit e8a2c66
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 21 deletions.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ RUN apt-get update && \
ADD modify-image.sh /usr/local/bin/modify-image
RUN chmod +x /usr/local/bin/modify-image

RUN mkdir -p /data/ /mnt/raspbian/
ADD firstboot.service /data/
RUN mkdir -p /mnt/raspbian/ /data/
ADD firstboot.service firstboot-script.service /data/

VOLUME /raspbian/
WORKDIR /raspbian/
Expand Down
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
Raspbian
=========

Literally just pure Raspbian Lite, but with added the ability to run a script on the first boot by putting it onto `/boot/` as `firstboot.sh`.
Literally just pure Raspbian Lite, but with added the ability to run a script on the first boot by putting it onto `/boot/` as either:

* `/boot/firstboot.sh` - Run provided script directly
* `/boot/firstboot-script.sh` - Run via [`script(1)`][script] for complete session recording, that can be later played back using [`scriptreplay(1)`][replay]

[script]: http://man7.org/linux/man-pages/man1/script.1.html
[replay]: http://man7.org/linux/man-pages/man1/scriptreplay.1.html

Repo is inspired by https://github.com/nmcclain/raspberian-firstboot, but has been automated, Dockerized, and fully scripted.

Expand Down Expand Up @@ -49,6 +55,10 @@ If you're on a Linux box, you can (after cloning this repo) run:

You can also completely ignore all contents of this repo, download Raspbian Lite, and (assuming you have the ability to mount `ext4` on your OS):

> **NOTE: For `firstboot-script.service` see [here].**
[here]: /firstboot-script.service

1. Mount second partition
1. Install the service, by creating `$MOUNT_PATH/etc/systemd/system/firstboot.service` file, with the following contents:
```unit file (systemd)
Expand All @@ -59,9 +69,9 @@ You can also completely ignore all contents of this repo, download Raspbian Lite
ConditionFileNotEmpty=/boot/firstboot.sh
[Service]
Type=oneshot
ExecStart=/boot/firstboot.sh
ExecStartPost=/bin/mv /boot/firstboot.sh /boot/firstboot.sh.done
Type=oneshot
RemainAfterExit=no
[Install]
Expand Down
55 changes: 55 additions & 0 deletions examples/firstboot-script.tor.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env sh

## This is an example script that:
# 1. Installs Tor
# 2. Sets up a stealth Tor Hidden Service for ssh access
# 3. Copies `hostname` to `/boot/` (necessary to access)
# 4. Halts RBP when done (unless `/boot/nohalt` exists)

set -e

RET_COUNT=20

retry() {
delay=${RET_DELAY:-10} # seconds
count=${RET_COUNT:-3}

_s=s
until $*; do
>&2 printf "'%s' failed (exit=%s)" "$1" "$?"
if [ $((count-=1)) = 0 ]; then
>&2 printf "\n"
return 1
fi

[ "$count" = 1 ] && _s=
>&2 printf ", retry in %ss (%s more time%s)…\n\n" "$delay" "$count" "$_s"
sleep "$delay"
done
}

do_tor() {
retry apt-get install -y tor

retry test -f /etc/tor/torrc || exit 1

cat << EOF >> /etc/tor/torrc
HiddenServiceDir /var/lib/tor/ssh/
HiddenServiceVersion 2
HiddenServicePort 22 127.0.0.1:22
HiddenServiceAuthorizeClient stealth ssh
EOF

retry systemctl restart tor
retry systemctl restart tor@default

RET_COUNT=10 retry cp /var/lib/tor/ssh/hostname /boot/
}

retry apt-get update

do_tor

RET_COUNT=100 RET_DELAY=5 retry test -f /boot/nohalt || halt

exit 0
14 changes: 14 additions & 0 deletions firstboot-script.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[Unit]
Description=FirstBoot
After=network.target
Before=rc-local.service
ConditionFileNotEmpty=/boot/firstboot-script.sh

[Service]
Type=oneshot
ExecStart=/usr/bin/script --command=/boot/firstboot-script.sh --return --flush --timing=/boot/firstboot-script-log.tm /boot/firstboot-script-log.out
ExecStartPost=/bin/mv /boot/firstboot-script.sh /boot/firstboot-script.sh.done
RemainAfterExit=no

[Install]
WantedBy=multi-user.target
2 changes: 1 addition & 1 deletion firstboot.service
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ Before=rc-local.service
ConditionFileNotEmpty=/boot/firstboot.sh

[Service]
Type=oneshot
ExecStart=/boot/firstboot.sh
ExecStartPost=/bin/mv /boot/firstboot.sh /boot/firstboot.sh.done
Type=oneshot
RemainAfterExit=no

[Install]
Expand Down
36 changes: 20 additions & 16 deletions modify-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -198,22 +198,26 @@ log_ok


os_path=etc/systemd/system
service_file=firstboot.service
service_src="$(pwd)/$service_file"

# Change $service_src, when running in Docker
[ -f "/data/$service_file" ] && service_src="/data/$service_file"

log "Installing service" "$service_file"
cp "$service_src" "$mount_dir/$os_path/"
log_ok "Installed at /$os_path/$service_file"

# Another subshell to avoid cd (we (need (to (go (deeper(!))))))
(
cd "$mount_dir/$os_path/multi-user.target.wants/"
ln -s "/$os_path/$service_file" .
log_ok "Enabled as /$os_path/multi-user.target.wants/$service_file"
)

log "Installing services"
for service in firstboot firstboot-script; do
service_file="$service.service"
service_src="$(pwd)/$service_file"

# Change $service_src, when running in Docker
[ -f "/data/$service_file" ] && service_src="/data/$service_file"

cp "$service_src" "$mount_dir/$os_path/"
log_ok "$service installed at /$os_path/$service_file"

# Another subshell to avoid cd (we (need (to (go (deeper(!))))))
(
cd "$mount_dir/$os_path/multi-user.target.wants/"
ln -s "/$os_path/$service_file" .
log_ok "$service enabled as /$os_path/multi-user.target.wants/$service_file"
)

done


log "Unmounting" "$mount_dir"
Expand Down

0 comments on commit e8a2c66

Please sign in to comment.