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" \
209 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
210 " <property name=\"HandleSleepKey\" type=\"s\" access=\"read\"/>\n" \
211 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
214 #define INTROSPECTION_BEGIN \
215 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
217 BUS_MANAGER_INTERFACE \
218 BUS_PROPERTIES_INTERFACE \
220 BUS_INTROSPECTABLE_INTERFACE
222 #define INTROSPECTION_END \
225 #define INTERFACES_LIST \
226 BUS_GENERIC_INTERFACES_LIST \
227 "org.freedesktop.login1.Manager\0"
229 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
237 b = manager_get_idle_hint(m, NULL) > 0;
238 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
244 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
253 manager_get_idle_hint(m, &t);
254 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
256 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
262 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
267 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
268 p = inhibit_what_to_string(w);
270 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
276 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
277 Session *session = NULL;
279 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
280 uint32_t uid, leader, audit_id = 0;
281 dbus_bool_t remote, kill_processes;
282 char **controllers = NULL, **reset_controllers = NULL;
286 DBusMessageIter iter;
291 DBusMessage *reply = NULL;
298 if (!dbus_message_iter_init(message, &iter) ||
299 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
302 dbus_message_iter_get_basic(&iter, &uid);
304 if (!dbus_message_iter_next(&iter) ||
305 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
308 dbus_message_iter_get_basic(&iter, &leader);
311 !dbus_message_iter_next(&iter) ||
312 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
315 dbus_message_iter_get_basic(&iter, &service);
317 if (!dbus_message_iter_next(&iter) ||
318 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
321 dbus_message_iter_get_basic(&iter, &type);
322 t = session_type_from_string(type);
325 !dbus_message_iter_next(&iter) ||
326 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
329 dbus_message_iter_get_basic(&iter, &class);
333 c = session_class_from_string(class);
336 !dbus_message_iter_next(&iter) ||
337 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
340 dbus_message_iter_get_basic(&iter, &seat);
345 s = hashmap_get(m->seats, seat);
350 if (!dbus_message_iter_next(&iter) ||
351 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
354 dbus_message_iter_get_basic(&iter, &vtnr);
356 if (!dbus_message_iter_next(&iter) ||
357 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
360 dbus_message_iter_get_basic(&iter, &tty);
362 if (tty_is_vc(tty)) {
367 else if (s != m->vtconsole)
370 v = vtnr_from_tty(tty);
373 return v < 0 ? v : -EINVAL;
377 else if (vtnr != (uint32_t) v)
379 } else if (tty_is_console(tty)) {
383 else if (s != m->vtconsole)
389 } else if (!isempty(tty) && s && seat_is_vtconsole(s))
393 if (seat_can_multi_session(s)) {
402 if (!dbus_message_iter_next(&iter) ||
403 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
406 dbus_message_iter_get_basic(&iter, &display);
408 if (!dbus_message_iter_next(&iter) ||
409 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
412 dbus_message_iter_get_basic(&iter, &remote);
414 if (!dbus_message_iter_next(&iter) ||
415 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
418 dbus_message_iter_get_basic(&iter, &remote_user);
420 if (!dbus_message_iter_next(&iter) ||
421 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
424 dbus_message_iter_get_basic(&iter, &remote_host);
426 if (!dbus_message_iter_next(&iter) ||
427 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
428 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
431 r = bus_parse_strv_iter(&iter, &controllers);
435 if (strv_contains(controllers, "systemd") ||
436 !dbus_message_iter_next(&iter) ||
437 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
438 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
443 r = bus_parse_strv_iter(&iter, &reset_controllers);
447 if (strv_contains(reset_controllers, "systemd") ||
448 !dbus_message_iter_next(&iter) ||
449 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
454 dbus_message_iter_get_basic(&iter, &kill_processes);
456 r = manager_add_user_by_uid(m, uid, &user);
460 audit_session_from_pid(leader, &audit_id);
463 asprintf(&id, "%lu", (unsigned long) audit_id);
470 session = hashmap_get(m->sessions, id);
475 fifo_fd = session_create_fifo(session);
481 /* Session already exists, client is probably
482 * something like "su" which changes uid but
483 * is still the same audit session */
485 reply = dbus_message_new_method_return(message);
491 p = session_bus_path(session);
497 seat = session->seat ? session->seat->id : "";
498 vtnr = session->vtnr;
499 b = dbus_message_append_args(
501 DBUS_TYPE_STRING, &session->id,
502 DBUS_TYPE_OBJECT_PATH, &p,
503 DBUS_TYPE_STRING, &session->user->runtime_path,
504 DBUS_TYPE_UNIX_FD, &fifo_fd,
505 DBUS_TYPE_STRING, &seat,
506 DBUS_TYPE_UINT32, &vtnr,
515 close_nointr_nofail(fifo_fd);
518 strv_free(controllers);
519 strv_free(reset_controllers);
529 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
534 } while (hashmap_get(m->sessions, id));
537 r = manager_add_session(m, user, id, &session);
542 session->leader = leader;
543 session->audit_id = audit_id;
546 session->remote = remote;
547 session->controllers = controllers;
548 session->reset_controllers = reset_controllers;
549 session->kill_processes = kill_processes;
550 session->vtnr = vtnr;
552 controllers = reset_controllers = NULL;
555 session->tty = strdup(tty);
562 if (!isempty(display)) {
563 session->display = strdup(display);
564 if (!session->display) {
570 if (!isempty(remote_user)) {
571 session->remote_user = strdup(remote_user);
572 if (!session->remote_user) {
578 if (!isempty(remote_host)) {
579 session->remote_host = strdup(remote_host);
580 if (!session->remote_host) {
586 if (!isempty(service)) {
587 session->service = strdup(service);
588 if (!session->service) {
594 fifo_fd = session_create_fifo(session);
601 r = seat_attach_session(s, session);
606 r = session_start(session);
610 reply = dbus_message_new_method_return(message);
616 p = session_bus_path(session);
622 seat = s ? s->id : "";
623 b = dbus_message_append_args(
625 DBUS_TYPE_STRING, &session->id,
626 DBUS_TYPE_OBJECT_PATH, &p,
627 DBUS_TYPE_STRING, &session->user->runtime_path,
628 DBUS_TYPE_UNIX_FD, &fifo_fd,
629 DBUS_TYPE_STRING, &seat,
630 DBUS_TYPE_UINT32, &vtnr,
639 close_nointr_nofail(fifo_fd);
645 strv_free(controllers);
646 strv_free(reset_controllers);
649 session_add_to_gc_queue(session);
652 user_add_to_gc_queue(user);
655 close_nointr_nofail(fifo_fd);
658 dbus_message_unref(reply);
663 static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
666 const char *who, *why, *what, *mode;
672 DBusMessage *reply = NULL;
680 if (!dbus_message_get_args(
683 DBUS_TYPE_STRING, &what,
684 DBUS_TYPE_STRING, &who,
685 DBUS_TYPE_STRING, &why,
686 DBUS_TYPE_STRING, &mode,
687 DBUS_TYPE_INVALID)) {
692 w = inhibit_what_from_string(what);
698 mm = inhibit_mode_from_string(mode);
704 r = verify_polkit(connection, message,
706 "org.freedesktop.login1.inhibit-block" :
707 "org.freedesktop.login1.inhibit-delay", false, NULL, error);
711 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
712 if (ul == (unsigned long) -1) {
717 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
727 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
731 } while (hashmap_get(m->inhibitors, id));
733 r = manager_add_inhibitor(m, id, &i);
743 i->why = strdup(why);
744 i->who = strdup(who);
746 if (!i->why || !i->who) {
751 fifo_fd = inhibitor_create_fifo(i);
757 reply = dbus_message_new_method_return(message);
763 if (!dbus_message_append_args(
765 DBUS_TYPE_UNIX_FD, &fifo_fd,
766 DBUS_TYPE_INVALID)) {
771 close_nointr_nofail(fifo_fd);
783 close_nointr_nofail(fifo_fd);
786 dbus_message_unref(reply);
791 static int trigger_device(Manager *m, struct udev_device *d) {
792 struct udev_enumerate *e;
793 struct udev_list_entry *first, *item;
798 e = udev_enumerate_new(m->udev);
805 if (udev_enumerate_add_match_parent(e, d) < 0) {
811 if (udev_enumerate_scan_devices(e) < 0) {
816 first = udev_enumerate_get_list_entry(e);
817 udev_list_entry_foreach(item, first) {
821 p = udev_list_entry_get_name(item);
823 t = strappend(p, "/uevent");
829 write_one_line_file(t, "change");
837 udev_enumerate_unref(e);
842 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
843 struct udev_device *d;
844 char *rule = NULL, *file = NULL;
845 const char *id_for_seat;
852 d = udev_device_new_from_syspath(m->udev, sysfs);
856 if (!udev_device_has_tag(d, "seat")) {
861 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
867 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
872 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
877 mkdir_p_label("/etc/udev/rules.d", 0755);
878 r = write_one_line_file_atomic(file, rule);
882 r = trigger_device(m, d);
889 udev_device_unref(d);
894 static int flush_devices(Manager *m) {
899 d = opendir("/etc/udev/rules.d");
902 log_warning("Failed to open /etc/udev/rules.d: %m");
906 while ((de = readdir(d))) {
908 if (!dirent_is_file(de))
911 if (!startswith(de->d_name, "72-seat-"))
914 if (!endswith(de->d_name, ".rules"))
917 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
918 log_warning("Failed to unlink %s: %m", de->d_name);
924 return trigger_device(m, NULL);
927 static int have_multiple_sessions(
928 DBusConnection *connection,
930 DBusMessage *message,
939 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
940 if (ul == (unsigned long) -1)
943 /* Check for other users' sessions. Greeter sessions do not count. */
944 HASHMAP_FOREACH(session, m->sessions, i)
945 if (session->class == SESSION_USER && session->user->uid != ul)
951 static int send_start_unit(DBusConnection *connection, const char *unit_name, DBusError *error) {
952 DBusMessage *message, *reply;
953 const char *mode = "replace";
958 message = dbus_message_new_method_call(
959 "org.freedesktop.systemd1",
960 "/org/freedesktop/systemd1",
961 "org.freedesktop.systemd1.Manager",
966 if (!dbus_message_append_args(message,
967 DBUS_TYPE_STRING, &unit_name,
968 DBUS_TYPE_STRING, &mode,
969 DBUS_TYPE_INVALID)) {
970 dbus_message_unref(message);
974 reply = dbus_connection_send_with_reply_and_block(connection, message, -1, error);
975 dbus_message_unref(message);
980 dbus_message_unref(reply);
984 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
985 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
986 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
987 [INHIBIT_SLEEP] = "PrepareForSleep"
990 dbus_bool_t active = _active;
991 DBusMessage *message;
996 assert(w < _INHIBIT_WHAT_MAX);
997 assert(signal_name[w]);
999 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1003 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1004 !dbus_connection_send(m->bus, message, NULL))
1007 dbus_message_unref(message);
1011 static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
1014 assert(w < _INHIBIT_WHAT_MAX);
1016 /* Tell everybody to prepare for shutdown/sleep */
1017 send_prepare_for(m, w, true);
1019 /* Update timestamp for timeout */
1020 if (!m->delayed_unit)
1021 m->delayed_timestamp = now(CLOCK_MONOTONIC);
1023 /* Remember what we want to do, possibly overriding what kind
1024 * of unit we previously queued. */
1025 m->delayed_unit = unit_name;
1026 m->delayed_what = w;
1031 static int bus_manager_can_shutdown_or_sleep(
1033 DBusConnection *connection,
1034 DBusMessage *message,
1037 const char *action_multiple_sessions,
1038 const char *action_ignore_inhibit,
1039 const char *sleep_type,
1041 DBusMessage **_reply) {
1043 bool multiple_sessions, challenge, blocked, b;
1045 DBusMessage *reply = NULL;
1052 assert(w <= _INHIBIT_WHAT_MAX);
1054 assert(action_multiple_sessions);
1055 assert(action_ignore_inhibit);
1060 r = can_sleep(sleep_type);
1070 r = have_multiple_sessions(connection, m, message, error);
1074 multiple_sessions = r > 0;
1075 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1077 if (multiple_sessions) {
1078 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1085 result = "challenge";
1091 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1095 if (r > 0 && !result)
1097 else if (challenge && (!result || streq(result, "yes")))
1098 result = "challenge";
1103 if (!multiple_sessions && !blocked) {
1104 /* If neither inhibit nor multiple sessions
1105 * apply then just check the normal policy */
1107 r = verify_polkit(connection, message, action, false, &challenge, error);
1114 result = "challenge";
1120 reply = dbus_message_new_method_return(message);
1124 b = dbus_message_append_args(
1126 DBUS_TYPE_STRING, &result,
1129 dbus_message_unref(reply);
1137 int bus_manager_shutdown_or_sleep_now_or_later(
1139 const char *unit_name,
1149 assert(w <= _INHIBIT_WHAT_MAX);
1152 m->inhibit_delay_max > 0 &&
1153 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL);
1156 /* Shutdown is delayed, keep in mind what we
1157 * want to do, and start a timeout */
1158 r = delay_shutdown_or_sleep(m, w, unit_name);
1160 /* Shutdown is not delayed, execute it
1162 r = send_start_unit(m->bus, unit_name, error);
1167 static int bus_manager_do_shutdown_or_sleep(
1169 DBusConnection *connection,
1170 DBusMessage *message,
1171 const char *unit_name,
1174 const char *action_multiple_sessions,
1175 const char *action_ignore_inhibit,
1176 const char *sleep_type,
1178 DBusMessage **_reply) {
1180 dbus_bool_t interactive;
1181 bool multiple_sessions, blocked;
1182 DBusMessage *reply = NULL;
1190 assert(w <= _INHIBIT_WHAT_MAX);
1192 assert(action_multiple_sessions);
1193 assert(action_ignore_inhibit);
1197 if (!dbus_message_get_args(
1200 DBUS_TYPE_BOOLEAN, &interactive,
1205 r = can_sleep(sleep_type);
1213 r = have_multiple_sessions(connection, m, message, error);
1217 multiple_sessions = r > 0;
1218 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1220 if (multiple_sessions) {
1221 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1227 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1232 if (!multiple_sessions && !blocked) {
1233 r = verify_polkit(connection, message, action, interactive, NULL, error);
1238 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1242 reply = dbus_message_new_method_return(message);
1250 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
1252 static const BusProperty bus_login_manager_properties[] = {
1253 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1254 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1255 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1256 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1257 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1258 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1259 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1260 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1261 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1262 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1263 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1264 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1265 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1266 { "HandlePowerKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_power_key) },
1267 { "HandleSleepKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_sleep_key) },
1268 { "HandleLidSwitch", bus_manager_append_handle_button, "s", offsetof(Manager, handle_lid_switch) },
1272 static DBusHandlerResult manager_message_handler(
1273 DBusConnection *connection,
1274 DBusMessage *message,
1277 Manager *m = userdata;
1280 DBusMessage *reply = NULL;
1287 dbus_error_init(&error);
1289 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1295 if (!dbus_message_get_args(
1298 DBUS_TYPE_STRING, &name,
1300 return bus_send_error_reply(connection, message, &error, -EINVAL);
1302 session = hashmap_get(m->sessions, name);
1304 return bus_send_error_reply(connection, message, &error, -ENOENT);
1306 reply = dbus_message_new_method_return(message);
1310 p = session_bus_path(session);
1314 b = dbus_message_append_args(
1316 DBUS_TYPE_OBJECT_PATH, &p,
1323 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1329 if (!dbus_message_get_args(
1332 DBUS_TYPE_UINT32, &pid,
1334 return bus_send_error_reply(connection, message, &error, -EINVAL);
1336 r = manager_get_session_by_pid(m, pid, &session);
1338 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1340 reply = dbus_message_new_method_return(message);
1344 p = session_bus_path(session);
1348 b = dbus_message_append_args(
1350 DBUS_TYPE_OBJECT_PATH, &p,
1357 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1363 if (!dbus_message_get_args(
1366 DBUS_TYPE_UINT32, &uid,
1368 return bus_send_error_reply(connection, message, &error, -EINVAL);
1370 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1372 return bus_send_error_reply(connection, message, &error, -ENOENT);
1374 reply = dbus_message_new_method_return(message);
1378 p = user_bus_path(user);
1382 b = dbus_message_append_args(
1384 DBUS_TYPE_OBJECT_PATH, &p,
1391 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1397 if (!dbus_message_get_args(
1400 DBUS_TYPE_STRING, &name,
1402 return bus_send_error_reply(connection, message, &error, -EINVAL);
1404 seat = hashmap_get(m->seats, name);
1406 return bus_send_error_reply(connection, message, &error, -ENOENT);
1408 reply = dbus_message_new_method_return(message);
1412 p = seat_bus_path(seat);
1416 b = dbus_message_append_args(
1418 DBUS_TYPE_OBJECT_PATH, &p,
1425 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1429 DBusMessageIter iter, sub;
1430 const char *empty = "";
1432 reply = dbus_message_new_method_return(message);
1436 dbus_message_iter_init_append(reply, &iter);
1438 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1441 HASHMAP_FOREACH(session, m->sessions, i) {
1442 DBusMessageIter sub2;
1445 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1448 uid = session->user->uid;
1450 p = session_bus_path(session);
1454 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1455 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1456 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1457 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1458 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1465 if (!dbus_message_iter_close_container(&sub, &sub2))
1469 if (!dbus_message_iter_close_container(&iter, &sub))
1472 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1476 DBusMessageIter iter, sub;
1478 reply = dbus_message_new_method_return(message);
1482 dbus_message_iter_init_append(reply, &iter);
1484 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1487 HASHMAP_FOREACH(user, m->users, i) {
1488 DBusMessageIter sub2;
1491 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1496 p = user_bus_path(user);
1500 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1501 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1502 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1509 if (!dbus_message_iter_close_container(&sub, &sub2))
1513 if (!dbus_message_iter_close_container(&iter, &sub))
1516 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1520 DBusMessageIter iter, sub;
1522 reply = dbus_message_new_method_return(message);
1526 dbus_message_iter_init_append(reply, &iter);
1528 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1531 HASHMAP_FOREACH(seat, m->seats, i) {
1532 DBusMessageIter sub2;
1534 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1537 p = seat_bus_path(seat);
1541 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1542 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1549 if (!dbus_message_iter_close_container(&sub, &sub2))
1553 if (!dbus_message_iter_close_container(&iter, &sub))
1556 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1557 Inhibitor *inhibitor;
1559 DBusMessageIter iter, sub;
1561 reply = dbus_message_new_method_return(message);
1565 dbus_message_iter_init_append(reply, &iter);
1567 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1570 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1571 DBusMessageIter sub2;
1572 dbus_uint32_t uid, pid;
1573 const char *what, *who, *why, *mode;
1575 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1578 what = strempty(inhibit_what_to_string(inhibitor->what));
1579 who = strempty(inhibitor->who);
1580 why = strempty(inhibitor->why);
1581 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1582 uid = (dbus_uint32_t) inhibitor->uid;
1583 pid = (dbus_uint32_t) inhibitor->pid;
1585 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1586 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1587 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1588 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1589 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1590 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1593 if (!dbus_message_iter_close_container(&sub, &sub2))
1597 if (!dbus_message_iter_close_container(&iter, &sub))
1600 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1602 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1605 return bus_send_error_reply(connection, message, &error, r);
1608 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1610 r = bus_manager_create_session(m, message, &reply);
1612 /* Don't delay the work on OOM here, since it might be
1613 * triggered by a low RLIMIT_NOFILE here (since we
1614 * send a dupped fd to the client), and we'd rather
1615 * see this fail quickly then be retried later */
1618 return bus_send_error_reply(connection, message, NULL, r);
1620 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1624 if (!dbus_message_get_args(
1627 DBUS_TYPE_STRING, &name,
1629 return bus_send_error_reply(connection, message, &error, -EINVAL);
1631 session = hashmap_get(m->sessions, name);
1633 return bus_send_error_reply(connection, message, &error, -ENOENT);
1635 /* We use the FIFO to detect stray sessions where the
1636 process invoking PAM dies abnormally. We need to make
1637 sure that that process is not killed if at the clean
1638 end of the session it closes the FIFO. Hence, with
1639 this call explicitly turn off the FIFO logic, so that
1640 the PAM code can finish clean up on its own */
1641 session_remove_fifo(session);
1643 reply = dbus_message_new_method_return(message);
1647 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1651 if (!dbus_message_get_args(
1654 DBUS_TYPE_STRING, &name,
1656 return bus_send_error_reply(connection, message, &error, -EINVAL);
1658 session = hashmap_get(m->sessions, name);
1660 return bus_send_error_reply(connection, message, &error, -ENOENT);
1662 r = session_activate(session);
1664 return bus_send_error_reply(connection, message, NULL, r);
1666 reply = dbus_message_new_method_return(message);
1670 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1671 const char *session_name, *seat_name;
1675 /* Same as ActivateSession() but refuses to work if
1676 * the seat doesn't match */
1678 if (!dbus_message_get_args(
1681 DBUS_TYPE_STRING, &session_name,
1682 DBUS_TYPE_STRING, &seat_name,
1684 return bus_send_error_reply(connection, message, &error, -EINVAL);
1686 session = hashmap_get(m->sessions, session_name);
1688 return bus_send_error_reply(connection, message, &error, -ENOENT);
1690 seat = hashmap_get(m->seats, seat_name);
1692 return bus_send_error_reply(connection, message, &error, -ENOENT);
1694 if (session->seat != seat)
1695 return bus_send_error_reply(connection, message, &error, -EINVAL);
1697 r = session_activate(session);
1699 return bus_send_error_reply(connection, message, NULL, r);
1701 reply = dbus_message_new_method_return(message);
1705 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1706 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1710 if (!dbus_message_get_args(
1713 DBUS_TYPE_STRING, &name,
1715 return bus_send_error_reply(connection, message, &error, -EINVAL);
1717 session = hashmap_get(m->sessions, name);
1719 return bus_send_error_reply(connection, message, &error, -ENOENT);
1721 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1724 reply = dbus_message_new_method_return(message);
1728 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1735 if (!dbus_message_get_args(
1738 DBUS_TYPE_STRING, &name,
1739 DBUS_TYPE_STRING, &swho,
1740 DBUS_TYPE_INT32, &signo,
1742 return bus_send_error_reply(connection, message, &error, -EINVAL);
1747 who = kill_who_from_string(swho);
1749 return bus_send_error_reply(connection, message, &error, -EINVAL);
1752 if (signo <= 0 || signo >= _NSIG)
1753 return bus_send_error_reply(connection, message, &error, -EINVAL);
1755 session = hashmap_get(m->sessions, name);
1757 return bus_send_error_reply(connection, message, &error, -ENOENT);
1759 r = session_kill(session, who, signo);
1761 return bus_send_error_reply(connection, message, NULL, r);
1763 reply = dbus_message_new_method_return(message);
1767 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1772 if (!dbus_message_get_args(
1775 DBUS_TYPE_UINT32, &uid,
1776 DBUS_TYPE_INT32, &signo,
1778 return bus_send_error_reply(connection, message, &error, -EINVAL);
1780 if (signo <= 0 || signo >= _NSIG)
1781 return bus_send_error_reply(connection, message, &error, -EINVAL);
1783 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1785 return bus_send_error_reply(connection, message, &error, -ENOENT);
1787 r = user_kill(user, signo);
1789 return bus_send_error_reply(connection, message, NULL, r);
1791 reply = dbus_message_new_method_return(message);
1795 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1799 if (!dbus_message_get_args(
1802 DBUS_TYPE_STRING, &name,
1804 return bus_send_error_reply(connection, message, &error, -EINVAL);
1806 session = hashmap_get(m->sessions, name);
1808 return bus_send_error_reply(connection, message, &error, -ENOENT);
1810 r = session_stop(session);
1812 return bus_send_error_reply(connection, message, NULL, r);
1814 reply = dbus_message_new_method_return(message);
1818 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1822 if (!dbus_message_get_args(
1825 DBUS_TYPE_UINT32, &uid,
1827 return bus_send_error_reply(connection, message, &error, -EINVAL);
1829 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1831 return bus_send_error_reply(connection, message, &error, -ENOENT);
1833 r = user_stop(user);
1835 return bus_send_error_reply(connection, message, NULL, r);
1837 reply = dbus_message_new_method_return(message);
1841 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1845 if (!dbus_message_get_args(
1848 DBUS_TYPE_STRING, &name,
1850 return bus_send_error_reply(connection, message, &error, -EINVAL);
1852 seat = hashmap_get(m->seats, name);
1854 return bus_send_error_reply(connection, message, &error, -ENOENT);
1856 r = seat_stop_sessions(seat);
1858 return bus_send_error_reply(connection, message, NULL, r);
1860 reply = dbus_message_new_method_return(message);
1864 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1867 dbus_bool_t b, interactive;
1870 if (!dbus_message_get_args(
1873 DBUS_TYPE_UINT32, &uid,
1874 DBUS_TYPE_BOOLEAN, &b,
1875 DBUS_TYPE_BOOLEAN, &interactive,
1877 return bus_send_error_reply(connection, message, &error, -EINVAL);
1882 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1884 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1886 return bus_send_error_reply(connection, message, &error, r);
1888 mkdir_p_label("/var/lib/systemd", 0755);
1890 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1892 return bus_send_error_reply(connection, message, &error, r);
1894 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1905 return bus_send_error_reply(connection, message, &error, r);
1907 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1916 if (r < 0 && errno != ENOENT)
1917 return bus_send_error_reply(connection, message, &error, -errno);
1919 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1921 user_add_to_gc_queue(u);
1924 reply = dbus_message_new_method_return(message);
1928 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1929 const char *sysfs, *seat;
1930 dbus_bool_t interactive;
1932 if (!dbus_message_get_args(
1935 DBUS_TYPE_STRING, &seat,
1936 DBUS_TYPE_STRING, &sysfs,
1937 DBUS_TYPE_BOOLEAN, &interactive,
1939 return bus_send_error_reply(connection, message, &error, -EINVAL);
1941 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
1942 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1944 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
1946 return bus_send_error_reply(connection, message, &error, r);
1948 r = attach_device(m, seat, sysfs);
1950 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1952 reply = dbus_message_new_method_return(message);
1957 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
1958 dbus_bool_t interactive;
1960 if (!dbus_message_get_args(
1963 DBUS_TYPE_BOOLEAN, &interactive,
1965 return bus_send_error_reply(connection, message, &error, -EINVAL);
1967 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
1969 return bus_send_error_reply(connection, message, &error, r);
1971 r = flush_devices(m);
1973 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1975 reply = dbus_message_new_method_return(message);
1979 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
1981 r = bus_manager_do_shutdown_or_sleep(
1982 m, connection, message,
1983 SPECIAL_POWEROFF_TARGET,
1985 "org.freedesktop.login1.power-off",
1986 "org.freedesktop.login1.power-off-multiple-sessions",
1987 "org.freedesktop.login1.power-off-ignore-inhibit",
1991 return bus_send_error_reply(connection, message, &error, r);
1992 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
1993 r = bus_manager_do_shutdown_or_sleep(
1994 m, connection, message,
1995 SPECIAL_REBOOT_TARGET,
1997 "org.freedesktop.login1.reboot",
1998 "org.freedesktop.login1.reboot-multiple-sessions",
1999 "org.freedesktop.login1.reboot-ignore-inhibit",
2003 return bus_send_error_reply(connection, message, &error, r);
2005 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2006 r = bus_manager_do_shutdown_or_sleep(
2007 m, connection, message,
2008 SPECIAL_SUSPEND_TARGET,
2010 "org.freedesktop.login1.suspend",
2011 "org.freedesktop.login1.suspend-multiple-sessions",
2012 "org.freedesktop.login1.suspend-ignore-inhibit",
2016 return bus_send_error_reply(connection, message, &error, r);
2017 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2018 r = bus_manager_do_shutdown_or_sleep(
2019 m, connection, message,
2020 SPECIAL_HIBERNATE_TARGET,
2022 "org.freedesktop.login1.hibernate",
2023 "org.freedesktop.login1.hibernate-multiple-sessions",
2024 "org.freedesktop.login1.hibernate-ignore-inhibit",
2028 return bus_send_error_reply(connection, message, &error, r);
2030 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2032 r = bus_manager_can_shutdown_or_sleep(
2033 m, connection, message,
2035 "org.freedesktop.login1.power-off",
2036 "org.freedesktop.login1.power-off-multiple-sessions",
2037 "org.freedesktop.login1.power-off-ignore-inhibit",
2041 return bus_send_error_reply(connection, message, &error, r);
2042 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2043 r = bus_manager_can_shutdown_or_sleep(
2044 m, connection, message,
2046 "org.freedesktop.login1.reboot",
2047 "org.freedesktop.login1.reboot-multiple-sessions",
2048 "org.freedesktop.login1.reboot-ignore-inhibit",
2052 return bus_send_error_reply(connection, message, &error, r);
2054 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2055 r = bus_manager_can_shutdown_or_sleep(
2056 m, connection, message,
2058 "org.freedesktop.login1.suspend",
2059 "org.freedesktop.login1.suspend-multiple-sessions",
2060 "org.freedesktop.login1.suspend-ignore-inhibit",
2064 return bus_send_error_reply(connection, message, &error, r);
2066 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2067 r = bus_manager_can_shutdown_or_sleep(
2068 m, connection, message,
2070 "org.freedesktop.login1.hibernate",
2071 "org.freedesktop.login1.hibernate-multiple-sessions",
2072 "org.freedesktop.login1.hibernate-ignore-inhibit",
2076 return bus_send_error_reply(connection, message, &error, r);
2078 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2079 char *introspection = NULL;
2088 if (!(reply = dbus_message_new_method_return(message)))
2091 /* We roll our own introspection code here, instead of
2092 * relying on bus_default_message_handler() because we
2093 * need to generate our introspection string
2096 if (!(f = open_memstream(&introspection, &size)))
2099 fputs(INTROSPECTION_BEGIN, f);
2101 HASHMAP_FOREACH(seat, m->seats, i) {
2102 p = bus_path_escape(seat->id);
2105 fprintf(f, "<node name=\"seat/%s\"/>", p);
2110 HASHMAP_FOREACH(user, m->users, i)
2111 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2113 HASHMAP_FOREACH(session, m->sessions, i) {
2114 p = bus_path_escape(session->id);
2117 fprintf(f, "<node name=\"session/%s\"/>", p);
2122 fputs(INTROSPECTION_END, f);
2126 free(introspection);
2135 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2136 free(introspection);
2140 free(introspection);
2142 const BusBoundProperties bps[] = {
2143 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2146 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2150 if (!dbus_connection_send(connection, reply, NULL))
2153 dbus_message_unref(reply);
2156 return DBUS_HANDLER_RESULT_HANDLED;
2160 dbus_message_unref(reply);
2162 dbus_error_free(&error);
2164 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2167 const DBusObjectPathVTable bus_manager_vtable = {
2168 .message_function = manager_message_handler
2171 DBusHandlerResult bus_message_filter(
2172 DBusConnection *connection,
2173 DBusMessage *message,
2176 Manager *m = userdata;
2183 dbus_error_init(&error);
2185 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2188 if (!dbus_message_get_args(message, &error,
2189 DBUS_TYPE_STRING, &cgroup,
2191 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2193 manager_cgroup_notify_empty(m, cgroup);
2196 dbus_error_free(&error);
2198 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2201 int manager_send_changed(Manager *manager, const char *properties) {
2207 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2211 if (!dbus_connection_send(manager->bus, m, NULL))
2218 dbus_message_unref(m);
2223 int manager_dispatch_delayed(Manager *manager) {
2224 const char *unit_name;
2231 if (!manager->delayed_unit)
2234 /* Continue delay? */
2236 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2237 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL);
2241 /* Reset delay data */
2242 unit_name = manager->delayed_unit;
2243 manager->delayed_unit = NULL;
2245 /* Actually do the shutdown */
2246 dbus_error_init(&error);
2247 r = send_start_unit(manager->bus, unit_name, &error);
2249 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2250 dbus_error_free(&error);
2254 /* Tell people about it */
2255 send_prepare_for(manager, manager->delayed_what, false);