]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
logind: always check for inhibitor locks
authorLuca Boccassi <bluca@debian.org>
Sat, 2 Dec 2023 20:11:57 +0000 (20:11 +0000)
committerLuca Boccassi <bluca@debian.org>
Thu, 25 Jul 2024 11:22:36 +0000 (12:22 +0100)
Currently inhibitors are bypassed unless an explicit request is made to
check for them, or even in that case when the requestor is root or the
same uid as the holder of the lock.

But in many cases this makes it impractical to rely on inhibitor locks.
For example, in Debian there are several convoluted and archaic
workarounds that divert systemctl/reboot to some hacky custom scripts
to try and enforce blocking accidental reboots, when it's not expected
that the requestor will remember to specify the command line option
to enable checking for active inhibitor locks.

Also in many cases one wants to ensure that locks taken by a user are
respected by actions initiated by that same user.

Change logind so that inhibitors checks are not skipped in these
cases, and systemctl so that locks are checked in order to show a
friendly error message rather than "permission denied".

Add new block-weak and delay-weak modes that keep the previous
behaviour unchanged.

13 files changed:
docs/INHIBITOR_LOCKS.md
man/org.freedesktop.login1.xml
man/systemctl.xml
man/systemd-inhibit.xml
shell-completion/zsh/_systemd-inhibit
src/basic/login-util.h
src/login/inhibit.c
src/login/logind-action.c
src/login/logind-core.c
src/login/logind-dbus.c
src/login/logind-inhibit.c
src/login/logind-inhibit.h
src/systemctl/systemctl-logind.c

index 1308f6e3880f0bc9b247bdeafd1036dc3fc94c8f..b88704d330f4defe8f33a4b552e91adf43f7415a 100644 (file)
@@ -42,6 +42,9 @@ If such a lock is taken the operation will fail (but still may be overridden if
 The InhibitDelayMaxSec= setting in [logind.conf(5)](http://www.freedesktop.org/software/systemd/man/logind.conf.html) controls the timeout for this. This is intended to be used by applications which need a synchronous way to execute actions before system suspend but shall not be allowed to block suspend indefinitely.
 This mode is only available for _sleep_ and _shutdown_ locks.
 
+3. _block-weak_ and _delay-weak_ that work as the non-weak counterparts, but that in addition may be ignored
+automatically and silently under certain circumstances, unlike the formers which are always respected.
+
 Inhibitor locks are taken via the Inhibit() D-Bus call on the logind Manager object:
 
 ```
index cba371ca9e25df4a409ce351c083e281cb3360ea..bf00800cefc6c70bcad809fadaf316bfffb600d2 100644 (file)
@@ -665,15 +665,18 @@ node /org/freedesktop/login1 {
 #define SD_LOGIND_KEXEC_REBOOT                   (UINT64_C(1) &lt;&lt; 1)
 #define SD_LOGIND_SOFT_REBOOT                    (UINT64_C(1) &lt;&lt; 2)
 #define SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP (UINT64_C(1) &lt;&lt; 3)
+#define SD_LOGIND_SKIP_INHIBITORS                (UINT64_C(1) &lt;&lt; 4)
       </programlisting>
       <para>When the <varname>flags</varname> is 0 then these methods behave just like the versions without
-      flags. When <constant>SD_LOGIND_ROOT_CHECK_INHIBITORS</constant> (0x01) is set, active inhibitors are
-      honoured for privileged users too. When <constant>SD_LOGIND_KEXEC_REBOOT</constant> (0x02) is set,
-      then <function>RebootWithFlags()</function> performs a kexec reboot if kexec kernel is loaded. When
-      <constant>SD_LOGIND_SOFT_REBOOT</constant> (0x04) is set, or
-      <constant>SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP</constant> (0x08) is set and a new root file system
-      has been set up on <literal>/run/nextroot/</literal>, then <function>RebootWithFlags()</function>
-      performs a userspace reboot only. <constant>SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP</constant> and
+      flags. Since systemd version 256 <constant>SD_LOGIND_ROOT_CHECK_INHIBITORS</constant> (0x01) is deprecated,
+      and active inhibitors are always honoured by default for privileged users too, and a new flag
+      <constant>SD_LOGIND_SKIP_INHIBITORS</constant> (0x04) can be specified to bypass inhibitors. When
+      <constant>SD_LOGIND_KEXEC_REBOOT</constant> (0x02) is set, then <function>RebootWithFlags()</function>
+      performs a kexec reboot if kexec kernel is loaded. When <constant>SD_LOGIND_SOFT_REBOOT</constant>
+      (0x04) is set, or <constant>SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP</constant> (0x08) is set and a
+      new root file system has been set up on <literal>/run/nextroot/</literal>, then
+      <function>RebootWithFlags()</function> performs a userspace reboot only.
+      <constant>SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP</constant> and
       <constant>SD_LOGIND_KEXEC_REBOOT</constant> can be combined, with soft-reboot having precedence.</para>
 
       <para><function>SetRebootParameter()</function> sets a parameter for a subsequent reboot operation.
@@ -731,8 +734,10 @@ node /org/freedesktop/login1 {
       should be a short human readable string identifying the reason why the lock is taken. Finally,
       <varname>mode</varname> is either <literal>block</literal> or <literal>delay</literal> which encodes
       whether the inhibit shall be consider mandatory or whether it should just delay the operation to a
-      certain maximum time. The method returns a file descriptor. The lock is released the moment this file
-      descriptor and all its duplicates are closed. For more information on the inhibition logic see
+      certain maximum time, while the <literal>block-weak</literal> and <literal>delay-weak</literal>
+      variants will create an inhibitor that is automatically ignored in some circumstances. The method
+      returns a file descriptor. The lock is released the moment this file descriptor and all its duplicates
+      are closed. For more information on the inhibition logic see
       <ulink url="https://systemd.io/INHIBITOR_LOCKS">Inhibitor Locks</ulink>.
       </para>
     </refsect2>
index 55389a910bc6d2cad8cf6696dfefbd98bd5534a2..1cf5eaf08eb3e079e40ff98668fb458ea1c1c8b1 100644 (file)
@@ -2288,17 +2288,15 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
         <listitem>
           <para>When system shutdown or sleep state is requested, this option controls checking of inhibitor
           locks. It takes one of <literal>auto</literal>, <literal>yes</literal> or
-          <literal>no</literal>. Defaults to <literal>auto</literal>, which will behave like
-          <literal>yes</literal> for interactive invocations (i.e. from a TTY) and <literal>no</literal> for
-          non-interactive invocations. <literal>yes</literal> lets the request respect inhibitor locks.
-          <literal>no</literal> lets the request ignore inhibitor locks.</para>
+          <literal>no</literal>. Defaults to <literal>auto</literal>, which means logind will perform the
+          check and respect active inhibitor locks, but systemctl will only do a client-side check for
+          interactive invocations (i.e. from a TTY), so that a more friendly and informative error can be
+          returned to users. <literal>no</literal> disables both the systemctl and logind checks.</para>
 
           <para>Applications can establish inhibitor locks to prevent certain important operations (such as
           CD burning) from being interrupted by system shutdown or sleep. Any user may take these locks and
           privileged users may override these locks. If any locks are taken, shutdown and sleep state
-          requests will normally fail (unless privileged). However, if <literal>no</literal> is specified or
-          <literal>auto</literal> is specified on a non-interactive requests, the operation will be
-          attempted. If locks are present, the operation may require additional privileges.</para>
+          requests will normally fail (unless explicitly overridden with <literal>no</literal>).</para>
 
           <para>Option <option>--force</option> provides another way to override inhibitors.</para>
 
index 5299719525443f4f17483498e07b16217987e4ec..df0a6370865dd989d6bff466130de13d776074af 100644 (file)
       <varlistentry>
         <term><option>--mode=</option></term>
 
-        <listitem><para>Takes either <literal>block</literal> or
-        <literal>delay</literal> and describes how the lock is
-        applied. If <literal>block</literal> is used (the default),
-        the lock prohibits any of the requested operations without
-        time limit, and only privileged users may override it. If
-        <literal>delay</literal> is used, the lock can only delay the
-        requested operations for a limited time. If the time elapses,
-        the lock is ignored and the operation executed. The time limit
-        may be specified in
+        <listitem><para>Takes <literal>block</literal>, <literal>delay</literal>,
+        <literal>block-weak</literal> or <literal>delay-weak</literal> and describes how the lock is
+        applied. If <literal>block</literal> is used (the default), the lock prohibits any of the requested
+        operations without time limit, and only privileged users may override it. If
+        <literal>delay</literal> is used, the lock can only delay the requested operations for a limited
+        time. If the time elapses, the lock is ignored and the operation executed. The time limit may be
+        specified in
         <citerefentry><refentrytitle>logind.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
-        Note that <literal>delay</literal> is only available for
-        <literal>sleep</literal> and
-        <literal>shutdown</literal>.</para></listitem>
+        Note that <literal>delay</literal> is only available for <literal>sleep</literal> and
+        <literal>shutdown</literal>. In addition, the weak variants will automatically and silently be
+        bypassed under some circumstances.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 08bcf4208d71d65c82aeeea599fafd02c5192f39..d43c781834429b2960de0e8a0d69327fe87c33b3 100644 (file)
@@ -33,6 +33,6 @@ _arguments \
     '--what=[Operations to inhibit]:options:_systemd-inhibit_what' \
     '--who=[A descriptive string who is inhibiting]:who is inhibiting:' \
     '--why=[A descriptive string why is being inhibited]:reason for the lock:' \
-    '--mode=[One of block or delay]:lock mode:( block delay )' \
+    '--mode=[One of block, block-weak, delay, or delay-weak]:lock mode:( block block-weak delay delay-weak )' \
     '--list[List active inhibitors]' \
     '*:commands:_systemd-inhibit_commands'
index 4c9cae0f4fc57e2048c881d6ecad3a28d9b371c6..4d0c69208b90f100e43b24ed5afaa2a936748c1b 100644 (file)
@@ -8,11 +8,12 @@
 #define SD_LOGIND_REBOOT_VIA_KEXEC                (UINT64_C(1) << 1)
 #define SD_LOGIND_SOFT_REBOOT                     (UINT64_C(1) << 2)
 #define SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP  (UINT64_C(1) << 3)
+#define SD_LOGIND_SKIP_INHIBITORS                 (UINT64_C(1) << 4)
 
 /* For internal use only */
 #define SD_LOGIND_INTERACTIVE                     (UINT64_C(1) << 63)
 
-#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC (SD_LOGIND_ROOT_CHECK_INHIBITORS|SD_LOGIND_REBOOT_VIA_KEXEC|SD_LOGIND_SOFT_REBOOT|SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP)
+#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC (SD_LOGIND_ROOT_CHECK_INHIBITORS|SD_LOGIND_REBOOT_VIA_KEXEC|SD_LOGIND_SOFT_REBOOT|SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP|SD_LOGIND_SKIP_INHIBITORS)
 #define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_ALL    (SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC|SD_LOGIND_INTERACTIVE)
 
 bool session_id_valid(const char *id);
index 13ba4b82f46eacbbd59b030ccee23ead989acc02..990bda0cfd259991d8e2fe7357cd54691992d23d 100644 (file)
@@ -157,7 +157,7 @@ static int help(void) {
                "                          handle-lid-switch\n"
                "     --who=STRING         A descriptive string who is inhibiting\n"
                "     --why=STRING         A descriptive string why is being inhibited\n"
-               "     --mode=MODE          One of block or delay\n"
+               "     --mode=MODE          One of block, block-weak, delay, or delay-weak\n"
                "     --list               List active inhibitors\n"
                "\nSee the %s for details.\n",
                program_invocation_short_name,
index 686ba358f7e828ff3e0f299d787f653ee5689967..2a7766841f427580a2bbf081c913473bba688b13 100644 (file)
@@ -234,7 +234,7 @@ static int handle_action_execute(
         /* If the actual operation is inhibited, warn and fail */
         if (inhibit_what_is_valid(inhibit_operation) &&
             !ignore_inhibited &&
-            manager_is_inhibited(m, inhibit_operation, INHIBIT_BLOCK, NULL, false, false, 0, &offending)) {
+            manager_is_inhibited(m, inhibit_operation, /* block= */ true, NULL, false, false, 0, &offending)) {
                 _cleanup_free_ char *comm = NULL, *u = NULL;
 
                 (void) pidref_get_comm(&offending->pid, &comm);
@@ -372,7 +372,7 @@ int manager_handle_action(
 
         /* If the key handling is inhibited, don't do anything */
         if (inhibit_key > 0) {
-                if (manager_is_inhibited(m, inhibit_key, INHIBIT_BLOCK, NULL, true, false, 0, NULL)) {
+                if (manager_is_inhibited(m, inhibit_key, /* block= */ true, NULL, true, false, 0, NULL)) {
                         log_debug("Refusing %s operation, %s is inhibited.",
                                   handle_action_to_string(handle),
                                   inhibit_what_to_string(inhibit_key));
index 5e024c339de7a9d41cef3c58089ddf8218159a38..8742fe6a97ca44bb53a673b419a210ddfb53aabf 100644 (file)
@@ -411,7 +411,7 @@ int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
 
         assert(m);
 
-        idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, INHIBIT_BLOCK, t, false, false, 0, NULL);
+        idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, /* block= */ true, t, false, false, 0, NULL);
 
         HASHMAP_FOREACH(s, m->sessions) {
                 dual_timestamp k;
index c3bc956c62ebac532bc0d2d5957c77ef6d77018a..81bf0feace1f70255f2b1cdc5a8ec740ef26757e 100644 (file)
@@ -311,7 +311,7 @@ static int property_get_inhibited(
         assert(bus);
         assert(reply);
 
-        w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
+        w = manager_inhibit_what(m, /* block= */ streq(property, "BlockInhibited"));
 
         return sd_bus_message_append(reply, "s", inhibit_what_to_string(w));
 }
@@ -1881,7 +1881,7 @@ int manager_dispatch_delayed(Manager *manager, bool timeout) {
         if (!manager->delayed_action || manager->action_job)
                 return 0;
 
-        if (manager_is_inhibited(manager, manager->delayed_action->inhibit_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) {
+        if (manager_is_inhibited(manager, manager->delayed_action->inhibit_what, /* block= */ false, NULL, false, false, 0, &offending)) {
                 _cleanup_free_ char *comm = NULL, *u = NULL;
 
                 if (!timeout)
@@ -1978,7 +1978,7 @@ int bus_manager_shutdown_or_sleep_now_or_later(
 
         delayed =
                 m->inhibit_delay_max > 0 &&
-                manager_is_inhibited(m, a->inhibit_what, INHIBIT_DELAY, NULL, false, false, 0, NULL);
+                manager_is_inhibited(m, a->inhibit_what, /* block= */ false, NULL, false, false, 0, NULL);
 
         if (delayed)
                 /* Shutdown is delayed, keep in mind what we
@@ -2021,7 +2021,7 @@ static int verify_shutdown_creds(
                 return r;
 
         multiple_sessions = r > 0;
-        blocked = manager_is_inhibited(m, a->inhibit_what, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
+        blocked = manager_is_inhibited(m, a->inhibit_what, /* block= */ true, NULL, false, true, uid, NULL);
         interactive = flags & SD_LOGIND_INTERACTIVE;
 
         if (multiple_sessions) {
@@ -2040,17 +2040,23 @@ static int verify_shutdown_creds(
         }
 
         if (blocked) {
-                /* We don't check polkit for root here, because you can't be more privileged than root */
-                if (uid == 0 && (flags & SD_LOGIND_ROOT_CHECK_INHIBITORS))
+                if (!FLAGS_SET(flags, SD_LOGIND_SKIP_INHIBITORS))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED,
-                                                 "Access denied to root due to active block inhibitor");
+                                                 "Access denied due to active block inhibitor");
+
+                /* We want to always ask here, even for root, to only allow bypassing if explicitly allowed
+                 * by polkit */
+                PolkitFlags polkit_flags = POLKIT_ALWAYS_QUERY;
+
+                if (interactive)
+                        polkit_flags |= POLKIT_ALLOW_INTERACTIVE;
 
                 r = bus_verify_polkit_async_full(
                                 message,
                                 a->polkit_action_ignore_inhibit,
                                 /* details= */ NULL,
                                 /* good_user= */ UID_INVALID,
-                                interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
+                                polkit_flags,
                                 &m->polkit_registry,
                                 error);
                 if (r < 0)
@@ -2749,7 +2755,7 @@ static int method_can_shutdown_or_sleep(
                 return r;
 
         multiple_sessions = r > 0;
-        blocked = manager_is_inhibited(m, a->inhibit_what, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
+        blocked = manager_is_inhibited(m, a->inhibit_what, /* block= */ true, NULL, false, true, uid, NULL);
 
         if (check_unit_state && a->target) {
                 _cleanup_free_ char *load_state = NULL;
@@ -3587,7 +3593,7 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
                                          "Invalid mode specification %s", mode);
 
         /* Delay is only supported for shutdown/sleep */
-        if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP)))
+        if (IN_SET(mm, INHIBIT_DELAY, INHIBIT_DELAY_WEAK) && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP)))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
                                          "Delay inhibitors only supported for shutdown and sleep");
 
@@ -3604,8 +3610,8 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
 
                 r = bus_verify_polkit_async(
                                 message,
-                                v == INHIBIT_SHUTDOWN             ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
-                                v == INHIBIT_SLEEP                ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep"    : "org.freedesktop.login1.inhibit-delay-sleep") :
+                                v == INHIBIT_SHUTDOWN             ? (IN_SET(mm, INHIBIT_BLOCK, INHIBIT_BLOCK_WEAK) ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
+                                v == INHIBIT_SLEEP                ? (IN_SET(mm, INHIBIT_BLOCK, INHIBIT_BLOCK_WEAK) ? "org.freedesktop.login1.inhibit-block-sleep"    : "org.freedesktop.login1.inhibit-delay-sleep") :
                                 v == INHIBIT_IDLE                 ? "org.freedesktop.login1.inhibit-block-idle" :
                                 v == INHIBIT_HANDLE_POWER_KEY     ? "org.freedesktop.login1.inhibit-handle-power-key" :
                                 v == INHIBIT_HANDLE_SUSPEND_KEY   ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
index 4e64b9ebefe7909f7550b4112e0b8ff8d2702de2..c1798f927c8ec996582b0ccd3e53b0ab73d9a93f 100644 (file)
@@ -165,7 +165,7 @@ static int bus_manager_send_inhibited_change(Inhibitor *i) {
 
         assert(i);
 
-        property = i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited";
+        property = IN_SET(i->mode, INHIBIT_BLOCK, INHIBIT_BLOCK_WEAK) ? "BlockInhibited" : "DelayInhibited";
 
         return manager_send_changed(i->manager, property, NULL);
 }
@@ -363,14 +363,16 @@ bool inhibitor_is_orphan(Inhibitor *i) {
         return false;
 }
 
-InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm) {
+InhibitWhat manager_inhibit_what(Manager *m, bool block) {
         Inhibitor *i;
         InhibitWhat what = 0;
 
         assert(m);
 
         HASHMAP_FOREACH(i, m->inhibitors)
-                if (i->mode == mm && i->started)
+                if (i->started &&
+                    ((!block && IN_SET(i->mode, INHIBIT_DELAY, INHIBIT_DELAY_WEAK)) ||
+                     (block && IN_SET(i->mode, INHIBIT_BLOCK, INHIBIT_BLOCK_WEAK))))
                         what |= i->what;
 
         return what;
@@ -399,7 +401,7 @@ static int pidref_is_active_session(Manager *m, const PidRef *pid) {
 bool manager_is_inhibited(
                 Manager *m,
                 InhibitWhat w,
-                InhibitMode mm,
+                bool block,
                 dual_timestamp *since,
                 bool ignore_inactive,
                 bool ignore_uid,
@@ -421,13 +423,14 @@ bool manager_is_inhibited(
                 if (!(i->what & w))
                         continue;
 
-                if (i->mode != mm)
+                if ((block && !IN_SET(i->mode, INHIBIT_BLOCK, INHIBIT_BLOCK_WEAK)) ||
+                    (!block && !IN_SET(i->mode, INHIBIT_DELAY, INHIBIT_DELAY_WEAK)))
                         continue;
 
                 if (ignore_inactive && pidref_is_active_session(m, &i->pid) <= 0)
                         continue;
 
-                if (ignore_uid && i->uid == uid)
+                if (IN_SET(i->mode, INHIBIT_BLOCK_WEAK, INHIBIT_DELAY_WEAK) && ignore_uid && i->uid == uid)
                         continue;
 
                 if (!inhibited ||
@@ -525,8 +528,10 @@ int inhibit_what_from_string(const char *s) {
 }
 
 static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
-        [INHIBIT_BLOCK] = "block",
-        [INHIBIT_DELAY] = "delay"
+        [INHIBIT_BLOCK]      = "block",
+        [INHIBIT_BLOCK_WEAK] = "block-weak",
+        [INHIBIT_DELAY]      = "delay",
+        [INHIBIT_DELAY_WEAK] = "delay-weak"
 };
 
 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);
index 166e8f57ed7ab7647c4c79f2c15b3ca7e3cd0a82..b5167974af9158f6967cbac19a59bbc2b78c9516 100644 (file)
@@ -20,7 +20,9 @@ typedef enum InhibitWhat {
 
 typedef enum InhibitMode {
         INHIBIT_BLOCK,
+        INHIBIT_BLOCK_WEAK,
         INHIBIT_DELAY,
+        INHIBIT_DELAY_WEAK,
         _INHIBIT_MODE_MAX,
         _INHIBIT_MODE_INVALID = -EINVAL,
 } InhibitMode;
@@ -65,8 +67,8 @@ int inhibitor_create_fifo(Inhibitor *i);
 
 bool inhibitor_is_orphan(Inhibitor *i);
 
-InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm);
-bool manager_is_inhibited(Manager *m, InhibitWhat w, InhibitMode mm, dual_timestamp *since, bool ignore_inactive, bool ignore_uid, uid_t uid, Inhibitor **offending);
+InhibitWhat manager_inhibit_what(Manager *m, bool block);
+bool manager_is_inhibited(Manager *m, InhibitWhat w, bool block, dual_timestamp *since, bool ignore_inactive, bool ignore_uid, uid_t uid, Inhibitor **offending);
 
 static inline bool inhibit_what_is_valid(InhibitWhat w) {
         return w > 0 && w < _INHIBIT_WHAT_MAX;
index 87e96a3a174f31f207be9ae91444e291907ef62d..a727606eea7d4610d9719cc563f8c04346b39748 100644 (file)
@@ -82,6 +82,7 @@ int logind_reboot(enum action a) {
                 return 0;
 
         SET_FLAG(flags, SD_LOGIND_ROOT_CHECK_INHIBITORS, arg_check_inhibitors > 0);
+        SET_FLAG(flags, SD_LOGIND_SKIP_INHIBITORS, arg_check_inhibitors == 0);
         SET_FLAG(flags,
                  SD_LOGIND_REBOOT_VIA_KEXEC,
                  a == ACTION_KEXEC || (a == ACTION_REBOOT && getenv_bool("SYSTEMCTL_SKIP_AUTO_KEXEC") <= 0));
@@ -94,17 +95,17 @@ int logind_reboot(enum action a) {
         SET_FLAG(flags, SD_LOGIND_SOFT_REBOOT, a == ACTION_SOFT_REBOOT);
 
         r = bus_call_method(bus, bus_login_mgr, method_with_flags, &error, NULL, "t", flags);
+        if (r < 0 && FLAGS_SET(flags, SD_LOGIND_SKIP_INHIBITORS) &&
+                        sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
+                sd_bus_error_free(&error);
+                flags &= ~SD_LOGIND_SKIP_INHIBITORS;
+                r = bus_call_method(bus, bus_login_mgr, method_with_flags, &error, NULL, "t", flags);
+        }
         if (r < 0 && FLAGS_SET(flags, SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP) &&
                         sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
                 sd_bus_error_free(&error);
-                r = bus_call_method(
-                                bus,
-                                bus_login_mgr,
-                                method_with_flags,
-                                &error,
-                                NULL,
-                                "t",
-                                flags & ~SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP);
+                flags &= ~SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP;
+                r = bus_call_method(bus, bus_login_mgr, method_with_flags, &error, NULL, "t", flags);
         }
         if (r >= 0)
                 return 0;
@@ -144,13 +145,8 @@ int logind_check_inhibitors(enum action a) {
         if (arg_when > 0)
                 return 0;
 
-        if (arg_check_inhibitors < 0) {
-                if (geteuid() == 0)
-                        return 0;
-
-                if (!on_tty())
-                        return 0;
-        }
+        if (arg_check_inhibitors < 0 && !on_tty())
+                return 0;
 
         if (arg_transport != BUS_TRANSPORT_LOCAL)
                 return 0;
@@ -172,7 +168,10 @@ int logind_check_inhibitors(enum action a) {
                 _cleanup_free_ char *comm = NULL, *user = NULL;
                 _cleanup_strv_free_ char **sv = NULL;
 
-                if (!streq(mode, "block"))
+                if (!STR_IN_SET(mode, "block", "block-weak"))
+                        continue;
+
+                if (streq(mode, "block-weak") && (geteuid() == 0 || geteuid() == uid || !on_tty()))
                         continue;
 
                 sv = strv_split(what, ":");
@@ -233,6 +232,7 @@ int logind_check_inhibitors(enum action a) {
 
         return log_error_errno(SYNTHETIC_ERRNO(EPERM),
                                "Please retry operation after closing inhibitors and logging out other users.\n"
+                               "'systemd-inhibit' can be used to list active inhibitors.\n"
                                "Alternatively, ignore inhibitors and users with 'systemctl %s -i'.",
                                action_table[a].verb);
 #else