mirror of
https://github.com/systemd/systemd.git
synced 2026-11-06 13:27:45 +00:00
Working out how long the service manager keeps restarting a failing service takes the exponential backoff formula from systemd.service(5) and a manual simulation of the start rate limit. Getting either wrong means a service that's supposed to fail after a while is restarted forever. Let's add a restart-delays command that does both. It lists each restart until the delay stops growing, with the total of the delays up to that restart, and then says whether the start rate limit rejects a restart and when. Like security, it reads the settings of loaded units from the service manager, or loads unit files with --offline=yes. With --json=, it prints the same data as a JSON object. The command computes the delays with the same functions as the service manager. It checks the start rate limit with ratelimit_below_at() for each restart until the delay stops growing. After that, every restart waits the same delay. We then compute the rejected restart from the number of starts that the current window of the rate limit still allows.
327 lines
11 KiB
Bash
327 lines
11 KiB
Bash
# shellcheck shell=bash
|
|
# systemd-analyze(1) completion -*- shell-script -*-
|
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
|
#
|
|
# This file is part of systemd.
|
|
#
|
|
# Copyright © 2010 Ran Benita
|
|
#
|
|
# systemd is free software; you can redistribute it and/or modify it
|
|
# under the terms of the GNU Lesser General Public License as published by
|
|
# the Free Software Foundation; either version 2.1 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# systemd is distributed in the hope that it will be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public License
|
|
# along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
__contains_word () {
|
|
local w word=$1; shift
|
|
for w in "$@"; do
|
|
[[ $w = "$word" ]] && return
|
|
done
|
|
}
|
|
|
|
__get_machines() {
|
|
local a b
|
|
{ machinectl list --full --max-addresses=0 --no-legend --no-pager 2>/dev/null; echo ".host"; } |
|
|
{ while read -r a b; do echo " $a"; done; } |
|
|
sort -u
|
|
}
|
|
|
|
__get_units_all() {
|
|
systemctl list-units --no-legend --no-pager --plain --all $1 2>/dev/null |
|
|
{ while read -r a b c; do echo " $a"; done; }
|
|
}
|
|
|
|
__get_services() {
|
|
systemctl list-units --no-legend --no-pager --plain -t service --all $1 2>/dev/null |
|
|
{ while read -r a b c; do [[ $b == "loaded" ]] && echo " $a"; done; }
|
|
}
|
|
|
|
__get_syscall_sets() {
|
|
local line
|
|
systemd-analyze syscall-filter --no-pager 2>/dev/null | while IFS= read -r line; do
|
|
if [[ $line == @* ]]; then
|
|
printf '%s\n' "$line"
|
|
fi
|
|
done
|
|
}
|
|
|
|
__get_architectures() {
|
|
systemd-analyze --no-legend --no-pager architectures 2>/dev/null | { while read -r a b; do echo " $a"; done; }
|
|
}
|
|
|
|
__get_cpu_features() {
|
|
systemd-analyze --no-legend --no-pager cpu-features 2>/dev/null | { while read -r a b; do echo " $a"; done; }
|
|
}
|
|
|
|
__get_filesystem_sets() {
|
|
local line
|
|
systemd-analyze filesystems --no-pager 2>/dev/null | while IFS= read -r line; do
|
|
if [[ $line == @* ]]; then
|
|
printf '%s\n' "$line"
|
|
fi
|
|
done
|
|
}
|
|
|
|
_systemd_analyze() {
|
|
local i verb comps mode
|
|
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} words cword
|
|
|
|
local -A OPTS=(
|
|
[STANDALONE]='-h --help --version --system --user --global --order --require --no-pager
|
|
--man=no --generators=yes -q --quiet'
|
|
[ARG]='-H --host -M --machine --fuzz --from-pattern --to-pattern --root --debugger
|
|
-A --debugger-arguments'
|
|
)
|
|
|
|
local -A VERBS=(
|
|
[STANDALONE]='time unit-files unit-paths compare-versions timestamp timespan srk has-tpm2 smbios11 image-policy'
|
|
[STANDALONE_JSON]='blame exit-status pcrs nvpcrs identify-tpm2 chid'
|
|
[CRITICAL_CHAIN]='critical-chain'
|
|
[DOT]='dot'
|
|
[DUMP]='dump'
|
|
[VERIFY]='verify'
|
|
[SECCOMP_FILTER]='syscall-filter'
|
|
[CAT_CONFIG]='cat-config'
|
|
[SECURITY]='security'
|
|
[CONDITION]='condition'
|
|
[INSPECT_ELF]='inspect-elf'
|
|
[DLOPEN_METADATA]='dlopen-metadata'
|
|
[PLOT]='plot'
|
|
[ARCHITECTURES]='architectures'
|
|
[CPU_FEATURES]='cpu-features'
|
|
[FDSTORE]='fdstore'
|
|
[RESTART_DELAYS]='restart-delays'
|
|
[CAPABILITY]='capability'
|
|
[TRANSIENT_SETTINGS]='transient-settings'
|
|
[UNIT_SHELL]='unit-shell'
|
|
[UNIT_GDB]='unit-gdb'
|
|
[FILESYSTEMS]='filesystems'
|
|
[CALENDAR]='calendar'
|
|
)
|
|
|
|
local CONFIGS='locale.conf systemd/bootchart.conf systemd/coredump.conf systemd/journald.conf
|
|
systemd/journal-remote.conf systemd/journal-upload.conf systemd/logind.conf
|
|
systemd/resolved.conf systemd/networkd.conf systemd/pstore.conf systemd/report-geoip.conf systemd/resolved.conf
|
|
systemd/sleep.conf systemd/system.conf systemd/timedated.conf
|
|
systemd/timesyncd.conf systemd/user.conf udev/udev.conf'
|
|
|
|
_init_completion || return
|
|
|
|
for ((i=0; i < COMP_CWORD; i++)); do
|
|
if __contains_word "${COMP_WORDS[i]}" ${VERBS[*]} &&
|
|
! __contains_word "${COMP_WORDS[i-1]}" ${OPTS[ARG]}; then
|
|
verb=${COMP_WORDS[i]}
|
|
break
|
|
fi
|
|
done
|
|
|
|
if __contains_word "--user" ${COMP_WORDS[*]}; then
|
|
mode=--user
|
|
else
|
|
mode=--system
|
|
fi
|
|
|
|
if __contains_word "$prev" ${OPTS[ARG]}; then
|
|
case $prev in
|
|
--host|-H)
|
|
comps=$(compgen -A hostname)
|
|
;;
|
|
--machine|-M)
|
|
comps=$( __get_machines )
|
|
;;
|
|
--debugger)
|
|
comps="gdb lldb"
|
|
;;
|
|
*)
|
|
return 0
|
|
;;
|
|
esac
|
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
|
return 0
|
|
fi
|
|
|
|
if [[ -z ${verb-} && $cur = -* ]]; then
|
|
COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") )
|
|
return 0
|
|
fi
|
|
|
|
if [[ -z ${verb-} ]]; then
|
|
comps=${VERBS[*]}
|
|
|
|
elif __contains_word "$verb" ${VERBS[STANDALONE]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --system --user --global --no-pager'
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[STANDALONE_JSON]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --system --user --global --no-pager --json=off --json=pretty --json=short'
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[CRITICAL_CHAIN]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --system --user --fuzz --no-pager'
|
|
else
|
|
comps=$( __get_units_all $mode )
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[DOT]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --system --user --global --from-pattern --to-pattern --order --require'
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[DUMP]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --system --user --no-pager'
|
|
else
|
|
comps=$( __get_units_all $mode )
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[SECCOMP_FILTER]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --no-pager'
|
|
else
|
|
comps=$( __get_syscall_sets )
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[VERIFY]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --system --user --global --man=no --generators=yes --root --image --recursive-errors=no --recursive-errors=yes --recursive-errors=one'
|
|
else
|
|
comps=$( compgen -A file -- "$cur"
|
|
__get_units_all $mode )
|
|
compopt -o filenames
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[CAT_CONFIG]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --root --no-pager'
|
|
elif [[ -z $cur ]]; then
|
|
comps="$CONFIGS"
|
|
compopt -o filenames
|
|
else
|
|
comps="$CONFIGS $( compgen -A file -- "$cur" )"
|
|
compopt -o filenames
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[SECURITY]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --no-pager --system --user -H --host -M --machine --offline --threshold --security-policy --json=off --json=pretty --json=short --root --image --profile=default --profile=nonetwork --profile=strict --profile=trusted'
|
|
elif ! __contains_word "--offline" ${COMP_WORDS[*]}; then
|
|
comps=$( __get_services $mode )
|
|
else
|
|
comps="$CONFIGS $( compgen -A file -- "$cur" )"
|
|
compopt -o filenames
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[CONDITION]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --system --user --global --no-pager --root --image'
|
|
elif [[ $prev = "-u" ]] || [[ $prev = "--unit" ]]; then
|
|
comps=$( __get_services $mode )
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[INSPECT_ELF]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --json=off --json=pretty --json=short'
|
|
else
|
|
comps=$( compgen -A file -- "$cur" )
|
|
compopt -o filenames
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[DLOPEN_METADATA]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --json=off --json=pretty --json=short'
|
|
else
|
|
comps=$( compgen -A file -- "$cur" )
|
|
compopt -o filenames
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[PLOT]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --system --user --global --no-pager --json=off --json=pretty --json=short --table --no-legend --scale-svg --detailed'
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[ARCHITECTURES]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --no-pager --json=off --json=pretty --json=short --no-legend'
|
|
else
|
|
comps=$( __get_architectures )
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[CPU_FEATURES]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --no-pager --json=off --json=pretty --json=short --no-legend'
|
|
else
|
|
comps=$( __get_cpu_features )
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[FDSTORE]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --system --user --global -H --host -M --machine --no-pager --json=off --json=pretty --json=short --root --image'
|
|
else
|
|
comps=$( __get_services $mode )
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[RESTART_DELAYS]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --system --user -H --host -M --machine --no-pager --no-legend --json=off --json=pretty --json=short --offline --root --image --instance --generators'
|
|
elif ! __contains_word "--offline" ${COMP_WORDS[*]}; then
|
|
comps=$( __get_services $mode )
|
|
else
|
|
comps=$( compgen -A file -- "$cur" )
|
|
compopt -o filenames
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[CAPABILITY]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --no-pager --json=off --json=pretty --json=short -m --mask'
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[TRANSIENT_SETTINGS]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --no-pager'
|
|
else
|
|
comps="$(systemctl --no-legend --no-pager -t help)"
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[UNIT_SHELL]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version'
|
|
else
|
|
comps=$( __get_services $mode )
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[UNIT_GDB]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --debugger --debugger-arguments --root'
|
|
else
|
|
comps=$( __get_services $mode )
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[FILESYSTEMS]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --no-pager'
|
|
else
|
|
comps=$( __get_filesystem_sets )
|
|
fi
|
|
|
|
elif __contains_word "$verb" ${VERBS[CALENDAR]}; then
|
|
if [[ $cur = -* ]]; then
|
|
comps='--help --version --iterations --base-time'
|
|
fi
|
|
fi
|
|
|
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
|
return 0
|
|
}
|
|
|
|
complete -F _systemd_analyze systemd-analyze
|