logind-dbus.c revision a50df72b37ce2a7caf7775c70d18c3f9504b9e80
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering This file is part of systemd.
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering Copyright 2011 Lennart Poettering
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering (at your option) any later version.
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering systemd is distributed in the hope that it will be useful, but
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering Lesser General Public License for more details.
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering return sd_bus_message_append(reply, "b", manager_get_idle_hint(m, NULL) > 0);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering return sd_bus_message_append(reply, "t", streq(property, "IdleSinceHint") ? t.realtime : t.monotonic);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering return sd_bus_message_append(reply, "s", inhibit_what_to_string(w));
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering if (streq(property, "PreparingForShutdown"))
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering b = !!(m->action_what & INHIBIT_SHUTDOWN);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering return sd_bus_message_append(reply, "b", b);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poetteringstatic BUS_DEFINE_PROPERTY_GET_ENUM(property_get_handle_action, handle_action, HandleAction);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poetteringstatic int method_get_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering r = sd_bus_message_read(message, "s", &name);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering session = hashmap_get(m->sessions, name);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering return sd_bus_reply_method_return(message, "o", p);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poetteringstatic int method_get_session_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering assert_cc(sizeof(pid_t) == sizeof(uint32_t));
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering r = sd_bus_message_read(message, "u", &pid);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering r = manager_get_session_by_pid(m, pid, &session);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID, "PID %lu does not belong to any known session", (unsigned long) pid);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering return sd_bus_reply_method_return(message, "o", p);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poetteringstatic int method_get_user(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering r = sd_bus_message_read(message, "u", &uid);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "No user '%lu' known or logged in", (unsigned long) uid);
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering return sd_bus_reply_method_return(message, "o", p);
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poetteringstatic int method_get_user_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering assert_cc(sizeof(pid_t) == sizeof(uint32_t));
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering r = sd_bus_message_read(message, "u", &pid);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering r = manager_get_user_by_pid(m, pid, &user);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering 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);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering return sd_bus_reply_method_return(message, "o", p);
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poetteringstatic int method_get_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering r = sd_bus_message_read(message, "s", &name);
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", name);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering return sd_bus_reply_method_return(message, "o", p);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poetteringstatic int method_list_sessions(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering r = sd_bus_message_new_method_return(message, &reply);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering r = sd_bus_message_open_container(reply, 'a', "(susso)");
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering HASHMAP_FOREACH(session, m->sessions, i) {
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = sd_bus_message_append(reply, "(susso)",
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = sd_bus_message_close_container(reply);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poetteringstatic int method_list_users(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = sd_bus_message_new_method_return(message, &reply);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = sd_bus_message_open_container(reply, 'a', "(uso)");
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = sd_bus_message_append(reply, "(uso)",
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = sd_bus_message_close_container(reply);
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek return sd_bus_send(bus, reply, NULL);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poetteringstatic int method_list_seats(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = sd_bus_message_new_method_return(message, &reply);
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek r = sd_bus_message_open_container(reply, 'a', "(so)");
fa041593fe04b12ffd7e81d8b3598a7a6f313fb3Lennart Poettering r = sd_bus_message_append(reply, "(so)", seat->id, p);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = sd_bus_message_close_container(reply);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poetteringstatic int method_list_inhibitors(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
fa041593fe04b12ffd7e81d8b3598a7a6f313fb3Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = sd_bus_message_new_method_return(message, &reply);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = sd_bus_message_open_container(reply, 'a', "(ssssuu)");
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = sd_bus_message_append(reply, "(ssssuu)",
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering strempty(inhibit_what_to_string(inhibitor->what)),
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering strempty(inhibit_mode_to_string(inhibitor->mode)),
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = sd_bus_message_close_container(reply);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poetteringstatic int method_create_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = sd_bus_message_read(message, "uusssssussbss", &uid, &leader, &service, &type, &class, &desktop, &cseat, &vtnr, &tty, &display, &remote, &remote_user, &remote_host);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid session type %s", type);
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid session class %s", class);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid desktop string %s", desktop);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", cseat);
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek 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);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot determine VT number from virtual console TTY %s", tty);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified TTY and VT number do not match");
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but seat is not seat0");
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but VT number is not 0");
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "VT number out of range");
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Seat has no VTs but VT number not 0");
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek r = sd_bus_message_enter_container(message, 'a', "(sv)");
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering assert_cc(sizeof(uint32_t) == sizeof(pid_t));
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering manager_get_session_by_pid(m, leader, &session);
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering /* Session already exists, client is probably
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering * something like "su" which changes uid but is still
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering * the same session */
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering audit_session_from_pid(leader, &audit_id);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering /* Keep our session IDs and the audit session IDs in sync */
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0)
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering /* Wut? There's already a session by this name and we
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering * didn't find it above? Weird, then let's not trust
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering * the audit data and let's better register a new
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering log_warning("Existing logind session ID %s used by new audit session, ignoring", id);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering if (asprintf(&id, "c%lu", ++m->session_counter) < 0)
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering r = manager_add_user_by_uid(m, uid, &user);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering r = manager_add_session(m, id, &session);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering session->remote_user = strdup(remote_user);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering session->remote_host = strdup(remote_host);
9a5cb1371b6d8b0a04bd08665bcf9b06cb40c64cZbigniew Jędrzejewski-Szmek session->create_message = sd_bus_message_ref(message);
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering /* Now, let's wait until the slice unit and stuff got
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering * created. We send the reply back from
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering * session_send_create_reply().*/
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poetteringstatic int method_release_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering r = sd_bus_message_read(message, "s", &name);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering session = hashmap_get(m->sessions, name);
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
3db604b907323b8df0fc810216f6112056d26a02Lennart Poettering return sd_bus_reply_method_return(message, NULL);
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poetteringstatic int method_activate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering r = sd_bus_message_read(message, "s", &name);
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering session = hashmap_get(m->sessions, name);
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering return sd_bus_reply_method_return(message, NULL);
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poetteringstatic int method_activate_session_on_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering /* Same as ActivateSession() but refuses to work if
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering * the seat doesn't match */
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering r = sd_bus_message_read(message, "ss", &session_name, &seat_name);
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering session = hashmap_get(m->sessions, session_name);
if (!seat)
return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", session_name, seat_name);
static int method_lock_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *name;
assert(m);
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(m);
m->action_what = 0;
if (session) {
sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
if (user) {
sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
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)
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,
const char *after,
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,