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,
937 if (hashmap_size(m->sessions) > 1)
940 /* Hmm, there's only one session, but let's make sure it
941 * actually belongs to the user who is asking. If not, better
942 * be safe than sorry. */
944 s = hashmap_first(m->sessions);
948 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
949 if (ul == (unsigned long) -1)
952 return s->user->uid != ul;
958 static int send_start_unit(DBusConnection *connection, const char *unit_name, DBusError *error) {
959 DBusMessage *message, *reply;
960 const char *mode = "replace";
965 message = dbus_message_new_method_call(
966 "org.freedesktop.systemd1",
967 "/org/freedesktop/systemd1",
968 "org.freedesktop.systemd1.Manager",
973 if (!dbus_message_append_args(message,
974 DBUS_TYPE_STRING, &unit_name,
975 DBUS_TYPE_STRING, &mode,
976 DBUS_TYPE_INVALID)) {
977 dbus_message_unref(message);
981 reply = dbus_connection_send_with_reply_and_block(connection, message, -1, error);
982 dbus_message_unref(message);
987 dbus_message_unref(reply);
991 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
992 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
993 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
994 [INHIBIT_SLEEP] = "PrepareForSleep"
997 dbus_bool_t active = _active;
998 DBusMessage *message;
1003 assert(w < _INHIBIT_WHAT_MAX);
1004 assert(signal_name[w]);
1006 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1010 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1011 !dbus_connection_send(m->bus, message, NULL))
1014 dbus_message_unref(message);
1018 static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
1021 assert(w < _INHIBIT_WHAT_MAX);
1023 /* Tell everybody to prepare for shutdown/sleep */
1024 send_prepare_for(m, w, true);
1026 /* Update timestamp for timeout */
1027 if (!m->delayed_unit)
1028 m->delayed_timestamp = now(CLOCK_MONOTONIC);
1030 /* Remember what we want to do, possibly overriding what kind
1031 * of unit we previously queued. */
1032 m->delayed_unit = unit_name;
1033 m->delayed_what = w;
1038 static int bus_manager_can_shutdown_or_sleep(
1040 DBusConnection *connection,
1041 DBusMessage *message,
1044 const char *action_multiple_sessions,
1045 const char *action_ignore_inhibit,
1046 const char *sleep_type,
1048 DBusMessage **_reply) {
1050 bool multiple_sessions, challenge, blocked, b;
1052 DBusMessage *reply = NULL;
1059 assert(w <= _INHIBIT_WHAT_MAX);
1061 assert(action_multiple_sessions);
1062 assert(action_ignore_inhibit);
1067 r = can_sleep(sleep_type);
1077 r = have_multiple_sessions(connection, m, message, error);
1081 multiple_sessions = r > 0;
1082 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1084 if (multiple_sessions) {
1085 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1092 result = "challenge";
1098 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1102 if (r > 0 && !result)
1104 else if (challenge && (!result || streq(result, "yes")))
1105 result = "challenge";
1110 if (!multiple_sessions && !blocked) {
1111 /* If neither inhibit nor multiple sessions
1112 * apply then just check the normal policy */
1114 r = verify_polkit(connection, message, action, false, &challenge, error);
1121 result = "challenge";
1127 reply = dbus_message_new_method_return(message);
1131 b = dbus_message_append_args(
1133 DBUS_TYPE_STRING, &result,
1136 dbus_message_unref(reply);
1144 int bus_manager_shutdown_or_sleep_now_or_later(
1146 const char *unit_name,
1156 assert(w <= _INHIBIT_WHAT_MAX);
1159 m->inhibit_delay_max > 0 &&
1160 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL);
1163 /* Shutdown is delayed, keep in mind what we
1164 * want to do, and start a timeout */
1165 r = delay_shutdown_or_sleep(m, w, unit_name);
1167 /* Shutdown is not delayed, execute it
1169 r = send_start_unit(m->bus, unit_name, error);
1174 static int bus_manager_do_shutdown_or_sleep(
1176 DBusConnection *connection,
1177 DBusMessage *message,
1178 const char *unit_name,
1181 const char *action_multiple_sessions,
1182 const char *action_ignore_inhibit,
1183 const char *sleep_type,
1185 DBusMessage **_reply) {
1187 dbus_bool_t interactive;
1188 bool multiple_sessions, blocked;
1189 DBusMessage *reply = NULL;
1197 assert(w <= _INHIBIT_WHAT_MAX);
1199 assert(action_multiple_sessions);
1200 assert(action_ignore_inhibit);
1204 if (!dbus_message_get_args(
1207 DBUS_TYPE_BOOLEAN, &interactive,
1212 r = can_sleep(sleep_type);
1220 r = have_multiple_sessions(connection, m, message, error);
1224 multiple_sessions = r > 0;
1225 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1227 if (multiple_sessions) {
1228 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1234 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1239 if (!multiple_sessions && !blocked) {
1240 r = verify_polkit(connection, message, action, interactive, NULL, error);
1245 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1249 reply = dbus_message_new_method_return(message);
1257 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
1259 static const BusProperty bus_login_manager_properties[] = {
1260 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1261 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1262 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1263 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1264 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1265 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1266 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1267 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1268 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1269 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1270 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1271 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1272 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1273 { "HandlePowerKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_power_key) },
1274 { "HandleSleepKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_sleep_key) },
1275 { "HandleLidSwitch", bus_manager_append_handle_button, "s", offsetof(Manager, handle_lid_switch) },
1279 static DBusHandlerResult manager_message_handler(
1280 DBusConnection *connection,
1281 DBusMessage *message,
1284 Manager *m = userdata;
1287 DBusMessage *reply = NULL;
1294 dbus_error_init(&error);
1296 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1302 if (!dbus_message_get_args(
1305 DBUS_TYPE_STRING, &name,
1307 return bus_send_error_reply(connection, message, &error, -EINVAL);
1309 session = hashmap_get(m->sessions, name);
1311 return bus_send_error_reply(connection, message, &error, -ENOENT);
1313 reply = dbus_message_new_method_return(message);
1317 p = session_bus_path(session);
1321 b = dbus_message_append_args(
1323 DBUS_TYPE_OBJECT_PATH, &p,
1330 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1336 if (!dbus_message_get_args(
1339 DBUS_TYPE_UINT32, &pid,
1341 return bus_send_error_reply(connection, message, &error, -EINVAL);
1343 r = manager_get_session_by_pid(m, pid, &session);
1345 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1347 reply = dbus_message_new_method_return(message);
1351 p = session_bus_path(session);
1355 b = dbus_message_append_args(
1357 DBUS_TYPE_OBJECT_PATH, &p,
1364 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1370 if (!dbus_message_get_args(
1373 DBUS_TYPE_UINT32, &uid,
1375 return bus_send_error_reply(connection, message, &error, -EINVAL);
1377 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1379 return bus_send_error_reply(connection, message, &error, -ENOENT);
1381 reply = dbus_message_new_method_return(message);
1385 p = user_bus_path(user);
1389 b = dbus_message_append_args(
1391 DBUS_TYPE_OBJECT_PATH, &p,
1398 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1404 if (!dbus_message_get_args(
1407 DBUS_TYPE_STRING, &name,
1409 return bus_send_error_reply(connection, message, &error, -EINVAL);
1411 seat = hashmap_get(m->seats, name);
1413 return bus_send_error_reply(connection, message, &error, -ENOENT);
1415 reply = dbus_message_new_method_return(message);
1419 p = seat_bus_path(seat);
1423 b = dbus_message_append_args(
1425 DBUS_TYPE_OBJECT_PATH, &p,
1432 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1436 DBusMessageIter iter, sub;
1437 const char *empty = "";
1439 reply = dbus_message_new_method_return(message);
1443 dbus_message_iter_init_append(reply, &iter);
1445 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1448 HASHMAP_FOREACH(session, m->sessions, i) {
1449 DBusMessageIter sub2;
1452 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1455 uid = session->user->uid;
1457 p = session_bus_path(session);
1461 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1462 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1463 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1464 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1465 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1472 if (!dbus_message_iter_close_container(&sub, &sub2))
1476 if (!dbus_message_iter_close_container(&iter, &sub))
1479 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1483 DBusMessageIter iter, sub;
1485 reply = dbus_message_new_method_return(message);
1489 dbus_message_iter_init_append(reply, &iter);
1491 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1494 HASHMAP_FOREACH(user, m->users, i) {
1495 DBusMessageIter sub2;
1498 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1503 p = user_bus_path(user);
1507 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1508 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1509 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1516 if (!dbus_message_iter_close_container(&sub, &sub2))
1520 if (!dbus_message_iter_close_container(&iter, &sub))
1523 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1527 DBusMessageIter iter, sub;
1529 reply = dbus_message_new_method_return(message);
1533 dbus_message_iter_init_append(reply, &iter);
1535 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1538 HASHMAP_FOREACH(seat, m->seats, i) {
1539 DBusMessageIter sub2;
1541 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1544 p = seat_bus_path(seat);
1548 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1549 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1556 if (!dbus_message_iter_close_container(&sub, &sub2))
1560 if (!dbus_message_iter_close_container(&iter, &sub))
1563 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1564 Inhibitor *inhibitor;
1566 DBusMessageIter iter, sub;
1568 reply = dbus_message_new_method_return(message);
1572 dbus_message_iter_init_append(reply, &iter);
1574 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1577 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1578 DBusMessageIter sub2;
1579 dbus_uint32_t uid, pid;
1580 const char *what, *who, *why, *mode;
1582 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1585 what = strempty(inhibit_what_to_string(inhibitor->what));
1586 who = strempty(inhibitor->who);
1587 why = strempty(inhibitor->why);
1588 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1589 uid = (dbus_uint32_t) inhibitor->uid;
1590 pid = (dbus_uint32_t) inhibitor->pid;
1592 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1593 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1594 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1595 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1596 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1597 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1600 if (!dbus_message_iter_close_container(&sub, &sub2))
1604 if (!dbus_message_iter_close_container(&iter, &sub))
1607 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1609 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1612 return bus_send_error_reply(connection, message, &error, r);
1615 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1617 r = bus_manager_create_session(m, message, &reply);
1619 /* Don't delay the work on OOM here, since it might be
1620 * triggered by a low RLIMIT_NOFILE here (since we
1621 * send a dupped fd to the client), and we'd rather
1622 * see this fail quickly then be retried later */
1625 return bus_send_error_reply(connection, message, NULL, r);
1627 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1631 if (!dbus_message_get_args(
1634 DBUS_TYPE_STRING, &name,
1636 return bus_send_error_reply(connection, message, &error, -EINVAL);
1638 session = hashmap_get(m->sessions, name);
1640 return bus_send_error_reply(connection, message, &error, -ENOENT);
1642 /* We use the FIFO to detect stray sessions where the
1643 process invoking PAM dies abnormally. We need to make
1644 sure that that process is not killed if at the clean
1645 end of the session it closes the FIFO. Hence, with
1646 this call explicitly turn off the FIFO logic, so that
1647 the PAM code can finish clean up on its own */
1648 session_remove_fifo(session);
1650 reply = dbus_message_new_method_return(message);
1654 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1658 if (!dbus_message_get_args(
1661 DBUS_TYPE_STRING, &name,
1663 return bus_send_error_reply(connection, message, &error, -EINVAL);
1665 session = hashmap_get(m->sessions, name);
1667 return bus_send_error_reply(connection, message, &error, -ENOENT);
1669 r = session_activate(session);
1671 return bus_send_error_reply(connection, message, NULL, r);
1673 reply = dbus_message_new_method_return(message);
1677 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1678 const char *session_name, *seat_name;
1682 /* Same as ActivateSession() but refuses to work if
1683 * the seat doesn't match */
1685 if (!dbus_message_get_args(
1688 DBUS_TYPE_STRING, &session_name,
1689 DBUS_TYPE_STRING, &seat_name,
1691 return bus_send_error_reply(connection, message, &error, -EINVAL);
1693 session = hashmap_get(m->sessions, session_name);
1695 return bus_send_error_reply(connection, message, &error, -ENOENT);
1697 seat = hashmap_get(m->seats, seat_name);
1699 return bus_send_error_reply(connection, message, &error, -ENOENT);
1701 if (session->seat != seat)
1702 return bus_send_error_reply(connection, message, &error, -EINVAL);
1704 r = session_activate(session);
1706 return bus_send_error_reply(connection, message, NULL, r);
1708 reply = dbus_message_new_method_return(message);
1712 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1713 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1717 if (!dbus_message_get_args(
1720 DBUS_TYPE_STRING, &name,
1722 return bus_send_error_reply(connection, message, &error, -EINVAL);
1724 session = hashmap_get(m->sessions, name);
1726 return bus_send_error_reply(connection, message, &error, -ENOENT);
1728 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1731 reply = dbus_message_new_method_return(message);
1735 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1742 if (!dbus_message_get_args(
1745 DBUS_TYPE_STRING, &name,
1746 DBUS_TYPE_STRING, &swho,
1747 DBUS_TYPE_INT32, &signo,
1749 return bus_send_error_reply(connection, message, &error, -EINVAL);
1754 who = kill_who_from_string(swho);
1756 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 session = hashmap_get(m->sessions, name);
1764 return bus_send_error_reply(connection, message, &error, -ENOENT);
1766 r = session_kill(session, who, 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", "KillUser")) {
1779 if (!dbus_message_get_args(
1782 DBUS_TYPE_UINT32, &uid,
1783 DBUS_TYPE_INT32, &signo,
1785 return bus_send_error_reply(connection, message, &error, -EINVAL);
1787 if (signo <= 0 || signo >= _NSIG)
1788 return bus_send_error_reply(connection, message, &error, -EINVAL);
1790 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1792 return bus_send_error_reply(connection, message, &error, -ENOENT);
1794 r = user_kill(user, signo);
1796 return bus_send_error_reply(connection, message, NULL, r);
1798 reply = dbus_message_new_method_return(message);
1802 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1806 if (!dbus_message_get_args(
1809 DBUS_TYPE_STRING, &name,
1811 return bus_send_error_reply(connection, message, &error, -EINVAL);
1813 session = hashmap_get(m->sessions, name);
1815 return bus_send_error_reply(connection, message, &error, -ENOENT);
1817 r = session_stop(session);
1819 return bus_send_error_reply(connection, message, NULL, r);
1821 reply = dbus_message_new_method_return(message);
1825 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1829 if (!dbus_message_get_args(
1832 DBUS_TYPE_UINT32, &uid,
1834 return bus_send_error_reply(connection, message, &error, -EINVAL);
1836 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1838 return bus_send_error_reply(connection, message, &error, -ENOENT);
1840 r = user_stop(user);
1842 return bus_send_error_reply(connection, message, NULL, r);
1844 reply = dbus_message_new_method_return(message);
1848 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1852 if (!dbus_message_get_args(
1855 DBUS_TYPE_STRING, &name,
1857 return bus_send_error_reply(connection, message, &error, -EINVAL);
1859 seat = hashmap_get(m->seats, name);
1861 return bus_send_error_reply(connection, message, &error, -ENOENT);
1863 r = seat_stop_sessions(seat);
1865 return bus_send_error_reply(connection, message, NULL, r);
1867 reply = dbus_message_new_method_return(message);
1871 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1874 dbus_bool_t b, interactive;
1877 if (!dbus_message_get_args(
1880 DBUS_TYPE_UINT32, &uid,
1881 DBUS_TYPE_BOOLEAN, &b,
1882 DBUS_TYPE_BOOLEAN, &interactive,
1884 return bus_send_error_reply(connection, message, &error, -EINVAL);
1889 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1891 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1893 return bus_send_error_reply(connection, message, &error, r);
1895 mkdir_p_label("/var/lib/systemd", 0755);
1897 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1899 return bus_send_error_reply(connection, message, &error, r);
1901 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1912 return bus_send_error_reply(connection, message, &error, r);
1914 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1923 if (r < 0 && errno != ENOENT)
1924 return bus_send_error_reply(connection, message, &error, -errno);
1926 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1928 user_add_to_gc_queue(u);
1931 reply = dbus_message_new_method_return(message);
1935 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1936 const char *sysfs, *seat;
1937 dbus_bool_t interactive;
1939 if (!dbus_message_get_args(
1942 DBUS_TYPE_STRING, &seat,
1943 DBUS_TYPE_STRING, &sysfs,
1944 DBUS_TYPE_BOOLEAN, &interactive,
1946 return bus_send_error_reply(connection, message, &error, -EINVAL);
1948 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
1949 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1951 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
1953 return bus_send_error_reply(connection, message, &error, r);
1955 r = attach_device(m, seat, sysfs);
1957 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1959 reply = dbus_message_new_method_return(message);
1964 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
1965 dbus_bool_t interactive;
1967 if (!dbus_message_get_args(
1970 DBUS_TYPE_BOOLEAN, &interactive,
1972 return bus_send_error_reply(connection, message, &error, -EINVAL);
1974 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
1976 return bus_send_error_reply(connection, message, &error, r);
1978 r = flush_devices(m);
1980 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1982 reply = dbus_message_new_method_return(message);
1986 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
1988 r = bus_manager_do_shutdown_or_sleep(
1989 m, connection, message,
1990 SPECIAL_POWEROFF_TARGET,
1992 "org.freedesktop.login1.power-off",
1993 "org.freedesktop.login1.power-off-multiple-sessions",
1994 "org.freedesktop.login1.power-off-ignore-inhibit",
1998 return bus_send_error_reply(connection, message, &error, r);
1999 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2000 r = bus_manager_do_shutdown_or_sleep(
2001 m, connection, message,
2002 SPECIAL_REBOOT_TARGET,
2004 "org.freedesktop.login1.reboot",
2005 "org.freedesktop.login1.reboot-multiple-sessions",
2006 "org.freedesktop.login1.reboot-ignore-inhibit",
2010 return bus_send_error_reply(connection, message, &error, r);
2012 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2013 r = bus_manager_do_shutdown_or_sleep(
2014 m, connection, message,
2015 SPECIAL_SUSPEND_TARGET,
2017 "org.freedesktop.login1.suspend",
2018 "org.freedesktop.login1.suspend-multiple-sessions",
2019 "org.freedesktop.login1.suspend-ignore-inhibit",
2023 return bus_send_error_reply(connection, message, &error, r);
2024 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2025 r = bus_manager_do_shutdown_or_sleep(
2026 m, connection, message,
2027 SPECIAL_HIBERNATE_TARGET,
2029 "org.freedesktop.login1.hibernate",
2030 "org.freedesktop.login1.hibernate-multiple-sessions",
2031 "org.freedesktop.login1.hibernate-ignore-inhibit",
2035 return bus_send_error_reply(connection, message, &error, r);
2037 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2039 r = bus_manager_can_shutdown_or_sleep(
2040 m, connection, message,
2042 "org.freedesktop.login1.power-off",
2043 "org.freedesktop.login1.power-off-multiple-sessions",
2044 "org.freedesktop.login1.power-off-ignore-inhibit",
2048 return bus_send_error_reply(connection, message, &error, r);
2049 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2050 r = bus_manager_can_shutdown_or_sleep(
2051 m, connection, message,
2053 "org.freedesktop.login1.reboot",
2054 "org.freedesktop.login1.reboot-multiple-sessions",
2055 "org.freedesktop.login1.reboot-ignore-inhibit",
2059 return bus_send_error_reply(connection, message, &error, r);
2061 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2062 r = bus_manager_can_shutdown_or_sleep(
2063 m, connection, message,
2065 "org.freedesktop.login1.suspend",
2066 "org.freedesktop.login1.suspend-multiple-sessions",
2067 "org.freedesktop.login1.suspend-ignore-inhibit",
2071 return bus_send_error_reply(connection, message, &error, r);
2073 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2074 r = bus_manager_can_shutdown_or_sleep(
2075 m, connection, message,
2077 "org.freedesktop.login1.hibernate",
2078 "org.freedesktop.login1.hibernate-multiple-sessions",
2079 "org.freedesktop.login1.hibernate-ignore-inhibit",
2083 return bus_send_error_reply(connection, message, &error, r);
2085 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2086 char *introspection = NULL;
2095 if (!(reply = dbus_message_new_method_return(message)))
2098 /* We roll our own introspection code here, instead of
2099 * relying on bus_default_message_handler() because we
2100 * need to generate our introspection string
2103 if (!(f = open_memstream(&introspection, &size)))
2106 fputs(INTROSPECTION_BEGIN, f);
2108 HASHMAP_FOREACH(seat, m->seats, i) {
2109 p = bus_path_escape(seat->id);
2112 fprintf(f, "<node name=\"seat/%s\"/>", p);
2117 HASHMAP_FOREACH(user, m->users, i)
2118 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2120 HASHMAP_FOREACH(session, m->sessions, i) {
2121 p = bus_path_escape(session->id);
2124 fprintf(f, "<node name=\"session/%s\"/>", p);
2129 fputs(INTROSPECTION_END, f);
2133 free(introspection);
2142 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2143 free(introspection);
2147 free(introspection);
2149 const BusBoundProperties bps[] = {
2150 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2153 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2157 if (!dbus_connection_send(connection, reply, NULL))
2160 dbus_message_unref(reply);
2163 return DBUS_HANDLER_RESULT_HANDLED;
2167 dbus_message_unref(reply);
2169 dbus_error_free(&error);
2171 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2174 const DBusObjectPathVTable bus_manager_vtable = {
2175 .message_function = manager_message_handler
2178 DBusHandlerResult bus_message_filter(
2179 DBusConnection *connection,
2180 DBusMessage *message,
2183 Manager *m = userdata;
2190 dbus_error_init(&error);
2192 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2195 if (!dbus_message_get_args(message, &error,
2196 DBUS_TYPE_STRING, &cgroup,
2198 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2200 manager_cgroup_notify_empty(m, cgroup);
2203 dbus_error_free(&error);
2205 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2208 int manager_send_changed(Manager *manager, const char *properties) {
2214 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2218 if (!dbus_connection_send(manager->bus, m, NULL))
2225 dbus_message_unref(m);
2230 int manager_dispatch_delayed(Manager *manager) {
2231 const char *unit_name;
2238 if (!manager->delayed_unit)
2241 /* Continue delay? */
2243 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2244 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL);
2248 /* Reset delay data */
2249 unit_name = manager->delayed_unit;
2250 manager->delayed_unit = NULL;
2252 /* Actually do the shutdown */
2253 dbus_error_init(&error);
2254 r = send_start_unit(manager->bus, unit_name, &error);
2256 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2257 dbus_error_free(&error);
2261 /* Tell people about it */
2262 send_prepare_for(manager, manager->delayed_what, false);