From 0344f1e32f2649f62a09ef48c3a11f4ef8b724c6 Mon Sep 17 00:00:00 2001 From: Donald Buczek Date: Sun, 21 Jun 2026 17:33:12 +0200 Subject: [PATCH] mxstartup: Run startstop commands as transient user services Attempt to run startstop commands inside a user service unit. First make sure that a user service manager is running ("systemctl start user@UID") then start the startstop from this service manager as a transient service ("systemd-run --user"). It that doesn't seem to work, fall back to the previous ("su -c ... &") mechanism. Running the startstop commands as a user service unit has the advantage that the execution environment of the startstop command is disconnected from the execution environment of the process calling mxtstartup. Additionally, the startstop command can use the service manager to manage its own services: #! /usr/bin/bash set -e case $1 in start) systemd-run --user --unit sleeper --same-dir sleep infinity ;; stop) systemctl --user stop sleeper ;; *) echo "usage: $0 {start|stop}" >&1 exit 1 ;; esac Output of the startup script and additional services goes to the journal and is visible to the user. Note, that this is not true for some old accounts which have a UID < 1000 which are regarded system users by journald systemd and don't get an individual journal log file with an acl on it to give the user read access. --- mxstartup/mxservicectl | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/mxstartup/mxservicectl b/mxstartup/mxservicectl index 1808f652..3b65b20f 100755 --- a/mxstartup/mxservicectl +++ b/mxstartup/mxservicectl @@ -11,6 +11,26 @@ shopt -s nullglob # exit on any error set -e +# Run "$@" as a user service of $MX_SRV_USER +# +function run_as_user_service() { + local uid cmd + uid=$(id -u "${MX_SRV_USER}") || return 1 + printf -v cmd '%q ' "$@" + systemctl start user@$uid || return 1 + su -l "${MX_SRV_USER}" -s /usr/bin/bash -c "XDG_RUNTIME_DIR=/run/user/$uid systemd-run --user --no-ask-password $cmd" || return 1 +} + +# Run "$@" as user $MX_SRV_USER +# Attempt to run as a user service. If that fails, fall back to running it in the background +# +function run_as_user() { + run_as_user_service "$@" && return 0 + local cmd + printf -v cmd '%q ' "$@" + su -l "${MX_SRV_USER}" -s /usr/bin/bash -c "$cmd" & +} + function mxsrv_start_one() { local cfg=$1 local -i i mip mfwd @@ -26,7 +46,7 @@ function mxsrv_start_one() { systemctl start "${MX_SRV_SCRIPT}" || true ;; *) - su - ${MX_SRV_USER} -c "${MX_SRV_SCRIPT} start" & + run_as_user ${MX_SRV_SCRIPT} start ;; esac @@ -50,7 +70,7 @@ function mxsrv_stop_one() { systemctl stop "${MX_SRV_SCRIPT}" || true ;; *) - su - ${MX_SRV_USER} -c "${MX_SRV_SCRIPT} stop" & + run_as_user ${MX_SRV_SCRIPT} stop ;; esac