initial commit

This commit is contained in:
2026-09-26 17:37:13 +02:00
commit 839bebd8d4
226 changed files with 58701 additions and 0 deletions
+324
View File
@@ -0,0 +1,324 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_PATH="${BASH_SOURCE[0]:-${0}}"
SCRIPT_DIR="$(cd "$(dirname "${SCRIPT_PATH}")" && pwd)"
TAURI_DIR="${SCRIPT_DIR}/ui-tauri-react/src-tauri"
BUILD_SCRIPT="${SCRIPT_DIR}/build-rust-runtime.sh"
RUNTIME_INSTALL_DIR="/usr/local/libexec/zenbook-duo"
RUNTIME_BINS=(
zenbook-duo-daemon
zenbook-duo-session-agent
zenbook-duo-lifecycle
zenbook-duo-usb-remap-helper
)
BUILD_ONLY=false
INSTALL_ONLY=false
usage() {
cat <<'EOF'
install-rust-runtime.sh - build and/or install Zenbook Duo background services
Usage:
./install-rust-runtime.sh # build, then install (default)
./install-rust-runtime.sh --build-only # compile binaries only
./install-rust-runtime.sh --install-only # install existing binaries + systemd units
Build output: ui-tauri-react/src-tauri/target/release/
Install path: /usr/local/libexec/zenbook-duo/
EOF
}
while [ "$#" -gt 0 ]; do
case "$1" in
--build-only)
BUILD_ONLY=true
shift
;;
--install-only)
INSTALL_ONLY=true
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "ERROR: unknown argument: $1" >&2
usage >&2
exit 1
;;
esac
done
if [ "${BUILD_ONLY}" = true ] && [ "${INSTALL_ONLY}" = true ]; then
echo "ERROR: Choose only one of --build-only or --install-only" >&2
exit 1
fi
SYSTEM_SERVICE_NAME="zenbook-duo-rust-daemon.service"
LIFECYCLE_SERVICE_NAME="zenbook-duo-rust-lifecycle.service"
USER_SERVICE_NAME="zenbook-duo-session-agent.service"
SYSTEM_SLEEP_HOOK_PATH="/usr/lib/systemd/system-sleep/zenbook-duo-rust-lifecycle"
SYSTEM_SLEEP_HOOK_DIR="$(dirname "${SYSTEM_SLEEP_HOOK_PATH}")"
TARGET_USER="${USER:-}"
if [ "${EUID}" = "0" ]; then
if [ -n "${SUDO_USER:-}" ] && [ "${SUDO_USER}" != "root" ]; then
TARGET_USER="${SUDO_USER}"
else
echo "ERROR: install-rust-runtime.sh must be launched from a real user session." >&2
exit 1
fi
fi
TARGET_UID="$(id -u "${TARGET_USER}" 2>/dev/null || true)"
if [ -z "${TARGET_UID}" ]; then
echo "ERROR: failed to resolve target user '${TARGET_USER}'" >&2
exit 1
fi
TARGET_GID="$(id -g "${TARGET_USER}" 2>/dev/null || true)"
if [ -z "${TARGET_GID}" ]; then
echo "ERROR: failed to resolve primary group for '${TARGET_USER}'" >&2
exit 1
fi
TARGET_HOME="$(getent passwd "${TARGET_USER}" 2>/dev/null | cut -d: -f6)"
if [ -z "${TARGET_HOME}" ]; then
echo "ERROR: failed to resolve home directory for '${TARGET_USER}'" >&2
exit 1
fi
die() {
echo "ERROR: $*" >&2
exit 1
}
emit_systemctl_failure() {
local manager="$1"
local command_display="$2"
local output="${3:-}"
echo "ERROR: ${manager} systemd manager is unavailable; cannot run: ${command_display}" >&2
if [ -n "${output}" ]; then
printf '%s\n' "${output}" | sed 's/^/ systemctl: /' >&2
fi
}
run_system_systemctl() {
local output=""
if ! output="$(sudo systemctl --system "$@" 2>&1)"; then
emit_systemctl_failure "The system" "sudo systemctl --system $*" "${output}"
echo "Make sure this machine is booted with systemd and that 'sudo systemctl status' works, then rerun ./install.sh." >&2
exit 1
fi
if [ -n "${output}" ]; then
printf '%s\n' "${output}"
fi
}
run_user_systemctl() {
local runtime_dir="/run/user/${TARGET_UID}"
local bus_address="unix:path=${runtime_dir}/bus"
if [ "${TARGET_USER}" = "${USER:-}" ] && [ "${EUID}" != "0" ]; then
XDG_RUNTIME_DIR="${runtime_dir}" \
DBUS_SESSION_BUS_ADDRESS="${bus_address}" \
systemctl --user "$@"
return
fi
sudo -u "${TARGET_USER}" \
XDG_RUNTIME_DIR="${runtime_dir}" \
DBUS_SESSION_BUS_ADDRESS="${bus_address}" \
systemctl --user "$@"
}
run_user_systemctl_checked() {
local output=""
if ! output="$(run_user_systemctl "$@" 2>&1)"; then
emit_systemctl_failure "The ${TARGET_USER} user" "systemctl --user $*" "${output}"
echo "Run the installer from an active desktop login where 'systemctl --user status' works, then rerun ./install.sh." >&2
exit 1
fi
if [ -n "${output}" ]; then
printf '%s\n' "${output}"
fi
}
ensure_system_manager_available() {
local output=""
if ! output="$(sudo systemctl --system show --property=Version --value 2>&1)"; then
emit_systemctl_failure "The system" "sudo systemctl --system show --property=Version --value" "${output}"
echo "Make sure this machine is booted with systemd and that 'sudo systemctl status' works, then rerun ./install.sh." >&2
exit 1
fi
}
ensure_user_manager_available() {
local runtime_dir="/run/user/${TARGET_UID}"
local bus_path="${runtime_dir}/bus"
local output=""
if [ ! -d "${runtime_dir}" ]; then
die "The systemd user runtime directory is missing for ${TARGET_USER}: ${runtime_dir}. Log in as ${TARGET_USER} and rerun ./install.sh from that desktop session."
fi
if [ ! -S "${bus_path}" ]; then
die "The systemd user bus is missing for ${TARGET_USER}: ${bus_path}. Log in as ${TARGET_USER} and rerun ./install.sh from that desktop session."
fi
if ! output="$(run_user_systemctl show-environment 2>&1)"; then
emit_systemctl_failure "The ${TARGET_USER} user" "systemctl --user show-environment" "${output}"
echo "Run the installer from an active desktop login where 'systemctl --user status' works, then rerun ./install.sh." >&2
exit 1
fi
}
import_user_environment() {
run_user_systemctl import-environment DISPLAY WAYLAND_DISPLAY NIRI_SOCKET XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP DESKTOP_SESSION XDG_SESSION_TYPE >/dev/null 2>&1 || true
if command -v dbus-update-activation-environment >/dev/null 2>&1; then
if [ "${TARGET_USER}" = "${USER:-}" ] && [ "${EUID}" != "0" ]; then
XDG_RUNTIME_DIR="/run/user/${TARGET_UID}" \
DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/${TARGET_UID}/bus" \
dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY NIRI_SOCKET XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP DESKTOP_SESSION XDG_SESSION_TYPE >/dev/null 2>&1 || true
else
sudo -u "${TARGET_USER}" \
XDG_RUNTIME_DIR="/run/user/${TARGET_UID}" \
DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/${TARGET_UID}/bus" \
dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY NIRI_SOCKET XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP DESKTOP_SESSION XDG_SESSION_TYPE >/dev/null 2>&1 || true
fi
fi
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "ERROR: Missing required command: $1" >&2
exit 1
}
}
if [ "${BUILD_ONLY}" = true ]; then
exec "${BUILD_SCRIPT}"
fi
if [ "${INSTALL_ONLY}" = false ]; then
"${BUILD_SCRIPT}"
fi
for binary in "${RUNTIME_BINS[@]}"; do
if [ ! -x "${TAURI_DIR}/target/release/${binary}" ]; then
die "Missing built binary ${TAURI_DIR}/target/release/${binary}. Run ./build-rust-runtime.sh first."
fi
done
need_cmd systemctl
ensure_system_manager_available
ensure_user_manager_available
echo "Installing Rust runtime binaries..."
sudo mkdir -p "${RUNTIME_INSTALL_DIR}"
sudo install -m 0755 \
"${TAURI_DIR}/target/release/zenbook-duo-daemon" \
"${RUNTIME_INSTALL_DIR}/zenbook-duo-daemon"
sudo install -m 0755 \
"${TAURI_DIR}/target/release/zenbook-duo-session-agent" \
"${RUNTIME_INSTALL_DIR}/zenbook-duo-session-agent"
sudo install -m 0755 \
"${TAURI_DIR}/target/release/zenbook-duo-lifecycle" \
"${RUNTIME_INSTALL_DIR}/zenbook-duo-lifecycle"
sudo install -m 0755 \
"${TAURI_DIR}/target/release/zenbook-duo-usb-remap-helper" \
"${RUNTIME_INSTALL_DIR}/zenbook-duo-usb-remap-helper"
echo "Installed Rust runtime versions:"
for binary in \
zenbook-duo-daemon \
zenbook-duo-session-agent \
zenbook-duo-lifecycle \
zenbook-duo-usb-remap-helper; do
"${RUNTIME_INSTALL_DIR}/${binary}" --version || true
done
echo "Installing Rust runtime services..."
cat <<EOF | sudo tee "/etc/systemd/system/${SYSTEM_SERVICE_NAME}" >/dev/null
[Unit]
Description=Zenbook Duo Rust Daemon
After=network.target
[Service]
Type=simple
ExecStart=${RUNTIME_INSTALL_DIR}/zenbook-duo-daemon
Environment=ZENBOOK_DUO_HOME=${TARGET_HOME}
Environment=ZENBOOK_DUO_USER=${TARGET_USER}
Environment=ZENBOOK_DUO_UID=${TARGET_UID}
Environment=ZENBOOK_DUO_GID=${TARGET_GID}
Restart=on-failure
RestartSec=1
[Install]
WantedBy=multi-user.target
EOF
cat <<EOF | sudo tee "/etc/systemd/system/${LIFECYCLE_SERVICE_NAME}" >/dev/null
[Unit]
Description=Zenbook Duo Rust Lifecycle Handler
DefaultDependencies=no
Before=shutdown.target
After=multi-user.target
[Service]
Type=oneshot
ExecStart=${RUNTIME_INSTALL_DIR}/zenbook-duo-lifecycle boot
ExecStop=${RUNTIME_INSTALL_DIR}/zenbook-duo-lifecycle shutdown
RemainAfterExit=yes
TimeoutStartSec=10
TimeoutStopSec=10
[Install]
WantedBy=multi-user.target
EOF
cat <<EOF | sudo tee "/etc/systemd/user/${USER_SERVICE_NAME}" >/dev/null
[Unit]
Description=Zenbook Duo Session Agent
ConditionUser=!gdm
After=graphical-session.target
StartLimitIntervalSec=0
[Service]
Type=simple
ExecStartPre=/bin/sh -c 'test -n "\${DISPLAY:-}\${WAYLAND_DISPLAY:-}\${NIRI_SOCKET:-}"'
ExecStart=${RUNTIME_INSTALL_DIR}/zenbook-duo-session-agent
Restart=on-failure
RestartSec=2
TimeoutStopSec=5
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=%t/bus
[Install]
WantedBy=default.target
EOF
sudo mkdir -p "${SYSTEM_SLEEP_HOOK_DIR}"
sudo rm -f "${SYSTEM_SLEEP_HOOK_PATH}"
sudo ln -sfn "${RUNTIME_INSTALL_DIR}/zenbook-duo-lifecycle" "${SYSTEM_SLEEP_HOOK_PATH}"
sudo systemctl disable zenbook-duo.service 2>/dev/null || true
sudo systemctl stop zenbook-duo.service 2>/dev/null || true
sudo rm -f /usr/lib/systemd/system-sleep/duo
run_system_systemctl daemon-reload
run_system_systemctl enable "${SYSTEM_SERVICE_NAME}"
run_system_systemctl enable "${LIFECYCLE_SERVICE_NAME}"
run_system_systemctl restart "${SYSTEM_SERVICE_NAME}"
run_system_systemctl restart "${LIFECYCLE_SERVICE_NAME}"
ensure_user_manager_available
run_user_systemctl_checked daemon-reload
import_user_environment
run_user_systemctl disable zenbook-duo-user.service >/dev/null 2>&1 || true
run_user_systemctl stop zenbook-duo-user.service >/dev/null 2>&1 || true
run_user_systemctl_checked enable "${USER_SERVICE_NAME}"
run_user_systemctl_checked restart "${USER_SERVICE_NAME}"
echo "Rust runtime services installed."