Skip to content

Commit e8a2c66

Browse files
committed
Added ability to run record firstboot scripts with script(1)
1 parent ead93f8 commit e8a2c66

File tree

6 files changed

+104
-21
lines changed

6 files changed

+104
-21
lines changed

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ RUN apt-get update && \
1212
ADD modify-image.sh /usr/local/bin/modify-image
1313
RUN chmod +x /usr/local/bin/modify-image
1414

15-
RUN mkdir -p /data/ /mnt/raspbian/
16-
ADD firstboot.service /data/
15+
RUN mkdir -p /mnt/raspbian/ /data/
16+
ADD firstboot.service firstboot-script.service /data/
1717

1818
VOLUME /raspbian/
1919
WORKDIR /raspbian/

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
Raspbian
22
=========
33

4-
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`.
4+
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:
5+
6+
* `/boot/firstboot.sh` - Run provided script directly
7+
* `/boot/firstboot-script.sh` - Run via [`script(1)`][script] for complete session recording, that can be later played back using [`scriptreplay(1)`][replay]
8+
9+
[script]: http://man7.org/linux/man-pages/man1/script.1.html
10+
[replay]: http://man7.org/linux/man-pages/man1/scriptreplay.1.html
511

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

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

5056
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):
5157

58+
> **NOTE: For `firstboot-script.service` see [here].**
59+
60+
[here]: /firstboot-script.service
61+
5262
1. Mount second partition
5363
1. Install the service, by creating `$MOUNT_PATH/etc/systemd/system/firstboot.service` file, with the following contents:
5464
```unit file (systemd)
@@ -59,9 +69,9 @@ You can also completely ignore all contents of this repo, download Raspbian Lite
5969
ConditionFileNotEmpty=/boot/firstboot.sh
6070
6171
[Service]
72+
Type=oneshot
6273
ExecStart=/boot/firstboot.sh
6374
ExecStartPost=/bin/mv /boot/firstboot.sh /boot/firstboot.sh.done
64-
Type=oneshot
6575
RemainAfterExit=no
6676
6777
[Install]

examples/firstboot-script.tor.sh

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env sh
2+
3+
## This is an example script that:
4+
# 1. Installs Tor
5+
# 2. Sets up a stealth Tor Hidden Service for ssh access
6+
# 3. Copies `hostname` to `/boot/` (necessary to access)
7+
# 4. Halts RBP when done (unless `/boot/nohalt` exists)
8+
9+
set -e
10+
11+
RET_COUNT=20
12+
13+
retry() {
14+
delay=${RET_DELAY:-10} # seconds
15+
count=${RET_COUNT:-3}
16+
17+
_s=s
18+
until $*; do
19+
>&2 printf "'%s' failed (exit=%s)" "$1" "$?"
20+
if [ $((count-=1)) = 0 ]; then
21+
>&2 printf "\n"
22+
return 1
23+
fi
24+
25+
[ "$count" = 1 ] && _s=
26+
>&2 printf ", retry in %ss (%s more time%s)…\n\n" "$delay" "$count" "$_s"
27+
sleep "$delay"
28+
done
29+
}
30+
31+
do_tor() {
32+
retry apt-get install -y tor
33+
34+
retry test -f /etc/tor/torrc || exit 1
35+
36+
cat << EOF >> /etc/tor/torrc
37+
HiddenServiceDir /var/lib/tor/ssh/
38+
HiddenServiceVersion 2
39+
HiddenServicePort 22 127.0.0.1:22
40+
HiddenServiceAuthorizeClient stealth ssh
41+
EOF
42+
43+
retry systemctl restart tor
44+
retry systemctl restart tor@default
45+
46+
RET_COUNT=10 retry cp /var/lib/tor/ssh/hostname /boot/
47+
}
48+
49+
retry apt-get update
50+
51+
do_tor
52+
53+
RET_COUNT=100 RET_DELAY=5 retry test -f /boot/nohalt || halt
54+
55+
exit 0

firstboot-script.service

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[Unit]
2+
Description=FirstBoot
3+
After=network.target
4+
Before=rc-local.service
5+
ConditionFileNotEmpty=/boot/firstboot-script.sh
6+
7+
[Service]
8+
Type=oneshot
9+
ExecStart=/usr/bin/script --command=/boot/firstboot-script.sh --return --flush --timing=/boot/firstboot-script-log.tm /boot/firstboot-script-log.out
10+
ExecStartPost=/bin/mv /boot/firstboot-script.sh /boot/firstboot-script.sh.done
11+
RemainAfterExit=no
12+
13+
[Install]
14+
WantedBy=multi-user.target

firstboot.service

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ Before=rc-local.service
55
ConditionFileNotEmpty=/boot/firstboot.sh
66

77
[Service]
8+
Type=oneshot
89
ExecStart=/boot/firstboot.sh
910
ExecStartPost=/bin/mv /boot/firstboot.sh /boot/firstboot.sh.done
10-
Type=oneshot
1111
RemainAfterExit=no
1212

1313
[Install]

modify-image.sh

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -198,22 +198,26 @@ log_ok
198198

199199

200200
os_path=etc/systemd/system
201-
service_file=firstboot.service
202-
service_src="$(pwd)/$service_file"
203-
204-
# Change $service_src, when running in Docker
205-
[ -f "/data/$service_file" ] && service_src="/data/$service_file"
206-
207-
log "Installing service" "$service_file"
208-
cp "$service_src" "$mount_dir/$os_path/"
209-
log_ok "Installed at /$os_path/$service_file"
210-
211-
# Another subshell to avoid cd (we (need (to (go (deeper(!))))))
212-
(
213-
cd "$mount_dir/$os_path/multi-user.target.wants/"
214-
ln -s "/$os_path/$service_file" .
215-
log_ok "Enabled as /$os_path/multi-user.target.wants/$service_file"
216-
)
201+
202+
log "Installing services"
203+
for service in firstboot firstboot-script; do
204+
service_file="$service.service"
205+
service_src="$(pwd)/$service_file"
206+
207+
# Change $service_src, when running in Docker
208+
[ -f "/data/$service_file" ] && service_src="/data/$service_file"
209+
210+
cp "$service_src" "$mount_dir/$os_path/"
211+
log_ok "$service installed at /$os_path/$service_file"
212+
213+
# Another subshell to avoid cd (we (need (to (go (deeper(!))))))
214+
(
215+
cd "$mount_dir/$os_path/multi-user.target.wants/"
216+
ln -s "/$os_path/$service_file" .
217+
log_ok "$service enabled as /$os_path/multi-user.target.wants/$service_file"
218+
)
219+
220+
done
217221

218222

219223
log "Unmounting" "$mount_dir"

0 commit comments

Comments
 (0)