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);
1075 r = have_multiple_sessions(connection, m, message, error);
1079 multiple_sessions = r > 0;
1080 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1082 if (multiple_sessions) {
1083 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1090 result = "challenge";
1096 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1100 if (r > 0 && !result)
1102 else if (challenge && (!result || streq(result, "yes")))
1103 result = "challenge";
1108 if (!multiple_sessions && !blocked) {
1109 /* If neither inhibit nor multiple sessions
1110 * apply then just check the normal policy */
1112 r = verify_polkit(connection, message, action, false, &challenge, error);
1119 result = "challenge";
1125 reply = dbus_message_new_method_return(message);
1129 b = dbus_message_append_args(
1131 DBUS_TYPE_STRING, &result,
1134 dbus_message_unref(reply);
1142 int bus_manager_shutdown_or_sleep_now_or_later(
1144 const char *unit_name,
1154 assert(w <= _INHIBIT_WHAT_MAX);
1157 m->inhibit_delay_max > 0 &&
1158 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL);
1161 /* Shutdown is delayed, keep in mind what we
1162 * want to do, and start a timeout */
1163 r = delay_shutdown_or_sleep(m, w, unit_name);
1165 /* Shutdown is not delayed, execute it
1167 r = send_start_unit(m->bus, unit_name, error);
1172 static int bus_manager_do_shutdown_or_sleep(
1174 DBusConnection *connection,
1175 DBusMessage *message,
1176 const char *unit_name,
1179 const char *action_multiple_sessions,
1180 const char *action_ignore_inhibit,
1181 const char *sleep_type,
1183 DBusMessage **_reply) {
1185 dbus_bool_t interactive;
1186 bool multiple_sessions, blocked;
1187 DBusMessage *reply = NULL;
1195 assert(w <= _INHIBIT_WHAT_MAX);
1197 assert(action_multiple_sessions);
1198 assert(action_ignore_inhibit);
1202 if (!dbus_message_get_args(
1205 DBUS_TYPE_BOOLEAN, &interactive,
1210 r = can_sleep(sleep_type);
1218 r = have_multiple_sessions(connection, m, message, error);
1222 multiple_sessions = r > 0;
1223 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1225 if (multiple_sessions) {
1226 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1232 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1237 if (!multiple_sessions && !blocked) {
1238 r = verify_polkit(connection, message, action, interactive, NULL, error);
1243 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1247 reply = dbus_message_new_method_return(message);
1255 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
1257 static const BusProperty bus_login_manager_properties[] = {
1258 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1259 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1260 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1261 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1262 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1263 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1264 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1265 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1266 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1267 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1268 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1269 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1270 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1271 { "HandlePowerKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_power_key) },
1272 { "HandleSleepKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_sleep_key) },
1273 { "HandleLidSwitch", bus_manager_append_handle_button, "s", offsetof(Manager, handle_lid_switch) },
1277 static DBusHandlerResult manager_message_handler(
1278 DBusConnection *connection,
1279 DBusMessage *message,
1282 Manager *m = userdata;
1285 DBusMessage *reply = NULL;
1292 dbus_error_init(&error);
1294 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1300 if (!dbus_message_get_args(
1303 DBUS_TYPE_STRING, &name,
1305 return bus_send_error_reply(connection, message, &error, -EINVAL);
1307 session = hashmap_get(m->sessions, name);
1309 return bus_send_error_reply(connection, message, &error, -ENOENT);
1311 reply = dbus_message_new_method_return(message);
1315 p = session_bus_path(session);
1319 b = dbus_message_append_args(
1321 DBUS_TYPE_OBJECT_PATH, &p,
1328 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1334 if (!dbus_message_get_args(
1337 DBUS_TYPE_UINT32, &pid,
1339 return bus_send_error_reply(connection, message, &error, -EINVAL);
1341 r = manager_get_session_by_pid(m, pid, &session);
1343 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1345 reply = dbus_message_new_method_return(message);
1349 p = session_bus_path(session);
1353 b = dbus_message_append_args(
1355 DBUS_TYPE_OBJECT_PATH, &p,
1362 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1368 if (!dbus_message_get_args(
1371 DBUS_TYPE_UINT32, &uid,
1373 return bus_send_error_reply(connection, message, &error, -EINVAL);
1375 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1377 return bus_send_error_reply(connection, message, &error, -ENOENT);
1379 reply = dbus_message_new_method_return(message);
1383 p = user_bus_path(user);
1387 b = dbus_message_append_args(
1389 DBUS_TYPE_OBJECT_PATH, &p,
1396 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1402 if (!dbus_message_get_args(
1405 DBUS_TYPE_STRING, &name,
1407 return bus_send_error_reply(connection, message, &error, -EINVAL);
1409 seat = hashmap_get(m->seats, name);
1411 return bus_send_error_reply(connection, message, &error, -ENOENT);
1413 reply = dbus_message_new_method_return(message);
1417 p = seat_bus_path(seat);
1421 b = dbus_message_append_args(
1423 DBUS_TYPE_OBJECT_PATH, &p,
1430 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1434 DBusMessageIter iter, sub;
1435 const char *empty = "";
1437 reply = dbus_message_new_method_return(message);
1441 dbus_message_iter_init_append(reply, &iter);
1443 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1446 HASHMAP_FOREACH(session, m->sessions, i) {
1447 DBusMessageIter sub2;
1450 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1453 uid = session->user->uid;
1455 p = session_bus_path(session);
1459 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1460 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1461 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1462 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1463 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1470 if (!dbus_message_iter_close_container(&sub, &sub2))
1474 if (!dbus_message_iter_close_container(&iter, &sub))
1477 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1481 DBusMessageIter iter, sub;
1483 reply = dbus_message_new_method_return(message);
1487 dbus_message_iter_init_append(reply, &iter);
1489 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1492 HASHMAP_FOREACH(user, m->users, i) {
1493 DBusMessageIter sub2;
1496 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1501 p = user_bus_path(user);
1505 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1506 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1507 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1514 if (!dbus_message_iter_close_container(&sub, &sub2))
1518 if (!dbus_message_iter_close_container(&iter, &sub))
1521 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1525 DBusMessageIter iter, sub;
1527 reply = dbus_message_new_method_return(message);
1531 dbus_message_iter_init_append(reply, &iter);
1533 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1536 HASHMAP_FOREACH(seat, m->seats, i) {
1537 DBusMessageIter sub2;
1539 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1542 p = seat_bus_path(seat);
1546 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1547 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1554 if (!dbus_message_iter_close_container(&sub, &sub2))
1558 if (!dbus_message_iter_close_container(&iter, &sub))
1561 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1562 Inhibitor *inhibitor;
1564 DBusMessageIter iter, sub;
1566 reply = dbus_message_new_method_return(message);
1570 dbus_message_iter_init_append(reply, &iter);
1572 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1575 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1576 DBusMessageIter sub2;
1577 dbus_uint32_t uid, pid;
1578 const char *what, *who, *why, *mode;
1580 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1583 what = strempty(inhibit_what_to_string(inhibitor->what));
1584 who = strempty(inhibitor->who);
1585 why = strempty(inhibitor->why);
1586 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1587 uid = (dbus_uint32_t) inhibitor->uid;
1588 pid = (dbus_uint32_t) inhibitor->pid;
1590 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1591 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1592 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1593 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1594 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1595 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1598 if (!dbus_message_iter_close_container(&sub, &sub2))
1602 if (!dbus_message_iter_close_container(&iter, &sub))
1605 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1607 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1610 return bus_send_error_reply(connection, message, &error, r);
1613 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1615 r = bus_manager_create_session(m, message, &reply);
1617 /* Don't delay the work on OOM here, since it might be
1618 * triggered by a low RLIMIT_NOFILE here (since we
1619 * send a dupped fd to the client), and we'd rather
1620 * see this fail quickly then be retried later */
1623 return bus_send_error_reply(connection, message, NULL, r);
1625 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1629 if (!dbus_message_get_args(
1632 DBUS_TYPE_STRING, &name,
1634 return bus_send_error_reply(connection, message, &error, -EINVAL);
1636 session = hashmap_get(m->sessions, name);
1638 return bus_send_error_reply(connection, message, &error, -ENOENT);
1640 /* We use the FIFO to detect stray sessions where the
1641 process invoking PAM dies abnormally. We need to make
1642 sure that that process is not killed if at the clean
1643 end of the session it closes the FIFO. Hence, with
1644 this call explicitly turn off the FIFO logic, so that
1645 the PAM code can finish clean up on its own */
1646 session_remove_fifo(session);
1648 reply = dbus_message_new_method_return(message);
1652 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1656 if (!dbus_message_get_args(
1659 DBUS_TYPE_STRING, &name,
1661 return bus_send_error_reply(connection, message, &error, -EINVAL);
1663 session = hashmap_get(m->sessions, name);
1665 return bus_send_error_reply(connection, message, &error, -ENOENT);
1667 r = session_activate(session);
1669 return bus_send_error_reply(connection, message, NULL, r);
1671 reply = dbus_message_new_method_return(message);
1675 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1676 const char *session_name, *seat_name;
1680 /* Same as ActivateSession() but refuses to work if
1681 * the seat doesn't match */
1683 if (!dbus_message_get_args(
1686 DBUS_TYPE_STRING, &session_name,
1687 DBUS_TYPE_STRING, &seat_name,
1689 return bus_send_error_reply(connection, message, &error, -EINVAL);
1691 session = hashmap_get(m->sessions, session_name);
1693 return bus_send_error_reply(connection, message, &error, -ENOENT);
1695 seat = hashmap_get(m->seats, seat_name);
1697 return bus_send_error_reply(connection, message, &error, -ENOENT);
1699 if (session->seat != seat)
1700 return bus_send_error_reply(connection, message, &error, -EINVAL);
1702 r = session_activate(session);
1704 return bus_send_error_reply(connection, message, NULL, r);
1706 reply = dbus_message_new_method_return(message);
1710 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1711 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1715 if (!dbus_message_get_args(
1718 DBUS_TYPE_STRING, &name,
1720 return bus_send_error_reply(connection, message, &error, -EINVAL);
1722 session = hashmap_get(m->sessions, name);
1724 return bus_send_error_reply(connection, message, &error, -ENOENT);
1726 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1729 reply = dbus_message_new_method_return(message);
1733 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1740 if (!dbus_message_get_args(
1743 DBUS_TYPE_STRING, &name,
1744 DBUS_TYPE_STRING, &swho,
1745 DBUS_TYPE_INT32, &signo,
1747 return bus_send_error_reply(connection, message, &error, -EINVAL);
1752 who = kill_who_from_string(swho);
1754 return bus_send_error_reply(connection, message, &error, -EINVAL);
1757 if (signo <= 0 || signo >= _NSIG)
1758 return bus_send_error_reply(connection, message, &error, -EINVAL);
1760 session = hashmap_get(m->sessions, name);
1762 return bus_send_error_reply(connection, message, &error, -ENOENT);
1764 r = session_kill(session, who, signo);
1766 return bus_send_error_reply(connection, message, NULL, r);
1768 reply = dbus_message_new_method_return(message);
1772 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1777 if (!dbus_message_get_args(
1780 DBUS_TYPE_UINT32, &uid,
1781 DBUS_TYPE_INT32, &signo,
1783 return bus_send_error_reply(connection, message, &error, -EINVAL);
1785 if (signo <= 0 || signo >= _NSIG)
1786 return bus_send_error_reply(connection, message, &error, -EINVAL);
1788 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1790 return bus_send_error_reply(connection, message, &error, -ENOENT);
1792 r = user_kill(user, signo);
1794 return bus_send_error_reply(connection, message, NULL, r);
1796 reply = dbus_message_new_method_return(message);
1800 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1804 if (!dbus_message_get_args(
1807 DBUS_TYPE_STRING, &name,
1809 return bus_send_error_reply(connection, message, &error, -EINVAL);
1811 session = hashmap_get(m->sessions, name);
1813 return bus_send_error_reply(connection, message, &error, -ENOENT);
1815 r = session_stop(session);
1817 return bus_send_error_reply(connection, message, NULL, r);
1819 reply = dbus_message_new_method_return(message);
1823 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1827 if (!dbus_message_get_args(
1830 DBUS_TYPE_UINT32, &uid,
1832 return bus_send_error_reply(connection, message, &error, -EINVAL);
1834 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1836 return bus_send_error_reply(connection, message, &error, -ENOENT);
1838 r = user_stop(user);
1840 return bus_send_error_reply(connection, message, NULL, r);
1842 reply = dbus_message_new_method_return(message);
1846 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1850 if (!dbus_message_get_args(
1853 DBUS_TYPE_STRING, &name,
1855 return bus_send_error_reply(connection, message, &error, -EINVAL);
1857 seat = hashmap_get(m->seats, name);
1859 return bus_send_error_reply(connection, message, &error, -ENOENT);
1861 r = seat_stop_sessions(seat);
1863 return bus_send_error_reply(connection, message, NULL, r);
1865 reply = dbus_message_new_method_return(message);
1869 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1872 dbus_bool_t b, interactive;
1875 if (!dbus_message_get_args(
1878 DBUS_TYPE_UINT32, &uid,
1879 DBUS_TYPE_BOOLEAN, &b,
1880 DBUS_TYPE_BOOLEAN, &interactive,
1882 return bus_send_error_reply(connection, message, &error, -EINVAL);
1887 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1889 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1891 return bus_send_error_reply(connection, message, &error, r);
1893 mkdir_p_label("/var/lib/systemd", 0755);
1895 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1897 return bus_send_error_reply(connection, message, &error, r);
1899 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1910 return bus_send_error_reply(connection, message, &error, r);
1912 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1921 if (r < 0 && errno != ENOENT)
1922 return bus_send_error_reply(connection, message, &error, -errno);
1924 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1926 user_add_to_gc_queue(u);
1929 reply = dbus_message_new_method_return(message);
1933 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1934 const char *sysfs, *seat;
1935 dbus_bool_t interactive;
1937 if (!dbus_message_get_args(
1940 DBUS_TYPE_STRING, &seat,
1941 DBUS_TYPE_STRING, &sysfs,
1942 DBUS_TYPE_BOOLEAN, &interactive,
1944 return bus_send_error_reply(connection, message, &error, -EINVAL);
1946 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
1947 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1949 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
1951 return bus_send_error_reply(connection, message, &error, r);
1953 r = attach_device(m, seat, sysfs);
1955 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1957 reply = dbus_message_new_method_return(message);
1962 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
1963 dbus_bool_t interactive;
1965 if (!dbus_message_get_args(
1968 DBUS_TYPE_BOOLEAN, &interactive,
1970 return bus_send_error_reply(connection, message, &error, -EINVAL);
1972 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
1974 return bus_send_error_reply(connection, message, &error, r);
1976 r = flush_devices(m);
1978 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1980 reply = dbus_message_new_method_return(message);
1984 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
1986 r = bus_manager_do_shutdown_or_sleep(
1987 m, connection, message,
1988 SPECIAL_POWEROFF_TARGET,
1990 "org.freedesktop.login1.power-off",
1991 "org.freedesktop.login1.power-off-multiple-sessions",
1992 "org.freedesktop.login1.power-off-ignore-inhibit",
1996 return bus_send_error_reply(connection, message, &error, r);
1997 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
1998 r = bus_manager_do_shutdown_or_sleep(
1999 m, connection, message,
2000 SPECIAL_REBOOT_TARGET,
2002 "org.freedesktop.login1.reboot",
2003 "org.freedesktop.login1.reboot-multiple-sessions",
2004 "org.freedesktop.login1.reboot-ignore-inhibit",
2008 return bus_send_error_reply(connection, message, &error, r);
2010 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2011 r = bus_manager_do_shutdown_or_sleep(
2012 m, connection, message,
2013 SPECIAL_SUSPEND_TARGET,
2015 "org.freedesktop.login1.suspend",
2016 "org.freedesktop.login1.suspend-multiple-sessions",
2017 "org.freedesktop.login1.suspend-ignore-inhibit",
2021 return bus_send_error_reply(connection, message, &error, r);
2022 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2023 r = bus_manager_do_shutdown_or_sleep(
2024 m, connection, message,
2025 SPECIAL_HIBERNATE_TARGET,
2027 "org.freedesktop.login1.hibernate",
2028 "org.freedesktop.login1.hibernate-multiple-sessions",
2029 "org.freedesktop.login1.hibernate-ignore-inhibit",
2033 return bus_send_error_reply(connection, message, &error, r);
2035 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2037 r = bus_manager_can_shutdown_or_sleep(
2038 m, connection, message,
2040 "org.freedesktop.login1.power-off",
2041 "org.freedesktop.login1.power-off-multiple-sessions",
2042 "org.freedesktop.login1.power-off-ignore-inhibit",
2046 return bus_send_error_reply(connection, message, &error, r);
2047 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2048 r = bus_manager_can_shutdown_or_sleep(
2049 m, connection, message,
2051 "org.freedesktop.login1.reboot",
2052 "org.freedesktop.login1.reboot-multiple-sessions",
2053 "org.freedesktop.login1.reboot-ignore-inhibit",
2057 return bus_send_error_reply(connection, message, &error, r);
2059 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2060 r = bus_manager_can_shutdown_or_sleep(
2061 m, connection, message,
2063 "org.freedesktop.login1.suspend",
2064 "org.freedesktop.login1.suspend-multiple-sessions",
2065 "org.freedesktop.login1.suspend-ignore-inhibit",
2069 return bus_send_error_reply(connection, message, &error, r);
2071 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2072 r = bus_manager_can_shutdown_or_sleep(
2073 m, connection, message,
2075 "org.freedesktop.login1.hibernate",
2076 "org.freedesktop.login1.hibernate-multiple-sessions",
2077 "org.freedesktop.login1.hibernate-ignore-inhibit",
2081 return bus_send_error_reply(connection, message, &error, r);
2083 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2084 char *introspection = NULL;
2093 if (!(reply = dbus_message_new_method_return(message)))
2096 /* We roll our own introspection code here, instead of
2097 * relying on bus_default_message_handler() because we
2098 * need to generate our introspection string
2101 if (!(f = open_memstream(&introspection, &size)))
2104 fputs(INTROSPECTION_BEGIN, f);
2106 HASHMAP_FOREACH(seat, m->seats, i) {
2107 p = bus_path_escape(seat->id);
2110 fprintf(f, "<node name=\"seat/%s\"/>", p);
2115 HASHMAP_FOREACH(user, m->users, i)
2116 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2118 HASHMAP_FOREACH(session, m->sessions, i) {
2119 p = bus_path_escape(session->id);
2122 fprintf(f, "<node name=\"session/%s\"/>", p);
2127 fputs(INTROSPECTION_END, f);
2131 free(introspection);
2140 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2141 free(introspection);
2145 free(introspection);
2147 const BusBoundProperties bps[] = {
2148 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2151 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2155 if (!dbus_connection_send(connection, reply, NULL))
2158 dbus_message_unref(reply);
2161 return DBUS_HANDLER_RESULT_HANDLED;
2165 dbus_message_unref(reply);
2167 dbus_error_free(&error);
2169 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2172 const DBusObjectPathVTable bus_manager_vtable = {
2173 .message_function = manager_message_handler
2176 DBusHandlerResult bus_message_filter(
2177 DBusConnection *connection,
2178 DBusMessage *message,
2181 Manager *m = userdata;
2188 dbus_error_init(&error);
2190 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2193 if (!dbus_message_get_args(message, &error,
2194 DBUS_TYPE_STRING, &cgroup,
2196 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2198 manager_cgroup_notify_empty(m, cgroup);
2201 dbus_error_free(&error);
2203 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2206 int manager_send_changed(Manager *manager, const char *properties) {
2212 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2216 if (!dbus_connection_send(manager->bus, m, NULL))
2223 dbus_message_unref(m);
2228 int manager_dispatch_delayed(Manager *manager) {
2229 const char *unit_name;
2236 if (!manager->delayed_unit)
2239 /* Continue delay? */
2241 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2242 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL);
2246 /* Reset delay data */
2247 unit_name = manager->delayed_unit;
2248 manager->delayed_unit = NULL;
2250 /* Actually do the shutdown */
2251 dbus_error_init(&error);
2252 r = send_start_unit(manager->bus, unit_name, &error);
2254 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2255 dbus_error_free(&error);
2259 /* Tell people about it */
2260 send_prepare_for(manager, manager->delayed_what, false);