logind-dbus.c revision 151b9b9662a90455262ce575a8a8ae74bf4ff336
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann This file is part of systemd.
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann Copyright 2011 Lennart Poettering
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann systemd is free software; you can redistribute it and/or modify it
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann under the terms of the GNU Lesser General Public License as published by
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann the Free Software Foundation; either version 2.1 of the License, or
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann (at your option) any later version.
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann systemd is distributed in the hope that it will be useful, but
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann WITHOUT ANY WARRANTY; without even the implied warranty of
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann Lesser General Public License for more details.
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann You should have received a copy of the GNU Lesser General Public License
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann along with systemd; If not, see <http://www.gnu.org/licenses/>.
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_message_append(reply, "b", manager_get_idle_hint(m, NULL) > 0);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_message_append(reply, "t", streq(property, "IdleSinceHint") ? t.realtime : t.monotonic);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_message_append(reply, "s", inhibit_what_to_string(w));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic BUS_DEFINE_PROPERTY_GET_ENUM(property_get_handle_action, handle_action, HandleAction);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int method_get_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_message_read(message, "s", &name);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_reply_method_return(message, "o", p);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int method_get_session_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert_cc(sizeof(pid_t) == sizeof(uint32_t));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = manager_get_session_by_pid(m, pid, &session);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID, "PID %lu does not belong to any known session", (unsigned long) pid);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_reply_method_return(message, "o", p);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int method_get_user(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "No user '%lu' known or logged in", (unsigned long) uid);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_reply_method_return(message, "o", p);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int method_get_user_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert_cc(sizeof(pid_t) == sizeof(uint32_t));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID, "PID %lu does not belong to any known or logged in user", (unsigned long) pid);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_reply_method_return(message, "o", p);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int method_get_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_message_read(message, "s", &name);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", name);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_reply_method_return(message, "o", p);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int method_list_sessions(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_message_new_method_return(message, &reply);
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann r = sd_bus_message_open_container(reply, 'a', "(susso)");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int method_list_users(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_message_new_method_return(message, &reply);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_message_open_container(reply, 'a', "(uso)");
d27efd93841a2ac2127fd53321368cc3f975c564Lennart Poetteringstatic int method_list_seats(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_message_new_method_return(message, &reply);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_message_open_container(reply, 'a', "(so)");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_message_append(reply, "(so)", seat->id, p);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int method_list_inhibitors(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_message_new_method_return(message, &reply);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_message_open_container(reply, 'a', "(ssssuu)");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1140e154100f7224fb8bab55ba7fc087409f9d76Lennart Poettering r = sd_bus_message_append(reply, "(ssssuu)",
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann strempty(inhibit_what_to_string(inhibitor->what)),
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann strempty(inhibit_mode_to_string(inhibitor->mode)),
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int method_create_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
05bae4a60c32e29797597979cee2f3684eb3bc1eDavid Herrmann const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_message_read(message, "uusssssussbss", &uid, &leader, &service, &type, &class, &desktop, &cseat, &vtnr, &tty, &display, &remote, &remote_user, &remote_host);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid session type %s", type);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid session class %s", class);
05bae4a60c32e29797597979cee2f3684eb3bc1eDavid Herrmann return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid desktop string %s", desktop);
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", cseat);
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "TTY %s is virtual console but seat %s is not seat0", tty, seat->id);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot determine VT number from virtual console TTY %s", tty);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified TTY and VT number do not match");
7447362c530e3f7128f16a35d1e43da4251144ccDavid Herrmann return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but seat is not seat0");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but VT number is not 0");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "VT number out of range");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Seat has no VTs but VT number not 0");
c4bc1a8434f2a34840ea6f63064fa998ecfae738David Herrmann r = sd_bus_message_enter_container(message, 'a', "(sv)");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann assert_cc(sizeof(uint32_t) == sizeof(pid_t));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann manager_get_session_by_pid(m, leader, &session);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Session already exists, client is probably
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * something like "su" which changes uid but is still
d27efd93841a2ac2127fd53321368cc3f975c564Lennart Poettering * the same session */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Keep our session IDs and the audit session IDs in sync */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Wut? There's already a session by this name and we
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * didn't find it above? Weird, then let's not trust
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * the audit data and let's better register a new
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_warning("Existing logind session ID %s used by new audit session, ignoring", id);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (asprintf(&id, "c%lu", ++m->session_counter) < 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann session->create_message = sd_bus_message_ref(message);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Now, let's wait until the slice unit and stuff got
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * created. We send the reply back from
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * session_send_create_reply().*/
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int method_release_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_message_read(message, "s", &name);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_reply_method_return(message, NULL);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int method_activate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_message_read(message, "s", &name);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_reply_method_return(message, NULL);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int method_activate_session_on_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* Same as ActivateSession() but refuses to work if
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * the seat doesn't match */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_message_read(message, "ss", &session_name, &seat_name);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann session = hashmap_get(m->sessions, session_name);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", session_name);
d27efd93841a2ac2127fd53321368cc3f975c564Lennart Poettering return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", seat_name);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", session_name, seat_name);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return sd_bus_reply_method_return(message, NULL);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int method_lock_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann r = sd_bus_message_read(message, "s", &name);
if (!session)
static int method_lock_sessions(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
assert(m);
static int method_kill_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
assert(m);
if (who < 0)
if (!session)
static int method_kill_user(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
assert(m);
if (!user)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "No user '%lu' known or logged in", (unsigned long) uid);
static int method_terminate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *name;
assert(m);
if (!session)
static int method_terminate_user(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
assert(m);
if (!user)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "No user '%lu' known or logged in", (unsigned long) uid);
static int method_terminate_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *name;
assert(m);
if (!seat)
static int method_set_user_linger(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *path;
int interactive;
assert(m);
errno = 0;
if (!pw)
&m->polkit_registry,
"org.freedesktop.login1.set-user-linger",
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
if (!cc)
return -ENOMEM;
User *u;
user_start(u);
User *u;
return -errno;
assert(m);
return -ENOMEM;
r = udev_enumerate_add_match_parent(e, d);
r = udev_enumerate_scan_devices(e);
return -ENOMEM;
const char *id_for_seat;
assert(m);
return -ENODEV;
return -ENODEV;
if (!id_for_seat)
return -ENODEV;
return -ENOMEM;
if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0)
return -ENOMEM;
return trigger_device(m, d);
assert(m);
static int method_attach_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
int interactive, r;
assert(m);
&m->polkit_registry,
method_attach_device, m);
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
static int method_flush_devices(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
int interactive, r;
assert(m);
&m->polkit_registry,
method_flush_devices, m);
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = flush_devices(m);
static int have_multiple_sessions(
Manager *m,
Iterator i;
assert(m);
static int bus_manager_log_shutdown(
Manager *m,
InhibitWhat w,
const char *unit_name) {
assert(m);
if (w != INHIBIT_SHUTDOWN)
q = NULL;
q, NULL);
static int execute_shutdown_or_sleep(
Manager *m,
InhibitWhat w,
const char *unit_name,
assert(m);
assert(w >= 0);
r = sd_bus_call_method(
m->bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
&reply,
c = strdup(p);
return -ENOMEM;
m->action_job = c;
m->action_what = w;
static int delay_shutdown_or_sleep(
Manager *m,
InhibitWhat w,
const char *unit_name) {
assert(m);
assert(w >= 0);
m->action_what = w;
assert(m);
assert(w >= 0);
"/org/freedesktop/login1",
signal_name[w],
active);
Manager *m,
const char *unit_name,
InhibitWhat w,
bool delayed;
assert(m);
assert(w >= 0);
send_prepare_for(m, w, true);
delayed =
m->inhibit_delay_max > 0 &&
if (delayed)
static int method_do_shutdown_or_sleep(
Manager *m,
const char *unit_name,
InhibitWhat w,
const char *action,
const char *action_multiple_sessions,
const char *action_ignore_inhibit,
const char *sleep_verb,
int interactive, r;
assert(m);
assert(w >= 0);
if (m->action_what)
return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "There's already a shutdown or sleep operation in progress");
if (sleep_verb) {
multiple_sessions = r > 0;
if (multiple_sessions) {
if (blocked) {
static int method_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_do_shutdown_or_sleep(
m, message,
NULL,
error);
static int method_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_do_shutdown_or_sleep(
m, message,
NULL,
error);
static int method_suspend(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_do_shutdown_or_sleep(
m, message,
"org.freedesktop.login1.suspend",
"org.freedesktop.login1.suspend-multiple-sessions",
"org.freedesktop.login1.suspend-ignore-inhibit",
error);
static int method_hibernate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_do_shutdown_or_sleep(
m, message,
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
error);
static int method_hybrid_sleep(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_do_shutdown_or_sleep(
m, message,
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
error);
static int method_can_shutdown_or_sleep(
Manager *m,
InhibitWhat w,
const char *action,
const char *action_multiple_sessions,
const char *action_ignore_inhibit,
const char *sleep_verb,
assert(m);
assert(w >= 0);
if (sleep_verb) {
multiple_sessions = r > 0;
if (multiple_sessions) {
else if (challenge)
if (blocked) {
if (r > 0 && !result)
else if (challenge)
static int method_can_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_can_shutdown_or_sleep(
m, message,
NULL,
error);
static int method_can_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_can_shutdown_or_sleep(
m, message,
NULL,
error);
static int method_can_suspend(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_can_shutdown_or_sleep(
m, message,
"org.freedesktop.login1.suspend",
"org.freedesktop.login1.suspend-multiple-sessions",
"org.freedesktop.login1.suspend-ignore-inhibit",
error);
static int method_can_hibernate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_can_shutdown_or_sleep(
m, message,
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
error);
static int method_can_hybrid_sleep(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_can_shutdown_or_sleep(
m, message,
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
error);
static int method_inhibit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
InhibitWhat w;
assert(m);
if (mm < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delay inhibitors only supported for shutdown and sleep");
if (m->action_what & w)
return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "The operation inhibition has been requested for is already running");
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") :
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
return -ENOMEM;
i->what = w;
r = -ENOMEM;
goto fail;
if (fifo_fd < 0) {
r = fifo_fd;
goto fail;
inhibitor_start(i);
fail:
inhibitor_free(i);
SD_BUS_PROPERTY("KillOnlyUsers", "as", NULL, offsetof(Manager, kill_only_users), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KillExcludeUsers", "as", NULL, offsetof(Manager, kill_exclude_users), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KillUserProcesses", "b", NULL, offsetof(Manager, kill_user_processes), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("BlockInhibited", "s", property_get_inhibited, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
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("HandlePowerKey", "s", property_get_handle_action, offsetof(Manager, handle_power_key), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HandleSuspendKey", "s", property_get_handle_action, offsetof(Manager, handle_suspend_key), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HandleHibernateKey", "s", property_get_handle_action, offsetof(Manager, handle_hibernate_key), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HandleLidSwitch", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IdleAction", "s", property_get_handle_action, offsetof(Manager, idle_action), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IdleActionUSec", "t", NULL, offsetof(Manager, idle_action_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("ListInhibitors", NULL, "a(ssssuu)", method_list_inhibitors, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ActivateSessionOnSeat", "ss", NULL, method_activate_session_on_seat, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("TerminateSession", "s", NULL, method_terminate_session, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
SD_BUS_METHOD("TerminateUser", "u", NULL, method_terminate_user, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
SD_BUS_METHOD("TerminateSeat", "s", NULL, method_terminate_seat, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
assert(s);
if (!s->started)
sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
r = session_send_create_reply(s, &e);
assert(m);
m->action_what = 0;
if (session) {
if (user) {
assert(m);
if (session)
if (user)
int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *path;
assert(m);
if (!path)
return r == -EINVAL ? 0 : r;
if (session)
if (user)
Iterator i;
int match_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
Iterator i;
char *key;
if (!key)
"/org/freedesktop/login1",
if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) {
int manager_start_scope(
const char *scope,
const char *slice,
const char *description,
char **job) {
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
r = sd_bus_message_close_container(m);
if (job) {
char *copy;
if (!copy)
return -ENOMEM;
r = sd_bus_call_method(
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
&reply,
if (job) {
char *copy;
if (!copy)
return -ENOMEM;
r = sd_bus_call_method(
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
&reply,
if (job)
if (job) {
char *copy;
if (!copy)
return -ENOMEM;
if (!path)
return -ENOMEM;
r = sd_bus_call_method(
"org.freedesktop.systemd1",
path,
"org.freedesktop.systemd1.Scope",
NULL,
NULL);
int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
return sd_bus_call_method(
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
NULL,
const char *state;
if (!path)
return -ENOMEM;
r = sd_bus_get_property(
"org.freedesktop.systemd1",
path,
"org.freedesktop.systemd1.Unit",
&error,
&reply,
return -EINVAL;
r = sd_bus_get_property(
"org.freedesktop.systemd1",
path,
"org.freedesktop.systemd1.Job",
&error,
&reply,