Compare commits
2 Commits
e263862335
...
256b90bfbb
Author | SHA1 | Date |
---|---|---|
macmpi | 256b90bfbb | |
macmpi | f430fc3ce5 |
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2022 macmpi
|
Copyright (c) 2022-2023 macmpi
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
23
README.md
23
README.md
|
@ -4,45 +4,46 @@
|
||||||
However, in many cases one might want to deploy a headless system that is only available through a network connection (ethernet, wifi or as USB ethernet gadget).
|
However, in many cases one might want to deploy a headless system that is only available through a network connection (ethernet, wifi or as USB ethernet gadget).
|
||||||
|
|
||||||
This repo provides an **overlay file** to initially bootstrap[^1] a headless system (leveraging Alpine distro's `initramfs` feature): it starts a ssh server to log-into from another Computer, so that actual install on fresh system (or rescue on existing disk-based system) can then be performed remotely.\
|
This repo provides an **overlay file** to initially bootstrap[^1] a headless system (leveraging Alpine distro's `initramfs` feature): it starts a ssh server to log-into from another Computer, so that actual install on fresh system (or rescue on existing disk-based system) can then be performed remotely.\
|
||||||
An optional script may be launched at startup, to perform automated actions/setup.
|
An optional script may also be launched during that same initial bootstrap, to perform fully automated setup.
|
||||||
|
|
||||||
|
|
||||||
## Setup procedure:
|
## Setup procedure:
|
||||||
Please follow [Alpine Linux Wiki](https://wiki.alpinelinux.org/wiki/Installation#Installation_Overview) to download & create installation media for the target platform.\
|
Please follow [Alpine Linux Wiki](https://wiki.alpinelinux.org/wiki/Installation#Installation_Overview) to download & create installation media for the target platform.\
|
||||||
Tools provided here can be used on any plaform for any install modes (diskless, data disk, system disk).
|
Tools provided here can be used on any plaform for any install modes (diskless, data disk, system disk).
|
||||||
|
|
||||||
Just add [**headless.apkovl.tar.gz**](https://is.gd/apkovl_master)[^2] overlay file at the root of Alpine Linux boot media (or onto any custom side-media) and boot-up the system.\
|
Just add [**headless.apkovl.tar.gz**](https://is.gd/apkovl_master)[^2] overlay file *as-is* at the root of Alpine Linux boot media (or onto any custom side-media) and boot-up the system.\
|
||||||
With default network interface definitions (and [SSID/pass file](#extra-configuration) if using wifi), system can then be remotely accessed with: `ssh root@<IP>`\
|
With default DCHP-based network interface definitions (and [SSID/pass file](#extra-configuration) if using wifi), system can then be remotely accessed with: `ssh root@<IP>`\
|
||||||
(system IP address may be determined with any IP scanning tools such as `nmap`).
|
(system IP address may be determined with any IP scanning tools such as `nmap`).
|
||||||
|
|
||||||
As with Alpine Linux initial bring-up, `root` account has no password initially (change that during setup!).\
|
As with Alpine Linux initial bring-up, `root` account has no password initially (change that during target setup!).\
|
||||||
From there, actual system install can be performed as usual with `setup-alpine` for instance (check [wiki](https://wiki.alpinelinux.org/wiki/Alpine_setup_scripts#setup-alpine) for details).
|
From there, actual system install can be performed as usual with `setup-alpine` for instance (check [wiki](https://wiki.alpinelinux.org/wiki/Alpine_setup_scripts#setup-alpine) for details).
|
||||||
|
|
||||||
## Extra configuration:
|
## Extra configuration:
|
||||||
Extra files may be added next to `headless.apkovl.tar.gz` to customise boostrapping configuration (check sample files):
|
Extra files may be added next to `headless.apkovl.tar.gz` to customise boostrapping configuration (check sample files):
|
||||||
- `wpa_supplicant.conf`[^3] (*mandatory for wifi usecase*): define wifi SSID & password.
|
- `wpa_supplicant.conf`[^3] (*mandatory for wifi usecase*): define wifi SSID & password.
|
||||||
|
- `unattended.sh`[^3] (*optional*): provide a deployment script to automate setup & customizations during initial bootstrap.
|
||||||
- `interfaces`[^3] (*optional*): define network interfaces at will, if defaults DCHP-based are not suitable.
|
- `interfaces`[^3] (*optional*): define network interfaces at will, if defaults DCHP-based are not suitable.
|
||||||
- `authorized_keys` (*optional*): provide client's public SSH key to secure `root` ssh login.
|
- `authorized_keys` (*optional*): provide client's public SSH key to secure `root` ssh login.
|
||||||
- `ssh_host_*_key*` (*optional*): provide server's custom ssh keys to be injected (may be stored), instead of using bundled ones[^2] (not stored). Providing an empty key file will trigger new keys generation (ssh server may take longer to start).
|
- `ssh_host_*_key*` (*optional*): provide server's custom ssh keys to be injected (may be stored), instead of using bundled ones[^2] (not stored). Providing an empty key file will trigger new keys generation (ssh server may take longer to start).
|
||||||
- `unattended.sh`[^3] (*optional*): create custom automated deployment script to further tune & extend actual setup (backgrounded).
|
|
||||||
|
|
||||||
|
|
||||||
**Goody:** seamless USB-ethernet gadget boostrapping (PiZero for instance):\
|
**Goody:** seamless USB-serial & USB-ethernet gadget mode (PiZero for instance):\
|
||||||
On supporting Pi devices, just add `dtoverlay=dwc2` in `usercfg.txt` (or `config.txt`), and plug USB cable into Computer port.\
|
On supporting Pi devices, just add `dtoverlay=dwc2,dr_mode=peripheral` in `usercfg.txt` (or `config.txt`), and plug USB cable into host Computer port.\
|
||||||
With Computer set-up to share networking with USB interface as 10.42.0.1 gateway, one can log into device from Computer with: `ssh root@10.42.0.2`
|
Serial terminal can then be connected-to from host Computer (xon/xoff flow control: e.g. on Linux with `cu -l ttyACM0`).\
|
||||||
|
Alternatively, with host Computer set-up to share networking with USB interface as 10.42.0.1 gateway, one can log into device from host with: `ssh root@10.42.0.2`.
|
||||||
|
|
||||||
Main execution steps are logged in `/var/log/messages`.
|
Main execution steps are logged: `cat /var/log/messages | grep headless`.
|
||||||
|
|
||||||
[^1]: Initial boot fully preserves system's original state (config files & installed packages): a fresh system will therefore come-up as unconfigured.
|
[^1]: Initial boot fully preserves system's original state (config files & installed packages): a fresh system will therefore come-up as unconfigured.
|
||||||
|
|
||||||
[^2]: About bundled ssh keys: this overlay is meant to **quickly bootstrap** system in order to then proceed with proper install; therefore it purposely embeds [some ssh keys](https://github.com/macmpi/alpine-linux-headless-bootstrap/tree/main/overlay/etc/ssh) so that bootstrapping is as fast as possible. Those temporary keys are moved in RAM /tmp: they will **not be stored/reused** once actual system install is performed (whether or not ssh server is installed in final setup).
|
[^2]: About bundled ssh keys: this overlay is meant to **quickly bootstrap** system in order to then proceed with proper install; therefore it purposely embeds [some ssh keys](https://github.com/macmpi/alpine-linux-headless-bootstrap/tree/main/overlay/tmp/.trash) so that bootstrapping is as fast as possible. Those temporary keys are moved in RAM /tmp: they will **not be stored/reused** once actual system install is performed (whether or not ssh server is installed in final setup).
|
||||||
|
|
||||||
[^3]: These files are linux text files: Windows/macOS users need to use text editors supporting linux text line-ending (such as [notepad++](https://notepad-plus-plus.org/), BBEdit or any similar).
|
[^3]: These files are linux text files: Windows/macOS users need to use text editors supporting linux text line-ending (such as [notepad++](https://notepad-plus-plus.org/), BBEdit or any similar).
|
||||||
|
|
||||||
|
|
||||||
## Want to tweak more ?
|
## Want to tweak more ?
|
||||||
This repository may be forked/cloned/downloaded.\
|
This repository may be forked/cloned/downloaded.\
|
||||||
Main script file is [`headless.start`](https://github.com/macmpi/alpine-linux-headless-bootstrap/blob/main/overlay/etc/local.d/headless.start).\
|
Main script file is [`headless.start`](https://github.com/macmpi/alpine-linux-headless-bootstrap/tree/main/overlay/usr/local/bin/headless_bootstrap).\
|
||||||
Execute `./make.sh` to rebuild `headless.apkovl.tar.gz` after changes.
|
Execute `./make.sh` to rebuild `headless.apkovl.tar.gz` after changes.
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
32
make.sh
32
make.sh
|
@ -1,8 +1,30 @@
|
||||||
#!/bin/sh
|
#!/bin/busybox sh
|
||||||
|
|
||||||
# Copyright 2022 - 2023, macmpi
|
# SPDX-FileCopyrightText: Copyright 2022-2023, macmpi
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
chmod 600 overlay/etc/ssh/ssh_host_*_key
|
|
||||||
chmod +x overlay/etc/local.d/headless.start
|
command -v doas > /dev/null || alias doas="/usr/bin/sudo"
|
||||||
tar czvf headless.apkovl.tar.gz -C overlay etc --owner=0 --group=0
|
|
||||||
|
build_path="$(mktemp -d)"
|
||||||
|
if [ -n "$build_path" ]; then
|
||||||
|
cp -r overlay "$build_path"/.
|
||||||
|
find "$build_path"/overlay/ -exec touch -md "$(date '+%F 00:00:00')" {} \;
|
||||||
|
|
||||||
|
# setting owner/groups for runtime (won't affect mtime)
|
||||||
|
find "$build_path"/overlay/etc -type d -exec chmod 755 {} \;
|
||||||
|
chmod +x "$build_path"/overlay/etc/init.d/*
|
||||||
|
find "$build_path"/overlay/usr -type d -exec chmod 755 {} \;
|
||||||
|
chmod +x "$build_path"/overlay/usr/local/bin/*
|
||||||
|
chmod 777 "$build_path"/overlay/tmp
|
||||||
|
chmod 700 "$build_path"/overlay/tmp/.trash
|
||||||
|
chmod 600 "$build_path"/overlay/tmp/.trash/ssh_host_*_key
|
||||||
|
doas chown -R 0:0 "$build_path"/overlay/*
|
||||||
|
|
||||||
|
doas tar -cvf "$build_path"/headless.apkovl.tar -C "$build_path"/overlay etc usr tmp
|
||||||
|
gzip -nk9 "$build_path"/headless.apkovl.tar && mv "$build_path"/headless.apkovl.tar.gz .
|
||||||
|
touch -md "$(date '+%F 00:00:00')" headless.apkovl.tar.gz
|
||||||
|
|
||||||
|
doas rm -rf "$build_path"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/sbin/openrc-run
|
||||||
|
|
||||||
|
# SPDX-FileCopyrightText: Copyright 2022-2023, macmpi
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
description="Headless main boostrappring script"
|
||||||
|
name="Headless bootstrap"
|
||||||
|
|
||||||
|
command="/usr/local/bin/headless_bootstrap"
|
||||||
|
command_background=true
|
||||||
|
pidfile="/run/${RC_SVCNAME}.pid"
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/sbin/openrc-run
|
||||||
|
|
||||||
|
# SPDX-FileCopyrightText: Copyright 2022-2023, macmpi
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
description="Headless cleanup script"
|
||||||
|
name="Headless cleanup"
|
||||||
|
|
||||||
|
command="/tmp/.trash/headless_cleanup"
|
||||||
|
command_background=true
|
||||||
|
pidfile="/run/${RC_SVCNAME}.pid"
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/sbin/openrc-run
|
||||||
|
|
||||||
|
# SPDX-FileCopyrightText: Copyright 2022-2023, macmpi
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
description="Headless unattended setup script (optional)"
|
||||||
|
name="Headless unattended"
|
||||||
|
|
||||||
|
command="/tmp/headless_unattended"
|
||||||
|
command_background=true
|
||||||
|
pidfile="/run/${RC_SVCNAME}.pid"
|
||||||
|
|
|
@ -1,247 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# Copyright 2022 - 2023, macmpi
|
|
||||||
# SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
VERSION="0.9"
|
|
||||||
|
|
||||||
|
|
||||||
_apk() {
|
|
||||||
local cmd="$1"
|
|
||||||
local pkg="$2"
|
|
||||||
|
|
||||||
case $cmd in
|
|
||||||
add) # install only if not already present
|
|
||||||
if ! apk info | grep -wq "${pkg}"; then
|
|
||||||
apk add "$pkg" && printf "${pkg} " >> /tmp/.trash/installed
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
del) # delete only if previously installed
|
|
||||||
if grep -wq "$pkg" /tmp/.trash/installed; then
|
|
||||||
apk del "$pkg" && sed -i 's/\b'"${pkg}"'\b//' /tmp/.trash/installed
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "only add/del: wrong usage"; exit
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
_preserve() {
|
|
||||||
[ -f "$1" ] && cp "$1" "${1}.orig"
|
|
||||||
}
|
|
||||||
|
|
||||||
_restore() {
|
|
||||||
if [ -f "${1}.orig" ]; then
|
|
||||||
mv -- "${1}.orig" "${1}"
|
|
||||||
else
|
|
||||||
rm -rf "${1}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
##### End of part to be duplicated into post-cleanup (do not alter!)
|
|
||||||
|
|
||||||
|
|
||||||
# Redirect stdout and errors to console as rc.local does not log anything
|
|
||||||
exec 1>/dev/console 2>&1
|
|
||||||
|
|
||||||
logger -st ${0##*/} "Alpine Linux headless bootstrap v$VERSION by macmpi"
|
|
||||||
|
|
||||||
install -dm 0700 /tmp/.trash
|
|
||||||
|
|
||||||
# grab used ovl filename from dmesg
|
|
||||||
ovl="$( dmesg | grep -o 'Loading user settings from .*:' | awk '{print $5}' | sed 's/:.*$//' )"
|
|
||||||
ovl="$( basename "${ovl}" )"
|
|
||||||
# search path again as mountpoint may have been changed later in the boot process...
|
|
||||||
ovlpath=$( find /media -maxdepth 2 -type d -path '*/.*' -prune -o -type f -name "${ovl}" -exec dirname {} \; | head -1 )
|
|
||||||
|
|
||||||
# Help randomness for wpa_supplicant and ssh server
|
|
||||||
rc-service seedrng start
|
|
||||||
|
|
||||||
## Setup Network interfaces
|
|
||||||
if [ -f "${ovlpath}/wpa_supplicant.conf" ]; then
|
|
||||||
logger -st ${0##*/} "Configuring wifi..."
|
|
||||||
_apk add wpa_supplicant
|
|
||||||
_preserve "/etc/wpa_supplicant/wpa_supplicant.conf"
|
|
||||||
install -m600 "${ovlpath}/wpa_supplicant.conf" /etc/wpa_supplicant/wpa_supplicant.conf
|
|
||||||
else
|
|
||||||
logger -st ${0##*/} "No wifi setup supplied !"
|
|
||||||
fi
|
|
||||||
|
|
||||||
_preserve "/etc/network/interfaces"
|
|
||||||
if ! install -m644 "${ovlpath}/interfaces" /etc/network/interfaces; then
|
|
||||||
# set default interfaces if not specified by interface file on boot storage
|
|
||||||
logger -st ${0##*/} "No interfaces file supplied, building defaults..."
|
|
||||||
for dev in $(ls /sys/class/net)
|
|
||||||
do
|
|
||||||
case ${dev%%[0-9]*} in
|
|
||||||
lo)
|
|
||||||
cat <<-EOF >> /etc/network/interfaces
|
|
||||||
auto $dev
|
|
||||||
iface $dev inet loopback
|
|
||||||
|
|
||||||
EOF
|
|
||||||
;;
|
|
||||||
eth)
|
|
||||||
cat <<-EOF >> /etc/network/interfaces
|
|
||||||
auto $dev
|
|
||||||
iface $dev inet dhcp
|
|
||||||
|
|
||||||
EOF
|
|
||||||
;;
|
|
||||||
wlan)
|
|
||||||
[ -f /etc/wpa_supplicant/wpa_supplicant.conf ] && cat <<-EOF >> /etc/network/interfaces
|
|
||||||
auto $dev
|
|
||||||
iface $dev inet dhcp
|
|
||||||
|
|
||||||
EOF
|
|
||||||
;;
|
|
||||||
usb)
|
|
||||||
cat <<-EOF >> /etc/network/interfaces
|
|
||||||
auto $dev
|
|
||||||
iface $dev inet static
|
|
||||||
address 10.42.0.2/24
|
|
||||||
gateway 10.42.0.1
|
|
||||||
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cat <<-EOF > /etc/resolv.conf
|
|
||||||
nameserver 208.67.222.222
|
|
||||||
nameserver 208.67.220.220
|
|
||||||
|
|
||||||
EOF
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Using following network interfaces:"
|
|
||||||
cat /etc/network/interfaces
|
|
||||||
|
|
||||||
_preserve "/etc/hostname"
|
|
||||||
echo "alpine-headless" > /etc/hostname
|
|
||||||
hostname -F /etc/hostname
|
|
||||||
|
|
||||||
grep -q "wlan" /etc/network/interfaces && \
|
|
||||||
[ -f /etc/wpa_supplicant/wpa_supplicant.conf ] && \
|
|
||||||
rc-service wpa_supplicant start
|
|
||||||
rc-service networking start
|
|
||||||
|
|
||||||
|
|
||||||
## Setup temporary SSH server (root login, no password)
|
|
||||||
## We use some bundled (or optionaly provided) keys to avoid generation at startup and save time
|
|
||||||
_apk add openssh
|
|
||||||
_preserve "/etc/ssh/sshd_config"
|
|
||||||
_preserve "/etc/conf.d/sshd"
|
|
||||||
|
|
||||||
cat <<-EOF > /etc/ssh/sshd_config
|
|
||||||
PermitRootLogin yes
|
|
||||||
Banner /tmp/.trash/banner
|
|
||||||
EOF
|
|
||||||
|
|
||||||
if install -m600 "${ovlpath}/authorized_keys" /tmp/.trash/authorized_keys; then
|
|
||||||
logger -st ${0##*/} "Enabling public key SSH authentication..."
|
|
||||||
cat <<-EOF >> /etc/ssh/sshd_config
|
|
||||||
AuthenticationMethods publickey
|
|
||||||
AuthorizedKeysFile /tmp/.trash/authorized_keys
|
|
||||||
# relax strict mode as authorized_keys are inside /tmp
|
|
||||||
StrictModes no
|
|
||||||
EOF
|
|
||||||
else
|
|
||||||
logger -st ${0##*/} "No SSH authentication."
|
|
||||||
cat <<-EOF >> /etc/ssh/sshd_config
|
|
||||||
AuthenticationMethods none
|
|
||||||
PermitEmptyPasswords yes
|
|
||||||
EOF
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Banner file
|
|
||||||
warn=""
|
|
||||||
grep -q "${ovlpath}.*[[:space:]]ro[[:space:],]" /proc/mounts; RO=$?
|
|
||||||
[ "$RO" -eq "0" ] && warn="(remount partition rw!)"
|
|
||||||
|
|
||||||
cat <<-EOF > /tmp/.trash/banner
|
|
||||||
|
|
||||||
Alpine Linux headless bootstrap v$VERSION by macmpi
|
|
||||||
|
|
||||||
You may want to delete/rename .apkovl file before reboot ${warn}:
|
|
||||||
${ovlpath}/${ovl}
|
|
||||||
(can be done automatically with unattended script - see sample snippet)
|
|
||||||
|
|
||||||
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Bundled temporary keys are moved in RAM /tmp so they won't be stored
|
|
||||||
# within permanent config later (new ones will then be generated at reboot)
|
|
||||||
KEYGEN_STANCE="sshd_disable_keygen=yes"
|
|
||||||
mv /etc/ssh/ssh_host_*_key* /tmp/.trash/.
|
|
||||||
|
|
||||||
# Inject optional custom keys (those might be stored)
|
|
||||||
if install -m600 "${ovlpath}"/ssh_host_*_key* /etc/ssh/; then
|
|
||||||
# check for empty key within injected ones: if found, generate new keys
|
|
||||||
if find /etc/ssh/ -maxdepth 1 -type f -name 'ssh_host_*_key*' -empty | grep -q .; then
|
|
||||||
rm /etc/ssh/ssh_host_*_key*
|
|
||||||
KEYGEN_STANCE=""
|
|
||||||
logger -st ${0##*/} "Will generate new SSH keys..."
|
|
||||||
else
|
|
||||||
chmod 644 /etc/ssh/ssh_host_*_key.pub
|
|
||||||
logger -st ${0##*/} "Using injected SSH keys..."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
logger -st ${0##*/} "Using bundled ssh keys from RAM..."
|
|
||||||
cat <<-EOF >> /etc/ssh/sshd_config
|
|
||||||
HostKey /tmp/.trash/ssh_host_ed25519_key
|
|
||||||
HostKey /tmp/.trash/ssh_host_rsa_key
|
|
||||||
EOF
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "$KEYGEN_STANCE" >> /etc/conf.d/sshd
|
|
||||||
rc-service sshd start
|
|
||||||
|
|
||||||
## Prep for final post-cleanup
|
|
||||||
## clears any installed packages and settings
|
|
||||||
# copy begininng of this file to keep functions
|
|
||||||
sed -n '/^#* End .*alter!)$/q;p' /etc/local.d/headless.start > /tmp/.trash/post-cleanup
|
|
||||||
|
|
||||||
cat <<-EOF >> /tmp/.trash/post-cleanup
|
|
||||||
|
|
||||||
_tst_inet() {
|
|
||||||
## Tested URL redirects to github project page: is.gd shortener provides basic analytics.
|
|
||||||
## Analytics are public and can be checked at https://is.gd/stats.php?url=apkovl_run
|
|
||||||
## Privacy policy: https://is.gd/privacy.php
|
|
||||||
INET="failed"
|
|
||||||
wget -q -T 10 --spider https://is.gd/apkovl_run > /dev/null 2>&1 &&
|
|
||||||
INET="success"
|
|
||||||
logger -st ${0##*/} "Internet access: \$INET"
|
|
||||||
}
|
|
||||||
|
|
||||||
logger -st ${0##*/} "Cleaning-up..."
|
|
||||||
_restore "/etc/ssh/sshd_config"
|
|
||||||
_restore "/etc/conf.d/sshd"
|
|
||||||
_apk del openssh
|
|
||||||
_restore "/etc/wpa_supplicant/wpa_supplicant.conf"
|
|
||||||
_apk del wpa_supplicant
|
|
||||||
_restore "/etc/network/interfaces"
|
|
||||||
_restore "/etc/hostname"
|
|
||||||
rm /etc/modules-load.d/g_ether.conf
|
|
||||||
rm /etc/modprobe.d/g_ether.conf
|
|
||||||
rc-update del local default
|
|
||||||
rm /etc/local.d/headless.start
|
|
||||||
|
|
||||||
# Internet connectivity test
|
|
||||||
# Can be skipped by creating a 'opt-out'-named dummy file aside apkovl file
|
|
||||||
[ -f "${ovlpath}/opt-out" ] || _tst_inet &
|
|
||||||
|
|
||||||
# Run unattended script if available
|
|
||||||
if [ -f "${ovlpath}/unattended.sh" ]; then
|
|
||||||
install -m755 "${ovlpath}/unattended.sh" /tmp/unattended.sh
|
|
||||||
/tmp/unattended.sh >/dev/console 2>&1 &
|
|
||||||
logger -st ${0##*/} "/tmp/unattended.sh script launched in the background with PID \$!"
|
|
||||||
fi
|
|
||||||
|
|
||||||
logger -st ${0##*/} "Done !!"
|
|
||||||
EOF
|
|
||||||
|
|
||||||
chmod +x /tmp/.trash/post-cleanup
|
|
||||||
exec /tmp/.trash/post-cleanup
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
# Copyright 2022 - 2023, macmpi
|
|
||||||
# SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
# added to support USB-Ethernet gadget mode at boot for Pi devices
|
|
||||||
|
|
||||||
options g_ether dev_addr=ea:64:2f:e8:19:94 host_addr=f6:67:ce:b3:c0:ea
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
# SPDX-FileCopyrightText: Copyright 2022-2023, macmpi
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
# support g_cdc USB-Ethernet gadget mode at boot for Pi devices
|
||||||
|
|
||||||
|
options g_cdc dev_addr=ea:64:2f:e8:19:94 host_addr=f6:67:ce:b3:c0:ea
|
|
@ -1,9 +0,0 @@
|
||||||
# Copyright 2022 - 2023, macmpi
|
|
||||||
# SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
# added to support USB-Ethernet gadget mode at boot for Pi devices
|
|
||||||
# also requires dtoverlay=dwc2 is added to usercfg.txt or config.txt
|
|
||||||
|
|
||||||
dwc2
|
|
||||||
g_ether
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
../../init.d/headless_bootstrap
|
|
@ -1 +0,0 @@
|
||||||
/etc/init.d/local
|
|
|
@ -0,0 +1,306 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# SPDX-FileCopyrightText: Copyright 2022-2023, macmpi
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
HDLSBSTRP_VERSION="1.0"
|
||||||
|
|
||||||
|
_apk() {
|
||||||
|
local cmd="$1"
|
||||||
|
local pkg="$2"
|
||||||
|
|
||||||
|
case $cmd in
|
||||||
|
add) # install only if not already present
|
||||||
|
if ! apk info | grep -wq "${pkg}"; then
|
||||||
|
apk add "$pkg" && printf '%s ' "${pkg}" >> /tmp/.trash/installed
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
del) # delete only if previously installed
|
||||||
|
if grep -wq "$pkg" /tmp/.trash/installed > /dev/null 2>&1; then
|
||||||
|
apk del "$pkg" && sed -i 's/\b'"${pkg}"'\b//' /tmp/.trash/installed
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "only add/del: wrong usage"; exit
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
_preserve() {
|
||||||
|
# create a back-up of element (file, folder, symlink)
|
||||||
|
[ -z "${1}" ] && return 1
|
||||||
|
[ -e "$1" ] && cp -a "$1" "${1}.orig"
|
||||||
|
}
|
||||||
|
|
||||||
|
_restore() {
|
||||||
|
# remove element (file, folder, symlink) and replace by
|
||||||
|
# previous back-up if available
|
||||||
|
[ -z "${1}" ] && return 1
|
||||||
|
rm -rf "${1}"
|
||||||
|
[ -e "${1}.orig" ] && mv -f "${1}.orig" "${1}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# shellcheck disable=SC2142 # known special case
|
||||||
|
alias _logger='logger -st "${0##*/}"'
|
||||||
|
|
||||||
|
##### End of part to be duplicated into headless_cleanup (do not alter!)
|
||||||
|
|
||||||
|
_prep_cleanup() {
|
||||||
|
## Prep for final headless_cleanup
|
||||||
|
# clears any installed packages and settings
|
||||||
|
# copy begininng of this file to keep functions
|
||||||
|
sed -n '/^#* End .*alter!)$/q;p' /usr/local/bin/headless_bootstrap > /tmp/.trash/headless_cleanup
|
||||||
|
cat <<-EOF >> /tmp/.trash/headless_cleanup
|
||||||
|
# Redirect stdout and errors to console as service won't show messages
|
||||||
|
exec 1>/dev/console 2>&1
|
||||||
|
|
||||||
|
_logger "Cleaning-up..."
|
||||||
|
_restore "/etc/ssh/sshd_config"
|
||||||
|
_restore "/etc/conf.d/sshd"
|
||||||
|
_apk del openssh-server
|
||||||
|
_restore "/etc/wpa_supplicant/wpa_supplicant.conf"
|
||||||
|
_apk del wpa_supplicant
|
||||||
|
_restore "/etc/network/interfaces"
|
||||||
|
_restore "/etc/hostname"
|
||||||
|
rm -f /etc/modprobe.d/headless_gadget.conf
|
||||||
|
|
||||||
|
# remove from boot service to avoid spurious openrc recalls from unattended script
|
||||||
|
rm -f /etc/runlevels/default/headless_bootstrap
|
||||||
|
rm -f /usr/local/bin/headless_bootstrap
|
||||||
|
|
||||||
|
# Run unattended script if available
|
||||||
|
install -m755 "${ovlpath}/unattended.sh" /tmp/headless_unattended > /dev/null 2>&1 && \
|
||||||
|
_logger "Starting headless_unattended service" && \
|
||||||
|
rc-service headless_unattended start
|
||||||
|
|
||||||
|
rm -f /etc/init.d/headless_*
|
||||||
|
_logger "Clean-up done, enjoy !"
|
||||||
|
cat /tmp/.trash/banner > /dev/console
|
||||||
|
if [ -c /dev/ttyGS0 ]; then
|
||||||
|
# Enabling terminal login into ttyGS0 serial for 60 sec
|
||||||
|
# no choice than making permanent change to pre 3.19 versions of /etc/securetty
|
||||||
|
grep -q "ttyGS0" /etc/securetty || echo "ttyGS0" >> /etc/securetty
|
||||||
|
/sbin/getty -L 115200 ttyGS0 vt100 &
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
chmod +x /tmp/.trash/headless_cleanup
|
||||||
|
}
|
||||||
|
|
||||||
|
_setup_sshd() {
|
||||||
|
## Setup temporary SSH server (root login, no password)
|
||||||
|
# We use some bundled (or optionaly provided) keys to avoid generation at startup and save time
|
||||||
|
_apk add openssh-server
|
||||||
|
_preserve "/etc/ssh/sshd_config"
|
||||||
|
_preserve "/etc/conf.d/sshd"
|
||||||
|
|
||||||
|
cat <<-EOF > /etc/ssh/sshd_config
|
||||||
|
PermitRootLogin yes
|
||||||
|
Banner /tmp/.trash/banner
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Client authorized_keys or no authentication
|
||||||
|
if install -m600 "${ovlpath}/authorized_keys" /tmp/.trash/authorized_keys > /dev/null 2>&1; then
|
||||||
|
_logger "Enabling public key SSH authentication..."
|
||||||
|
cat <<-EOF >> /etc/ssh/sshd_config
|
||||||
|
AuthenticationMethods publickey
|
||||||
|
AuthorizedKeysFile /tmp/.trash/authorized_keys
|
||||||
|
# relax strict mode as authorized_keys are inside /tmp
|
||||||
|
StrictModes no
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
_logger "No SSH authentication."
|
||||||
|
cat <<-EOF >> /etc/ssh/sshd_config
|
||||||
|
AuthenticationMethods none
|
||||||
|
PermitEmptyPasswords yes
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Server keys: inject optional custom keys, or generate new (might be stored),
|
||||||
|
# or use bundeled ones (not stored)
|
||||||
|
local keygen_stance="sshd_disable_keygen=yes"
|
||||||
|
if install -m600 "${ovlpath}"/ssh_host_*_key* /etc/ssh/ > /dev/null 2>&1; then
|
||||||
|
# check for empty key within injected ones: if found, generate new keys
|
||||||
|
if find /etc/ssh/ -maxdepth 1 -type f -name 'ssh_host_*_key*' -empty | grep -q .; then
|
||||||
|
rm /etc/ssh/ssh_host_*_key*
|
||||||
|
keygen_stance=""
|
||||||
|
_logger "Will generate new SSH keys..."
|
||||||
|
else
|
||||||
|
chmod 644 /etc/ssh/ssh_host_*_key.pub
|
||||||
|
_logger "Using injected SSH keys..."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
_logger "Using bundled ssh keys from RAM..."
|
||||||
|
cat <<-EOF >> /etc/ssh/sshd_config
|
||||||
|
HostKey /tmp/.trash/ssh_host_ed25519_key
|
||||||
|
HostKey /tmp/.trash/ssh_host_rsa_key
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$keygen_stance" >> /etc/conf.d/sshd
|
||||||
|
rc-service sshd restart
|
||||||
|
}
|
||||||
|
|
||||||
|
_tst_version() {
|
||||||
|
# Tested URL redirects to github project page: is.gd shortener provides basic analytics.
|
||||||
|
# Analytics are public and can be checked at https://is.gd/stats.php?url=apkovl_run
|
||||||
|
# Privacy policy: https://is.gd/privacy.php
|
||||||
|
local new_vers=""
|
||||||
|
local status="failed"
|
||||||
|
local ref="/macmpi/alpine-linux-headless-bootstrap/releases/tag/v"
|
||||||
|
if wget -q -O /tmp/homepg -T 10 https://is.gd/apkovl_run > /dev/null 2>&1; then
|
||||||
|
status="success"
|
||||||
|
ver="$( grep -o "$ref.*\"" /tmp/homepg | grep -Eo '[0-9]+[\.[0-9]+]*' )"
|
||||||
|
rm -f /tmp/homepg
|
||||||
|
[ -n "$ver" ] && ! [ "$ver" = "$HDLSBSTRP_VERSION" ] && \
|
||||||
|
new_vers="!! Version $ver is available on Github project page !!" && \
|
||||||
|
_logger "$new_vers" && \
|
||||||
|
printf '%s\n\n' "$new_vers" >> /tmp/.trash/banner
|
||||||
|
fi
|
||||||
|
_logger "Internet access: $status"
|
||||||
|
}
|
||||||
|
|
||||||
|
_setup_networking() {
|
||||||
|
## Setup Network interfaces
|
||||||
|
if [ -d "/sys/class/net/wlan0" ] && [ -f "${ovlpath}/wpa_supplicant.conf" ]; then
|
||||||
|
_logger "Configuring wifi..."
|
||||||
|
_apk add wpa_supplicant
|
||||||
|
_preserve "/etc/wpa_supplicant/wpa_supplicant.conf"
|
||||||
|
install -m600 "${ovlpath}/wpa_supplicant.conf" /etc/wpa_supplicant/wpa_supplicant.conf
|
||||||
|
else
|
||||||
|
_logger "No wifi interface or setup file supplied"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_preserve "/etc/network/interfaces"
|
||||||
|
if ! install -m644 "${ovlpath}/interfaces" /etc/network/interfaces > /dev/null 2>&1; then
|
||||||
|
# set default interfaces if not specified by interface file on boot storage
|
||||||
|
_logger "No interfaces file supplied, building defaults..."
|
||||||
|
for dev in /sys/class/net/*; do
|
||||||
|
dev="$(basename "$dev")"
|
||||||
|
case ${dev%%[0-9]*} in
|
||||||
|
lo)
|
||||||
|
cat <<-EOF >> /etc/network/interfaces
|
||||||
|
auto $dev
|
||||||
|
iface $dev inet loopback
|
||||||
|
|
||||||
|
EOF
|
||||||
|
;;
|
||||||
|
eth)
|
||||||
|
cat <<-EOF >> /etc/network/interfaces
|
||||||
|
auto $dev
|
||||||
|
iface $dev inet dhcp
|
||||||
|
|
||||||
|
EOF
|
||||||
|
;;
|
||||||
|
wlan)
|
||||||
|
[ -f /etc/wpa_supplicant/wpa_supplicant.conf ] && cat <<-EOF >> /etc/network/interfaces
|
||||||
|
auto $dev
|
||||||
|
iface $dev inet dhcp
|
||||||
|
|
||||||
|
EOF
|
||||||
|
;;
|
||||||
|
usb)
|
||||||
|
cat <<-EOF >> /etc/network/interfaces
|
||||||
|
auto $dev
|
||||||
|
iface $dev inet static
|
||||||
|
address 10.42.0.2/24
|
||||||
|
gateway 10.42.0.1
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat <<-EOF > /etc/resolv.conf
|
||||||
|
nameserver 208.67.222.222
|
||||||
|
nameserver 208.67.220.220
|
||||||
|
|
||||||
|
EOF
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "###################################"
|
||||||
|
echo "Using following network interfaces:"
|
||||||
|
cat /etc/network/interfaces
|
||||||
|
echo "###################################"
|
||||||
|
|
||||||
|
_preserve "/etc/hostname"
|
||||||
|
echo "alpine-headless" > /etc/hostname
|
||||||
|
hostname -F /etc/hostname
|
||||||
|
|
||||||
|
grep -q "wlan" /etc/network/interfaces && \
|
||||||
|
[ -f /etc/wpa_supplicant/wpa_supplicant.conf ] && \
|
||||||
|
rc-service wpa_supplicant restart
|
||||||
|
rc-service networking restart
|
||||||
|
}
|
||||||
|
|
||||||
|
_setup_gadget() {
|
||||||
|
# load composite USB Serial/USB Ethernel driver & setup terminal
|
||||||
|
_logger "Enabling USB-gadget Serial and Ethernet ports"
|
||||||
|
lsmod | grep -q "dwc2" || modprobe -qs dwc2
|
||||||
|
modprobe -qs g_cdc
|
||||||
|
# default config: xon/xoff flow control
|
||||||
|
stty -g -F /dev/ttyGS0 >/dev/null 2>&1 && setconsole /dev/ttyGS0
|
||||||
|
# notes to users willing to connect from Linux Ubuntu-based host terminal:
|
||||||
|
# - user on host needs to be part of dialout group (reboot required), and
|
||||||
|
# - disable spurious AT commands from ModemManager on host-side Gadget serial port
|
||||||
|
# you may create a /etc/udev/rules.d/99-ttyacms-gadget.rules as per:
|
||||||
|
# https://linux-tips.com/t/prevent-modem-manager-to-capture-usb-serial-devices/284/2
|
||||||
|
# ATTRS{idVendor}=="0525" ATTRS{idProduct}=="a4aa", ENV{ID_MM_DEVICE_IGNORE}="1"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
## Main
|
||||||
|
|
||||||
|
# Redirect stdout and errors to console as service won't show messages
|
||||||
|
exec 1>/dev/console 2>&1
|
||||||
|
_logger "Alpine Linux headless bootstrap v$HDLSBSTRP_VERSION by macmpi"
|
||||||
|
|
||||||
|
# help randomness for wpa_supplicant and sshd (urandom until 3.16)
|
||||||
|
rc-service seedrng restart || rc-service urandom restart
|
||||||
|
|
||||||
|
# setup USB gadget mode if device has compatible device-tree
|
||||||
|
find /proc/device-tree/soc/usb* -name "dr_mode" -print0 | \
|
||||||
|
xargs -0 grep -q "peripheral" && _setup_gadget
|
||||||
|
|
||||||
|
# Determine ovl file location
|
||||||
|
# grab used ovl filename from dmesg
|
||||||
|
ovl="$( dmesg | grep -o 'Loading user settings from .*:' | awk '{print $5}' | sed 's/:.*$//' )"
|
||||||
|
if [ -f "${ovl}" ]; then
|
||||||
|
ovlpath="$( dirname "$ovl" )"
|
||||||
|
else
|
||||||
|
# search path again as mountpoint have been changed later in the boot process...
|
||||||
|
ovl="$( basename "${ovl}" )"
|
||||||
|
ovlpath=$( find /media -maxdepth 2 -type d -path '*/.*' -prune -o -type f -name "${ovl}" -exec dirname {} \; | head -1 )
|
||||||
|
ovl="${ovlpath}/${ovl}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create banner file
|
||||||
|
warn=""
|
||||||
|
grep -q "${ovlpath}.*[[:space:]]ro[[:space:],]" /proc/mounts; RO=$?
|
||||||
|
[ "$RO" -eq "0" ] && warn="(remount partition rw!)"
|
||||||
|
cat <<-EOF > /tmp/.trash/banner
|
||||||
|
|
||||||
|
Alpine Linux headless bootstrap v$HDLSBSTRP_VERSION by macmpi
|
||||||
|
|
||||||
|
You may want to delete/rename .apkovl file before reboot ${warn}:
|
||||||
|
${ovl}
|
||||||
|
(can be done automatically with unattended script - see sample snippet)
|
||||||
|
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
_setup_networking
|
||||||
|
|
||||||
|
# Test latest available version online
|
||||||
|
# Can be skipped by creating a 'opt-out'-named dummy file aside apkovl file
|
||||||
|
[ -f "${ovlpath}/opt-out" ] || _tst_version &
|
||||||
|
|
||||||
|
# setup sshd unless unattended.sh script prevents it
|
||||||
|
grep -q "^#NO_SSH$" "${ovlpath}/unattended.sh" > /dev/null 2>&1 \
|
||||||
|
|| _setup_sshd
|
||||||
|
|
||||||
|
_prep_cleanup
|
||||||
|
_logger "Initial setup done, handing-over to clean-up"
|
||||||
|
rc-service headless_cleanup start
|
||||||
|
exit 0
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright 2022 - 2023, macmpi
|
# SPDX-FileCopyrightText: Copyright 2022-2023, macmpi
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
# Sample network interfaces file
|
# Sample network interfaces file
|
||||||
|
@ -8,15 +8,12 @@ iface lo inet loopback
|
||||||
|
|
||||||
auto eth0
|
auto eth0
|
||||||
iface eth0 inet dhcp
|
iface eth0 inet dhcp
|
||||||
hostname localhost
|
|
||||||
|
|
||||||
auto wlan0
|
auto wlan0
|
||||||
iface wlan0 inet dhcp
|
iface wlan0 inet dhcp
|
||||||
hostname localhost
|
|
||||||
|
|
||||||
auto usb0
|
auto usb0
|
||||||
iface usb0 inet static
|
iface usb0 inet static
|
||||||
address 10.42.0.2/24
|
address 10.42.0.2/24
|
||||||
gateway 10.42.0.1
|
gateway 10.42.0.1
|
||||||
hostname localhost
|
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,45 @@
|
||||||
#/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
# Copyright 2022 - 2023, macmpi
|
# SPDX-FileCopyrightText: Copyright 2022-2023, macmpi
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
## collection of few code snippets as sample unnatteded actions some may find usefull
|
## collection of few code snippets as sample unnatteded actions some may find usefull
|
||||||
|
|
||||||
|
## will run encapusated within headless_unattended OpenRC service
|
||||||
|
|
||||||
## Obvious one; reminder: is run in the background
|
# To prevent headless bootstrap script from starting sshd
|
||||||
echo hello world !!
|
# only keep a single starting # on the line below
|
||||||
|
##NO_SSH
|
||||||
|
|
||||||
|
# Uncomment to enable stdout and errors redirection to console (service won't show messages)
|
||||||
|
# exec 1>/dev/console 2>&1
|
||||||
|
|
||||||
|
# shellcheck disable=SC2142 # known special case
|
||||||
|
alias _logger='logger -st "${0##*/}"'
|
||||||
|
|
||||||
|
## Obvious one; reminder: is run as background service
|
||||||
|
_logger "hello world !!"
|
||||||
sleep 60
|
sleep 60
|
||||||
|
_logger "Finished script"
|
||||||
########################################################
|
########################################################
|
||||||
|
|
||||||
|
|
||||||
## This snippet removes apkovl file on volume after initial boot
|
## This snippet removes apkovl file on volume after initial boot
|
||||||
# grab used ovl filename from dmesg
|
# grab used ovl filename from dmesg
|
||||||
ovl="$( dmesg | grep -o 'Loading user settings from .*:' | awk '{print $5}' | sed 's/:.*$//' )"
|
ovl="$( dmesg | grep -o 'Loading user settings from .*:' | awk '{print $5}' | sed 's/:.*$//' )"
|
||||||
ovl="$( basename "${ovl}" )"
|
if [ -f "${ovl}" ]; then
|
||||||
# search path again as mountpoint may have been changed later in the boot process...
|
ovlpath="$( dirname "$ovl" )"
|
||||||
ovlpath=$( find /media -maxdepth 2 -type d -path '*/.*' -prune -o -type f -name "${ovl}" -exec dirname {} \; | head -1 )
|
else
|
||||||
|
# search path again as mountpoint have been changed later in the boot process...
|
||||||
|
ovl="$( basename "${ovl}" )"
|
||||||
|
ovlpath=$( find /media -maxdepth 2 -type d -path '*/.*' -prune -o -type f -name "${ovl}" -exec dirname {} \; | head -1 )
|
||||||
|
ovl="${ovlpath}/${ovl}"
|
||||||
|
fi
|
||||||
|
|
||||||
# also works in case volume is mounted read-only
|
# also works in case volume is mounted read-only
|
||||||
grep -q "${ovlpath}.*[[:space:]]ro[[:space:],]" /proc/mounts; RO=$?
|
grep -q "${ovlpath}.*[[:space:]]ro[[:space:],]" /proc/mounts; RO=$?
|
||||||
[ "$RO" -eq "0" ] && mount -o remount,rw "${ovlpath}"
|
[ "$RO" -eq "0" ] && mount -o remount,rw "${ovlpath}"
|
||||||
rm -f "${ovlpath}/${ovl}"
|
rm -f "${ovl}"
|
||||||
[ "$RO" -eq "0" ] && mount -o remount,ro "${ovlpath}"
|
[ "$RO" -eq "0" ] && mount -o remount,ro "${ovlpath}"
|
||||||
|
|
||||||
########################################################
|
########################################################
|
||||||
|
@ -33,7 +49,7 @@ rm -f "${ovlpath}/${ovl}"
|
||||||
# note: with INTERFACESOPTS=none, no networking will be setup so it won't work after reboot!
|
# note: with INTERFACESOPTS=none, no networking will be setup so it won't work after reboot!
|
||||||
# Change it or run setup-interfaces in interractive mode afterwards (and lbu commit -d thenafter)
|
# Change it or run setup-interfaces in interractive mode afterwards (and lbu commit -d thenafter)
|
||||||
|
|
||||||
logger -st ${0##*/} "Setting-up minimal environment"
|
_logger "Setting-up minimal environment"
|
||||||
|
|
||||||
cat <<-EOF > /tmp/ANSWERFILE
|
cat <<-EOF > /tmp/ANSWERFILE
|
||||||
# base answer file for setup-alpine script
|
# base answer file for setup-alpine script
|
||||||
|
@ -88,5 +104,5 @@ lbu commit -d
|
||||||
########################################################
|
########################################################
|
||||||
|
|
||||||
|
|
||||||
logger -st ${0##*/} "Finished unattended script"
|
_logger "Finished unattended script"
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright 2022 - 2023, macmpi
|
# SPDX-FileCopyrightText: Copyright 2022-2023, macmpi
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
# Sample wpa_supplicant.conf
|
# Sample wpa_supplicant.conf
|
||||||
|
|
Loading…
Reference in New Issue