1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "dbus-common.h"
31 #include "path-util.h"
35 #define BUS_MANAGER_INTERFACE \
36 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
37 " <method name=\"GetSession\">\n" \
38 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
39 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
41 " <method name=\"GetSessionByPID\">\n" \
42 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
43 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
45 " <method name=\"GetUser\">\n" \
46 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
47 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
49 " <method name=\"GetSeat\">\n" \
50 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
51 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
53 " <method name=\"ListSessions\">\n" \
54 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
56 " <method name=\"ListUsers\">\n" \
57 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
59 " <method name=\"ListSeats\">\n" \
60 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
62 " <method name=\"CreateSession\">\n" \
63 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
64 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
65 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
66 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
67 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
68 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
69 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
70 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
72 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
73 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
74 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
75 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
76 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
77 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
78 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
79 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
80 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
81 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
82 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
83 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
85 " <method name=\"ReleaseSession\">\n" \
86 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
88 " <method name=\"ActivateSession\">\n" \
89 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
91 " <method name=\"ActivateSessionOnSeat\">\n" \
92 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
93 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
95 " <method name=\"LockSession\">\n" \
96 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
98 " <method name=\"UnlockSession\">\n" \
99 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
101 " <method name=\"KillSession\">\n" \
102 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
103 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
104 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
106 " <method name=\"KillUser\">\n" \
107 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
108 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
110 " <method name=\"TerminateSession\">\n" \
111 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
113 " <method name=\"TerminateUser\">\n" \
114 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
116 " <method name=\"TerminateSeat\">\n" \
117 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
119 " <method name=\"SetUserLinger\">\n" \
120 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
121 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
122 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
124 " <method name=\"AttachDevice\">\n" \
125 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
126 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
127 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
129 " <method name=\"FlushDevices\">\n" \
130 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
132 " <method name=\"PowerOff\">\n" \
133 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
135 " <method name=\"Reboot\">\n" \
136 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
138 " <method name=\"Suspend\">\n" \
139 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
141 " <method name=\"Hibernate\">\n" \
142 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
144 " <method name=\"CanPowerOff\">\n" \
145 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
147 " <method name=\"CanReboot\">\n" \
148 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
150 " <method name=\"CanSuspend\">\n" \
151 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
153 " <method name=\"CanHibernate\">\n" \
154 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
156 " <method name=\"Inhibit\">\n" \
157 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
158 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
159 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
160 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
161 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
163 " <method name=\"ListInhibitors\">\n" \
164 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
166 " <signal name=\"SessionNew\">\n" \
167 " <arg name=\"id\" type=\"s\"/>\n" \
168 " <arg name=\"path\" type=\"o\"/>\n" \
170 " <signal name=\"SessionRemoved\">\n" \
171 " <arg name=\"id\" type=\"s\"/>\n" \
172 " <arg name=\"path\" type=\"o\"/>\n" \
174 " <signal name=\"UserNew\">\n" \
175 " <arg name=\"uid\" type=\"u\"/>\n" \
176 " <arg name=\"path\" type=\"o\"/>\n" \
178 " <signal name=\"UserRemoved\">\n" \
179 " <arg name=\"uid\" type=\"u\"/>\n" \
180 " <arg name=\"path\" type=\"o\"/>\n" \
182 " <signal name=\"SeatNew\">\n" \
183 " <arg name=\"id\" type=\"s\"/>\n" \
184 " <arg name=\"path\" type=\"o\"/>\n" \
186 " <signal name=\"SeatRemoved\">\n" \
187 " <arg name=\"id\" type=\"s\"/>\n" \
188 " <arg name=\"path\" type=\"o\"/>\n" \
190 " <signal name=\"PrepareForShutdown\">\n" \
191 " <arg name=\"active\" type=\"b\"/>\n" \
193 " <signal name=\"PrepareForSleep\">\n" \
194 " <arg name=\"active\" type=\"b\"/>\n" \
196 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
197 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
198 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
199 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
200 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
201 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
202 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
203 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
204 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
205 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
206 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
207 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
208 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
211 #define INTROSPECTION_BEGIN \
212 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
214 BUS_MANAGER_INTERFACE \
215 BUS_PROPERTIES_INTERFACE \
217 BUS_INTROSPECTABLE_INTERFACE
219 #define INTROSPECTION_END \
222 #define INTERFACES_LIST \
223 BUS_GENERIC_INTERFACES_LIST \
224 "org.freedesktop.login1.Manager\0"
226 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
234 b = manager_get_idle_hint(m, NULL) > 0;
235 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
241 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
250 manager_get_idle_hint(m, &t);
251 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
253 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
259 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
264 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
265 p = inhibit_what_to_string(w);
267 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
273 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
274 Session *session = NULL;
276 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
277 uint32_t uid, leader, audit_id = 0;
278 dbus_bool_t remote, kill_processes;
279 char **controllers = NULL, **reset_controllers = NULL;
283 DBusMessageIter iter;
288 DBusMessage *reply = NULL;
295 if (!dbus_message_iter_init(message, &iter) ||
296 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
299 dbus_message_iter_get_basic(&iter, &uid);
301 if (!dbus_message_iter_next(&iter) ||
302 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
305 dbus_message_iter_get_basic(&iter, &leader);
308 !dbus_message_iter_next(&iter) ||
309 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
312 dbus_message_iter_get_basic(&iter, &service);
314 if (!dbus_message_iter_next(&iter) ||
315 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
318 dbus_message_iter_get_basic(&iter, &type);
319 t = session_type_from_string(type);
322 !dbus_message_iter_next(&iter) ||
323 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
326 dbus_message_iter_get_basic(&iter, &class);
330 c = session_class_from_string(class);
333 !dbus_message_iter_next(&iter) ||
334 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
337 dbus_message_iter_get_basic(&iter, &seat);
342 s = hashmap_get(m->seats, seat);
347 if (!dbus_message_iter_next(&iter) ||
348 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
351 dbus_message_iter_get_basic(&iter, &vtnr);
353 if (!dbus_message_iter_next(&iter) ||
354 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
357 dbus_message_iter_get_basic(&iter, &tty);
359 if (tty_is_vc(tty)) {
364 else if (s != m->vtconsole)
367 v = vtnr_from_tty(tty);
370 return v < 0 ? v : -EINVAL;
374 else if (vtnr != (uint32_t) v)
376 } else if (tty_is_console(tty)) {
380 else if (s != m->vtconsole)
386 } else if (!isempty(tty) && s && seat_is_vtconsole(s))
390 if (seat_can_multi_session(s)) {
399 if (!dbus_message_iter_next(&iter) ||
400 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
403 dbus_message_iter_get_basic(&iter, &display);
405 if (!dbus_message_iter_next(&iter) ||
406 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
409 dbus_message_iter_get_basic(&iter, &remote);
411 if (!dbus_message_iter_next(&iter) ||
412 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
415 dbus_message_iter_get_basic(&iter, &remote_user);
417 if (!dbus_message_iter_next(&iter) ||
418 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
421 dbus_message_iter_get_basic(&iter, &remote_host);
423 if (!dbus_message_iter_next(&iter) ||
424 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
425 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
428 r = bus_parse_strv_iter(&iter, &controllers);
432 if (strv_contains(controllers, "systemd") ||
433 !dbus_message_iter_next(&iter) ||
434 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
435 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
440 r = bus_parse_strv_iter(&iter, &reset_controllers);
444 if (strv_contains(reset_controllers, "systemd") ||
445 !dbus_message_iter_next(&iter) ||
446 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
451 dbus_message_iter_get_basic(&iter, &kill_processes);
453 r = manager_add_user_by_uid(m, uid, &user);
457 audit_session_from_pid(leader, &audit_id);
460 asprintf(&id, "%lu", (unsigned long) audit_id);
467 session = hashmap_get(m->sessions, id);
472 fifo_fd = session_create_fifo(session);
478 /* Session already exists, client is probably
479 * something like "su" which changes uid but
480 * is still the same audit session */
482 reply = dbus_message_new_method_return(message);
488 p = session_bus_path(session);
494 seat = session->seat ? session->seat->id : "";
495 vtnr = session->vtnr;
496 b = dbus_message_append_args(
498 DBUS_TYPE_STRING, &session->id,
499 DBUS_TYPE_OBJECT_PATH, &p,
500 DBUS_TYPE_STRING, &session->user->runtime_path,
501 DBUS_TYPE_UNIX_FD, &fifo_fd,
502 DBUS_TYPE_STRING, &seat,
503 DBUS_TYPE_UINT32, &vtnr,
512 close_nointr_nofail(fifo_fd);
515 strv_free(controllers);
516 strv_free(reset_controllers);
526 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
531 } while (hashmap_get(m->sessions, id));
534 r = manager_add_session(m, user, id, &session);
539 session->leader = leader;
540 session->audit_id = audit_id;
543 session->remote = remote;
544 session->controllers = controllers;
545 session->reset_controllers = reset_controllers;
546 session->kill_processes = kill_processes;
547 session->vtnr = vtnr;
549 controllers = reset_controllers = NULL;
552 session->tty = strdup(tty);
559 if (!isempty(display)) {
560 session->display = strdup(display);
561 if (!session->display) {
567 if (!isempty(remote_user)) {
568 session->remote_user = strdup(remote_user);
569 if (!session->remote_user) {
575 if (!isempty(remote_host)) {
576 session->remote_host = strdup(remote_host);
577 if (!session->remote_host) {
583 if (!isempty(service)) {
584 session->service = strdup(service);
585 if (!session->service) {
591 fifo_fd = session_create_fifo(session);
598 r = seat_attach_session(s, session);
603 r = session_start(session);
607 reply = dbus_message_new_method_return(message);
613 p = session_bus_path(session);
619 seat = s ? s->id : "";
620 b = dbus_message_append_args(
622 DBUS_TYPE_STRING, &session->id,
623 DBUS_TYPE_OBJECT_PATH, &p,
624 DBUS_TYPE_STRING, &session->user->runtime_path,
625 DBUS_TYPE_UNIX_FD, &fifo_fd,
626 DBUS_TYPE_STRING, &seat,
627 DBUS_TYPE_UINT32, &vtnr,
636 close_nointr_nofail(fifo_fd);
642 strv_free(controllers);
643 strv_free(reset_controllers);
646 session_add_to_gc_queue(session);
649 user_add_to_gc_queue(user);
652 close_nointr_nofail(fifo_fd);
655 dbus_message_unref(reply);
660 static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
663 const char *who, *why, *what, *mode;
669 DBusMessage *reply = NULL;
677 if (!dbus_message_get_args(
680 DBUS_TYPE_STRING, &what,
681 DBUS_TYPE_STRING, &who,
682 DBUS_TYPE_STRING, &why,
683 DBUS_TYPE_STRING, &mode,
684 DBUS_TYPE_INVALID)) {
689 w = inhibit_what_from_string(what);
695 mm = inhibit_mode_from_string(mode);
701 r = verify_polkit(connection, message,
703 "org.freedesktop.login1.inhibit-block" :
704 "org.freedesktop.login1.inhibit-delay", false, NULL, error);
708 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
709 if (ul == (unsigned long) -1) {
714 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
724 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
728 } while (hashmap_get(m->inhibitors, id));
730 r = manager_add_inhibitor(m, id, &i);
740 i->why = strdup(why);
741 i->who = strdup(who);
743 if (!i->why || !i->who) {
748 fifo_fd = inhibitor_create_fifo(i);
754 reply = dbus_message_new_method_return(message);
760 if (!dbus_message_append_args(
762 DBUS_TYPE_UNIX_FD, &fifo_fd,
763 DBUS_TYPE_INVALID)) {
768 close_nointr_nofail(fifo_fd);
780 close_nointr_nofail(fifo_fd);
783 dbus_message_unref(reply);
788 static int trigger_device(Manager *m, struct udev_device *d) {
789 struct udev_enumerate *e;
790 struct udev_list_entry *first, *item;
795 e = udev_enumerate_new(m->udev);
802 if (udev_enumerate_add_match_parent(e, d) < 0) {
808 if (udev_enumerate_scan_devices(e) < 0) {
813 first = udev_enumerate_get_list_entry(e);
814 udev_list_entry_foreach(item, first) {
818 p = udev_list_entry_get_name(item);
820 t = strappend(p, "/uevent");
826 write_one_line_file(t, "change");
834 udev_enumerate_unref(e);
839 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
840 struct udev_device *d;
841 char *rule = NULL, *file = NULL;
842 const char *id_for_seat;
849 d = udev_device_new_from_syspath(m->udev, sysfs);
853 if (!udev_device_has_tag(d, "seat")) {
858 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
864 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
869 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
874 mkdir_p("/etc/udev/rules.d", 0755);
875 r = write_one_line_file_atomic(file, rule);
879 r = trigger_device(m, d);
886 udev_device_unref(d);
891 static int flush_devices(Manager *m) {
896 d = opendir("/etc/udev/rules.d");
899 log_warning("Failed to open /etc/udev/rules.d: %m");
903 while ((de = readdir(d))) {
905 if (!dirent_is_file(de))
908 if (!startswith(de->d_name, "72-seat-"))
911 if (!endswith(de->d_name, ".rules"))
914 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
915 log_warning("Failed to unlink %s: %m", de->d_name);
921 return trigger_device(m, NULL);
924 static int have_multiple_sessions(
925 DBusConnection *connection,
927 DBusMessage *message,
934 if (hashmap_size(m->sessions) > 1)
937 /* Hmm, there's only one session, but let's make sure it
938 * actually belongs to the user who is asking. If not, better
939 * be safe than sorry. */
941 s = hashmap_first(m->sessions);
945 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
946 if (ul == (unsigned long) -1)
949 return s->user->uid != ul;
955 static int send_start_unit(DBusConnection *connection, const char *unit_name, DBusError *error) {
956 DBusMessage *message, *reply;
957 const char *mode = "replace";
962 message = dbus_message_new_method_call(
963 "org.freedesktop.systemd1",
964 "/org/freedesktop/systemd1",
965 "org.freedesktop.systemd1.Manager",
970 if (!dbus_message_append_args(message,
971 DBUS_TYPE_STRING, &unit_name,
972 DBUS_TYPE_STRING, &mode,
973 DBUS_TYPE_INVALID)) {
974 dbus_message_unref(message);
978 reply = dbus_connection_send_with_reply_and_block(connection, message, -1, error);
979 dbus_message_unref(message);
984 dbus_message_unref(reply);
988 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
989 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
990 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
991 [INHIBIT_SLEEP] = "PrepareForSleep"
994 dbus_bool_t active = _active;
995 DBusMessage *message;
1000 assert(w < _INHIBIT_WHAT_MAX);
1001 assert(signal_name[w]);
1003 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1007 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1008 !dbus_connection_send(m->bus, message, NULL))
1011 dbus_message_unref(message);
1015 static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
1018 assert(w < _INHIBIT_WHAT_MAX);
1020 /* Tell everybody to prepare for shutdown/sleep */
1021 send_prepare_for(m, w, true);
1023 /* Update timestamp for timeout */
1024 if (!m->delayed_unit)
1025 m->delayed_timestamp = now(CLOCK_MONOTONIC);
1027 /* Remember what we want to do, possibly overriding what kind
1028 * of unit we previously queued. */
1029 m->delayed_unit = unit_name;
1030 m->delayed_what = w;
1035 static int bus_manager_can_shutdown_or_sleep(
1037 DBusConnection *connection,
1038 DBusMessage *message,
1041 const char *action_multiple_sessions,
1042 const char *action_ignore_inhibit,
1043 const char *sleep_type,
1045 DBusMessage **_reply) {
1047 bool multiple_sessions, challenge, blocked, b;
1049 DBusMessage *reply = NULL;
1056 assert(w <= _INHIBIT_WHAT_MAX);
1058 assert(action_multiple_sessions);
1059 assert(action_ignore_inhibit);
1064 r = can_sleep(sleep_type);
1072 r = have_multiple_sessions(connection, m, message, error);
1076 multiple_sessions = r > 0;
1077 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1079 if (multiple_sessions) {
1080 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1087 result = "challenge";
1093 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1097 if (r > 0 && !result)
1099 else if (challenge && (!result || streq(result, "yes")))
1100 result = "challenge";
1105 if (!multiple_sessions && !blocked) {
1106 /* If neither inhibit nor multiple sessions
1107 * apply then just check the normal policy */
1109 r = verify_polkit(connection, message, action, false, &challenge, error);
1116 result = "challenge";
1122 reply = dbus_message_new_method_return(message);
1126 b = dbus_message_append_args(
1128 DBUS_TYPE_STRING, &result,
1131 dbus_message_unref(reply);
1139 static int bus_manager_do_shutdown_or_sleep(
1141 DBusConnection *connection,
1142 DBusMessage *message,
1143 const char *unit_name,
1146 const char *action_multiple_sessions,
1147 const char *action_ignore_inhibit,
1148 const char *sleep_type,
1150 DBusMessage **_reply) {
1152 dbus_bool_t interactive;
1153 bool multiple_sessions, blocked, delayed;
1154 DBusMessage *reply = NULL;
1162 assert(w <= _INHIBIT_WHAT_MAX);
1164 assert(action_multiple_sessions);
1165 assert(action_ignore_inhibit);
1169 if (!dbus_message_get_args(
1172 DBUS_TYPE_BOOLEAN, &interactive,
1177 r = can_sleep(sleep_type);
1185 r = have_multiple_sessions(connection, m, message, error);
1189 multiple_sessions = r > 0;
1190 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1192 if (multiple_sessions) {
1193 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1199 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1204 if (!multiple_sessions && !blocked) {
1205 r = verify_polkit(connection, message, action, interactive, NULL, error);
1211 m->inhibit_delay_max > 0 &&
1212 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL);
1215 /* Shutdown is delayed, keep in mind what we
1216 * want to do, and start a timeout */
1217 r = delay_shutdown_or_sleep(m, w, unit_name);
1219 /* Shutdown is not delayed, execute it
1221 r = send_start_unit(connection, unit_name, error);
1226 reply = dbus_message_new_method_return(message);
1234 static const BusProperty bus_login_manager_properties[] = {
1235 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1236 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1237 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1238 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1239 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1240 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1241 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1242 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1243 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1244 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1245 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1246 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1247 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1251 static DBusHandlerResult manager_message_handler(
1252 DBusConnection *connection,
1253 DBusMessage *message,
1256 Manager *m = userdata;
1259 DBusMessage *reply = NULL;
1266 dbus_error_init(&error);
1268 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1274 if (!dbus_message_get_args(
1277 DBUS_TYPE_STRING, &name,
1279 return bus_send_error_reply(connection, message, &error, -EINVAL);
1281 session = hashmap_get(m->sessions, name);
1283 return bus_send_error_reply(connection, message, &error, -ENOENT);
1285 reply = dbus_message_new_method_return(message);
1289 p = session_bus_path(session);
1293 b = dbus_message_append_args(
1295 DBUS_TYPE_OBJECT_PATH, &p,
1302 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1308 if (!dbus_message_get_args(
1311 DBUS_TYPE_UINT32, &pid,
1313 return bus_send_error_reply(connection, message, &error, -EINVAL);
1315 r = manager_get_session_by_pid(m, pid, &session);
1317 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1319 reply = dbus_message_new_method_return(message);
1323 p = session_bus_path(session);
1327 b = dbus_message_append_args(
1329 DBUS_TYPE_OBJECT_PATH, &p,
1336 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1342 if (!dbus_message_get_args(
1345 DBUS_TYPE_UINT32, &uid,
1347 return bus_send_error_reply(connection, message, &error, -EINVAL);
1349 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1351 return bus_send_error_reply(connection, message, &error, -ENOENT);
1353 reply = dbus_message_new_method_return(message);
1357 p = user_bus_path(user);
1361 b = dbus_message_append_args(
1363 DBUS_TYPE_OBJECT_PATH, &p,
1370 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1376 if (!dbus_message_get_args(
1379 DBUS_TYPE_STRING, &name,
1381 return bus_send_error_reply(connection, message, &error, -EINVAL);
1383 seat = hashmap_get(m->seats, name);
1385 return bus_send_error_reply(connection, message, &error, -ENOENT);
1387 reply = dbus_message_new_method_return(message);
1391 p = seat_bus_path(seat);
1395 b = dbus_message_append_args(
1397 DBUS_TYPE_OBJECT_PATH, &p,
1404 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1408 DBusMessageIter iter, sub;
1409 const char *empty = "";
1411 reply = dbus_message_new_method_return(message);
1415 dbus_message_iter_init_append(reply, &iter);
1417 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1420 HASHMAP_FOREACH(session, m->sessions, i) {
1421 DBusMessageIter sub2;
1424 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1427 uid = session->user->uid;
1429 p = session_bus_path(session);
1433 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1434 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1435 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1436 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1437 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1444 if (!dbus_message_iter_close_container(&sub, &sub2))
1448 if (!dbus_message_iter_close_container(&iter, &sub))
1451 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1455 DBusMessageIter iter, sub;
1457 reply = dbus_message_new_method_return(message);
1461 dbus_message_iter_init_append(reply, &iter);
1463 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1466 HASHMAP_FOREACH(user, m->users, i) {
1467 DBusMessageIter sub2;
1470 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1475 p = user_bus_path(user);
1479 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1480 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1481 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1488 if (!dbus_message_iter_close_container(&sub, &sub2))
1492 if (!dbus_message_iter_close_container(&iter, &sub))
1495 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1499 DBusMessageIter iter, sub;
1501 reply = dbus_message_new_method_return(message);
1505 dbus_message_iter_init_append(reply, &iter);
1507 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1510 HASHMAP_FOREACH(seat, m->seats, i) {
1511 DBusMessageIter sub2;
1513 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1516 p = seat_bus_path(seat);
1520 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1521 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1528 if (!dbus_message_iter_close_container(&sub, &sub2))
1532 if (!dbus_message_iter_close_container(&iter, &sub))
1535 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1536 Inhibitor *inhibitor;
1538 DBusMessageIter iter, sub;
1540 reply = dbus_message_new_method_return(message);
1544 dbus_message_iter_init_append(reply, &iter);
1546 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1549 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1550 DBusMessageIter sub2;
1551 dbus_uint32_t uid, pid;
1552 const char *what, *who, *why, *mode;
1554 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1557 what = strempty(inhibit_what_to_string(inhibitor->what));
1558 who = strempty(inhibitor->who);
1559 why = strempty(inhibitor->why);
1560 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1561 uid = (dbus_uint32_t) inhibitor->uid;
1562 pid = (dbus_uint32_t) inhibitor->pid;
1564 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1565 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1566 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1567 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1568 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1569 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1572 if (!dbus_message_iter_close_container(&sub, &sub2))
1576 if (!dbus_message_iter_close_container(&iter, &sub))
1579 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1581 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1584 return bus_send_error_reply(connection, message, &error, r);
1587 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1589 r = bus_manager_create_session(m, message, &reply);
1591 /* Don't delay the work on OOM here, since it might be
1592 * triggered by a low RLIMIT_NOFILE here (since we
1593 * send a dupped fd to the client), and we'd rather
1594 * see this fail quickly then be retried later */
1597 return bus_send_error_reply(connection, message, NULL, r);
1599 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1603 if (!dbus_message_get_args(
1606 DBUS_TYPE_STRING, &name,
1608 return bus_send_error_reply(connection, message, &error, -EINVAL);
1610 session = hashmap_get(m->sessions, name);
1612 return bus_send_error_reply(connection, message, &error, -ENOENT);
1614 /* We use the FIFO to detect stray sessions where the
1615 process invoking PAM dies abnormally. We need to make
1616 sure that that process is not killed if at the clean
1617 end of the session it closes the FIFO. Hence, with
1618 this call explicitly turn off the FIFO logic, so that
1619 the PAM code can finish clean up on its own */
1620 session_remove_fifo(session);
1622 reply = dbus_message_new_method_return(message);
1626 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1630 if (!dbus_message_get_args(
1633 DBUS_TYPE_STRING, &name,
1635 return bus_send_error_reply(connection, message, &error, -EINVAL);
1637 session = hashmap_get(m->sessions, name);
1639 return bus_send_error_reply(connection, message, &error, -ENOENT);
1641 r = session_activate(session);
1643 return bus_send_error_reply(connection, message, NULL, r);
1645 reply = dbus_message_new_method_return(message);
1649 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1650 const char *session_name, *seat_name;
1654 /* Same as ActivateSession() but refuses to work if
1655 * the seat doesn't match */
1657 if (!dbus_message_get_args(
1660 DBUS_TYPE_STRING, &session_name,
1661 DBUS_TYPE_STRING, &seat_name,
1663 return bus_send_error_reply(connection, message, &error, -EINVAL);
1665 session = hashmap_get(m->sessions, session_name);
1667 return bus_send_error_reply(connection, message, &error, -ENOENT);
1669 seat = hashmap_get(m->seats, seat_name);
1671 return bus_send_error_reply(connection, message, &error, -ENOENT);
1673 if (session->seat != seat)
1674 return bus_send_error_reply(connection, message, &error, -EINVAL);
1676 r = session_activate(session);
1678 return bus_send_error_reply(connection, message, NULL, r);
1680 reply = dbus_message_new_method_return(message);
1684 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1685 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1689 if (!dbus_message_get_args(
1692 DBUS_TYPE_STRING, &name,
1694 return bus_send_error_reply(connection, message, &error, -EINVAL);
1696 session = hashmap_get(m->sessions, name);
1698 return bus_send_error_reply(connection, message, &error, -ENOENT);
1700 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1703 reply = dbus_message_new_method_return(message);
1707 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1714 if (!dbus_message_get_args(
1717 DBUS_TYPE_STRING, &name,
1718 DBUS_TYPE_STRING, &swho,
1719 DBUS_TYPE_INT32, &signo,
1721 return bus_send_error_reply(connection, message, &error, -EINVAL);
1726 who = kill_who_from_string(swho);
1728 return bus_send_error_reply(connection, message, &error, -EINVAL);
1731 if (signo <= 0 || signo >= _NSIG)
1732 return bus_send_error_reply(connection, message, &error, -EINVAL);
1734 session = hashmap_get(m->sessions, name);
1736 return bus_send_error_reply(connection, message, &error, -ENOENT);
1738 r = session_kill(session, who, signo);
1740 return bus_send_error_reply(connection, message, NULL, r);
1742 reply = dbus_message_new_method_return(message);
1746 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1751 if (!dbus_message_get_args(
1754 DBUS_TYPE_UINT32, &uid,
1755 DBUS_TYPE_INT32, &signo,
1757 return bus_send_error_reply(connection, message, &error, -EINVAL);
1759 if (signo <= 0 || signo >= _NSIG)
1760 return bus_send_error_reply(connection, message, &error, -EINVAL);
1762 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1764 return bus_send_error_reply(connection, message, &error, -ENOENT);
1766 r = user_kill(user, signo);
1768 return bus_send_error_reply(connection, message, NULL, r);
1770 reply = dbus_message_new_method_return(message);
1774 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1778 if (!dbus_message_get_args(
1781 DBUS_TYPE_STRING, &name,
1783 return bus_send_error_reply(connection, message, &error, -EINVAL);
1785 session = hashmap_get(m->sessions, name);
1787 return bus_send_error_reply(connection, message, &error, -ENOENT);
1789 r = session_stop(session);
1791 return bus_send_error_reply(connection, message, NULL, r);
1793 reply = dbus_message_new_method_return(message);
1797 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1801 if (!dbus_message_get_args(
1804 DBUS_TYPE_UINT32, &uid,
1806 return bus_send_error_reply(connection, message, &error, -EINVAL);
1808 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1810 return bus_send_error_reply(connection, message, &error, -ENOENT);
1812 r = user_stop(user);
1814 return bus_send_error_reply(connection, message, NULL, r);
1816 reply = dbus_message_new_method_return(message);
1820 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1824 if (!dbus_message_get_args(
1827 DBUS_TYPE_STRING, &name,
1829 return bus_send_error_reply(connection, message, &error, -EINVAL);
1831 seat = hashmap_get(m->seats, name);
1833 return bus_send_error_reply(connection, message, &error, -ENOENT);
1835 r = seat_stop_sessions(seat);
1837 return bus_send_error_reply(connection, message, NULL, r);
1839 reply = dbus_message_new_method_return(message);
1843 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1846 dbus_bool_t b, interactive;
1849 if (!dbus_message_get_args(
1852 DBUS_TYPE_UINT32, &uid,
1853 DBUS_TYPE_BOOLEAN, &b,
1854 DBUS_TYPE_BOOLEAN, &interactive,
1856 return bus_send_error_reply(connection, message, &error, -EINVAL);
1861 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1863 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1865 return bus_send_error_reply(connection, message, &error, r);
1867 mkdir_p("/var/lib/systemd", 0755);
1869 r = safe_mkdir("/var/lib/systemd/linger", 0755, 0, 0);
1871 return bus_send_error_reply(connection, message, &error, r);
1873 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1884 return bus_send_error_reply(connection, message, &error, r);
1886 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1895 if (r < 0 && errno != ENOENT)
1896 return bus_send_error_reply(connection, message, &error, -errno);
1898 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1900 user_add_to_gc_queue(u);
1903 reply = dbus_message_new_method_return(message);
1907 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1908 const char *sysfs, *seat;
1909 dbus_bool_t interactive;
1911 if (!dbus_message_get_args(
1914 DBUS_TYPE_STRING, &seat,
1915 DBUS_TYPE_STRING, &sysfs,
1916 DBUS_TYPE_BOOLEAN, &interactive,
1918 return bus_send_error_reply(connection, message, &error, -EINVAL);
1920 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
1921 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1923 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
1925 return bus_send_error_reply(connection, message, &error, r);
1927 r = attach_device(m, seat, sysfs);
1929 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1931 reply = dbus_message_new_method_return(message);
1936 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
1937 dbus_bool_t interactive;
1939 if (!dbus_message_get_args(
1942 DBUS_TYPE_BOOLEAN, &interactive,
1944 return bus_send_error_reply(connection, message, &error, -EINVAL);
1946 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
1948 return bus_send_error_reply(connection, message, &error, r);
1950 r = flush_devices(m);
1952 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1954 reply = dbus_message_new_method_return(message);
1958 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
1960 r = bus_manager_do_shutdown_or_sleep(
1961 m, connection, message,
1962 SPECIAL_POWEROFF_TARGET,
1964 "org.freedesktop.login1.power-off",
1965 "org.freedesktop.login1.power-off-multiple-sessions",
1966 "org.freedesktop.login1.power-off-ignore-inhibit",
1970 return bus_send_error_reply(connection, message, &error, r);
1971 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
1972 r = bus_manager_do_shutdown_or_sleep(
1973 m, connection, message,
1974 SPECIAL_REBOOT_TARGET,
1976 "org.freedesktop.login1.reboot",
1977 "org.freedesktop.login1.reboot-multiple-sessions",
1978 "org.freedesktop.login1.reboot-ignore-inhibit",
1982 return bus_send_error_reply(connection, message, &error, r);
1984 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
1985 r = bus_manager_do_shutdown_or_sleep(
1986 m, connection, message,
1987 SPECIAL_SUSPEND_TARGET,
1989 "org.freedesktop.login1.suspend",
1990 "org.freedesktop.login1.suspend-multiple-sessions",
1991 "org.freedesktop.login1.suspend-ignore-inhibit",
1995 return bus_send_error_reply(connection, message, &error, r);
1996 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
1997 r = bus_manager_do_shutdown_or_sleep(
1998 m, connection, message,
1999 SPECIAL_HIBERNATE_TARGET,
2001 "org.freedesktop.login1.hibernate",
2002 "org.freedesktop.login1.hibernate-multiple-sessions",
2003 "org.freedesktop.login1.hibernate-ignore-inhibit",
2007 return bus_send_error_reply(connection, message, &error, r);
2009 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2011 r = bus_manager_can_shutdown_or_sleep(
2012 m, connection, message,
2014 "org.freedesktop.login1.power-off",
2015 "org.freedesktop.login1.power-off-multiple-sessions",
2016 "org.freedesktop.login1.power-off-ignore-inhibit",
2020 return bus_send_error_reply(connection, message, &error, r);
2021 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2022 r = bus_manager_can_shutdown_or_sleep(
2023 m, connection, message,
2025 "org.freedesktop.login1.reboot",
2026 "org.freedesktop.login1.reboot-multiple-sessions",
2027 "org.freedesktop.login1.reboot-ignore-inhibit",
2031 return bus_send_error_reply(connection, message, &error, r);
2033 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2034 r = bus_manager_can_shutdown_or_sleep(
2035 m, connection, message,
2037 "org.freedesktop.login1.suspend",
2038 "org.freedesktop.login1.suspend-multiple-sessions",
2039 "org.freedesktop.login1.suspend-ignore-inhibit",
2043 return bus_send_error_reply(connection, message, &error, r);
2045 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2046 r = bus_manager_can_shutdown_or_sleep(
2047 m, connection, message,
2049 "org.freedesktop.login1.hibernate",
2050 "org.freedesktop.login1.hibernate-multiple-sessions",
2051 "org.freedesktop.login1.hibernate-ignore-inhibit",
2055 return bus_send_error_reply(connection, message, &error, r);
2057 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2058 char *introspection = NULL;
2067 if (!(reply = dbus_message_new_method_return(message)))
2070 /* We roll our own introspection code here, instead of
2071 * relying on bus_default_message_handler() because we
2072 * need to generate our introspection string
2075 if (!(f = open_memstream(&introspection, &size)))
2078 fputs(INTROSPECTION_BEGIN, f);
2080 HASHMAP_FOREACH(seat, m->seats, i) {
2081 p = bus_path_escape(seat->id);
2084 fprintf(f, "<node name=\"seat/%s\"/>", p);
2089 HASHMAP_FOREACH(user, m->users, i)
2090 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2092 HASHMAP_FOREACH(session, m->sessions, i) {
2093 p = bus_path_escape(session->id);
2096 fprintf(f, "<node name=\"session/%s\"/>", p);
2101 fputs(INTROSPECTION_END, f);
2105 free(introspection);
2114 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2115 free(introspection);
2119 free(introspection);
2121 const BusBoundProperties bps[] = {
2122 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2125 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2129 if (!dbus_connection_send(connection, reply, NULL))
2132 dbus_message_unref(reply);
2135 return DBUS_HANDLER_RESULT_HANDLED;
2139 dbus_message_unref(reply);
2141 dbus_error_free(&error);
2143 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2146 const DBusObjectPathVTable bus_manager_vtable = {
2147 .message_function = manager_message_handler
2150 DBusHandlerResult bus_message_filter(
2151 DBusConnection *connection,
2152 DBusMessage *message,
2155 Manager *m = userdata;
2162 dbus_error_init(&error);
2164 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2167 if (!dbus_message_get_args(message, &error,
2168 DBUS_TYPE_STRING, &cgroup,
2170 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2172 manager_cgroup_notify_empty(m, cgroup);
2175 dbus_error_free(&error);
2177 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2180 int manager_send_changed(Manager *manager, const char *properties) {
2186 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2190 if (!dbus_connection_send(manager->bus, m, NULL))
2197 dbus_message_unref(m);
2202 int manager_dispatch_delayed(Manager *manager) {
2203 const char *unit_name;
2210 if (!manager->delayed_unit)
2213 /* Continue delay? */
2215 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2216 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL);
2220 /* Reset delay data */
2221 unit_name = manager->delayed_unit;
2222 manager->delayed_unit = NULL;
2224 /* Actually do the shutdown */
2225 dbus_error_init(&error);
2226 r = send_start_unit(manager->bus, unit_name, &error);
2228 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2229 dbus_error_free(&error);
2233 /* Tell people about it */
2234 send_prepare_for(manager, manager->delayed_what, false);