You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
118 lines
3.1 KiB
118 lines
3.1 KiB
#!/bin/sh
|
|
|
|
DAEMON=/usr/bin/tera-seriald
|
|
PIDFILE=/run/tera-seriald/tera-seriald.pid
|
|
ENVFILE=/etc/tera/tera-seriald.env
|
|
RUN_AS=tera:tera
|
|
|
|
ensure_account() {
|
|
if ! grep -q '^tera:' /etc/group; then
|
|
addgroup -S tera || return 1
|
|
fi
|
|
if ! id tera >/dev/null 2>&1; then
|
|
adduser -S -D -H -s /bin/false -G tera tera || return 1
|
|
fi
|
|
normalize_service_account_password || return 1
|
|
}
|
|
|
|
normalize_service_account_password() {
|
|
shadow_value="$(awk -F: '$1 == "tera" { print $2 }' /etc/shadow)" || return 1
|
|
case "$shadow_value" in
|
|
""|!*) ;;
|
|
\**) ;;
|
|
*) return 0 ;;
|
|
esac
|
|
|
|
command -v mkpasswd >/dev/null 2>&1 || return 1
|
|
random_secret="$(dd if=/dev/urandom bs=48 count=1 2>/dev/null | sha256sum | cut -d' ' -f1)" || return 1
|
|
password_hash="$(mkpasswd -m sha-256 "$random_secret")" || return 1
|
|
unset random_secret
|
|
temporary_shadow="/etc/.shadow.tera.$$"
|
|
trap 'rm -f "$temporary_shadow"' EXIT HUP INT TERM
|
|
awk -F: -v OFS=: -v replacement="$password_hash" '
|
|
$1 == "tera" { $2 = replacement; found = 1 }
|
|
{ print }
|
|
END { if (!found) exit 1 }
|
|
' /etc/shadow >"$temporary_shadow" || return 1
|
|
chown 0:0 "$temporary_shadow" || return 1
|
|
chmod 0600 "$temporary_shadow" || return 1
|
|
mv -f "$temporary_shadow" /etc/shadow || return 1
|
|
trap - EXIT HUP INT TERM
|
|
}
|
|
|
|
wait_for_mapped_devices() {
|
|
mapping="${TERA_SERIALD_MAPPING:-/etc/tera/serial-map.json}"
|
|
[ -r "$mapping" ] || { echo "missing serial mapping $mapping" >&2; return 1; }
|
|
devices="$(sed -n 's/.*"device":[[:space:]]*"\([^"]*\)".*/\1/p' "$mapping")" || return 1
|
|
[ "$(printf '%s\n' "$devices" | grep -c '^/dev/ttyWCH[0-9][0-9]*$')" -eq 48 ] || {
|
|
echo "serial mapping must contain exactly 48 WCH devices" >&2
|
|
return 1
|
|
}
|
|
attempt=0
|
|
while [ "$attempt" -lt 100 ]; do
|
|
missing=0
|
|
for device in $devices; do
|
|
[ -c "$device" ] || { missing=1; break; }
|
|
done
|
|
[ "$missing" -eq 0 ] && return 0
|
|
attempt=$((attempt + 1))
|
|
sleep 0.1
|
|
done
|
|
echo "mapped WCH devices did not appear within 10 seconds" >&2
|
|
return 1
|
|
}
|
|
|
|
prepare_runtime() {
|
|
ensure_account || return 1
|
|
wait_for_mapped_devices || return 1
|
|
mkdir -p /run/tera-seriald /var/log/tera || return 1
|
|
chown tera:tera /run/tera-seriald /var/log/tera || return 1
|
|
for device in /dev/ttyWCH*; do
|
|
[ -c "$device" ] || continue
|
|
chgrp tera "$device" || return 1
|
|
chmod 0660 "$device" || return 1
|
|
done
|
|
}
|
|
|
|
load_environment() {
|
|
if [ -r "$ENVFILE" ]; then
|
|
set -a
|
|
. "$ENVFILE"
|
|
set +a
|
|
fi
|
|
}
|
|
|
|
is_running() {
|
|
[ -r "$PIDFILE" ] || return 1
|
|
pid="$(cat "$PIDFILE" 2>/dev/null)"
|
|
[ -n "$pid" ] && kill -0 "$pid" 2>/dev/null
|
|
}
|
|
|
|
start_service() {
|
|
if is_running; then
|
|
echo "tera-seriald is already running"
|
|
return 0
|
|
fi
|
|
rm -f "$PIDFILE"
|
|
[ -x "$DAEMON" ] || { echo "missing $DAEMON" >&2; return 1; }
|
|
load_environment
|
|
prepare_runtime || return 1
|
|
start-stop-daemon -S -q -b -m -p "$PIDFILE" -c "$RUN_AS" -x "$DAEMON"
|
|
}
|
|
|
|
stop_service() {
|
|
if ! is_running; then
|
|
rm -f "$PIDFILE"
|
|
return 0
|
|
fi
|
|
start-stop-daemon -K -q -p "$PIDFILE" -x "$DAEMON"
|
|
rm -f "$PIDFILE"
|
|
}
|
|
|
|
case "$1" in
|
|
start) start_service ;;
|
|
stop) stop_service ;;
|
|
restart) stop_service && start_service ;;
|
|
status) is_running ;;
|
|
*) echo "Usage: $0 {start|stop|restart|status}" >&2; exit 1 ;;
|
|
esac
|
|
|