summaryrefslogtreecommitdiffstats
path: root/src/login/logind-dbus.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/login/logind-dbus.c')
-rw-r--r--src/login/logind-dbus.c1183
1 files changed, 675 insertions, 508 deletions
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index cd2db2d..a657b6e 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -49,6 +49,7 @@
#include "sleep-config.h"
#include "special.h"
#include "serialize.h"
+#include "signal-util.h"
#include "stdio-util.h"
#include "strv.h"
#include "terminal-util.h"
@@ -70,9 +71,7 @@
#define SHUTDOWN_SCHEDULE_FILE "/run/systemd/shutdown/scheduled"
-static int update_schedule_file(Manager *m);
static void reset_scheduled_shutdown(Manager *m);
-static int manager_setup_shutdown_timers(Manager* m);
static int get_sender_session(
Manager *m,
@@ -141,9 +140,9 @@ int manager_get_session_from_creds(
assert(m);
assert(ret);
- if (SEAT_IS_SELF(name)) /* the caller's own session */
+ if (SESSION_IS_SELF(name)) /* the caller's own session */
return get_sender_session(m, message, false, error, ret);
- if (SEAT_IS_AUTO(name)) /* The caller's own session if they have one, otherwise their user's display session */
+ if (SESSION_IS_AUTO(name)) /* The caller's own session if they have one, otherwise their user's display session */
return get_sender_session(m, message, true, error, ret);
session = hashmap_get(m->sessions, name);
@@ -236,7 +235,6 @@ int manager_get_seat_from_creds(
static int return_test_polkit(
sd_bus_message *message,
- int capability,
const char *action,
const char **details,
uid_t good_user,
@@ -246,7 +244,7 @@ static int return_test_polkit(
bool challenge;
int r;
- r = bus_test_polkit(message, capability, action, details, good_user, &challenge, e);
+ r = bus_test_polkit(message, action, details, good_user, &challenge, e);
if (r < 0)
return r;
@@ -342,6 +340,29 @@ static int property_get_preparing(
return sd_bus_message_append(reply, "b", b);
}
+static int property_get_sleep_operations(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Manager *m = ASSERT_PTR(userdata);
+ _cleanup_strv_free_ char **actions = NULL;
+ int r;
+
+ assert(bus);
+ assert(reply);
+
+ r = handle_action_get_enabled_sleep_actions(m->handle_action_sleep_mask, &actions);
+ if (r < 0)
+ return r;
+
+ return sd_bus_message_append_strv(reply, actions);
+}
+
static int property_get_scheduled_shutdown(
sd_bus *bus,
const char *path,
@@ -361,9 +382,10 @@ static int property_get_scheduled_shutdown(
if (r < 0)
return r;
- r = sd_bus_message_append(reply, "st",
- m->scheduled_shutdown_action ? handle_action_to_string(m->scheduled_shutdown_action->handle) : NULL,
- m->scheduled_shutdown_timeout);
+ r = sd_bus_message_append(
+ reply, "st",
+ handle_action_to_string(m->scheduled_shutdown_action),
+ m->scheduled_shutdown_timeout);
if (r < 0)
return r;
@@ -568,6 +590,60 @@ static int method_list_sessions(sd_bus_message *message, void *userdata, sd_bus_
return sd_bus_send(NULL, reply, NULL);
}
+static int method_list_sessions_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = ASSERT_PTR(userdata);
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ int r;
+
+ assert(message);
+
+ r = sd_bus_message_new_method_return(message, &reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(reply, 'a', "(sussussbto)");
+ if (r < 0)
+ return r;
+
+ Session *s;
+ HASHMAP_FOREACH(s, m->sessions) {
+ _cleanup_free_ char *path = NULL;
+ dual_timestamp idle_ts;
+ bool idle;
+
+ assert(s->user);
+
+ path = session_bus_path(s);
+ if (!path)
+ return -ENOMEM;
+
+ r = session_get_idle_hint(s, &idle_ts);
+ if (r < 0)
+ return r;
+ idle = r > 0;
+
+ r = sd_bus_message_append(reply, "(sussussbto)",
+ s->id,
+ (uint32_t) s->user->user_record->uid,
+ s->user->user_record->user_name,
+ s->seat ? s->seat->id : "",
+ (uint32_t) s->leader.pid,
+ session_class_to_string(s->class),
+ s->tty,
+ idle,
+ idle_ts.monotonic,
+ path);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+
+ return sd_bus_send(NULL, reply, NULL);
+}
+
static int method_list_users(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
Manager *m = ASSERT_PTR(userdata);
@@ -682,8 +758,8 @@ static int create_session(
void *userdata,
sd_bus_error *error,
uid_t uid,
- pid_t pid,
- int pidfd,
+ pid_t leader_pid,
+ int leader_pidfd,
const char *service,
const char *type,
const char *class,
@@ -716,32 +792,18 @@ static int create_session(
if (flags != 0)
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Flags must be zero.");
- if (pidfd >= 0) {
- r = pidref_set_pidfd(&leader, pidfd);
- if (r < 0)
- return r;
- } else if (pid == 0) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- pid_t p;
-
- r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
- if (r < 0)
- return r;
-
- r = sd_bus_creds_get_pid(creds, &p);
- if (r < 0)
- return r;
-
- r = pidref_set_pid(&leader, p);
- if (r < 0)
- return r;
- } else {
- assert(pid > 0);
+ if (leader_pidfd >= 0)
+ r = pidref_set_pidfd(&leader, leader_pidfd);
+ else if (leader_pid == 0)
+ r = bus_query_sender_pidref(message, &leader);
+ else {
+ if (leader_pid < 0)
+ return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Leader PID is not valid");
- r = pidref_set_pid(&leader, pid);
- if (r < 0)
- return r;
+ r = pidref_set_pid(&leader, leader_pid);
}
+ if (r < 0)
+ return r;
if (leader.pid == 1 || leader.pid == getpid_cached())
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
@@ -842,25 +904,22 @@ static int create_session(
c = SESSION_USER;
}
- /* Check if we are already in a logind session. Or if we are in user@.service
- * which is a special PAM session that avoids creating a logind session. */
- r = manager_get_user_by_pid(m, leader.pid, NULL);
+ /* Check if we are already in a logind session, and if so refuse. */
+ r = manager_get_session_by_pidref(m, &leader, /* ret_session= */ NULL);
if (r < 0)
- return r;
+ return log_debug_errno(
+ r,
+ "Failed to check if process " PID_FMT " is already in a session: %m",
+ leader.pid);
if (r > 0)
return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY,
"Already running in a session or user slice");
- /*
- * Old gdm and lightdm start the user-session on the same VT as
- * the greeter session. But they destroy the greeter session
- * after the user-session and want the user-session to take
- * over the VT. We need to support this for
- * backwards-compatibility, so make sure we allow new sessions
- * on a VT that a greeter is running on. Furthermore, to allow
- * re-logins, we have to allow a greeter to take over a used VT for
- * the exact same reasons.
- */
+ /* Old gdm and lightdm start the user-session on the same VT as the greeter session. But they destroy
+ * the greeter session after the user-session and want the user-session to take over the VT. We need
+ * to support this for backwards-compatibility, so make sure we allow new sessions on a VT that a
+ * greeter is running on. Furthermore, to allow re-logins, we have to allow a greeter to take over a
+ * used VT for the exact same reasons. */
if (c != SESSION_GREETER &&
vtnr > 0 &&
vtnr < MALLOC_ELEMENTSOF(m->seat0->positions) &&
@@ -920,58 +979,54 @@ static int create_session(
goto fail;
session->original_type = session->type = t;
- session->class = c;
session->remote = remote;
session->vtnr = vtnr;
+ session->class = c;
+
+ /* Once the first session that is of a pinning class shows up we'll change the GC mode for the user
+ * from USER_GC_BY_ANY to USER_GC_BY_PIN, so that the user goes away once the last pinning session
+ * goes away. Background: we want that user@.service – when started manually – remains around (which
+ * itself is a non-pinning session), but gets stopped when the last pinning session goes away. */
+
+ if (SESSION_CLASS_PIN_USER(c))
+ user->gc_mode = USER_GC_BY_PIN;
if (!isempty(tty)) {
- session->tty = strdup(tty);
- if (!session->tty) {
- r = -ENOMEM;
+ r = strdup_to(&session->tty, tty);
+ if (r < 0)
goto fail;
- }
session->tty_validity = TTY_FROM_PAM;
}
if (!isempty(display)) {
- session->display = strdup(display);
- if (!session->display) {
- r = -ENOMEM;
+ r = strdup_to(&session->display, display);
+ if (r < 0)
goto fail;
- }
}
if (!isempty(remote_user)) {
- session->remote_user = strdup(remote_user);
- if (!session->remote_user) {
- r = -ENOMEM;
+ r = strdup_to(&session->remote_user, remote_user);
+ if (r < 0)
goto fail;
- }
}
if (!isempty(remote_host)) {
- session->remote_host = strdup(remote_host);
- if (!session->remote_host) {
- r = -ENOMEM;
+ r = strdup_to(&session->remote_host, remote_host);
+ if (r < 0)
goto fail;
- }
}
if (!isempty(service)) {
- session->service = strdup(service);
- if (!session->service) {
- r = -ENOMEM;
+ r = strdup_to(&session->service, service);
+ if (r < 0)
goto fail;
- }
}
if (!isempty(desktop)) {
- session->desktop = strdup(desktop);
- if (!session->desktop) {
- r = -ENOMEM;
+ r = strdup_to(&session->desktop, desktop);
+ if (r < 0)
goto fail;
- }
}
if (seat) {
@@ -994,8 +1049,14 @@ static int create_session(
session->create_message = sd_bus_message_ref(message);
- /* Now, let's wait until the slice unit and stuff got created. We send the reply back from
- * session_send_create_reply(). */
+ /* Now call into session_send_create_reply(), which will reply to this method call for us. Or it
+ * won't – in case we just spawned a session scope and/or user service manager, and they aren't ready
+ * yet. We'll call session_create_reply() again once the session scope or the user service manager is
+ * ready, where the function will check again if a reply is then ready to be sent, and then do so if
+ * all is complete - or wait again. */
+ r = session_send_create_reply(session, /* error= */ NULL);
+ if (r < 0)
+ return r;
return 1;
@@ -1011,32 +1072,32 @@ fail:
static int method_create_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
- pid_t leader;
+ pid_t leader_pid;
+ uint32_t vtnr;
uid_t uid;
- int remote;
- uint32_t vtnr = 0;
- int r;
+ int remote, r;
assert(message);
assert_cc(sizeof(pid_t) == sizeof(uint32_t));
assert_cc(sizeof(uid_t) == sizeof(uint32_t));
- r = sd_bus_message_read(message,
- "uusssssussbss",
- &uid,
- &leader,
- &service,
- &type,
- &class,
- &desktop,
- &cseat,
- &vtnr,
- &tty,
- &display,
- &remote,
- &remote_user,
- &remote_host);
+ r = sd_bus_message_read(
+ message,
+ "uusssssussbss",
+ &uid,
+ &leader_pid,
+ &service,
+ &type,
+ &class,
+ &desktop,
+ &cseat,
+ &vtnr,
+ &tty,
+ &display,
+ &remote,
+ &remote_user,
+ &remote_host);
if (r < 0)
return r;
@@ -1045,7 +1106,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
userdata,
error,
uid,
- leader,
+ leader_pid,
/* pidfd = */ -EBADF,
service,
type,
@@ -1063,29 +1124,28 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
static int method_create_session_pidfd(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
- int leaderfd = -EBADF;
- uid_t uid;
- int remote;
- uint32_t vtnr = 0;
uint64_t flags;
- int r;
+ uint32_t vtnr;
+ uid_t uid;
+ int leader_fd = -EBADF, remote, r;
- r = sd_bus_message_read(message,
- "uhsssssussbsst",
- &uid,
- &leaderfd,
- &service,
- &type,
- &class,
- &desktop,
- &cseat,
- &vtnr,
- &tty,
- &display,
- &remote,
- &remote_user,
- &remote_host,
- &flags);
+ r = sd_bus_message_read(
+ message,
+ "uhsssssussbsst",
+ &uid,
+ &leader_fd,
+ &service,
+ &type,
+ &class,
+ &desktop,
+ &cseat,
+ &vtnr,
+ &tty,
+ &display,
+ &remote,
+ &remote_user,
+ &remote_host,
+ &flags);
if (r < 0)
return r;
@@ -1094,8 +1154,8 @@ static int method_create_session_pidfd(sd_bus_message *message, void *userdata,
userdata,
error,
uid,
- /* pid = */ 0,
- leaderfd,
+ /* leader_pid = */ 0,
+ leader_fd,
service,
type,
class,
@@ -1112,7 +1172,7 @@ static int method_create_session_pidfd(sd_bus_message *message, void *userdata,
static int method_release_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = ASSERT_PTR(userdata);
- Session *session;
+ Session *session, *sender_session;
const char *name;
int r;
@@ -1126,6 +1186,14 @@ static int method_release_session(sd_bus_message *message, void *userdata, sd_bu
if (r < 0)
return r;
+ r = get_sender_session(m, message, /* consult_display= */ false, error, &sender_session);
+ if (r < 0)
+ return r;
+
+ if (session != sender_session)
+ return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED,
+ "Refused to release session, since it doesn't match the one of the client");
+
r = session_release(session);
if (r < 0)
return r;
@@ -1221,11 +1289,8 @@ static int method_lock_sessions(sd_bus_message *message, void *userdata, sd_bus_
r = bus_verify_polkit_async(
message,
- CAP_SYS_ADMIN,
"org.freedesktop.login1.lock-sessions",
- NULL,
- false,
- UID_INVALID,
+ /* details= */ NULL,
&m->polkit_registry,
error);
if (r < 0)
@@ -1336,28 +1401,25 @@ static int method_terminate_seat(sd_bus_message *message, void *userdata, sd_bus
}
static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- _cleanup_free_ char *cc = NULL;
Manager *m = ASSERT_PTR(userdata);
- int r, b, interactive;
- struct passwd *pw;
- const char *path;
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
uint32_t uid, auth_uid;
+ int r, enable, interactive;
assert(message);
- r = sd_bus_message_read(message, "ubb", &uid, &b, &interactive);
+ r = sd_bus_message_read(message, "ubb", &uid, &enable, &interactive);
if (r < 0)
return r;
- r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID |
- SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
+ r = sd_bus_query_sender_creds(message,
+ SD_BUS_CREDS_EUID|SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT,
+ &creds);
if (r < 0)
return r;
if (!uid_is_valid(uid)) {
- /* Note that we get the owner UID of the session or user unit,
- * not the actual client UID here! */
+ /* Note that we get the owner UID of the session or user unit, not the actual client UID here! */
r = sd_bus_creds_get_owner_uid(creds, &uid);
if (r < 0)
return r;
@@ -1368,19 +1430,19 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu
if (r < 0)
return r;
- errno = 0;
- pw = getpwuid(uid);
- if (!pw)
- return errno_or_else(ENOENT);
+ _cleanup_free_ struct passwd *pw = NULL;
- r = bus_verify_polkit_async(
+ r = getpwuid_malloc(uid, &pw);
+ if (r < 0)
+ return r;
+
+ r = bus_verify_polkit_async_full(
message,
- CAP_SYS_ADMIN,
uid == auth_uid ? "org.freedesktop.login1.set-self-linger" :
"org.freedesktop.login1.set-user-linger",
- NULL,
- interactive,
- UID_INVALID,
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
+ interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&m->polkit_registry,
error);
if (r < 0)
@@ -1393,24 +1455,30 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu
if (r < 0)
return r;
- cc = cescape(pw->pw_name);
- if (!cc)
+ _cleanup_free_ char *escaped = NULL;
+ const char *path;
+ User *u;
+
+ escaped = cescape(pw->pw_name);
+ if (!escaped)
return -ENOMEM;
- path = strjoina("/var/lib/systemd/linger/", cc);
- if (b) {
- User *u;
+ path = strjoina("/var/lib/systemd/linger/", escaped);
+ if (enable) {
r = touch(path);
if (r < 0)
return r;
- if (manager_add_user_by_uid(m, uid, &u) >= 0)
- user_start(u);
+ if (manager_add_user_by_uid(m, uid, &u) >= 0) {
+ r = user_start(u);
+ if (r < 0) {
+ user_add_to_gc_queue(u);
+ return r;
+ }
+ }
} else {
- User *u;
-
r = unlink(path);
if (r < 0 && errno != ENOENT)
return -errno;
@@ -1541,13 +1609,12 @@ static int method_attach_device(sd_bus_message *message, void *userdata, sd_bus_
} else if (!seat_name_is_valid(seat)) /* Note that a seat does not have to exist yet for this operation to succeed */
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Seat name %s is not valid", seat);
- r = bus_verify_polkit_async(
+ r = bus_verify_polkit_async_full(
message,
- CAP_SYS_ADMIN,
"org.freedesktop.login1.attach-device",
- NULL,
- interactive,
- UID_INVALID,
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
+ interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&m->polkit_registry,
error);
if (r < 0)
@@ -1572,13 +1639,12 @@ static int method_flush_devices(sd_bus_message *message, void *userdata, sd_bus_
if (r < 0)
return r;
- r = bus_verify_polkit_async(
+ r = bus_verify_polkit_async_full(
message,
- CAP_SYS_ADMIN,
"org.freedesktop.login1.flush-devices",
- NULL,
- interactive,
- UID_INVALID,
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
+ interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&m->polkit_registry,
error);
if (r < 0)
@@ -1604,7 +1670,7 @@ static int have_multiple_sessions(
/* Check for other users' sessions. Greeter sessions do not
* count, and non-login sessions do not count either. */
HASHMAP_FOREACH(session, m->sessions)
- if (session->class == SESSION_USER &&
+ if (IN_SET(session->class, SESSION_USER, SESSION_USER_EARLY) &&
session->user->user_record->uid != uid)
return true;
@@ -1713,16 +1779,36 @@ static int send_prepare_for(Manager *m, const HandleActionData *a, bool _active)
return RET_GATHER(k, r);
}
+static int strdup_job(sd_bus_message *reply, char **ret) {
+ const char *j;
+ char *job;
+ int r;
+
+ assert(reply);
+ assert(ret);
+
+ r = sd_bus_message_read_basic(reply, 'o', &j);
+ if (r < 0)
+ return r;
+
+ job = strdup(j);
+ if (!job)
+ return -ENOMEM;
+
+ *ret = job;
+ return 0;
+}
+
static int execute_shutdown_or_sleep(
Manager *m,
const HandleActionData *a,
sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- const char *p;
int r;
assert(m);
+ assert(!m->action_job);
assert(a);
if (a->inhibit_what == INHIBIT_SHUTDOWN)
@@ -1736,15 +1822,11 @@ static int execute_shutdown_or_sleep(
&reply,
"ss", a->target, "replace-irreversibly");
if (r < 0)
- goto error;
-
- r = sd_bus_message_read(reply, "o", &p);
- if (r < 0)
- goto error;
+ goto fail;
- r = free_and_strdup(&m->action_job, p);
+ r = strdup_job(reply, &m->action_job);
if (r < 0)
- goto error;
+ goto fail;
m->delayed_action = a;
@@ -1753,7 +1835,7 @@ static int execute_shutdown_or_sleep(
return 0;
-error:
+fail:
/* Tell people that they now may take a lock again */
(void) send_prepare_for(m, a, false);
@@ -1914,13 +1996,12 @@ static int verify_shutdown_creds(
interactive = flags & SD_LOGIND_INTERACTIVE;
if (multiple_sessions) {
- r = bus_verify_polkit_async(
+ r = bus_verify_polkit_async_full(
message,
- CAP_SYS_BOOT,
a->polkit_action_multiple_sessions,
- NULL,
- interactive,
- UID_INVALID,
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
+ interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&m->polkit_registry,
error);
if (r < 0)
@@ -1935,12 +2016,12 @@ static int verify_shutdown_creds(
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED,
"Access denied to root due to active block inhibitor");
- r = bus_verify_polkit_async(message,
- CAP_SYS_BOOT,
+ r = bus_verify_polkit_async_full(
+ message,
a->polkit_action_ignore_inhibit,
- NULL,
- interactive,
- UID_INVALID,
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
+ interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&m->polkit_registry,
error);
if (r < 0)
@@ -1950,12 +2031,12 @@ static int verify_shutdown_creds(
}
if (!multiple_sessions && !blocked) {
- r = bus_verify_polkit_async(message,
- CAP_SYS_BOOT,
+ r = bus_verify_polkit_async_full(
+ message,
a->polkit_action,
- NULL,
- interactive,
- UID_INVALID,
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
+ interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&m->polkit_registry,
error);
if (r < 0)
@@ -1993,7 +2074,7 @@ static int setup_wall_message_timer(Manager *m, sd_bus_message* message) {
static int method_do_shutdown_or_sleep(
Manager *m,
sd_bus_message *message,
- const HandleActionData *a,
+ HandleAction action,
bool with_flags,
sd_bus_error *error) {
@@ -2002,7 +2083,7 @@ static int method_do_shutdown_or_sleep(
assert(m);
assert(message);
- assert(a);
+ assert(HANDLE_ACTION_IS_SHUTDOWN(action) || HANDLE_ACTION_IS_SLEEP(action));
if (with_flags) {
/* New style method: with flags parameter (and interactive bool in the bus message header) */
@@ -2017,11 +2098,11 @@ static int method_do_shutdown_or_sleep(
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
"Both reboot via kexec and soft reboot selected, which is not supported");
- if (a->handle != HANDLE_REBOOT) {
- if (flags & SD_LOGIND_REBOOT_VIA_KEXEC)
+ if (action != HANDLE_REBOOT) {
+ if (FLAGS_SET(flags, SD_LOGIND_REBOOT_VIA_KEXEC))
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
"Reboot via kexec option is only applicable with reboot operations");
- if ((flags & SD_LOGIND_SOFT_REBOOT) || (flags & SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP))
+ if (flags & (SD_LOGIND_SOFT_REBOOT|SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP))
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
"Soft reboot option is only applicable with reboot operations");
}
@@ -2038,20 +2119,32 @@ static int method_do_shutdown_or_sleep(
flags = interactive ? SD_LOGIND_INTERACTIVE : 0;
}
- if ((flags & SD_LOGIND_SOFT_REBOOT) ||
- ((flags & SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP) && path_is_os_tree("/run/nextroot") > 0))
+ const HandleActionData *a = NULL;
+
+ if (FLAGS_SET(flags, SD_LOGIND_SOFT_REBOOT) ||
+ (FLAGS_SET(flags, SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP) && path_is_os_tree("/run/nextroot") > 0))
a = handle_action_lookup(HANDLE_SOFT_REBOOT);
- else if ((flags & SD_LOGIND_REBOOT_VIA_KEXEC) && kexec_loaded())
+ else if (FLAGS_SET(flags, SD_LOGIND_REBOOT_VIA_KEXEC) && kexec_loaded())
a = handle_action_lookup(HANDLE_KEXEC);
- /* Don't allow multiple jobs being executed at the same time */
- if (m->delayed_action)
- return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS,
- "There's already a shutdown or sleep operation in progress");
+ if (action == HANDLE_SLEEP) {
+ HandleAction selected;
+
+ selected = handle_action_sleep_select(m);
+ if (selected < 0)
+ return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
+ "None of the configured sleep operations are supported");
+
+ assert_se(a = handle_action_lookup(selected));
- if (a->sleep_operation >= 0) {
+ } else if (HANDLE_ACTION_IS_SLEEP(action)) {
SleepSupport support;
+ assert_se(a = handle_action_lookup(action));
+
+ assert(a->sleep_operation >= 0);
+ assert(a->sleep_operation < _SLEEP_OPERATION_MAX);
+
r = sleep_supported_full(a->sleep_operation, &support);
if (r < 0)
return r;
@@ -2074,6 +2167,14 @@ static int method_do_shutdown_or_sleep(
return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
"Not running on EFI and resume= is not set, or noresume is set. No available method to resume from hibernation");
+ case SLEEP_RESUME_DEVICE_MISSING:
+ return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
+ "Specified resume device is missing or is not an active swap device");
+
+ case SLEEP_RESUME_MISCONFIGURED:
+ return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
+ "Invalid resume config: resume= is not populated yet resume_offset= is");
+
case SLEEP_NOT_ENOUGH_SWAP_SPACE:
return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
"Not enough suitable swap space for hibernation available on compatible block devices and file systems");
@@ -2082,18 +2183,25 @@ static int method_do_shutdown_or_sleep(
assert_not_reached();
}
- }
+ } else if (!a)
+ assert_se(a = handle_action_lookup(action));
r = verify_shutdown_creds(m, message, a, flags, error);
if (r != 0)
return r;
+ if (m->delayed_action)
+ return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS,
+ "Action %s already in progress, refusing requested %s operation.",
+ handle_action_to_string(m->delayed_action->handle),
+ handle_action_to_string(a->handle));
+
/* reset case we're shorting a scheduled shutdown */
m->unlink_nologin = false;
reset_scheduled_shutdown(m);
m->scheduled_shutdown_timeout = 0;
- m->scheduled_shutdown_action = a;
+ m->scheduled_shutdown_action = action;
(void) setup_wall_message_timer(m, message);
@@ -2109,7 +2217,7 @@ static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error
return method_do_shutdown_or_sleep(
m, message,
- handle_action_lookup(HANDLE_POWEROFF),
+ HANDLE_POWEROFF,
sd_bus_message_is_method_call(message, NULL, "PowerOffWithFlags"),
error);
}
@@ -2119,7 +2227,7 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *
return method_do_shutdown_or_sleep(
m, message,
- handle_action_lookup(HANDLE_REBOOT),
+ HANDLE_REBOOT,
sd_bus_message_is_method_call(message, NULL, "RebootWithFlags"),
error);
}
@@ -2129,7 +2237,7 @@ static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *er
return method_do_shutdown_or_sleep(
m, message,
- handle_action_lookup(HANDLE_HALT),
+ HANDLE_HALT,
sd_bus_message_is_method_call(message, NULL, "HaltWithFlags"),
error);
}
@@ -2139,7 +2247,7 @@ static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error
return method_do_shutdown_or_sleep(
m, message,
- handle_action_lookup(HANDLE_SUSPEND),
+ HANDLE_SUSPEND,
sd_bus_message_is_method_call(message, NULL, "SuspendWithFlags"),
error);
}
@@ -2149,7 +2257,7 @@ static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_erro
return method_do_shutdown_or_sleep(
m, message,
- handle_action_lookup(HANDLE_HIBERNATE),
+ HANDLE_HIBERNATE,
sd_bus_message_is_method_call(message, NULL, "HibernateWithFlags"),
error);
}
@@ -2159,7 +2267,7 @@ static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_e
return method_do_shutdown_or_sleep(
m, message,
- handle_action_lookup(HANDLE_HYBRID_SLEEP),
+ HANDLE_HYBRID_SLEEP,
sd_bus_message_is_method_call(message, NULL, "HybridSleepWithFlags"),
error);
}
@@ -2169,17 +2277,27 @@ static int method_suspend_then_hibernate(sd_bus_message *message, void *userdata
return method_do_shutdown_or_sleep(
m, message,
- handle_action_lookup(HANDLE_SUSPEND_THEN_HIBERNATE),
+ HANDLE_SUSPEND_THEN_HIBERNATE,
sd_bus_message_is_method_call(message, NULL, "SuspendThenHibernateWithFlags"),
error);
}
+static int method_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+
+ return method_do_shutdown_or_sleep(
+ m, message,
+ HANDLE_SLEEP,
+ /* with_flags = */ true,
+ error);
+}
+
static int nologin_timeout_handler(
sd_event_source *s,
uint64_t usec,
void *userdata) {
- Manager *m = userdata;
+ Manager *m = ASSERT_PTR(userdata);
log_info("Creating /run/nologin, blocking further logins...");
@@ -2194,79 +2312,25 @@ static usec_t nologin_timeout_usec(usec_t elapse) {
return LESS_BY(elapse, 5 * USEC_PER_MINUTE);
}
-void manager_load_scheduled_shutdown(Manager *m) {
- _cleanup_fclose_ FILE *f = NULL;
- _cleanup_free_ char *usec = NULL,
- *warn_wall = NULL,
- *mode = NULL,
- *wall_message = NULL,
- *uid = NULL,
- *tty = NULL;
- int r;
-
+static void reset_scheduled_shutdown(Manager *m) {
assert(m);
- r = parse_env_file(f, SHUTDOWN_SCHEDULE_FILE,
- "USEC", &usec,
- "WARN_WALL", &warn_wall,
- "MODE", &mode,
- "WALL_MESSAGE", &wall_message,
- "UID", &uid,
- "TTY", &tty);
-
- /* reset will delete the file */
- reset_scheduled_shutdown(m);
-
- if (r == -ENOENT)
- return;
- if (r < 0)
- return (void) log_debug_errno(r, "Failed to parse " SHUTDOWN_SCHEDULE_FILE ": %m");
-
- HandleAction handle = handle_action_from_string(mode);
- if (handle < 0)
- return (void) log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse scheduled shutdown type: %s", mode);
-
- if (!usec)
- return (void) log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "USEC is required");
- if (deserialize_usec(usec, &m->scheduled_shutdown_timeout) < 0)
- return;
-
- /* assign parsed type only after we know usec is also valid */
- m->scheduled_shutdown_action = handle_action_lookup(handle);
-
- if (warn_wall) {
- r = parse_boolean(warn_wall);
- if (r < 0)
- log_debug_errno(r, "Failed to parse enabling wall messages");
- else
- m->enable_wall_messages = r;
- }
+ m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
+ m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source);
+ m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
- if (wall_message) {
- _cleanup_free_ char *unescaped = NULL;
- r = cunescape(wall_message, 0, &unescaped);
- if (r < 0)
- log_debug_errno(r, "Failed to parse wall message: %s", wall_message);
- else
- free_and_replace(m->wall_message, unescaped);
- }
+ m->scheduled_shutdown_action = _HANDLE_ACTION_INVALID;
+ m->scheduled_shutdown_timeout = USEC_INFINITY;
+ m->scheduled_shutdown_uid = UID_INVALID;
+ m->scheduled_shutdown_tty = mfree(m->scheduled_shutdown_tty);
+ m->shutdown_dry_run = false;
- if (uid) {
- r = parse_uid(uid, &m->scheduled_shutdown_uid);
- if (r < 0)
- log_debug_errno(r, "Failed to parse wall uid: %s", uid);
+ if (m->unlink_nologin) {
+ (void) unlink_or_warn("/run/nologin");
+ m->unlink_nologin = false;
}
- free_and_replace(m->scheduled_shutdown_tty, tty);
-
- r = manager_setup_shutdown_timers(m);
- if (r < 0)
- return reset_scheduled_shutdown(m);
-
- (void) manager_setup_wall_message_timer(m);
- (void) update_schedule_file(m);
-
- return;
+ (void) unlink(SHUTDOWN_SCHEDULE_FILE);
}
static int update_schedule_file(Manager *m) {
@@ -2275,7 +2339,7 @@ static int update_schedule_file(Manager *m) {
int r;
assert(m);
- assert(m->scheduled_shutdown_action);
+ assert(handle_action_valid(m->scheduled_shutdown_action));
r = mkdir_parents_label(SHUTDOWN_SCHEDULE_FILE, 0755);
if (r < 0)
@@ -2289,7 +2353,7 @@ static int update_schedule_file(Manager *m) {
serialize_usec(f, "USEC", m->scheduled_shutdown_timeout);
serialize_item_format(f, "WARN_WALL", "%s", one_zero(m->enable_wall_messages));
- serialize_item_format(f, "MODE", "%s", handle_action_to_string(m->scheduled_shutdown_action->handle));
+ serialize_item_format(f, "MODE", "%s", handle_action_to_string(m->scheduled_shutdown_action));
serialize_item_format(f, "UID", UID_FMT, m->scheduled_shutdown_uid);
if (m->scheduled_shutdown_tty)
@@ -2319,44 +2383,23 @@ fail:
return log_error_errno(r, "Failed to write information about scheduled shutdowns: %m");
}
-static void reset_scheduled_shutdown(Manager *m) {
- assert(m);
-
- m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
- m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source);
- m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
-
- m->scheduled_shutdown_action = NULL;
- m->scheduled_shutdown_timeout = USEC_INFINITY;
- m->scheduled_shutdown_uid = UID_INVALID;
- m->scheduled_shutdown_tty = mfree(m->scheduled_shutdown_tty);
- m->shutdown_dry_run = false;
-
- if (m->unlink_nologin) {
- (void) unlink_or_warn("/run/nologin");
- m->unlink_nologin = false;
- }
-
- (void) unlink(SHUTDOWN_SCHEDULE_FILE);
-}
-
static int manager_scheduled_shutdown_handler(
sd_event_source *s,
uint64_t usec,
void *userdata) {
- const HandleActionData *a = NULL;
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
Manager *m = ASSERT_PTR(userdata);
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ const HandleActionData *a;
int r;
- a = m->scheduled_shutdown_action;
- assert(a);
+ assert_se(a = handle_action_lookup(m->scheduled_shutdown_action));
/* Don't allow multiple jobs being executed at the same time */
if (m->delayed_action) {
- r = -EALREADY;
- log_error("Scheduled shutdown to %s failed: shutdown or sleep operation already in progress", a->target);
+ r = log_error_errno(SYNTHETIC_ERRNO(EALREADY),
+ "Scheduled shutdown to %s failed: shutdown or sleep operation already in progress.",
+ a->target);
goto error;
}
@@ -2373,7 +2416,7 @@ static int manager_scheduled_shutdown_handler(
return 0;
}
- r = bus_manager_shutdown_or_sleep_now_or_later(m, m->scheduled_shutdown_action, &error);
+ r = bus_manager_shutdown_or_sleep_now_or_later(m, a, &error);
if (r < 0) {
log_error_errno(r, "Scheduled shutdown to %s failed: %m", a->target);
goto error;
@@ -2386,6 +2429,111 @@ error:
return r;
}
+static int manager_setup_shutdown_timers(Manager* m) {
+ int r;
+
+ assert(m);
+
+ r = event_reset_time(m->event, &m->scheduled_shutdown_timeout_source,
+ CLOCK_REALTIME,
+ m->scheduled_shutdown_timeout, 0,
+ manager_scheduled_shutdown_handler, m,
+ 0, "scheduled-shutdown-timeout", true);
+ if (r < 0)
+ goto fail;
+
+ r = event_reset_time(m->event, &m->nologin_timeout_source,
+ CLOCK_REALTIME,
+ nologin_timeout_usec(m->scheduled_shutdown_timeout), 0,
+ nologin_timeout_handler, m,
+ 0, "nologin-timeout", true);
+ if (r < 0)
+ goto fail;
+
+ return 0;
+
+fail:
+ m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
+ m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
+
+ return r;
+}
+
+void manager_load_scheduled_shutdown(Manager *m) {
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char *usec = NULL,
+ *warn_wall = NULL,
+ *mode = NULL,
+ *wall_message = NULL,
+ *uid = NULL,
+ *tty = NULL;
+ int r;
+
+ assert(m);
+
+ r = parse_env_file(f, SHUTDOWN_SCHEDULE_FILE,
+ "USEC", &usec,
+ "WARN_WALL", &warn_wall,
+ "MODE", &mode,
+ "WALL_MESSAGE", &wall_message,
+ "UID", &uid,
+ "TTY", &tty);
+
+ /* reset will delete the file */
+ reset_scheduled_shutdown(m);
+
+ if (r == -ENOENT)
+ return;
+ if (r < 0)
+ return (void) log_debug_errno(r, "Failed to parse " SHUTDOWN_SCHEDULE_FILE ": %m");
+
+ HandleAction handle = handle_action_from_string(mode);
+ if (handle < 0)
+ return (void) log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse scheduled shutdown type: %s", mode);
+
+ if (!usec)
+ return (void) log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "USEC is required");
+ if (deserialize_usec(usec, &m->scheduled_shutdown_timeout) < 0)
+ return;
+
+ /* assign parsed type only after we know usec is also valid */
+ m->scheduled_shutdown_action = handle;
+
+ if (warn_wall) {
+ r = parse_boolean(warn_wall);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse enabling wall messages");
+ else
+ m->enable_wall_messages = r;
+ }
+
+ if (wall_message) {
+ _cleanup_free_ char *unescaped = NULL;
+ r = cunescape(wall_message, 0, &unescaped);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse wall message: %s", wall_message);
+ else
+ free_and_replace(m->wall_message, unescaped);
+ }
+
+ if (uid) {
+ r = parse_uid(uid, &m->scheduled_shutdown_uid);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse wall uid: %s", uid);
+ }
+
+ free_and_replace(m->scheduled_shutdown_tty, tty);
+
+ r = manager_setup_shutdown_timers(m);
+ if (r < 0)
+ return reset_scheduled_shutdown(m);
+
+ (void) manager_setup_wall_message_timer(m);
+ (void) update_schedule_file(m);
+
+ return;
+}
+
static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = ASSERT_PTR(userdata);
HandleAction handle;
@@ -2410,15 +2558,14 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
if (!HANDLE_ACTION_IS_SHUTDOWN(handle))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type: %s", type);
- a = handle_action_lookup(handle);
- assert(a);
+ assert_se(a = handle_action_lookup(handle));
assert(a->polkit_action);
r = verify_shutdown_creds(m, message, a, 0, error);
if (r != 0)
return r;
- m->scheduled_shutdown_action = a;
+ m->scheduled_shutdown_action = handle;
m->shutdown_dry_run = dry_run;
m->scheduled_shutdown_timeout = elapse;
@@ -2438,34 +2585,6 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
return sd_bus_reply_method_return(message, NULL);
}
-static int manager_setup_shutdown_timers(Manager* m) {
- int r;
-
- r = event_reset_time(m->event, &m->scheduled_shutdown_timeout_source,
- CLOCK_REALTIME,
- m->scheduled_shutdown_timeout, 0,
- manager_scheduled_shutdown_handler, m,
- 0, "scheduled-shutdown-timeout", true);
- if (r < 0)
- goto fail;
-
- r = event_reset_time(m->event, &m->nologin_timeout_source,
- CLOCK_REALTIME,
- nologin_timeout_usec(m->scheduled_shutdown_timeout), 0,
- nologin_timeout_handler, m,
- 0, "nologin-timeout", true);
- if (r < 0)
- goto fail;
-
- return 0;
-
-fail:
- m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
- m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
-
- return r;
-}
-
static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = ASSERT_PTR(userdata);
const HandleActionData *a;
@@ -2474,22 +2593,18 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd
assert(message);
- cancelled = m->scheduled_shutdown_action
- && !IN_SET(m->scheduled_shutdown_action->handle, HANDLE_IGNORE, _HANDLE_ACTION_INVALID);
+ cancelled = handle_action_valid(m->scheduled_shutdown_action) && m->scheduled_shutdown_action != HANDLE_IGNORE;
if (!cancelled)
return sd_bus_reply_method_return(message, "b", false);
- a = m->scheduled_shutdown_action;
+ assert_se(a = handle_action_lookup(m->scheduled_shutdown_action));
if (!a->polkit_action)
return sd_bus_error_set(error, SD_BUS_ERROR_AUTH_FAILED, "Unsupported shutdown type");
r = bus_verify_polkit_async(
message,
- CAP_SYS_BOOT,
a->polkit_action,
- NULL,
- false,
- UID_INVALID,
+ /* details= */ NULL,
&m->polkit_registry,
error);
if (r < 0)
@@ -2528,28 +2643,46 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd
static int method_can_shutdown_or_sleep(
Manager *m,
sd_bus_message *message,
- const HandleActionData *a,
+ HandleAction action,
sd_bus_error *error) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- bool multiple_sessions, challenge, blocked;
+ bool multiple_sessions, challenge, blocked, check_unit_state = true;
+ const HandleActionData *a;
const char *result = NULL;
uid_t uid;
int r;
assert(m);
assert(message);
- assert(a);
+ assert(HANDLE_ACTION_IS_SHUTDOWN(action) || HANDLE_ACTION_IS_SLEEP(action));
+
+ if (action == HANDLE_SLEEP) {
+ HandleAction selected;
+
+ selected = handle_action_sleep_select(m);
+ if (selected < 0)
+ return sd_bus_reply_method_return(message, "s", "na");
+
+ check_unit_state = false; /* Already handled by handle_action_sleep_select */
+
+ assert_se(a = handle_action_lookup(selected));
- if (a->sleep_operation >= 0) {
+ } else if (HANDLE_ACTION_IS_SLEEP(action)) {
SleepSupport support;
+ assert_se(a = handle_action_lookup(action));
+
+ assert(a->sleep_operation >= 0);
+ assert(a->sleep_operation < _SLEEP_OPERATION_MAX);
+
r = sleep_supported_full(a->sleep_operation, &support);
if (r < 0)
return r;
if (r == 0)
return sd_bus_reply_method_return(message, "s", support == SLEEP_DISABLED ? "no" : "na");
- }
+ } else
+ assert_se(a = handle_action_lookup(action));
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
if (r < 0)
@@ -2566,27 +2699,27 @@ static int method_can_shutdown_or_sleep(
multiple_sessions = r > 0;
blocked = manager_is_inhibited(m, a->inhibit_what, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
- HandleAction handle = handle_action_from_string(sleep_operation_to_string(a->sleep_operation));
- if (handle >= 0) {
- const char *target;
+ if (check_unit_state && a->target) {
+ _cleanup_free_ char *load_state = NULL;
- target = handle_action_lookup(handle)->target;
- if (target) {
- _cleanup_free_ char *load_state = NULL;
-
- r = unit_load_state(m->bus, target, &load_state);
- if (r < 0)
- return r;
+ r = unit_load_state(m->bus, a->target, &load_state);
+ if (r < 0)
+ return r;
- if (!streq(load_state, "loaded")) {
- result = "no";
- goto finish;
- }
+ if (!streq(load_state, "loaded")) {
+ result = "no";
+ goto finish;
}
}
if (multiple_sessions) {
- r = bus_test_polkit(message, CAP_SYS_BOOT, a->polkit_action_multiple_sessions, NULL, UID_INVALID, &challenge, error);
+ r = bus_test_polkit(
+ message,
+ a->polkit_action_multiple_sessions,
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
+ &challenge,
+ error);
if (r < 0)
return r;
@@ -2599,7 +2732,13 @@ static int method_can_shutdown_or_sleep(
}
if (blocked) {
- r = bus_test_polkit(message, CAP_SYS_BOOT, a->polkit_action_ignore_inhibit, NULL, UID_INVALID, &challenge, error);
+ r = bus_test_polkit(
+ message,
+ a->polkit_action_ignore_inhibit,
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
+ &challenge,
+ error);
if (r < 0)
return r;
@@ -2617,7 +2756,13 @@ static int method_can_shutdown_or_sleep(
/* If neither inhibit nor multiple sessions
* apply then just check the normal policy */
- r = bus_test_polkit(message, CAP_SYS_BOOT, a->polkit_action, NULL, UID_INVALID, &challenge, error);
+ r = bus_test_polkit(
+ message,
+ a->polkit_action,
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
+ &challenge,
+ error);
if (r < 0)
return r;
@@ -2636,57 +2781,49 @@ static int method_can_shutdown_or_sleep(
static int method_can_poweroff(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
- return method_can_shutdown_or_sleep(
- m, message, handle_action_lookup(HANDLE_POWEROFF),
- error);
+ return method_can_shutdown_or_sleep(m, message, HANDLE_POWEROFF, error);
}
static int method_can_reboot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
- return method_can_shutdown_or_sleep(
- m, message, handle_action_lookup(HANDLE_REBOOT),
- error);
+ return method_can_shutdown_or_sleep(m, message, HANDLE_REBOOT, error);
}
static int method_can_halt(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
- return method_can_shutdown_or_sleep(
- m, message, handle_action_lookup(HANDLE_HALT),
- error);
+ return method_can_shutdown_or_sleep(m, message, HANDLE_HALT, error);
}
static int method_can_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
- return method_can_shutdown_or_sleep(
- m, message, handle_action_lookup(HANDLE_SUSPEND),
- error);
+ return method_can_shutdown_or_sleep(m, message, HANDLE_SUSPEND, error);
}
static int method_can_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
- return method_can_shutdown_or_sleep(
- m, message, handle_action_lookup(HANDLE_HIBERNATE),
- error);
+ return method_can_shutdown_or_sleep(m, message, HANDLE_HIBERNATE, error);
}
static int method_can_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
- return method_can_shutdown_or_sleep(
- m, message, handle_action_lookup(HANDLE_HYBRID_SLEEP),
- error);
+ return method_can_shutdown_or_sleep(m, message, HANDLE_HYBRID_SLEEP, error);
}
static int method_can_suspend_then_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
- return method_can_shutdown_or_sleep(
- m, message, handle_action_lookup(HANDLE_SUSPEND_THEN_HIBERNATE),
- error);
+ return method_can_shutdown_or_sleep(m, message, HANDLE_SUSPEND_THEN_HIBERNATE, error);
+}
+
+static int method_can_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+
+ return method_can_shutdown_or_sleep(m, message, HANDLE_SLEEP, error);
}
static int property_get_reboot_parameter(
@@ -2726,6 +2863,9 @@ static int method_set_reboot_parameter(
if (r < 0)
return r;
+ if (!reboot_parameter_is_valid(arg))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid reboot parameter '%s'.", arg);
+
r = detect_container();
if (r < 0)
return r;
@@ -2733,14 +2873,12 @@ static int method_set_reboot_parameter(
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
"Reboot parameter not supported in containers, refusing.");
- r = bus_verify_polkit_async(message,
- CAP_SYS_ADMIN,
- "org.freedesktop.login1.set-reboot-parameter",
- NULL,
- false,
- UID_INVALID,
- &m->polkit_registry,
- error);
+ r = bus_verify_polkit_async(
+ message,
+ "org.freedesktop.login1.set-reboot-parameter",
+ /* details= */ NULL,
+ &m->polkit_registry,
+ error);
if (r < 0)
return r;
if (r == 0)
@@ -2771,10 +2909,9 @@ static int method_can_reboot_parameter(
return return_test_polkit(
message,
- CAP_SYS_ADMIN,
"org.freedesktop.login1.set-reboot-parameter",
- NULL,
- UID_INVALID,
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
error);
}
@@ -2852,14 +2989,12 @@ static int method_set_reboot_to_firmware_setup(
/* non-EFI case: $SYSTEMD_REBOOT_TO_FIRMWARE_SETUP is set to on */
use_efi = false;
- r = bus_verify_polkit_async(message,
- CAP_SYS_ADMIN,
- "org.freedesktop.login1.set-reboot-to-firmware-setup",
- NULL,
- false,
- UID_INVALID,
- &m->polkit_registry,
- error);
+ r = bus_verify_polkit_async(
+ message,
+ "org.freedesktop.login1.set-reboot-to-firmware-setup",
+ /* details= */ NULL,
+ &m->polkit_registry,
+ error);
if (r < 0)
return r;
if (r == 0)
@@ -2916,10 +3051,9 @@ static int method_can_reboot_to_firmware_setup(
return return_test_polkit(
message,
- CAP_SYS_ADMIN,
"org.freedesktop.login1.set-reboot-to-firmware-setup",
- NULL,
- UID_INVALID,
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
error);
}
@@ -3016,14 +3150,12 @@ static int method_set_reboot_to_boot_loader_menu(
/* non-EFI case: $SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU is set to on */
use_efi = false;
- r = bus_verify_polkit_async(message,
- CAP_SYS_ADMIN,
- "org.freedesktop.login1.set-reboot-to-boot-loader-menu",
- NULL,
- false,
- UID_INVALID,
- &m->polkit_registry,
- error);
+ r = bus_verify_polkit_async(
+ message,
+ "org.freedesktop.login1.set-reboot-to-boot-loader-menu",
+ /* details= */ NULL,
+ &m->polkit_registry,
+ error);
if (r < 0)
return r;
if (r == 0)
@@ -3091,10 +3223,9 @@ static int method_can_reboot_to_boot_loader_menu(
return return_test_polkit(
message,
- CAP_SYS_ADMIN,
"org.freedesktop.login1.set-reboot-to-boot-loader-menu",
- NULL,
- UID_INVALID,
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
error);
}
@@ -3215,14 +3346,12 @@ static int method_set_reboot_to_boot_loader_entry(
/* non-EFI case: $SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY is set to on */
use_efi = false;
- r = bus_verify_polkit_async(message,
- CAP_SYS_ADMIN,
- "org.freedesktop.login1.set-reboot-to-boot-loader-entry",
- NULL,
- false,
- UID_INVALID,
- &m->polkit_registry,
- error);
+ r = bus_verify_polkit_async(
+ message,
+ "org.freedesktop.login1.set-reboot-to-boot-loader-entry",
+ /* details= */ NULL,
+ &m->polkit_registry,
+ error);
if (r < 0)
return r;
if (r == 0)
@@ -3283,10 +3412,9 @@ static int method_can_reboot_to_boot_loader_entry(
return return_test_polkit(
message,
- CAP_SYS_ADMIN,
"org.freedesktop.login1.set-reboot-to-boot-loader-entry",
- NULL,
- UID_INVALID,
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
error);
}
@@ -3357,14 +3485,12 @@ static int method_set_wall_message(
m->enable_wall_messages == enable_wall_messages)
goto done;
- r = bus_verify_polkit_async(message,
- CAP_SYS_ADMIN,
- "org.freedesktop.login1.set-wall-message",
- NULL,
- false,
- UID_INVALID,
- &m->polkit_registry,
- error);
+ r = bus_verify_polkit_async(
+ message,
+ "org.freedesktop.login1.set-wall-message",
+ /* details= */ NULL,
+ &m->polkit_registry,
+ error);
if (r < 0)
return r;
if (r == 0)
@@ -3389,7 +3515,6 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
Manager *m = ASSERT_PTR(userdata);
InhibitMode mm;
InhibitWhat w;
- pid_t pid;
uid_t uid;
int r;
@@ -3424,7 +3549,6 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
r = bus_verify_polkit_async(
message,
- CAP_SYS_BOOT,
w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
@@ -3433,9 +3557,7 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
w == INHIBIT_HANDLE_REBOOT_KEY ? "org.freedesktop.login1.inhibit-handle-reboot-key" :
w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
"org.freedesktop.login1.inhibit-handle-lid-switch",
- NULL,
- false,
- UID_INVALID,
+ /* details= */ NULL,
&m->polkit_registry,
error);
if (r < 0)
@@ -3443,7 +3565,7 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID, &creds);
+ r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_PIDFD, &creds);
if (r < 0)
return r;
@@ -3451,14 +3573,10 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
if (r < 0)
return r;
- r = sd_bus_creds_get_pid(creds, &pid);
+ r = bus_creds_get_pidref(creds, &pidref);
if (r < 0)
return r;
- r = pidref_set_pid(&pidref, pid);
- if (r < 0)
- return sd_bus_error_set_errnof(error, r, "Failed pin source process "PID_FMT": %m", pid);
-
if (hashmap_size(m->inhibitors) >= m->inhibitors_max)
return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED,
"Maximum number of inhibitors (%" PRIu64 ") reached, refusing further inhibitors.",
@@ -3521,6 +3639,7 @@ static const sd_bus_vtable manager_vtable[] = {
SD_BUS_PROPERTY("DelayInhibited", "s", property_get_inhibited, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("InhibitDelayMaxUSec", "t", NULL, offsetof(Manager, inhibit_delay_max), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("UserStopDelayUSec", "t", NULL, offsetof(Manager, user_stop_delay), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("SleepOperation", "as", property_get_sleep_operations, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HandlePowerKey", "s", property_get_handle_action, offsetof(Manager, handle_power_key), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HandlePowerKeyLongPress", "s", property_get_handle_action, offsetof(Manager, handle_power_key_long_press), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HandleRebootKey", "s", property_get_handle_action, offsetof(Manager, handle_reboot_key), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -3581,6 +3700,11 @@ static const sd_bus_vtable manager_vtable[] = {
SD_BUS_RESULT("a(susso)", sessions),
method_list_sessions,
SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("ListSessionsEx",
+ SD_BUS_NO_ARGS,
+ SD_BUS_RESULT("a(sussussbto)", sessions),
+ method_list_sessions_ex,
+ SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("ListUsers",
SD_BUS_NO_ARGS,
SD_BUS_RESULT("a(uso)", users),
@@ -3651,7 +3775,7 @@ static const sd_bus_vtable manager_vtable[] = {
SD_BUS_ARGS("s", session_id),
SD_BUS_NO_RESULT,
method_release_session,
- 0),
+ SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("ActivateSession",
SD_BUS_ARGS("s", session_id),
SD_BUS_NO_RESULT,
@@ -3792,6 +3916,11 @@ static const sd_bus_vtable manager_vtable[] = {
SD_BUS_NO_RESULT,
method_suspend_then_hibernate,
SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("Sleep",
+ SD_BUS_ARGS("t", flags),
+ SD_BUS_NO_RESULT,
+ method_sleep,
+ SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("CanPowerOff",
SD_BUS_NO_ARGS,
SD_BUS_RESULT("s", result),
@@ -3827,6 +3956,11 @@ static const sd_bus_vtable manager_vtable[] = {
SD_BUS_RESULT("s", result),
method_can_suspend_then_hibernate,
SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("CanSleep",
+ SD_BUS_NO_ARGS,
+ SD_BUS_RESULT("s", result),
+ method_can_sleep,
+ SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("ScheduleShutdown",
SD_BUS_ARGS("s", type, "t", usec),
SD_BUS_NO_RESULT,
@@ -3928,30 +4062,32 @@ const BusObjectImplementation manager_object = {
&user_object),
};
-static int session_jobs_reply(Session *s, uint32_t jid, const char *unit, const char *result) {
+static void session_jobs_reply(Session *s, uint32_t jid, const char *unit, const char *result) {
assert(s);
assert(unit);
if (!s->started)
- return 0;
+ return;
if (result && !streq(result, "done")) {
_cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED,
"Job %u for unit '%s' failed with '%s'", jid, unit, result);
- return session_send_create_reply(s, &e);
+
+ (void) session_send_create_reply(s, &e);
+ (void) session_send_upgrade_reply(s, &e);
+ return;
}
- return session_send_create_reply(s, NULL);
+ (void) session_send_create_reply(s, /* error= */ NULL);
+ (void) session_send_upgrade_reply(s, /* error= */ NULL);
}
int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- const char *path, *result, *unit;
Manager *m = ASSERT_PTR(userdata);
- Session *session;
+ const char *path, *result, *unit;
uint32_t id;
- User *user;
int r;
assert(message);
@@ -3974,11 +4110,14 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
return 0;
}
+ Session *session;
+ User *user;
+
session = hashmap_get(m->session_units, unit);
if (session) {
if (streq_ptr(path, session->scope_job)) {
session->scope_job = mfree(session->scope_job);
- (void) session_jobs_reply(session, id, unit, result);
+ session_jobs_reply(session, id, unit, result);
session_save(session);
user_save(session->user);
@@ -3989,13 +4128,20 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
user = hashmap_get(m->user_units, unit);
if (user) {
- if (streq_ptr(path, user->service_job)) {
- user->service_job = mfree(user->service_job);
-
- LIST_FOREACH(sessions_by_user, s, user->sessions)
- (void) session_jobs_reply(s, id, unit, NULL /* don't propagate user service failures to the client */);
-
- user_save(user);
+ /* If the user is stopping, we're tracking stop jobs here. So don't send reply. */
+ if (!user->stopping) {
+ char **user_job;
+ FOREACH_ARGUMENT(user_job, &user->runtime_dir_job, &user->service_manager_job)
+ if (streq_ptr(path, *user_job)) {
+ *user_job = mfree(*user_job);
+
+ LIST_FOREACH(sessions_by_user, s, user->sessions)
+ /* Don't propagate user service failures to the client */
+ session_jobs_reply(s, id, unit, /* error = */ NULL);
+
+ user_save(user);
+ break;
+ }
}
user_add_to_gc_queue(user);
@@ -4102,49 +4248,34 @@ int manager_send_changed(Manager *manager, const char *property, ...) {
l);
}
-static int strdup_job(sd_bus_message *reply, char **job) {
- const char *j;
- char *copy;
- int r;
-
- r = sd_bus_message_read(reply, "o", &j);
- if (r < 0)
- return r;
-
- copy = strdup(j);
- if (!copy)
- return -ENOMEM;
-
- *job = copy;
- return 1;
-}
-
int manager_start_scope(
Manager *manager,
const char *scope,
const PidRef *pidref,
+ bool allow_pidfd,
const char *slice,
const char *description,
- char **wants,
- char **after,
+ const char * const *requires,
+ const char * const *extra_after,
const char *requires_mounts_for,
sd_bus_message *more_properties,
sd_bus_error *error,
- char **job) {
+ char **ret_job) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
int r;
assert(manager);
assert(scope);
assert(pidref_is_set(pidref));
- assert(job);
+ assert(ret_job);
r = bus_message_new_method_call(manager->bus, &m, bus_systemd_mgr, "StartTransientUnit");
if (r < 0)
return r;
- r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
+ r = sd_bus_message_append(m, "ss", scope, "fail");
if (r < 0)
return r;
@@ -4164,13 +4295,17 @@ int manager_start_scope(
return r;
}
- STRV_FOREACH(i, wants) {
- r = sd_bus_message_append(m, "(sv)", "Wants", "as", 1, *i);
+ STRV_FOREACH(i, requires) {
+ r = sd_bus_message_append(m, "(sv)", "Requires", "as", 1, *i);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "(sv)", "After", "as", 1, *i);
if (r < 0)
return r;
}
- STRV_FOREACH(i, after) {
+ STRV_FOREACH(i, extra_after) {
r = sd_bus_message_append(m, "(sv)", "After", "as", 1, *i);
if (r < 0)
return r;
@@ -4188,7 +4323,7 @@ int manager_start_scope(
if (r < 0)
return r;
- r = bus_append_scope_pidref(m, pidref);
+ r = bus_append_scope_pidref(m, pidref, allow_pidfd);
if (r < 0)
return r;
@@ -4218,20 +4353,39 @@ int manager_start_scope(
if (r < 0)
return r;
- r = sd_bus_call(manager->bus, m, 0, error, &reply);
- if (r < 0)
- return r;
+ r = sd_bus_call(manager->bus, m, 0, &e, &reply);
+ if (r < 0) {
+ /* If this failed with a property we couldn't write, this is quite likely because the server
+ * doesn't support PIDFDs yet, let's try without. */
+ if (allow_pidfd &&
+ sd_bus_error_has_names(&e, SD_BUS_ERROR_UNKNOWN_PROPERTY, SD_BUS_ERROR_PROPERTY_READ_ONLY))
+ return manager_start_scope(
+ manager,
+ scope,
+ pidref,
+ /* allow_pidfd = */ false,
+ slice,
+ description,
+ requires,
+ extra_after,
+ requires_mounts_for,
+ more_properties,
+ error,
+ ret_job);
+
+ return sd_bus_error_move(error, &e);
+ }
- return strdup_job(reply, job);
+ return strdup_job(reply, ret_job);
}
-int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
+int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **ret_job) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
int r;
assert(manager);
assert(unit);
- assert(job);
+ assert(ret_job);
r = bus_call_method(
manager->bus,
@@ -4243,11 +4397,18 @@ int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error,
if (r < 0)
return r;
- return strdup_job(reply, job);
+ return strdup_job(reply, ret_job);
}
-int manager_stop_unit(Manager *manager, const char *unit, const char *job_mode, sd_bus_error *error, char **ret_job) {
+int manager_stop_unit(
+ Manager *manager,
+ const char *unit,
+ const char *job_mode,
+ sd_bus_error *ret_error,
+ char **ret_job) {
+
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(manager);
@@ -4258,22 +4419,24 @@ int manager_stop_unit(Manager *manager, const char *unit, const char *job_mode,
manager->bus,
bus_systemd_mgr,
"StopUnit",
- error,
+ &error,
&reply,
"ss", unit, job_mode ?: "fail");
if (r < 0) {
- if (sd_bus_error_has_names(error, BUS_ERROR_NO_SUCH_UNIT,
- BUS_ERROR_LOAD_FAILED)) {
-
+ if (sd_bus_error_has_names(&error, BUS_ERROR_NO_SUCH_UNIT, BUS_ERROR_LOAD_FAILED)) {
*ret_job = NULL;
- sd_bus_error_free(error);
return 0;
}
+ sd_bus_error_move(ret_error, &error);
return r;
}
- return strdup_job(reply, ret_job);
+ r = strdup_job(reply, ret_job);
+ if (r < 0)
+ return r;
+
+ return 1;
}
int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *ret_error) {
@@ -4313,6 +4476,7 @@ int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *ret
int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
assert(manager);
assert(unit);
+ assert(SIGNAL_VALID(signo));
return bus_call_method(
manager->bus,
@@ -4320,7 +4484,10 @@ int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo
"KillUnit",
error,
NULL,
- "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
+ "ssi",
+ unit,
+ who == KILL_LEADER ? "main" : "all",
+ signo);
}
int manager_unit_is_active(Manager *manager, const char *unit, sd_bus_error *ret_error) {