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"
34 #include "sleep-config.h"
35 #include "systemd/sd-id128.h"
36 #include "systemd/sd-messages.h"
37 #include "fileio-label.h"
40 #include "unit-name.h"
42 #define BUS_MANAGER_INTERFACE \
43 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
44 " <method name=\"GetSession\">\n" \
45 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
46 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
48 " <method name=\"GetSessionByPID\">\n" \
49 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
50 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
52 " <method name=\"GetUser\">\n" \
53 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
54 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
56 " <method name=\"GetUserByPID\">\n" \
57 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
58 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
60 " <method name=\"GetSeat\">\n" \
61 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
62 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
64 " <method name=\"GetMachine\">\n" \
65 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
66 " <arg name=\"machine\" type=\"o\" direction=\"out\"/>\n" \
68 " <method name=\"GetMachineByPID\">\n" \
69 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
70 " <arg name=\"machine\" type=\"o\" direction=\"out\"/>\n" \
72 " <method name=\"ListSessions\">\n" \
73 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
75 " <method name=\"ListUsers\">\n" \
76 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
78 " <method name=\"ListSeats\">\n" \
79 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
81 " <method name=\"ListMachines\">\n" \
82 " <arg name=\"machines\" type=\"a(ssso)\" direction=\"out\"/>\n" \
84 " <method name=\"CreateSession\">\n" \
85 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
86 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
87 " <arg name=\"service\" type=\"s\" direction=\"in\"/>\n" \
88 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
89 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
90 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
91 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
92 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
93 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
94 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
95 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
96 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
97 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
98 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
99 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
100 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
101 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
102 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
103 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
104 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
105 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
106 " <arg name=\"existing\" type=\"b\" direction=\"out\"/>\n" \
108 " <method name=\"ReleaseSession\">\n" \
109 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
111 " <method name=\"CreateMachine\">\n" \
112 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
113 " <arg name=\"id\" type=\"ay\" direction=\"in\"/>\n" \
114 " <arg name=\"service\" type=\"s\" direction=\"in\"/>\n" \
115 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
116 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
117 " <arg name=\"slice\" type=\"s\" direction=\"in\"/>\n" \
118 " <arg name=\"root_directory\" type=\"s\" direction=\"in\"/>\n" \
119 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
121 " <method name=\"ActivateSession\">\n" \
122 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
124 " <method name=\"ActivateSessionOnSeat\">\n" \
125 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
126 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
128 " <method name=\"LockSession\">\n" \
129 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
131 " <method name=\"UnlockSession\">\n" \
132 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
134 " <method name=\"LockSessions\"/>\n" \
135 " <method name=\"UnlockSessions\"/>\n" \
136 " <method name=\"KillSession\">\n" \
137 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
138 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
139 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
141 " <method name=\"KillUser\">\n" \
142 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
143 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
145 " <method name=\"TerminateSession\">\n" \
146 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
148 " <method name=\"TerminateUser\">\n" \
149 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
151 " <method name=\"TerminateSeat\">\n" \
152 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
154 " <method name=\"TerminateMachine\">\n" \
155 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
157 " <method name=\"SetUserLinger\">\n" \
158 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
159 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
160 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
162 " <method name=\"AttachDevice\">\n" \
163 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
164 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
165 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
167 " <method name=\"FlushDevices\">\n" \
168 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
170 " <method name=\"PowerOff\">\n" \
171 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
173 " <method name=\"Reboot\">\n" \
174 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
176 " <method name=\"Suspend\">\n" \
177 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
179 " <method name=\"Hibernate\">\n" \
180 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
182 " <method name=\"HybridSleep\">\n" \
183 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
185 " <method name=\"CanPowerOff\">\n" \
186 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
188 " <method name=\"CanReboot\">\n" \
189 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
191 " <method name=\"CanSuspend\">\n" \
192 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
194 " <method name=\"CanHibernate\">\n" \
195 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
197 " <method name=\"CanHybridSleep\">\n" \
198 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
200 " <method name=\"Inhibit\">\n" \
201 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
202 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
203 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
204 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
205 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
207 " <method name=\"ListInhibitors\">\n" \
208 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
210 " <signal name=\"SessionNew\">\n" \
211 " <arg name=\"id\" type=\"s\"/>\n" \
212 " <arg name=\"path\" type=\"o\"/>\n" \
214 " <signal name=\"SessionRemoved\">\n" \
215 " <arg name=\"id\" type=\"s\"/>\n" \
216 " <arg name=\"path\" type=\"o\"/>\n" \
218 " <signal name=\"UserNew\">\n" \
219 " <arg name=\"uid\" type=\"u\"/>\n" \
220 " <arg name=\"path\" type=\"o\"/>\n" \
222 " <signal name=\"UserRemoved\">\n" \
223 " <arg name=\"uid\" type=\"u\"/>\n" \
224 " <arg name=\"path\" type=\"o\"/>\n" \
226 " <signal name=\"SeatNew\">\n" \
227 " <arg name=\"id\" type=\"s\"/>\n" \
228 " <arg name=\"path\" type=\"o\"/>\n" \
230 " <signal name=\"SeatRemoved\">\n" \
231 " <arg name=\"id\" type=\"s\"/>\n" \
232 " <arg name=\"path\" type=\"o\"/>\n" \
234 " <signal name=\"MachineNew\">\n" \
235 " <arg name=\"machine\" type=\"s\"/>\n" \
236 " <arg name=\"path\" type=\"o\"/>\n" \
238 " <signal name=\"MachineRemoved\">\n" \
239 " <arg name=\"machine\" type=\"s\"/>\n" \
240 " <arg name=\"path\" type=\"o\"/>\n" \
242 " <signal name=\"PrepareForShutdown\">\n" \
243 " <arg name=\"active\" type=\"b\"/>\n" \
245 " <signal name=\"PrepareForSleep\">\n" \
246 " <arg name=\"active\" type=\"b\"/>\n" \
248 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
249 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
250 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
251 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
252 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
253 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
254 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
255 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
256 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
257 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
258 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
259 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
260 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
261 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
262 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
263 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
264 " <property name=\"IdleAction\" type=\"s\" access=\"read\"/>\n" \
265 " <property name=\"IdleActionUSec\" type=\"t\" access=\"read\"/>\n" \
266 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
267 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
270 #define INTROSPECTION_BEGIN \
271 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
273 BUS_MANAGER_INTERFACE \
274 BUS_PROPERTIES_INTERFACE \
276 BUS_INTROSPECTABLE_INTERFACE
278 #define INTROSPECTION_END \
281 #define INTERFACES_LIST \
282 BUS_GENERIC_INTERFACES_LIST \
283 "org.freedesktop.login1.Manager\0"
285 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
293 b = manager_get_idle_hint(m, NULL) > 0;
294 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
300 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
309 manager_get_idle_hint(m, &t);
310 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
312 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
318 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
323 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
324 p = inhibit_what_to_string(w);
326 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
332 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
339 if (streq(property, "PreparingForShutdown"))
340 b = !!(m->action_what & INHIBIT_SHUTDOWN);
342 b = !!(m->action_what & INHIBIT_SLEEP);
344 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
348 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
349 const char *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *service;
350 uint32_t uid, leader, audit_id = 0;
351 dbus_bool_t remote, kill_processes, exists;
352 _cleanup_strv_free_ char **controllers = NULL, **reset_controllers = NULL;
353 _cleanup_free_ char *cgroup = NULL, *id = NULL, *p = NULL;
356 DBusMessageIter iter;
359 _cleanup_close_ int fifo_fd = -1;
360 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
361 Session *session = NULL;
370 if (!dbus_message_iter_init(message, &iter) ||
371 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
374 dbus_message_iter_get_basic(&iter, &uid);
376 if (!dbus_message_iter_next(&iter) ||
377 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
380 dbus_message_iter_get_basic(&iter, &leader);
382 if (!dbus_message_iter_next(&iter) ||
383 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
386 dbus_message_iter_get_basic(&iter, &service);
388 if (!dbus_message_iter_next(&iter) ||
389 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
392 dbus_message_iter_get_basic(&iter, &type);
394 t = _SESSION_TYPE_INVALID;
396 t = session_type_from_string(type);
401 if (!dbus_message_iter_next(&iter) ||
402 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
405 dbus_message_iter_get_basic(&iter, &class);
407 c = _SESSION_CLASS_INVALID;
409 c = session_class_from_string(class);
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, &cseat);
423 seat = hashmap_get(m->seats, cseat);
428 if (!dbus_message_iter_next(&iter) ||
429 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
432 dbus_message_iter_get_basic(&iter, &vtnr);
434 if (!dbus_message_iter_next(&iter) ||
435 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
438 dbus_message_iter_get_basic(&iter, &tty);
440 if (tty_is_vc(tty)) {
445 else if (seat != m->vtconsole)
448 v = vtnr_from_tty(tty);
451 return v < 0 ? v : -EINVAL;
455 else if (vtnr != (uint32_t) v)
457 } else if (tty_is_console(tty)) {
461 else if (seat != m->vtconsole)
469 if (seat_can_multi_session(seat)) {
478 if (!dbus_message_iter_next(&iter) ||
479 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
482 dbus_message_iter_get_basic(&iter, &display);
484 if (!dbus_message_iter_next(&iter) ||
485 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
488 if (t == _SESSION_TYPE_INVALID) {
489 if (!isempty(display))
491 else if (!isempty(tty))
494 t = SESSION_UNSPECIFIED;
497 if (c == _SESSION_CLASS_INVALID) {
498 if (!isempty(display) || !isempty(tty))
501 c = SESSION_BACKGROUND;
504 dbus_message_iter_get_basic(&iter, &remote);
506 if (!dbus_message_iter_next(&iter) ||
507 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
510 dbus_message_iter_get_basic(&iter, &remote_user);
512 if (!dbus_message_iter_next(&iter) ||
513 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
516 dbus_message_iter_get_basic(&iter, &remote_host);
518 if (!dbus_message_iter_next(&iter) ||
519 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
520 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
523 r = bus_parse_strv_iter(&iter, &controllers);
527 if (!dbus_message_iter_next(&iter) ||
528 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
529 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
534 r = bus_parse_strv_iter(&iter, &reset_controllers);
538 if (!dbus_message_iter_next(&iter) ||
539 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
544 dbus_message_iter_get_basic(&iter, &kill_processes);
547 leader = bus_get_unix_process_id(m->bus, dbus_message_get_sender(message), NULL);
552 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, leader, &cgroup);
556 r = manager_get_session_by_cgroup(m, cgroup, &session);
561 fifo_fd = session_create_fifo(session);
567 /* Session already exists, client is probably
568 * something like "su" which changes uid but
569 * is still the same audit session */
571 reply = dbus_message_new_method_return(message);
577 p = session_bus_path(session);
583 cseat = session->seat ? session->seat->id : "";
584 vtnr = session->vtnr;
587 b = dbus_message_append_args(
589 DBUS_TYPE_STRING, &session->id,
590 DBUS_TYPE_OBJECT_PATH, &p,
591 DBUS_TYPE_STRING, &session->user->runtime_path,
592 DBUS_TYPE_UNIX_FD, &fifo_fd,
593 DBUS_TYPE_STRING, &cseat,
594 DBUS_TYPE_UINT32, &vtnr,
595 DBUS_TYPE_BOOLEAN, &exists,
608 audit_session_from_pid(leader, &audit_id);
610 /* Keep our session IDs and the audit session IDs in sync */
612 if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0) {
617 /* Wut? There's already a session by this name and we
618 * didn't find it above? Weird, then let's not trust
619 * the audit data and let's better register a new
621 if (hashmap_get(m->sessions, id)) {
634 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
639 } while (hashmap_get(m->sessions, id));
642 r = manager_add_user_by_uid(m, uid, &user);
646 r = manager_add_session(m, id, &session);
650 session_set_user(session, user);
652 session->leader = leader;
653 session->audit_id = audit_id;
656 session->remote = remote;
657 session->kill_processes = kill_processes;
658 session->vtnr = vtnr;
660 session->controllers = cg_shorten_controllers(controllers);
661 session->reset_controllers = cg_shorten_controllers(reset_controllers);
662 controllers = reset_controllers = NULL;
665 session->tty = strdup(tty);
672 if (!isempty(display)) {
673 session->display = strdup(display);
674 if (!session->display) {
680 if (!isempty(remote_user)) {
681 session->remote_user = strdup(remote_user);
682 if (!session->remote_user) {
688 if (!isempty(remote_host)) {
689 session->remote_host = strdup(remote_host);
690 if (!session->remote_host) {
696 if (!isempty(service)) {
697 session->service = strdup(service);
698 if (!session->service) {
704 fifo_fd = session_create_fifo(session);
711 r = seat_attach_session(seat, session);
716 r = session_start(session);
720 reply = dbus_message_new_method_return(message);
726 p = session_bus_path(session);
732 cseat = seat ? seat->id : "";
734 b = dbus_message_append_args(
736 DBUS_TYPE_STRING, &session->id,
737 DBUS_TYPE_OBJECT_PATH, &p,
738 DBUS_TYPE_STRING, &session->user->runtime_path,
739 DBUS_TYPE_UNIX_FD, &fifo_fd,
740 DBUS_TYPE_STRING, &cseat,
741 DBUS_TYPE_UINT32, &vtnr,
742 DBUS_TYPE_BOOLEAN, &exists,
757 session_add_to_gc_queue(session);
760 user_add_to_gc_queue(user);
765 static bool valid_machine_name(const char *p) {
768 if (!filename_is_safe(p))
771 if (!ascii_is_valid(p))
782 static int bus_manager_create_machine(
784 DBusMessage *message,
785 DBusMessage **_reply) {
787 const char *name, *service, *class, *slice, *root_directory;
788 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
789 _cleanup_free_ char *p = NULL;
790 DBusMessageIter iter, sub;
803 if (!dbus_message_iter_init(message, &iter) ||
804 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
807 dbus_message_iter_get_basic(&iter, &name);
809 if (!valid_machine_name(name) ||
810 !dbus_message_iter_next(&iter) ||
811 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
812 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE)
815 dbus_message_iter_recurse(&iter, &sub);
816 dbus_message_iter_get_fixed_array(&sub, &v, &n);
825 if (!dbus_message_iter_next(&iter) ||
826 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
829 dbus_message_iter_get_basic(&iter, &service);
831 if (!dbus_message_iter_next(&iter) ||
832 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
835 dbus_message_iter_get_basic(&iter, &class);
838 c = _MACHINE_CLASS_INVALID;
840 c = machine_class_from_string(class);
845 if (!dbus_message_iter_next(&iter) ||
846 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
849 dbus_message_iter_get_basic(&iter, &leader);
850 if (!dbus_message_iter_next(&iter) ||
851 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
854 dbus_message_iter_get_basic(&iter, &slice);
855 if (!(isempty(slice) || (unit_name_is_valid(slice, false) && endswith(slice, ".slice"))) ||
856 !dbus_message_iter_next(&iter) ||
857 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
860 dbus_message_iter_get_basic(&iter, &root_directory);
862 if (!(isempty(root_directory) || path_is_absolute(root_directory)))
865 if (hashmap_get(manager->machines, name))
869 leader = bus_get_unix_process_id(manager->bus, dbus_message_get_sender(message), NULL);
874 r = manager_add_machine(manager, name, &m);
882 if (!isempty(service)) {
883 m->service = strdup(service);
890 if (!isempty(slice)) {
891 m->slice = strdup(slice);
898 if (!isempty(root_directory)) {
899 m->root_directory = strdup(root_directory);
900 if (!m->root_directory) {
906 r = machine_start(m);
910 reply = dbus_message_new_method_return(message);
916 p = machine_bus_path(m);
922 b = dbus_message_append_args(
924 DBUS_TYPE_OBJECT_PATH, &p,
937 machine_add_to_gc_queue(m);
942 static int bus_manager_inhibit(
944 DBusConnection *connection,
945 DBusMessage *message,
947 DBusMessage **_reply) {
951 const char *who, *why, *what, *mode;
957 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
965 if (!dbus_message_get_args(
968 DBUS_TYPE_STRING, &what,
969 DBUS_TYPE_STRING, &who,
970 DBUS_TYPE_STRING, &why,
971 DBUS_TYPE_STRING, &mode,
972 DBUS_TYPE_INVALID)) {
977 w = inhibit_what_from_string(what);
983 mm = inhibit_mode_from_string(mode);
989 /* Delay is only supported for shutdown/sleep */
990 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
995 /* Don't allow taking delay locks while we are already
996 * executing the operation. We shouldn't create the impression
997 * that the lock was successful if the machine is about to go
998 * down/suspend any moment. */
999 if (m->action_what & w) {
1004 r = verify_polkit(connection, message,
1005 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
1006 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
1007 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
1008 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
1009 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
1010 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
1011 "org.freedesktop.login1.inhibit-handle-lid-switch",
1012 false, NULL, error);
1016 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1017 if (ul == (unsigned long) -1) {
1022 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
1032 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
1036 } while (hashmap_get(m->inhibitors, id));
1038 r = manager_add_inhibitor(m, id, &i);
1047 i->uid = (uid_t) ul;
1048 i->why = strdup(why);
1049 i->who = strdup(who);
1051 if (!i->why || !i->who) {
1056 fifo_fd = inhibitor_create_fifo(i);
1062 reply = dbus_message_new_method_return(message);
1068 if (!dbus_message_append_args(
1070 DBUS_TYPE_UNIX_FD, &fifo_fd,
1071 DBUS_TYPE_INVALID)) {
1076 close_nointr_nofail(fifo_fd);
1089 close_nointr_nofail(fifo_fd);
1094 static int trigger_device(Manager *m, struct udev_device *d) {
1095 struct udev_enumerate *e;
1096 struct udev_list_entry *first, *item;
1101 e = udev_enumerate_new(m->udev);
1108 if (udev_enumerate_add_match_parent(e, d) < 0) {
1114 if (udev_enumerate_scan_devices(e) < 0) {
1119 first = udev_enumerate_get_list_entry(e);
1120 udev_list_entry_foreach(item, first) {
1124 p = udev_list_entry_get_name(item);
1126 t = strappend(p, "/uevent");
1132 write_string_file(t, "change");
1140 udev_enumerate_unref(e);
1145 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
1146 struct udev_device *d;
1147 _cleanup_free_ char *rule = NULL, *file = NULL;
1148 const char *id_for_seat;
1155 d = udev_device_new_from_syspath(m->udev, sysfs);
1159 if (!udev_device_has_tag(d, "seat")) {
1164 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
1170 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
1175 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
1180 mkdir_p_label("/etc/udev/rules.d", 0755);
1182 r = write_string_file_atomic_label(file, rule);
1186 r = trigger_device(m, d);
1190 udev_device_unref(d);
1195 static int flush_devices(Manager *m) {
1196 _cleanup_closedir_ DIR *d;
1200 d = opendir("/etc/udev/rules.d");
1202 if (errno != ENOENT)
1203 log_warning("Failed to open /etc/udev/rules.d: %m");
1207 while ((de = readdir(d))) {
1209 if (!dirent_is_file(de))
1212 if (!startswith(de->d_name, "72-seat-"))
1215 if (!endswith(de->d_name, ".rules"))
1218 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
1219 log_warning("Failed to unlink %s: %m", de->d_name);
1223 return trigger_device(m, NULL);
1226 static int have_multiple_sessions(
1235 /* Check for other users' sessions. Greeter sessions do not
1236 * count, and non-login sessions do not count either. */
1237 HASHMAP_FOREACH(session, m->sessions, i)
1238 if (session->class == SESSION_USER &&
1239 session->user->uid != uid)
1245 static int bus_manager_log_shutdown(
1248 const char *unit_name) {
1255 if (w != INHIBIT_SHUTDOWN)
1258 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1259 p = "MESSAGE=System is powering down.";
1260 q = "SHUTDOWN=power-off";
1261 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1262 p = "MESSAGE=System is halting.";
1263 q = "SHUTDOWN=halt";
1264 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1265 p = "MESSAGE=System is rebooting.";
1266 q = "SHUTDOWN=reboot";
1267 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1268 p = "MESSAGE=System is rebooting with kexec.";
1269 q = "SHUTDOWN=kexec";
1271 p = "MESSAGE=System is shutting down.";
1275 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1280 static int execute_shutdown_or_sleep(
1283 const char *unit_name,
1286 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1287 const char *mode = "replace-irreversibly", *p;
1293 assert(w < _INHIBIT_WHAT_MAX);
1296 bus_manager_log_shutdown(m, w, unit_name);
1298 r = bus_method_call_with_reply(
1300 "org.freedesktop.systemd1",
1301 "/org/freedesktop/systemd1",
1302 "org.freedesktop.systemd1.Manager",
1306 DBUS_TYPE_STRING, &unit_name,
1307 DBUS_TYPE_STRING, &mode,
1312 if (!dbus_message_get_args(
1315 DBUS_TYPE_OBJECT_PATH, &p,
1323 m->action_unit = unit_name;
1324 free(m->action_job);
1331 static int delay_shutdown_or_sleep(
1334 const char *unit_name) {
1338 assert(w < _INHIBIT_WHAT_MAX);
1341 m->action_timestamp = now(CLOCK_MONOTONIC);
1342 m->action_unit = unit_name;
1348 static int bus_manager_can_shutdown_or_sleep(
1350 DBusConnection *connection,
1351 DBusMessage *message,
1354 const char *action_multiple_sessions,
1355 const char *action_ignore_inhibit,
1356 const char *sleep_verb,
1358 DBusMessage **_reply) {
1360 bool multiple_sessions, challenge, blocked, b;
1361 const char *result = NULL;
1362 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1370 assert(w <= _INHIBIT_WHAT_MAX);
1372 assert(action_multiple_sessions);
1373 assert(action_ignore_inhibit);
1378 r = can_sleep(sleep_verb);
1387 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1388 if (ul == (unsigned long) -1)
1391 r = have_multiple_sessions(m, (uid_t) ul);
1395 multiple_sessions = r > 0;
1396 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1398 if (multiple_sessions) {
1399 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1406 result = "challenge";
1412 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1416 if (r > 0 && !result)
1418 else if (challenge && (!result || streq(result, "yes")))
1419 result = "challenge";
1424 if (!multiple_sessions && !blocked) {
1425 /* If neither inhibit nor multiple sessions
1426 * apply then just check the normal policy */
1428 r = verify_polkit(connection, message, action, false, &challenge, error);
1435 result = "challenge";
1441 reply = dbus_message_new_method_return(message);
1445 b = dbus_message_append_args(
1447 DBUS_TYPE_STRING, &result,
1457 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1458 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1459 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1460 [INHIBIT_SLEEP] = "PrepareForSleep"
1463 dbus_bool_t active = _active;
1464 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1468 assert(w < _INHIBIT_WHAT_MAX);
1469 assert(signal_name[w]);
1471 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1475 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1476 !dbus_connection_send(m->bus, message, NULL))
1482 int bus_manager_shutdown_or_sleep_now_or_later(
1484 const char *unit_name,
1494 assert(w <= _INHIBIT_WHAT_MAX);
1495 assert(!m->action_job);
1497 /* Tell everybody to prepare for shutdown/sleep */
1498 send_prepare_for(m, w, true);
1501 m->inhibit_delay_max > 0 &&
1502 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1505 /* Shutdown is delayed, keep in mind what we
1506 * want to do, and start a timeout */
1507 r = delay_shutdown_or_sleep(m, w, unit_name);
1509 /* Shutdown is not delayed, execute it
1511 r = execute_shutdown_or_sleep(m, w, unit_name, error);
1516 static int bus_manager_do_shutdown_or_sleep(
1518 DBusConnection *connection,
1519 DBusMessage *message,
1520 const char *unit_name,
1523 const char *action_multiple_sessions,
1524 const char *action_ignore_inhibit,
1525 const char *sleep_verb,
1527 DBusMessage **_reply) {
1529 dbus_bool_t interactive;
1530 bool multiple_sessions, blocked;
1531 DBusMessage *reply = NULL;
1540 assert(w <= _INHIBIT_WHAT_MAX);
1542 assert(action_multiple_sessions);
1543 assert(action_ignore_inhibit);
1547 /* Don't allow multiple jobs being executed at the same time */
1551 if (!dbus_message_get_args(
1554 DBUS_TYPE_BOOLEAN, &interactive,
1559 r = can_sleep(sleep_verb);
1567 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1568 if (ul == (unsigned long) -1)
1571 r = have_multiple_sessions(m, (uid_t) ul);
1575 multiple_sessions = r > 0;
1576 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1578 if (multiple_sessions) {
1579 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1585 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1590 if (!multiple_sessions && !blocked) {
1591 r = verify_polkit(connection, message, action, interactive, NULL, error);
1596 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1600 reply = dbus_message_new_method_return(message);
1608 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1610 static const BusProperty bus_login_manager_properties[] = {
1611 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1612 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1613 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1614 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1615 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1616 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1617 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1618 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1619 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1620 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1621 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1622 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1623 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1624 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1625 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1626 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1627 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1628 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1629 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1630 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1634 static DBusHandlerResult manager_message_handler(
1635 DBusConnection *connection,
1636 DBusMessage *message,
1639 Manager *m = userdata;
1642 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1649 dbus_error_init(&error);
1651 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1657 if (!dbus_message_get_args(
1660 DBUS_TYPE_STRING, &name,
1662 return bus_send_error_reply(connection, message, &error, -EINVAL);
1664 session = hashmap_get(m->sessions, name);
1666 return bus_send_error_reply(connection, message, &error, -ENOENT);
1668 reply = dbus_message_new_method_return(message);
1672 p = session_bus_path(session);
1676 b = dbus_message_append_args(
1678 DBUS_TYPE_OBJECT_PATH, &p,
1685 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1691 if (!dbus_message_get_args(
1694 DBUS_TYPE_UINT32, &pid,
1696 return bus_send_error_reply(connection, message, &error, -EINVAL);
1698 r = manager_get_session_by_pid(m, pid, &session);
1700 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1702 reply = dbus_message_new_method_return(message);
1706 p = session_bus_path(session);
1710 b = dbus_message_append_args(
1712 DBUS_TYPE_OBJECT_PATH, &p,
1719 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1725 if (!dbus_message_get_args(
1728 DBUS_TYPE_UINT32, &uid,
1730 return bus_send_error_reply(connection, message, &error, -EINVAL);
1732 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1734 return bus_send_error_reply(connection, message, &error, -ENOENT);
1736 reply = dbus_message_new_method_return(message);
1740 p = user_bus_path(user);
1744 b = dbus_message_append_args(
1746 DBUS_TYPE_OBJECT_PATH, &p,
1753 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUserByPID")) {
1759 if (!dbus_message_get_args(
1762 DBUS_TYPE_UINT32, &pid,
1764 return bus_send_error_reply(connection, message, &error, -EINVAL);
1766 r = manager_get_user_by_pid(m, pid, &user);
1768 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1770 reply = dbus_message_new_method_return(message);
1774 p = user_bus_path(user);
1778 b = dbus_message_append_args(
1780 DBUS_TYPE_OBJECT_PATH, &p,
1786 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetMachine")) {
1792 if (!dbus_message_get_args(
1795 DBUS_TYPE_STRING, &name,
1797 return bus_send_error_reply(connection, message, &error, -EINVAL);
1799 machine = hashmap_get(m->machines, name);
1801 return bus_send_error_reply(connection, message, &error, -ENOENT);
1803 reply = dbus_message_new_method_return(message);
1807 p = machine_bus_path(machine);
1811 b = dbus_message_append_args(
1813 DBUS_TYPE_OBJECT_PATH, &p,
1820 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetMachineByPID")) {
1826 if (!dbus_message_get_args(
1829 DBUS_TYPE_UINT32, &pid,
1831 return bus_send_error_reply(connection, message, &error, -EINVAL);
1833 r = manager_get_machine_by_pid(m, pid, &machine);
1835 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1837 reply = dbus_message_new_method_return(message);
1841 p = machine_bus_path(machine);
1845 b = dbus_message_append_args(
1847 DBUS_TYPE_OBJECT_PATH, &p,
1854 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1860 if (!dbus_message_get_args(
1863 DBUS_TYPE_STRING, &name,
1865 return bus_send_error_reply(connection, message, &error, -EINVAL);
1867 seat = hashmap_get(m->seats, name);
1869 return bus_send_error_reply(connection, message, &error, -ENOENT);
1871 reply = dbus_message_new_method_return(message);
1875 p = seat_bus_path(seat);
1879 b = dbus_message_append_args(
1881 DBUS_TYPE_OBJECT_PATH, &p,
1888 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1892 DBusMessageIter iter, sub;
1893 const char *empty = "";
1895 reply = dbus_message_new_method_return(message);
1899 dbus_message_iter_init_append(reply, &iter);
1901 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1904 HASHMAP_FOREACH(session, m->sessions, i) {
1905 DBusMessageIter sub2;
1908 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1911 uid = session->user->uid;
1913 p = session_bus_path(session);
1917 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1918 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1919 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1920 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1921 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1928 if (!dbus_message_iter_close_container(&sub, &sub2))
1932 if (!dbus_message_iter_close_container(&iter, &sub))
1935 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1938 DBusMessageIter iter, sub;
1940 reply = dbus_message_new_method_return(message);
1944 dbus_message_iter_init_append(reply, &iter);
1946 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1949 HASHMAP_FOREACH(user, m->users, i) {
1950 _cleanup_free_ char *p = NULL;
1951 DBusMessageIter sub2;
1954 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1959 p = user_bus_path(user);
1963 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1964 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1965 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1970 if (!dbus_message_iter_close_container(&sub, &sub2))
1974 if (!dbus_message_iter_close_container(&iter, &sub))
1977 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1980 DBusMessageIter iter, sub;
1982 reply = dbus_message_new_method_return(message);
1986 dbus_message_iter_init_append(reply, &iter);
1988 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1991 HASHMAP_FOREACH(seat, m->seats, i) {
1992 _cleanup_free_ char *p = NULL;
1993 DBusMessageIter sub2;
1995 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1998 p = seat_bus_path(seat);
2002 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
2003 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
2008 if (!dbus_message_iter_close_container(&sub, &sub2))
2012 if (!dbus_message_iter_close_container(&iter, &sub))
2015 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
2016 Inhibitor *inhibitor;
2018 DBusMessageIter iter, sub;
2020 reply = dbus_message_new_method_return(message);
2024 dbus_message_iter_init_append(reply, &iter);
2026 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
2029 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
2030 DBusMessageIter sub2;
2031 dbus_uint32_t uid, pid;
2032 const char *what, *who, *why, *mode;
2034 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
2037 what = strempty(inhibit_what_to_string(inhibitor->what));
2038 who = strempty(inhibitor->who);
2039 why = strempty(inhibitor->why);
2040 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
2041 uid = (dbus_uint32_t) inhibitor->uid;
2042 pid = (dbus_uint32_t) inhibitor->pid;
2044 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
2045 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
2046 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
2047 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
2048 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
2049 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
2052 if (!dbus_message_iter_close_container(&sub, &sub2))
2056 if (!dbus_message_iter_close_container(&iter, &sub))
2059 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListMachines")) {
2062 DBusMessageIter iter, sub;
2064 reply = dbus_message_new_method_return(message);
2068 dbus_message_iter_init_append(reply, &iter);
2070 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssso)", &sub))
2073 HASHMAP_FOREACH(machine, m->machines, i) {
2074 _cleanup_free_ char *p = NULL;
2075 DBusMessageIter sub2;
2078 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
2081 p = machine_bus_path(machine);
2085 class = strempty(machine_class_to_string(machine->class));
2087 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &machine->name) ||
2088 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &class) ||
2089 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &machine->service) ||
2090 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
2095 if (!dbus_message_iter_close_container(&sub, &sub2))
2099 if (!dbus_message_iter_close_container(&iter, &sub))
2102 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
2104 r = bus_manager_inhibit(m, connection, message, &error, &reply);
2107 return bus_send_error_reply(connection, message, &error, r);
2110 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
2112 r = bus_manager_create_session(m, message, &reply);
2114 /* Don't delay the work on OOM here, since it might be
2115 * triggered by a low RLIMIT_NOFILE here (since we
2116 * send a dupped fd to the client), and we'd rather
2117 * see this fail quickly then be retried later */
2120 return bus_send_error_reply(connection, message, NULL, r);
2121 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateMachine")) {
2123 r = bus_manager_create_machine(m, message, &reply);
2125 return bus_send_error_reply(connection, message, NULL, r);
2127 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
2131 if (!dbus_message_get_args(
2134 DBUS_TYPE_STRING, &name,
2136 return bus_send_error_reply(connection, message, &error, -EINVAL);
2138 session = hashmap_get(m->sessions, name);
2140 return bus_send_error_reply(connection, message, &error, -ENOENT);
2142 /* We use the FIFO to detect stray sessions where the
2143 process invoking PAM dies abnormally. We need to make
2144 sure that that process is not killed if at the clean
2145 end of the session it closes the FIFO. Hence, with
2146 this call explicitly turn off the FIFO logic, so that
2147 the PAM code can finish clean up on its own */
2148 session_remove_fifo(session);
2150 reply = dbus_message_new_method_return(message);
2154 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
2158 if (!dbus_message_get_args(
2161 DBUS_TYPE_STRING, &name,
2163 return bus_send_error_reply(connection, message, &error, -EINVAL);
2165 session = hashmap_get(m->sessions, name);
2167 return bus_send_error_reply(connection, message, &error, -ENOENT);
2169 r = session_activate(session);
2171 return bus_send_error_reply(connection, message, NULL, r);
2173 reply = dbus_message_new_method_return(message);
2177 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
2178 const char *session_name, *seat_name;
2182 /* Same as ActivateSession() but refuses to work if
2183 * the seat doesn't match */
2185 if (!dbus_message_get_args(
2188 DBUS_TYPE_STRING, &session_name,
2189 DBUS_TYPE_STRING, &seat_name,
2191 return bus_send_error_reply(connection, message, &error, -EINVAL);
2193 session = hashmap_get(m->sessions, session_name);
2195 return bus_send_error_reply(connection, message, &error, -ENOENT);
2197 seat = hashmap_get(m->seats, seat_name);
2199 return bus_send_error_reply(connection, message, &error, -ENOENT);
2201 if (session->seat != seat)
2202 return bus_send_error_reply(connection, message, &error, -EINVAL);
2204 r = session_activate(session);
2206 return bus_send_error_reply(connection, message, NULL, r);
2208 reply = dbus_message_new_method_return(message);
2212 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
2213 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
2217 if (!dbus_message_get_args(
2220 DBUS_TYPE_STRING, &name,
2222 return bus_send_error_reply(connection, message, &error, -EINVAL);
2224 session = hashmap_get(m->sessions, name);
2226 return bus_send_error_reply(connection, message, NULL, -ENOENT);
2228 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
2231 reply = dbus_message_new_method_return(message);
2235 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
2236 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
2238 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
2240 bus_send_error_reply(connection, message, NULL, r);
2242 reply = dbus_message_new_method_return(message);
2246 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
2253 if (!dbus_message_get_args(
2256 DBUS_TYPE_STRING, &name,
2257 DBUS_TYPE_STRING, &swho,
2258 DBUS_TYPE_INT32, &signo,
2260 return bus_send_error_reply(connection, message, &error, -EINVAL);
2265 who = kill_who_from_string(swho);
2267 return bus_send_error_reply(connection, message, &error, -EINVAL);
2270 if (signo <= 0 || signo >= _NSIG)
2271 return bus_send_error_reply(connection, message, &error, -EINVAL);
2273 session = hashmap_get(m->sessions, name);
2275 return bus_send_error_reply(connection, message, &error, -ENOENT);
2277 r = session_kill(session, who, signo);
2279 return bus_send_error_reply(connection, message, NULL, r);
2281 reply = dbus_message_new_method_return(message);
2285 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
2290 if (!dbus_message_get_args(
2293 DBUS_TYPE_UINT32, &uid,
2294 DBUS_TYPE_INT32, &signo,
2296 return bus_send_error_reply(connection, message, &error, -EINVAL);
2298 if (signo <= 0 || signo >= _NSIG)
2299 return bus_send_error_reply(connection, message, &error, -EINVAL);
2301 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2303 return bus_send_error_reply(connection, message, &error, -ENOENT);
2305 r = user_kill(user, signo);
2307 return bus_send_error_reply(connection, message, NULL, r);
2309 reply = dbus_message_new_method_return(message);
2313 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillMachine")) {
2320 if (!dbus_message_get_args(
2323 DBUS_TYPE_STRING, &name,
2324 DBUS_TYPE_STRING, &swho,
2325 DBUS_TYPE_INT32, &signo,
2327 return bus_send_error_reply(connection, message, &error, -EINVAL);
2332 who = kill_who_from_string(swho);
2334 return bus_send_error_reply(connection, message, &error, -EINVAL);
2337 if (signo <= 0 || signo >= _NSIG)
2338 return bus_send_error_reply(connection, message, &error, -EINVAL);
2340 machine = hashmap_get(m->machines, name);
2342 return bus_send_error_reply(connection, message, &error, -ENOENT);
2344 r = machine_kill(machine, who, signo);
2346 return bus_send_error_reply(connection, message, NULL, r);
2348 reply = dbus_message_new_method_return(message);
2352 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
2356 if (!dbus_message_get_args(
2359 DBUS_TYPE_STRING, &name,
2361 return bus_send_error_reply(connection, message, &error, -EINVAL);
2363 session = hashmap_get(m->sessions, name);
2365 return bus_send_error_reply(connection, message, &error, -ENOENT);
2367 r = session_stop(session);
2369 return bus_send_error_reply(connection, message, NULL, r);
2371 reply = dbus_message_new_method_return(message);
2375 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
2379 if (!dbus_message_get_args(
2382 DBUS_TYPE_UINT32, &uid,
2384 return bus_send_error_reply(connection, message, &error, -EINVAL);
2386 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2388 return bus_send_error_reply(connection, message, &error, -ENOENT);
2390 r = user_stop(user);
2392 return bus_send_error_reply(connection, message, NULL, r);
2394 reply = dbus_message_new_method_return(message);
2398 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
2402 if (!dbus_message_get_args(
2405 DBUS_TYPE_STRING, &name,
2407 return bus_send_error_reply(connection, message, &error, -EINVAL);
2409 seat = hashmap_get(m->seats, name);
2411 return bus_send_error_reply(connection, message, &error, -ENOENT);
2413 r = seat_stop_sessions(seat);
2415 return bus_send_error_reply(connection, message, NULL, r);
2417 reply = dbus_message_new_method_return(message);
2421 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateMachine")) {
2425 if (!dbus_message_get_args(
2428 DBUS_TYPE_STRING, &name,
2430 return bus_send_error_reply(connection, message, &error, -EINVAL);
2432 machine = hashmap_get(m->machines, name);
2434 return bus_send_error_reply(connection, message, &error, -ENOENT);
2436 r = machine_stop(machine);
2438 return bus_send_error_reply(connection, message, NULL, r);
2440 reply = dbus_message_new_method_return(message);
2444 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
2447 dbus_bool_t b, interactive;
2450 if (!dbus_message_get_args(
2453 DBUS_TYPE_UINT32, &uid,
2454 DBUS_TYPE_BOOLEAN, &b,
2455 DBUS_TYPE_BOOLEAN, &interactive,
2457 return bus_send_error_reply(connection, message, &error, -EINVAL);
2462 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2464 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2466 return bus_send_error_reply(connection, message, &error, r);
2468 mkdir_p_label("/var/lib/systemd", 0755);
2470 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2472 return bus_send_error_reply(connection, message, &error, r);
2474 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2485 return bus_send_error_reply(connection, message, &error, r);
2487 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2496 if (r < 0 && errno != ENOENT)
2497 return bus_send_error_reply(connection, message, &error, -errno);
2499 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2501 user_add_to_gc_queue(u);
2504 reply = dbus_message_new_method_return(message);
2508 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2509 const char *sysfs, *seat;
2510 dbus_bool_t interactive;
2512 if (!dbus_message_get_args(
2515 DBUS_TYPE_STRING, &seat,
2516 DBUS_TYPE_STRING, &sysfs,
2517 DBUS_TYPE_BOOLEAN, &interactive,
2519 return bus_send_error_reply(connection, message, &error, -EINVAL);
2521 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2522 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2524 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2526 return bus_send_error_reply(connection, message, &error, r);
2528 r = attach_device(m, seat, sysfs);
2530 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2532 reply = dbus_message_new_method_return(message);
2537 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2538 dbus_bool_t interactive;
2540 if (!dbus_message_get_args(
2543 DBUS_TYPE_BOOLEAN, &interactive,
2545 return bus_send_error_reply(connection, message, &error, -EINVAL);
2547 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2549 return bus_send_error_reply(connection, message, &error, r);
2551 r = flush_devices(m);
2553 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2555 reply = dbus_message_new_method_return(message);
2559 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2561 r = bus_manager_do_shutdown_or_sleep(
2562 m, connection, message,
2563 SPECIAL_POWEROFF_TARGET,
2565 "org.freedesktop.login1.power-off",
2566 "org.freedesktop.login1.power-off-multiple-sessions",
2567 "org.freedesktop.login1.power-off-ignore-inhibit",
2571 return bus_send_error_reply(connection, message, &error, r);
2572 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2573 r = bus_manager_do_shutdown_or_sleep(
2574 m, connection, message,
2575 SPECIAL_REBOOT_TARGET,
2577 "org.freedesktop.login1.reboot",
2578 "org.freedesktop.login1.reboot-multiple-sessions",
2579 "org.freedesktop.login1.reboot-ignore-inhibit",
2583 return bus_send_error_reply(connection, message, &error, r);
2585 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2586 r = bus_manager_do_shutdown_or_sleep(
2587 m, connection, message,
2588 SPECIAL_SUSPEND_TARGET,
2590 "org.freedesktop.login1.suspend",
2591 "org.freedesktop.login1.suspend-multiple-sessions",
2592 "org.freedesktop.login1.suspend-ignore-inhibit",
2596 return bus_send_error_reply(connection, message, &error, r);
2597 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2598 r = bus_manager_do_shutdown_or_sleep(
2599 m, connection, message,
2600 SPECIAL_HIBERNATE_TARGET,
2602 "org.freedesktop.login1.hibernate",
2603 "org.freedesktop.login1.hibernate-multiple-sessions",
2604 "org.freedesktop.login1.hibernate-ignore-inhibit",
2608 return bus_send_error_reply(connection, message, &error, r);
2610 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2611 r = bus_manager_do_shutdown_or_sleep(
2612 m, connection, message,
2613 SPECIAL_HYBRID_SLEEP_TARGET,
2615 "org.freedesktop.login1.hibernate",
2616 "org.freedesktop.login1.hibernate-multiple-sessions",
2617 "org.freedesktop.login1.hibernate-ignore-inhibit",
2621 return bus_send_error_reply(connection, message, &error, r);
2623 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2625 r = bus_manager_can_shutdown_or_sleep(
2626 m, connection, message,
2628 "org.freedesktop.login1.power-off",
2629 "org.freedesktop.login1.power-off-multiple-sessions",
2630 "org.freedesktop.login1.power-off-ignore-inhibit",
2634 return bus_send_error_reply(connection, message, &error, r);
2635 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2636 r = bus_manager_can_shutdown_or_sleep(
2637 m, connection, message,
2639 "org.freedesktop.login1.reboot",
2640 "org.freedesktop.login1.reboot-multiple-sessions",
2641 "org.freedesktop.login1.reboot-ignore-inhibit",
2645 return bus_send_error_reply(connection, message, &error, r);
2647 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2648 r = bus_manager_can_shutdown_or_sleep(
2649 m, connection, message,
2651 "org.freedesktop.login1.suspend",
2652 "org.freedesktop.login1.suspend-multiple-sessions",
2653 "org.freedesktop.login1.suspend-ignore-inhibit",
2657 return bus_send_error_reply(connection, message, &error, r);
2659 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2660 r = bus_manager_can_shutdown_or_sleep(
2661 m, connection, message,
2663 "org.freedesktop.login1.hibernate",
2664 "org.freedesktop.login1.hibernate-multiple-sessions",
2665 "org.freedesktop.login1.hibernate-ignore-inhibit",
2669 return bus_send_error_reply(connection, message, &error, r);
2671 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2672 r = bus_manager_can_shutdown_or_sleep(
2673 m, connection, message,
2675 "org.freedesktop.login1.hibernate",
2676 "org.freedesktop.login1.hibernate-multiple-sessions",
2677 "org.freedesktop.login1.hibernate-ignore-inhibit",
2681 return bus_send_error_reply(connection, message, &error, r);
2683 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2684 char *introspection = NULL;
2693 if (!(reply = dbus_message_new_method_return(message)))
2696 /* We roll our own introspection code here, instead of
2697 * relying on bus_default_message_handler() because we
2698 * need to generate our introspection string
2701 if (!(f = open_memstream(&introspection, &size)))
2704 fputs(INTROSPECTION_BEGIN, f);
2706 HASHMAP_FOREACH(seat, m->seats, i) {
2707 p = bus_path_escape(seat->id);
2710 fprintf(f, "<node name=\"seat/%s\"/>", p);
2715 HASHMAP_FOREACH(user, m->users, i)
2716 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2718 HASHMAP_FOREACH(session, m->sessions, i) {
2719 p = bus_path_escape(session->id);
2722 fprintf(f, "<node name=\"session/%s\"/>", p);
2727 fputs(INTROSPECTION_END, f);
2731 free(introspection);
2740 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2741 free(introspection);
2745 free(introspection);
2747 const BusBoundProperties bps[] = {
2748 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2751 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2755 if (!bus_maybe_send_reply(connection, message, reply))
2759 return DBUS_HANDLER_RESULT_HANDLED;
2762 dbus_error_free(&error);
2764 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2767 const DBusObjectPathVTable bus_manager_vtable = {
2768 .message_function = manager_message_handler
2771 DBusHandlerResult bus_message_filter(
2772 DBusConnection *connection,
2773 DBusMessage *message,
2776 Manager *m = userdata;
2783 dbus_error_init(&error);
2785 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2788 if (!dbus_message_get_args(message, &error,
2789 DBUS_TYPE_STRING, &cgroup,
2791 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2793 manager_cgroup_notify_empty(m, cgroup);
2795 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2797 const char *path, *result, *unit;
2799 if (!dbus_message_get_args(message, &error,
2800 DBUS_TYPE_UINT32, &id,
2801 DBUS_TYPE_OBJECT_PATH, &path,
2802 DBUS_TYPE_STRING, &unit,
2803 DBUS_TYPE_STRING, &result,
2805 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2807 else if (m->action_job && streq(m->action_job, path)) {
2808 log_info("Operation finished.");
2810 /* Tell people that they now may take a lock again */
2811 send_prepare_for(m, m->action_what, false);
2813 free(m->action_job);
2814 m->action_job = NULL;
2815 m->action_unit = NULL;
2820 dbus_error_free(&error);
2822 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2825 int manager_send_changed(Manager *manager, const char *properties) {
2826 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
2830 m = bus_properties_changed_new("/org/freedesktop/login1",
2831 "org.freedesktop.login1.Manager",
2836 if (!dbus_connection_send(manager->bus, m, NULL))
2842 int manager_dispatch_delayed(Manager *manager) {
2848 if (manager->action_what == 0 || manager->action_job)
2851 /* Continue delay? */
2852 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
2854 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2857 log_info("Delay lock is active but inhibitor timeout is reached.");
2860 /* Actually do the operation */
2861 dbus_error_init(&error);
2862 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
2864 log_warning("Failed to send delayed message: %s", bus_error(&error, r));
2865 dbus_error_free(&error);
2867 manager->action_unit = NULL;
2868 manager->action_what = 0;