diff --git a/NEWS b/NEWS index a47f0f37a12..f0ddeb44321 100644 --- a/NEWS +++ b/NEWS @@ -64,6 +64,14 @@ CHANGES WITH 260 in spe: directory or not, we make use of it unconditionally and have dropped support for the old way using protofiles. + * The org.systemd.login1.Manager D-Bus interface has a minor API break. + The `CanPowerOff()`, `CanReboot()`, `CanSuspend()`, etc. family of + methods have introduced new return values which may break downstream + consumers, such as desktop environments. The new return values more + precisely communicate the status of inhibitors. This allows desktops + to differentiate between system administrator policy and + temporary restrictions imposed by inhibitors. + New system interfaces and components: * The os-release(3) gained a new field FANCY_NAME= that is similar diff --git a/man/org.freedesktop.login1.xml b/man/org.freedesktop.login1.xml index 464fdab108d..dc80e967177 100644 --- a/man/org.freedesktop.login1.xml +++ b/man/org.freedesktop.login1.xml @@ -276,7 +276,6 @@ node /org/freedesktop/login1 { readonly t RuntimeDirectoryInodesMax = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly t InhibitorsMax = ...; - @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly t NCurrentInhibitors = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly t SessionsMax = ...; @@ -711,12 +710,19 @@ node /org/freedesktop/login1 { CanRebootParameter(), CanRebootToFirmwareSetup(), CanRebootToBootLoaderMenu(), and CanRebootToBootLoaderEntry() test whether the system supports the respective operation and whether the calling user is allowed to - execute it. Returns one of na, yes, no, and - challenge. If na is returned, the operation is not available because - hardware, kernel, or drivers do not support it. If yes is returned, the operation is - supported and the user may execute the operation without further authentication. If no - is returned, the operation is available but the user is not allowed to execute the operation. If - challenge is returned, the operation is available but only after authorization. + execute it. Returns one of na, yes, no, + challenge, and inhibited. If na is returned, + the operation is not available because hardware, kernel, or drivers do not support it. If yes + is returned, the operation is supported and the user may execute the operation without further authentication. + If no is returned, the operation is available but the user is not allowed to execute + the operation. If challenge is returned, the operation is available but only after + authorization. If inhibited is returned, the operation is normally available without + authorization but is currently inhibited. The operation is available only if inhibitors are ignored and + after authorization. If inhibitor-blocked is returned, the operation is normally + available without authorization but is currently inhibited. While the inhibitor remains active, the user + is not allowed to execute the operation. challenge-inhibitor-blocked is similar: + the operation is normally available after authorization but a held inhibitor disallows the user from + executing the operation. ScheduleShutdown() schedules a shutdown operation type at time usec in microseconds since the UNIX epoch. Alternatively, if diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 87cc4f14bc8..b50e69809fe 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -2927,7 +2927,6 @@ static int method_can_shutdown_or_sleep( _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; bool multiple_sessions, challenge, blocked, check_unit_state = true; const HandleActionData *a; - const char *result = NULL; uid_t uid; int r; @@ -2984,12 +2983,27 @@ static int method_can_shutdown_or_sleep( if (r < 0) return r; - if (!streq(load_state, "loaded")) { - result = "no"; - goto finish; - } + if (!streq(load_state, "loaded")) + return sd_bus_reply_method_return(message, "s", "no"); } + const char *result; + r = bus_test_polkit( + message, + a->polkit_action, + /* details= */ NULL, + /* good_user= */ UID_INVALID, + &challenge, + error); + if (r < 0) + return r; + if (r > 0) + result = "yes"; + else if (challenge) + result = "challenge"; + else + result = "no"; + if (multiple_sessions) { r = bus_test_polkit( message, @@ -3001,12 +3015,13 @@ static int method_can_shutdown_or_sleep( if (r < 0) return r; - if (r > 0) - result = "yes"; - else if (challenge) - result = "challenge"; - else - result = "no"; + if (r == 0) { + if (challenge) { + if (streq(result, "yes")) /* Avoid upgrading no -> challenge */ + result = "challenge"; + } else + result = "no"; + } } if (blocked) { @@ -3020,39 +3035,21 @@ static int method_can_shutdown_or_sleep( if (r < 0) return r; - if (r > 0) { - if (!result) - result = "yes"; - } else if (challenge) { - if (!result || streq(result, "yes")) - result = "challenge"; - } else - result = "no"; + if (r == 0) { + if (challenge) { + if (streq(result, "yes")) + result = "inhibited"; + /* If result is already "challenge" or "no", the held inhibitor has no effect */ + } else { + if (streq(result, "yes")) + result = "inhibitor-blocked"; + else if (streq(result, "challenge")) + result = "challenge-inhibitor-blocked"; + /* If the result is already "no", the held inhibitor has no effect */ + } + } } - if (!multiple_sessions && !blocked) { - /* If neither inhibit nor multiple sessions - * apply then just check the normal policy */ - - r = bus_test_polkit( - message, - a->polkit_action, - /* details= */ NULL, - /* good_user= */ UID_INVALID, - &challenge, - error); - if (r < 0) - return r; - - if (r > 0) - result = "yes"; - else if (challenge) - result = "challenge"; - else - result = "no"; - } - - finish: return sd_bus_reply_method_return(message, "s", result); } @@ -3963,7 +3960,7 @@ static const sd_bus_vtable manager_vtable[] = { SD_BUS_PROPERTY("RuntimeDirectorySize", "t", NULL, offsetof(Manager, runtime_dir_size), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RuntimeDirectoryInodesMax", "t", NULL, offsetof(Manager, runtime_dir_inodes), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("InhibitorsMax", "t", NULL, offsetof(Manager, inhibitors_max), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("NCurrentInhibitors", "t", property_get_hashmap_size, offsetof(Manager, inhibitors), 0), + SD_BUS_PROPERTY("NCurrentInhibitors", "t", property_get_hashmap_size, offsetof(Manager, inhibitors), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("SessionsMax", "t", NULL, offsetof(Manager, sessions_max), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("NCurrentSessions", "t", property_get_hashmap_size, offsetof(Manager, sessions), 0), SD_BUS_PROPERTY("UserTasksMax", "t", property_get_compat_user_tasks_max, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c index 2ef15588f28..b78d39d02d7 100644 --- a/src/login/logind-inhibit.c +++ b/src/login/logind-inhibit.c @@ -148,13 +148,11 @@ static int inhibitor_save(Inhibitor *i) { } static int bus_manager_send_inhibited_change(Inhibitor *i) { - const char *property; - assert(i); - property = IN_SET(i->mode, INHIBIT_BLOCK, INHIBIT_BLOCK_WEAK) ? "BlockInhibited" : "DelayInhibited"; - - return manager_send_changed(i->manager, property); + return manager_send_changed(i->manager, + i->mode == INHIBIT_DELAY ? "DelayInhibited" : "BlockInhibited", + "NCurrentInhibitors"); } int inhibitor_start(Inhibitor *i) {