b677e7
From f875436b93c6c5e83f46ab32429c977db4f0b10c Mon Sep 17 00:00:00 2001
b677e7
From: Felix Stupp <felix.stupp@outlook.com>
b677e7
Date: Thu, 29 Oct 2020 12:48:48 +0100
b677e7
Subject: [PATCH] Added option --check-inhibitors for non-tty usage
b677e7
b677e7
As described in #2680, systemctl did ignore inhibitors if it is not
b677e7
attached to a tty to allow scripts to ignore inhibitors automatically.
b677e7
This pull request preserves this behavior but allows scripts to
b677e7
explicit check inhibitors if required.
b677e7
b677e7
The new parameter '--check-inhibitors=yes' enables this feature.
b677e7
The old parameter '-i'/'--ignore-inhibitors' was deprecated in favor
b677e7
of '--check-inhibitors=no', the default behaviour can be specified
b677e7
with '--check-inhibitors=auto'.
b677e7
The new parameter is also described in the documentations and shell
b677e7
completions found here.
b677e7
b677e7
(cherry picked from commit b8ebe378b49a31549b8531d4b3177095ef385d55)
b677e7
b677e7
Related: #1269726
b677e7
---
b677e7
 man/systemctl.xml                  | 38 ++++++++++++++++++++----------
b677e7
 shell-completion/bash/systemctl.in |  7 ++++--
b677e7
 shell-completion/zsh/_systemctl.in |  9 ++++++-
b677e7
 src/systemctl/systemctl.c          | 37 +++++++++++++++++++++--------
b677e7
 4 files changed, 65 insertions(+), 26 deletions(-)
b677e7
b677e7
diff --git a/man/systemctl.xml b/man/systemctl.xml
b677e7
index ed60a0739f..9f0f4d46ea 100644
b677e7
--- a/man/systemctl.xml
b677e7
+++ b/man/systemctl.xml
b677e7
@@ -323,23 +323,35 @@
b677e7
         </listitem>
b677e7
       </varlistentry>
b677e7
 
b677e7
+      <varlistentry>
b677e7
+        <term><option>--check-inhibitors=</option></term>
b677e7
+
b677e7
+        <listitem>
b677e7
+          <para>When system shutdown or sleep state is request, this option controls how to deal with
b677e7
+          inhibitor locks. It takes one of <literal>auto</literal>, <literal>yes</literal> or
b677e7
+          <literal>no</literal>. Defaults to <literal>auto</literal>, which will behave like
b677e7
+          <literal>yes</literal> for interactive invocations (i.e. from a TTY) and <literal>no</literal>
b677e7
+          for non-interactive invocations.
b677e7
+          <literal>yes</literal> will let the request respect inhibitor locks.
b677e7
+          <literal>no</literal> will let the request ignore inhibitor locks.
b677e7
+          </para>
b677e7
+          <para>Applications can establish inhibitor locks to avoid that certain important operations
b677e7
+          (such as CD burning or suchlike) are interrupted by system shutdown or a sleep state. Any user may
b677e7
+          take these locks and privileged users may override these locks.
b677e7
+          If any locks are taken, shutdown and sleep state requests will normally fail (unless privileged)
b677e7
+          and a list of active locks is printed.
b677e7
+          However, if <literal>no</literal> is specified or <literal>auto</literal> is specified on a
b677e7
+          non-interactive requests, the established locks are ignored and not shown, and the operation
b677e7
+          attempted anyway, possibly requiring additional privileges.
b677e7
+          May be overriden by <option>--force</option>.</para>
b677e7
+        </listitem>
b677e7
+      </varlistentry>
b677e7
+
b677e7
       <varlistentry>
b677e7
         <term><option>-i</option></term>
b677e7
-        <term><option>--ignore-inhibitors</option></term>
b677e7
 
b677e7
         <listitem>
b677e7
-          <para>When system shutdown or a sleep state is requested,
b677e7
-          ignore inhibitor locks. Applications can establish inhibitor
b677e7
-          locks to avoid that certain important operations (such as CD
b677e7
-          burning or suchlike) are interrupted by system shutdown or a
b677e7
-          sleep state. Any user may take these locks and privileged
b677e7
-          users may override these locks. If any locks are taken,
b677e7
-          shutdown and sleep state requests will normally fail
b677e7
-          (regardless of whether privileged or not) and a list of active locks
b677e7
-          is printed. However, if <option>--ignore-inhibitors</option>
b677e7
-          is specified, the locks are ignored and not printed, and the
b677e7
-          operation attempted anyway, possibly requiring additional
b677e7
-          privileges.</para>
b677e7
+          <para>Shortcut for <option>--check-inhibitors=no</option>.</para>
b677e7
         </listitem>
b677e7
       </varlistentry>
b677e7
 
b677e7
diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in
b677e7
index ba51ae0d34..0c7afea57d 100644
b677e7
--- a/shell-completion/bash/systemctl.in
b677e7
+++ b/shell-completion/bash/systemctl.in
b677e7
@@ -111,9 +111,9 @@ _systemctl () {
b677e7
                [STANDALONE]='--all -a --reverse --after --before --defaults --force -f --full -l --global
b677e7
                              --help -h --no-ask-password --no-block --no-legend --no-pager --no-reload --no-wall --now
b677e7
                              --quiet -q --system --user --version --runtime --recursive -r --firmware-setup
b677e7
-                             --show-types -i --ignore-inhibitors --plain --failed --value --fail --dry-run --wait'
b677e7
+                             --show-types --plain --failed --value --fail --dry-run --wait'
b677e7
                       [ARG]='--host -H --kill-who --property -p --signal -s --type -t --state --job-mode --root
b677e7
-                             --preset-mode -n --lines -o --output -M --machine --message'
b677e7
+                             --preset-mode -n --lines -o --output -M --machine --message --check-inhibitors'
b677e7
         )
b677e7
 
b677e7
         if __contains_word "--user" ${COMP_WORDS[*]}; then
b677e7
@@ -163,6 +163,9 @@ _systemctl () {
b677e7
                         --machine|-M)
b677e7
                                 comps=$( __get_machines )
b677e7
                         ;;
b677e7
+                        --check-inhibitors)
b677e7
+                                comps='auto yes no'
b677e7
+                        ;;
b677e7
                 esac
b677e7
                 COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
b677e7
                 return 0
b677e7
diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in
b677e7
index 9f576ed77d..b3c51cc843 100644
b677e7
--- a/shell-completion/zsh/_systemctl.in
b677e7
+++ b/shell-completion/zsh/_systemctl.in
b677e7
@@ -363,6 +363,13 @@ _job_modes() {
b677e7
     _values -s , "${_modes[@]}"
b677e7
 }
b677e7
 
b677e7
+(( $+functions[_systemctl_check_inhibitors] )) ||
b677e7
+    _systemctl_check_inhibitors() {
b677e7
+        local -a _modes
b677e7
+        _modes=(auto yes no)
b677e7
+        _values -s , "${_modes[@]}"
b677e7
+    }
b677e7
+
b677e7
 # Build arguments for "systemctl" to be used in completion.
b677e7
 local -a _modes; _modes=("--user" "--system")
b677e7
 # Use the last mode (they are exclusive and the last one is used).
b677e7
@@ -380,7 +387,7 @@ _arguments -s \
b677e7
     '--before[Show units ordered before]' \
b677e7
     {-l,--full}"[Don't ellipsize unit names on output]" \
b677e7
     '--show-types[When showing sockets, show socket type]' \
b677e7
-    {-i,--ignore-inhibitors}'[When executing a job, ignore jobs dependencies]' \
b677e7
+    '--check-inhibitors[Specify if inhibitors should be checked]:mode:_systemctl_check_inhibitors' \
b677e7
     {-q,--quiet}'[Suppress output]' \
b677e7
     '--no-block[Do not wait until operation finished]' \
b677e7
     '--no-legend[Do not print a legend, i.e. the column headers and the footer with hints]' \
b677e7
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
b677e7
index 8bec798373..8bcbf6bf4b 100644
b677e7
--- a/src/systemctl/systemctl.c
b677e7
+++ b/src/systemctl/systemctl.c
b677e7
@@ -121,7 +121,7 @@ static bool arg_no_wall = false;
b677e7
 static bool arg_no_reload = false;
b677e7
 static bool arg_value = false;
b677e7
 static bool arg_show_types = false;
b677e7
-static bool arg_ignore_inhibitors = false;
b677e7
+static int arg_check_inhibitors = -1;
b677e7
 static bool arg_dry_run = false;
b677e7
 static bool arg_quiet = false;
b677e7
 static bool arg_full = false;
b677e7
@@ -3313,17 +3313,19 @@ static int logind_check_inhibitors(enum action a) {
b677e7
         char **s;
b677e7
         int r;
b677e7
 
b677e7
-        if (arg_ignore_inhibitors || arg_force > 0)
b677e7
+        if (arg_check_inhibitors == 0 || arg_force > 0)
b677e7
                 return 0;
b677e7
 
b677e7
         if (arg_when > 0)
b677e7
                 return 0;
b677e7
 
b677e7
-        if (geteuid() == 0)
b677e7
-                return 0;
b677e7
+        if (arg_check_inhibitors < 0) {
b677e7
+                if (geteuid() == 0)
b677e7
+                        return 0;
b677e7
 
b677e7
-        if (!on_tty())
b677e7
-                return 0;
b677e7
+                if (!on_tty())
b677e7
+                        return 0;
b677e7
+        }
b677e7
 
b677e7
         if (arg_transport != BUS_TRANSPORT_LOCAL)
b677e7
                 return 0;
b677e7
@@ -7237,8 +7239,10 @@ static void systemctl_help(void) {
b677e7
                "                      When enqueuing a unit job, show full transaction\n"
b677e7
                "     --show-types     When showing sockets, explicitly show their type\n"
b677e7
                "     --value          When showing properties, only print the value\n"
b677e7
-               "  -i --ignore-inhibitors\n"
b677e7
-               "                      When shutting down or sleeping, ignore inhibitors\n"
b677e7
+               "     --check-inhibitors=MODE\n"
b677e7
+               "                      Specify if checking inhibitors before shutting down,\n"
b677e7
+               "                      sleeping or hibernating\n"
b677e7
+               "  -i                  Shortcut for --check-inhibitors=no\n"
b677e7
                "     --kill-who=WHO   Who to send signal to\n"
b677e7
                "  -s --signal=SIGNAL  Which signal to send\n"
b677e7
                "     --now            Start or stop unit in addition to enabling or disabling it\n"
b677e7
@@ -7475,6 +7479,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
b677e7
                 ARG_REVERSE,
b677e7
                 ARG_AFTER,
b677e7
                 ARG_BEFORE,
b677e7
+                ARG_CHECK_INHIBITORS,
b677e7
                 ARG_DRY_RUN,
b677e7
                 ARG_SHOW_TYPES,
b677e7
                 ARG_IRREVERSIBLE,
b677e7
@@ -7520,7 +7525,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
b677e7
                 { "fail",                no_argument,       NULL, ARG_FAIL                }, /* compatibility only */
b677e7
                 { "irreversible",        no_argument,       NULL, ARG_IRREVERSIBLE        }, /* compatibility only */
b677e7
                 { "ignore-dependencies", no_argument,       NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */
b677e7
-                { "ignore-inhibitors",   no_argument,       NULL, 'i'                     },
b677e7
+                { "ignore-inhibitors",   no_argument,       NULL, 'i'                     }, /* compatibility only */
b677e7
+                { "check-inhibitors",    required_argument, NULL, ARG_CHECK_INHIBITORS    },
b677e7
                 { "value",               no_argument,       NULL, ARG_VALUE               },
b677e7
                 { "user",                no_argument,       NULL, ARG_USER                },
b677e7
                 { "system",              no_argument,       NULL, ARG_SYSTEM              },
b677e7
@@ -7813,7 +7819,18 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
b677e7
                         break;
b677e7
 
b677e7
                 case 'i':
b677e7
-                        arg_ignore_inhibitors = true;
b677e7
+                        arg_check_inhibitors = 0;
b677e7
+                        break;
b677e7
+
b677e7
+                case ARG_CHECK_INHIBITORS:
b677e7
+                        if (streq(optarg, "auto"))
b677e7
+                                arg_check_inhibitors = -1;
b677e7
+                        else {
b677e7
+                                r = parse_boolean(optarg);
b677e7
+                                if (r < 0)
b677e7
+                                        return log_error_errno(r, "Failed to parse --check-inhibitors= argument: %s", optarg);
b677e7
+                                arg_check_inhibitors = r;
b677e7
+                        }
b677e7
                         break;
b677e7
 
b677e7
                 case ARG_PLAIN: