From 78425992badba050d666327e2f9f8f2aaa69ed82 Mon Sep 17 00:00:00 2001 From: Vladimir-csp <4061903+Vladimir-csp@users.noreply.github.com> Date: Wed, 2 Aug 2023 22:46:52 +0300 Subject: [PATCH 01/11] Support dbus replacements, some revamps * Operate with proper unit ID of active dbus service (i.e. dbus-broker.service) * ID starting point is hook name, support dbus-broker.service via a symlink * Kill PIDs of dbus service after restart (sometimes dbus processes linger, causing troubles) * Rewrite command creation logic, pre-render command * Better messaging --- ex/restart.d/dbus-broker.service | 1 + ex/restart.d/dbus.service | 92 ++++++++++++++++++++++---------- 2 files changed, 66 insertions(+), 27 deletions(-) create mode 120000 ex/restart.d/dbus-broker.service diff --git a/ex/restart.d/dbus-broker.service b/ex/restart.d/dbus-broker.service new file mode 120000 index 00000000..db57a589 --- /dev/null +++ b/ex/restart.d/dbus-broker.service @@ -0,0 +1 @@ +dbus.service \ No newline at end of file diff --git a/ex/restart.d/dbus.service b/ex/restart.d/dbus.service index e9a94248..b9ed2217 100755 --- a/ex/restart.d/dbus.service +++ b/ex/restart.d/dbus.service @@ -13,7 +13,7 @@ # enable xtrace if we should be verbose if [ "$NR_VERBOSE" = '1' ]; then - set -x + set -x fi if [ "$(id -ru)" != "0" ] @@ -30,52 +30,90 @@ then exit 0 fi -get_active_deps(){ +# start from the name of the hook, get real unit ID (for example, dbus-broker replaces dbus) +DBUS_SERVICE_NAME=$( + systemctl show --value -p Id "$(basename "$0")" +) + +# if DM is active, return canonical ID +DISPLAY_MANAGER=$( + systemctl -q is-active display-manager.service && \ + systemctl show --value -p Id display-manager.service +) + +# get dependencies +ACTIVE_DEPS=$( # return all dbus dependencies, filter out dbus and DM, leave only active { systemctl list-dependencies -l --reverse --plain dbus.socket - systemctl list-dependencies -l --reverse --plain dbus.service + systemctl list-dependencies -l --reverse --plain $DBUS_SERVICE_NAME } | grep -o '[^[:space:]]\+.service' | sort -u | while read SERVICE do - if [ "$SERVICE" != "dbus.service" -a "$SERVICE" != "$DISPLAY_MANAGER" ] && systemctl -q is-active "$SERVICE" + if [ "$SERVICE" != "$DBUS_SERVICE_NAME" ] && \ + [ "$SERVICE" != "$DISPLAY_MANAGER" ] && \ + systemctl -q is-active "$SERVICE" then echo "$SERVICE" fi - done -} - -# if DM is active, return canonical ID -DISPLAY_MANAGER="$(systemctl -q is-active display-manager.service && systemctl show --value -p Id display-manager.service)" - -# get dependencies -ACTIVE_DEPS="$(get_active_deps)" + done | tr '\n' ' ' | tr -s ' ' +) # get logind sessions -SESSIONS="$(loginctl list-sessions --no-legend | grep -o '^[[:space:]]*[0-9]\+' | tr '\n' ' ')" +SESSIONS=$(loginctl list-sessions --no-legend | grep -o '^[[:space:]]*[0-9]\+' | tr '\n' ' ') + +# get current dbus service PIDs +DBUS_PIDS=$( + ps -eo pid,unit | grep -E "[[:space:]]+${DBUS_SERVICE_NAME}[[:space:]]*$" \ + | grep -oE '^[[:space:]]*[0-9]+' \ + | tr '\n' ' ' | tr -s ' ' +) + +# assemble commands +COMMANDS='' +# terminate sessions +[ -n "$SESSIONS" ] && COMMANDS="${COMMANDS}${COMMANDS:+ ; }loginctl terminate-session $SESSIONS" +# stop display manager +[ -n "$DISPLAY_MANAGER" ] && COMMANDS="${COMMANDS}${COMMANDS:+ ; }systemctl stop $DISPLAY_MANAGER" +# restart dbus +COMMANDS="${COMMANDS}${COMMANDS:+ ; }sleep 1 ; systemctl restart $DBUS_SERVICE_NAME" +# kill previous dbus pids +[ -n "$DBUS_PIDS" ] && COMMANDS="${COMMANDS}${COMMANDS:+ ; }sleep 1 ; kill $DBUS_PIDS 2>/dev/null" +# restart active dependencies +COMMANDS="${COMMANDS}${COMMANDS:+ ; }sleep 1 ; systemctl restart $ACTIVE_DEPS" +# start display manager +[ -n "$DISPLAY_MANAGER" ] && COMMANDS="${COMMANDS}${COMMANDS:+ ; }systemctl start $DISPLAY_MANAGER" +# normalize to single line +COMMANDS=$(echo "$COMMANDS" | tr '\n' ' ' | tr -s ' ') cat << EOF -!!! In $PAUSE seconds dbus restart will be performed !!! +!!! $DBUS_SERVICE_NAME restart will be performed !!! + User sessions to be terminated: $SESSIONS Services to be restarted: -$ACTIVE_DEPS -$DISPLAY_MANAGER -EOF +$(echo $ACTIVE_DEPS | tr ' ' '\n' | sed 's/^/ /') -[ -t 0 ] && read -p "Press Enter to continue > " PRESSENTER +Display manager will be restarted: ${DISPLAY_MANAGER:-no active DM found} -# prepare list to be a CLI arg -ACTIVE_DEPS="$(echo "$ACTIVE_DEPS" | tr '\n' ' ')" +Command set to run as transient unit restart-dbus.service: + $(echo $COMMANDS | sed -r 's/ ; /\n /g') -# run restart sequence as transient unit... -if [ -n "$DISPLAY_MANAGER" ] +Logs can be viewed by: journalctl -u restart-dbus +EOF + +# if interactive, ask for continuation +if [ -t 0 ] then - # terminate user sessions, stop DM, restart dbus, reexec systemd, restart dbus dependencies, start DM - systemd-run -G --unit=restart-dbus sh -c "loginctl terminate-session $SESSIONS ; systemctl stop $DISPLAY_MANAGER ; systemctl restart dbus.service ; sleep 1 ; systemctl daemon-reexec ; sleep 1 ; systemctl restart $ACTIVE_DEPS ; systemctl start $DISPLAY_MANAGER" + read -p " +Press Enter to continue > " PRESSENTER else - # terminate user sessions, restart dbus, reexec systemd, restart dbus dependencies - systemd-run -G --unit=restart-dbus sh -c "loginctl terminate-session $SESSIONS ; systemctl restart dbus.service ; sleep 1 ; systemctl daemon-reexec ; sleep 1 ; systemctl restart $ACTIVE_DEPS" + echo " +Restart in 5 seconds..." + sleep 5 + echo "Restarting..." fi -# restart sequence runs as a unit, so it is possible to view its output in the log if, any: +# run restart sequence as transient unit... +# it is possible to view its output in the log if any: # journalctl -u restart-dbus +systemd-run -G --unit=restart-dbus --description="transient dbus restarter" sh -c "$COMMANDS" From 7ac1546111487106823bb43b737ccd930b5f3b1f Mon Sep 17 00:00:00 2001 From: Vladimir-csp <4061903+Vladimir-csp@users.noreply.github.com> Date: Wed, 2 Aug 2023 23:22:17 +0300 Subject: [PATCH 02/11] message to stderr if noninteractive --- ex/restart.d/dbus.service | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/ex/restart.d/dbus.service b/ex/restart.d/dbus.service index b9ed2217..a98fb09a 100755 --- a/ex/restart.d/dbus.service +++ b/ex/restart.d/dbus.service @@ -11,6 +11,9 @@ # This is a replacement for original dbus.service script by Thomas Liske # Dbus dependencies are enumerated dynamically and restarted after dbus and systemd daemon reexec +# delay in non-interactive mode +NONINTERACTIVE_DELAY=10 + # enable xtrace if we should be verbose if [ "$NR_VERBOSE" = '1' ]; then set -x @@ -85,7 +88,19 @@ COMMANDS="${COMMANDS}${COMMANDS:+ ; }sleep 1 ; systemctl restart $ACTIVE_DEPS" # normalize to single line COMMANDS=$(echo "$COMMANDS" | tr '\n' ' ' | tr -s ' ') -cat << EOF +if [ -t 0 ] +then + INTERACTIVE=true +else + INTERACTIVE=false +fi + +if [ "$INTERACTIVE" = "true" ] +then + cat +else + cat >&2 +fi << EOF !!! $DBUS_SERVICE_NAME restart will be performed !!! User sessions to be terminated: $SESSIONS @@ -93,7 +108,7 @@ User sessions to be terminated: $SESSIONS Services to be restarted: $(echo $ACTIVE_DEPS | tr ' ' '\n' | sed 's/^/ /') -Display manager will be restarted: ${DISPLAY_MANAGER:-no active DM found} +Display manager to be restarted: ${DISPLAY_MANAGER:-no active DM found} Command set to run as transient unit restart-dbus.service: $(echo $COMMANDS | sed -r 's/ ; /\n /g') @@ -102,15 +117,15 @@ Logs can be viewed by: journalctl -u restart-dbus EOF # if interactive, ask for continuation -if [ -t 0 ] +if [ "$INTERACTIVE" = "true" ] then read -p " Press Enter to continue > " PRESSENTER else echo " -Restart in 5 seconds..." - sleep 5 - echo "Restarting..." +Restart in $NONINTERACTIVE_DELAY seconds..." >&2 + sleep $NONINTERACTIVE_DELAY + echo "Restarting..." >&2 fi # run restart sequence as transient unit... From d3c1a8ae276678d5b705564ddc072cbcc9583f17 Mon Sep 17 00:00:00 2001 From: Vladimir-csp <4061903+Vladimir-csp@users.noreply.github.com> Date: Wed, 2 Aug 2023 23:41:06 +0300 Subject: [PATCH 03/11] interactivity modes --- ex/restart.d/dbus.service | 40 ++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/ex/restart.d/dbus.service b/ex/restart.d/dbus.service index a98fb09a..834a7f4e 100755 --- a/ex/restart.d/dbus.service +++ b/ex/restart.d/dbus.service @@ -11,14 +11,25 @@ # This is a replacement for original dbus.service script by Thomas Liske # Dbus dependencies are enumerated dynamically and restarted after dbus and systemd daemon reexec -# delay in non-interactive mode -NONINTERACTIVE_DELAY=10 +# delay in semi-interactive mode +DELAY_SECONDS=10 # enable xtrace if we should be verbose if [ "$NR_VERBOSE" = '1' ]; then set -x fi +# choose interactivity mode +if [ "${DEBIAN_FRONTEND:-other}" = "noninteractive" ] +then + CONSOLE_MODE=skip +elif [ -t 0 ] +then + CONSOLE_MODE=interactive +else + CONSOLE_MODE=delay +fi + if [ "$(id -ru)" != "0" ] then echo "Not root, exiting" >&2 @@ -88,18 +99,14 @@ COMMANDS="${COMMANDS}${COMMANDS:+ ; }sleep 1 ; systemctl restart $ACTIVE_DEPS" # normalize to single line COMMANDS=$(echo "$COMMANDS" | tr '\n' ' ' | tr -s ' ') -if [ -t 0 ] -then - INTERACTIVE=true -else - INTERACTIVE=false -fi - -if [ "$INTERACTIVE" = "true" ] +if [ "$CONSOLE_MODE" = "interactive" ] then cat -else +elif [ "$CONSOLE_MODE" = "delay" ] +then cat >&2 +else + true fi << EOF !!! $DBUS_SERVICE_NAME restart will be performed !!! @@ -117,15 +124,18 @@ Logs can be viewed by: journalctl -u restart-dbus EOF # if interactive, ask for continuation -if [ "$INTERACTIVE" = "true" ] +if [ "$CONSOLE_MODE" = "interactive" ] then read -p " Press Enter to continue > " PRESSENTER -else +elif [ "$CONSOLE_MODE" = "delay" ] +then echo " -Restart in $NONINTERACTIVE_DELAY seconds..." >&2 - sleep $NONINTERACTIVE_DELAY +Restart in $DELAY_SECONDS seconds..." >&2 + sleep $DELAY_SECONDS echo "Restarting..." >&2 +else + true fi # run restart sequence as transient unit... From 31534364d7cefb5cf00f5b2aa17ea1968a4cf4ec Mon Sep 17 00:00:00 2001 From: Vladimir-csp <4061903+Vladimir-csp@users.noreply.github.com> Date: Fri, 4 Aug 2023 10:54:28 +0300 Subject: [PATCH 04/11] terminate users, not sessions --- ex/restart.d/dbus.service | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ex/restart.d/dbus.service b/ex/restart.d/dbus.service index 834a7f4e..c98a0d74 100755 --- a/ex/restart.d/dbus.service +++ b/ex/restart.d/dbus.service @@ -72,8 +72,13 @@ ACTIVE_DEPS=$( done | tr '\n' ' ' | tr -s ' ' ) -# get logind sessions -SESSIONS=$(loginctl list-sessions --no-legend | grep -o '^[[:space:]]*[0-9]\+' | tr '\n' ' ') +# get logind users +USERS=$( + loginctl list-users --no-legend \ + | grep -oE '^[[:space:]]*[0-9]+[[:space:]]+[^[:space:]]+' \ + | grep -oE '[^[:space:]]+$' \ + | tr '\n' ' ' | tr -s ' ' +) # get current dbus service PIDs DBUS_PIDS=$( @@ -84,8 +89,8 @@ DBUS_PIDS=$( # assemble commands COMMANDS='' -# terminate sessions -[ -n "$SESSIONS" ] && COMMANDS="${COMMANDS}${COMMANDS:+ ; }loginctl terminate-session $SESSIONS" +# terminate users +[ -n "$USERS" ] && COMMANDS="${COMMANDS}${COMMANDS:+ ; }loginctl terminate-user $USERS" # stop display manager [ -n "$DISPLAY_MANAGER" ] && COMMANDS="${COMMANDS}${COMMANDS:+ ; }systemctl stop $DISPLAY_MANAGER" # restart dbus @@ -110,7 +115,7 @@ else fi << EOF !!! $DBUS_SERVICE_NAME restart will be performed !!! -User sessions to be terminated: $SESSIONS +Users to be terminated: $USERS Services to be restarted: $(echo $ACTIVE_DEPS | tr ' ' '\n' | sed 's/^/ /') From 67bc7cb7696eff3da9d0d92b007083fbbb76fff1 Mon Sep 17 00:00:00 2001 From: Vladimir-csp <4061903+Vladimir-csp@users.noreply.github.com> Date: Fri, 15 Dec 2023 18:19:17 +0300 Subject: [PATCH 05/11] actually use shell in shell, cleanups --- ex/restart.d/dbus.service | 129 +++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 64 deletions(-) diff --git a/ex/restart.d/dbus.service b/ex/restart.d/dbus.service index c98a0d74..730e359d 100755 --- a/ex/restart.d/dbus.service +++ b/ex/restart.d/dbus.service @@ -20,26 +20,22 @@ if [ "$NR_VERBOSE" = '1' ]; then fi # choose interactivity mode -if [ "${DEBIAN_FRONTEND:-other}" = "noninteractive" ] -then +if [ "${DEBIAN_FRONTEND:-other}" = "noninteractive" ]; then CONSOLE_MODE=skip -elif [ -t 0 ] -then +elif [ -t 0 ]; then CONSOLE_MODE=interactive else CONSOLE_MODE=delay fi -if [ "$(id -ru)" != "0" ] -then +if [ "$(id -ru)" != "0" ]; then echo "Not root, exiting" >&2 exit 1 fi INIT_EXEC="$(readlink /proc/1/exe)" -if [ "$(basename "$INIT_EXEC")" != "systemd" ] -then +if [ "$(basename "$INIT_EXEC")" != "systemd" ]; then echo "Init system is not systemd ($INIT_EXEC), doing nothing" exit 0 fi @@ -51,41 +47,46 @@ DBUS_SERVICE_NAME=$( # if DM is active, return canonical ID DISPLAY_MANAGER=$( - systemctl -q is-active display-manager.service && \ - systemctl show --value -p Id display-manager.service + systemctl -q is-active display-manager.service \ + && systemctl show --value -p Id display-manager.service ) # get dependencies -ACTIVE_DEPS=$( - # return all dbus dependencies, filter out dbus and DM, leave only active - { +ACTIVE_DEPS='' +while read -r service; do + case "$service" in + "$DISPLAY_MANAGER" | "$DBUS_SERVICE_NAME") continue ;; + *.service) + case " $ACTIVE_DEPS " in + *" $service "*) true ;; + *) systemctl -q is-active "$service" && ACTIVE_DEPS="${ACTIVE_DEPS}${ACTIVE_DEPS:+ }${service}" ;; + esac + ;; + esac +done <<- EOF + $( systemctl list-dependencies -l --reverse --plain dbus.socket - systemctl list-dependencies -l --reverse --plain $DBUS_SERVICE_NAME - } | grep -o '[^[:space:]]\+.service' | sort -u | while read SERVICE - do - if [ "$SERVICE" != "$DBUS_SERVICE_NAME" ] && \ - [ "$SERVICE" != "$DISPLAY_MANAGER" ] && \ - systemctl -q is-active "$SERVICE" - then - echo "$SERVICE" - fi - done | tr '\n' ' ' | tr -s ' ' -) + systemctl list-dependencies -l --reverse --plain "$DBUS_SERVICE_NAME" + ) +EOF # get logind users -USERS=$( - loginctl list-users --no-legend \ - | grep -oE '^[[:space:]]*[0-9]+[[:space:]]+[^[:space:]]+' \ - | grep -oE '[^[:space:]]+$' \ - | tr '\n' ' ' | tr -s ' ' -) +USERS='' +while read -r uid user linger state; do + USERS="${USERS}${USERS:+ }${user}" +done <<- EOF + $(loginctl list-users --no-legend) +EOF # get current dbus service PIDs -DBUS_PIDS=$( - ps -eo pid,unit | grep -E "[[:space:]]+${DBUS_SERVICE_NAME}[[:space:]]*$" \ - | grep -oE '^[[:space:]]*[0-9]+' \ - | tr '\n' ' ' | tr -s ' ' -) +DBUS_PIDS='' +while read -r pid unit; do + case "$unit" in + "${DBUS_SERVICE_NAME}") DBUS_PIDS="${DBUS_PIDS}${DBUS_PIDS:+ }${pid}" ;; + esac +done <<- EOF + $(ps -eo pid,unit) +EOF # assemble commands COMMANDS='' @@ -104,46 +105,46 @@ COMMANDS="${COMMANDS}${COMMANDS:+ ; }sleep 1 ; systemctl restart $ACTIVE_DEPS" # normalize to single line COMMANDS=$(echo "$COMMANDS" | tr '\n' ' ' | tr -s ' ') -if [ "$CONSOLE_MODE" = "interactive" ] -then - cat -elif [ "$CONSOLE_MODE" = "delay" ] -then - cat >&2 -else - true -fi << EOF -!!! $DBUS_SERVICE_NAME restart will be performed !!! +shcat() { + while IFS='' read -r line; do + printf '%s\n' "$line" + done +} + +case "$CONSOLE_MODE" in +interactive) shcat ;; +delay) shcat >&2 ;; +*) shcat > /dev/null ;; +esac <<- EOF + !!! $DBUS_SERVICE_NAME restart will be performed !!! -Users to be terminated: $USERS + Users to be terminated: $USERS -Services to be restarted: -$(echo $ACTIVE_DEPS | tr ' ' '\n' | sed 's/^/ /') + Services to be restarted: + $(printf ' %s\n' $ACTIVE_DEPS) -Display manager to be restarted: ${DISPLAY_MANAGER:-no active DM found} + Display manager to be restarted: ${DISPLAY_MANAGER:-no active DM found} -Command set to run as transient unit restart-dbus.service: - $(echo $COMMANDS | sed -r 's/ ; /\n /g') + Command set to run as transient unit restart-dbus.service: + $(IFS=';' printf ' %s\n' $COMMANDS) -Logs can be viewed by: journalctl -u restart-dbus + Logs can be viewed by: journalctl -u restart-dbus EOF # if interactive, ask for continuation -if [ "$CONSOLE_MODE" = "interactive" ] -then - read -p " -Press Enter to continue > " PRESSENTER -elif [ "$CONSOLE_MODE" = "delay" ] -then - echo " -Restart in $DELAY_SECONDS seconds..." >&2 +case "$CONSOLE_MODE" in +interactive) + printf '\n%s' "Press Enter to continue > " + read -r PRESSENTER + ;; +delay) + printf '\n%s\n' "Restart in $DELAY_SECONDS seconds..." >&2 sleep $DELAY_SECONDS echo "Restarting..." >&2 -else - true -fi + ;; +esac # run restart sequence as transient unit... # it is possible to view its output in the log if any: # journalctl -u restart-dbus -systemd-run -G --unit=restart-dbus --description="transient dbus restarter" sh -c "$COMMANDS" +systemd-run -G --unit=restart-dbus --description="Transient dbus restarter" sh -c "$COMMANDS" From 250ad05bec6be92029d145849c2bd9668dfa066a Mon Sep 17 00:00:00 2001 From: Vladimir-csp <4061903+Vladimir-csp@users.noreply.github.com> Date: Fri, 15 Dec 2023 18:45:51 +0300 Subject: [PATCH 06/11] formating fixes --- ex/restart.d/dbus.service | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ex/restart.d/dbus.service b/ex/restart.d/dbus.service index 730e359d..6272e48b 100755 --- a/ex/restart.d/dbus.service +++ b/ex/restart.d/dbus.service @@ -116,9 +116,11 @@ interactive) shcat ;; delay) shcat >&2 ;; *) shcat > /dev/null ;; esac <<- EOF + !!! $DBUS_SERVICE_NAME restart will be performed !!! - Users to be terminated: $USERS + Users to be terminated: + $(printf ' %s\n' $USERS) Services to be restarted: $(printf ' %s\n' $ACTIVE_DEPS) @@ -126,7 +128,7 @@ esac <<- EOF Display manager to be restarted: ${DISPLAY_MANAGER:-no active DM found} Command set to run as transient unit restart-dbus.service: - $(IFS=';' printf ' %s\n' $COMMANDS) + $(IFS=';' ; printf ' %s\n' $COMMANDS) Logs can be viewed by: journalctl -u restart-dbus EOF From c91cc37e3482d847d6e89913c3fe4dd96eca57cc Mon Sep 17 00:00:00 2001 From: Vladimir-csp <4061903+Vladimir-csp@users.noreply.github.com> Date: Tue, 28 May 2024 13:01:20 +0300 Subject: [PATCH 07/11] Add ALWAYS_RESTART_SERVICES list With systemd-timesyncd inside, fixes #255 --- ex/restart.d/dbus.service | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ex/restart.d/dbus.service b/ex/restart.d/dbus.service index 6272e48b..0f1985c4 100755 --- a/ex/restart.d/dbus.service +++ b/ex/restart.d/dbus.service @@ -14,6 +14,9 @@ # delay in semi-interactive mode DELAY_SECONDS=10 +# service units to always restart after dbus restart (whitespace-separated) +ALWAYS_RESTART_SERVICES='systemd-timesyncd.service' + # enable xtrace if we should be verbose if [ "$NR_VERBOSE" = '1' ]; then set -x @@ -65,8 +68,8 @@ while read -r service; do esac done <<- EOF $( - systemctl list-dependencies -l --reverse --plain dbus.socket - systemctl list-dependencies -l --reverse --plain "$DBUS_SERVICE_NAME" + systemctl list-dependencies -l --reverse --plain dbus.socket "$DBUS_SERVICE_NAME" + printf '%s\n' $ALWAYS_RESTART_SERVICES ) EOF From d4e4d910c3b2f3ace316256379874792a33e3bf7 Mon Sep 17 00:00:00 2001 From: Vladimir-csp <4061903+Vladimir-csp@users.noreply.github.com> Date: Tue, 28 May 2024 13:30:15 +0300 Subject: [PATCH 08/11] Make shellcheck happy --- ex/restart.d/dbus.service | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ex/restart.d/dbus.service b/ex/restart.d/dbus.service index 0f1985c4..dd5ba216 100755 --- a/ex/restart.d/dbus.service +++ b/ex/restart.d/dbus.service @@ -75,7 +75,7 @@ EOF # get logind users USERS='' -while read -r uid user linger state; do +while read -r _uid user _linger _state; do USERS="${USERS}${USERS:+ }${user}" done <<- EOF $(loginctl list-users --no-legend) @@ -114,6 +114,7 @@ shcat() { done } +# shellcheck disable=SC2086 case "$CONSOLE_MODE" in interactive) shcat ;; delay) shcat >&2 ;; @@ -140,7 +141,7 @@ EOF case "$CONSOLE_MODE" in interactive) printf '\n%s' "Press Enter to continue > " - read -r PRESSENTER + read -r _PRESSENTER ;; delay) printf '\n%s\n' "Restart in $DELAY_SECONDS seconds..." >&2 From 3f25452159a42b50adc2f918d2d9df667d5edb63 Mon Sep 17 00:00:00 2001 From: Vladimir-csp <4061903+Vladimir-csp@users.noreply.github.com> Date: Tue, 28 May 2024 14:02:54 +0300 Subject: [PATCH 09/11] Misc tweaks Replace some external calls with builtins, use ps instead of readlink on /proc/..., prettify. --- ex/restart.d/dbus.service | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/ex/restart.d/dbus.service b/ex/restart.d/dbus.service index dd5ba216..4f675c36 100755 --- a/ex/restart.d/dbus.service +++ b/ex/restart.d/dbus.service @@ -36,16 +36,20 @@ if [ "$(id -ru)" != "0" ]; then exit 1 fi -INIT_EXEC="$(readlink /proc/1/exe)" +# get init system process name +INIT_EXEC="$(ps -p 1 -o comm=)" -if [ "$(basename "$INIT_EXEC")" != "systemd" ]; then +case "$INIT_EXEC" in +systemd | */systemd) true ;; +*) echo "Init system is not systemd ($INIT_EXEC), doing nothing" exit 0 -fi + ;; +esac # start from the name of the hook, get real unit ID (for example, dbus-broker replaces dbus) DBUS_SERVICE_NAME=$( - systemctl show --value -p Id "$(basename "$0")" + systemctl show --value -p Id "${0##*/}" ) # if DM is active, return canonical ID @@ -132,7 +136,12 @@ esac <<- EOF Display manager to be restarted: ${DISPLAY_MANAGER:-no active DM found} Command set to run as transient unit restart-dbus.service: - $(IFS=';' ; printf ' %s\n' $COMMANDS) + $( + IFS=';' + # consequent commands have a space after preceeding semicolons, compensate for that + printf '%s' ' ' + printf ' %s\n' $COMMANDS + ) Logs can be viewed by: journalctl -u restart-dbus EOF From ee13c7b0215e0d5c73715fbcc53c6b17b605924d Mon Sep 17 00:00:00 2001 From: Vladimir-csp <4061903+Vladimir-csp@users.noreply.github.com> Date: Wed, 29 May 2024 12:25:01 +0300 Subject: [PATCH 10/11] Get active services with BusName defined Even better solution for #255, not relying on hardcoded lists --- ex/restart.d/dbus.service | 49 ++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/ex/restart.d/dbus.service b/ex/restart.d/dbus.service index 4f675c36..f59f02fb 100755 --- a/ex/restart.d/dbus.service +++ b/ex/restart.d/dbus.service @@ -14,9 +14,6 @@ # delay in semi-interactive mode DELAY_SECONDS=10 -# service units to always restart after dbus restart (whitespace-separated) -ALWAYS_RESTART_SERVICES='systemd-timesyncd.service' - # enable xtrace if we should be verbose if [ "$NR_VERBOSE" = '1' ]; then set -x @@ -58,22 +55,58 @@ DISPLAY_MANAGER=$( && systemctl show --value -p Id display-manager.service ) -# get dependencies +# get active dependencies ACTIVE_DEPS='' while read -r service; do case "$service" in - "$DISPLAY_MANAGER" | "$DBUS_SERVICE_NAME") continue ;; + "$DISPLAY_MANAGER" | dbus.service | "$DBUS_SERVICE_NAME") continue ;; *.service) case " $ACTIVE_DEPS " in *" $service "*) true ;; - *) systemctl -q is-active "$service" && ACTIVE_DEPS="${ACTIVE_DEPS}${ACTIVE_DEPS:+ }${service}" ;; + *) ACTIVE_DEPS="${ACTIVE_DEPS}${ACTIVE_DEPS:+ }${service}" ;; + esac + ;; + esac +done <<- EOF + $( + systemctl list-dependencies -l --reverse --plain --all \ + --type=service \ + --state=active,reloading,failed,activating \ + dbus.socket dbus.service "$DBUS_SERVICE_NAME" + ) +EOF + +# get active services with BusName +capture_id=false +while IFS='=' read -r option value; do + case "${capture_id}:${option}=${value}" in + # empty BusName, disable Id capture + *':BusName=') + capture_id=false + continue + ;; + # non-empty BusName, enable Id capture + *':BusName='*) + capture_id=true + continue + ;; + *":Id=${DISPLAY_MANAGER}" | *':Id=dbus.service' | *":Id=$DBUS_SERVICE_NAME") continue ;; + # Id capture is enabled, do it, add to list + 'true:Id='*) + service="$value" + case " $ACTIVE_DEPS " in + *" $service "*) true ;; + *) ACTIVE_DEPS="${ACTIVE_DEPS}${ACTIVE_DEPS:+ }${service}" ;; esac ;; + *) continue ;; esac done <<- EOF $( - systemctl list-dependencies -l --reverse --plain dbus.socket "$DBUS_SERVICE_NAME" - printf '%s\n' $ALWAYS_RESTART_SERVICES + systemctl show --plain --all \ + --type=service \ + --state=active,reloading,failed,activating \ + --property=BusName --property=Id ) EOF From 2d9cc3cba644b43ea90478baca4d64f98f046779 Mon Sep 17 00:00:00 2001 From: Vladimir-csp <4061903+Vladimir-csp@users.noreply.github.com> Date: Wed, 29 May 2024 14:03:16 +0300 Subject: [PATCH 11/11] Be agnostic to 'systemctl show' property output order Order of properties in `systemctl show` output is undefined, use blank lines and ending marker as a trigger to test and capture previous values. --- ex/restart.d/dbus.service | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/ex/restart.d/dbus.service b/ex/restart.d/dbus.service index f59f02fb..c1218f62 100755 --- a/ex/restart.d/dbus.service +++ b/ex/restart.d/dbus.service @@ -77,37 +77,48 @@ done <<- EOF EOF # get active services with BusName -capture_id=false +current_busname='' +current_id='' while IFS='=' read -r option value; do - case "${capture_id}:${option}=${value}" in - # empty BusName, disable Id capture - *':BusName=') - capture_id=false + case "${option}" in + BusName) + current_busname="$value" continue ;; - # non-empty BusName, enable Id capture - *':BusName='*) - capture_id=true + Id) + current_id="$value" continue ;; - *":Id=${DISPLAY_MANAGER}" | *':Id=dbus.service' | *":Id=$DBUS_SERVICE_NAME") continue ;; - # Id capture is enabled, do it, add to list - 'true:Id='*) - service="$value" + '') + if [ -z "$current_busname" ] || [ -z "$current_id" ]; then + current_busname='' + current_id='' + continue + fi + service=$current_id + current_busname='' + current_id='' + case "$service" in + "$DISPLAY_MANAGER" | dbus.service | "$DBUS_SERVICE_NAME") continue ;; + esac case " $ACTIVE_DEPS " in *" $service "*) true ;; *) ACTIVE_DEPS="${ACTIVE_DEPS}${ACTIVE_DEPS:+ }${service}" ;; esac ;; - *) continue ;; + *) + current_busname='' + current_id='' + ;; esac done <<- EOF $( systemctl show --plain --all \ --type=service \ --state=active,reloading,failed,activating \ - --property=BusName --property=Id + --property=BusName,Id ) + =end EOF # get logind users