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"
41 #include "bus-errors.h"
44 #define BUS_MANAGER_INTERFACE \
45 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
46 " <method name=\"GetSession\">\n" \
47 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
48 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
50 " <method name=\"GetSessionByPID\">\n" \
51 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
52 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
54 " <method name=\"GetUser\">\n" \
55 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
56 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
58 " <method name=\"GetUserByPID\">\n" \
59 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
60 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
62 " <method name=\"GetSeat\">\n" \
63 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
64 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
66 " <method name=\"GetMachine\">\n" \
67 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
68 " <arg name=\"machine\" type=\"o\" direction=\"out\"/>\n" \
70 " <method name=\"GetMachineByPID\">\n" \
71 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
72 " <arg name=\"machine\" type=\"o\" direction=\"out\"/>\n" \
74 " <method name=\"ListSessions\">\n" \
75 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
77 " <method name=\"ListUsers\">\n" \
78 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
80 " <method name=\"ListSeats\">\n" \
81 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
83 " <method name=\"ListMachines\">\n" \
84 " <arg name=\"machines\" type=\"a(ssso)\" direction=\"out\"/>\n" \
86 " <method name=\"CreateSession\">\n" \
87 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
88 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
89 " <arg name=\"service\" type=\"s\" direction=\"in\"/>\n" \
90 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
91 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
92 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
93 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
94 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
95 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
96 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
97 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
98 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
99 " <arg name=\"scope_properties\" type=\"a(sv)\" 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=\"root_directory\" type=\"s\" direction=\"in\"/>\n" \
118 " <arg name=\"scope_properties\" type=\"a(sv)\" 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) {
350 const char *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *service;
351 uint32_t uid, leader, audit_id = 0;
352 _cleanup_free_ char *id = NULL;
353 Session *session = NULL;
356 DBusMessageIter iter;
367 if (!dbus_message_iter_init(message, &iter) ||
368 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
371 dbus_message_iter_get_basic(&iter, &uid);
373 if (!dbus_message_iter_next(&iter) ||
374 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
377 dbus_message_iter_get_basic(&iter, &leader);
379 if (!dbus_message_iter_next(&iter) ||
380 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
383 dbus_message_iter_get_basic(&iter, &service);
385 if (!dbus_message_iter_next(&iter) ||
386 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
389 dbus_message_iter_get_basic(&iter, &type);
391 t = _SESSION_TYPE_INVALID;
393 t = session_type_from_string(type);
398 if (!dbus_message_iter_next(&iter) ||
399 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
402 dbus_message_iter_get_basic(&iter, &class);
404 c = _SESSION_CLASS_INVALID;
406 c = session_class_from_string(class);
411 if (!dbus_message_iter_next(&iter) ||
412 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
415 dbus_message_iter_get_basic(&iter, &cseat);
420 seat = hashmap_get(m->seats, cseat);
425 if (!dbus_message_iter_next(&iter) ||
426 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
429 dbus_message_iter_get_basic(&iter, &vtnr);
431 if (!dbus_message_iter_next(&iter) ||
432 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
435 dbus_message_iter_get_basic(&iter, &tty);
437 if (tty_is_vc(tty)) {
442 else if (seat != m->vtconsole)
445 v = vtnr_from_tty(tty);
448 return v < 0 ? v : -EINVAL;
452 else if (vtnr != (uint32_t) v)
454 } else if (tty_is_console(tty)) {
458 else if (seat != m->vtconsole)
466 if (seat_can_multi_session(seat)) {
475 if (!dbus_message_iter_next(&iter) ||
476 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
479 dbus_message_iter_get_basic(&iter, &display);
481 if (!dbus_message_iter_next(&iter) ||
482 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
485 if (t == _SESSION_TYPE_INVALID) {
486 if (!isempty(display))
488 else if (!isempty(tty))
491 t = SESSION_UNSPECIFIED;
494 if (c == _SESSION_CLASS_INVALID) {
495 if (!isempty(display) || !isempty(tty))
498 c = SESSION_BACKGROUND;
501 dbus_message_iter_get_basic(&iter, &remote);
503 if (!dbus_message_iter_next(&iter) ||
504 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
507 dbus_message_iter_get_basic(&iter, &remote_user);
509 if (!dbus_message_iter_next(&iter) ||
510 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
513 dbus_message_iter_get_basic(&iter, &remote_host);
516 leader = bus_get_unix_process_id(m->bus, dbus_message_get_sender(message), NULL);
521 r = manager_get_session_by_pid(m, leader, &session);
523 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
524 _cleanup_free_ char *path = NULL;
525 _cleanup_close_ int fifo_fd = -1;
528 /* Session already exists, client is probably
529 * something like "su" which changes uid but is still
530 * the same session */
532 fifo_fd = session_create_fifo(session);
538 path = session_bus_path(session);
544 reply = dbus_message_new_method_return(message);
550 cseat = session->seat ? session->seat->id : "";
551 vtnr = session->vtnr;
554 b = dbus_message_append_args(
556 DBUS_TYPE_STRING, &session->id,
557 DBUS_TYPE_OBJECT_PATH, &path,
558 DBUS_TYPE_STRING, &session->user->runtime_path,
559 DBUS_TYPE_UNIX_FD, &fifo_fd,
560 DBUS_TYPE_STRING, &cseat,
561 DBUS_TYPE_UINT32, &vtnr,
562 DBUS_TYPE_BOOLEAN, &exists,
569 if (!dbus_connection_send(m->bus, reply, NULL)) {
577 audit_session_from_pid(leader, &audit_id);
579 /* Keep our session IDs and the audit session IDs in sync */
581 if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0) {
586 /* Wut? There's already a session by this name and we
587 * didn't find it above? Weird, then let's not trust
588 * the audit data and let's better register a new
590 if (hashmap_get(m->sessions, id)) {
603 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
608 } while (hashmap_get(m->sessions, id));
611 r = manager_add_user_by_uid(m, uid, &user);
615 r = manager_add_session(m, id, &session);
619 session_set_user(session, user);
621 session->leader = leader;
622 session->audit_id = audit_id;
625 session->remote = remote;
626 session->vtnr = vtnr;
629 session->tty = strdup(tty);
636 if (!isempty(display)) {
637 session->display = strdup(display);
638 if (!session->display) {
644 if (!isempty(remote_user)) {
645 session->remote_user = strdup(remote_user);
646 if (!session->remote_user) {
652 if (!isempty(remote_host)) {
653 session->remote_host = strdup(remote_host);
654 if (!session->remote_host) {
660 if (!isempty(service)) {
661 session->service = strdup(service);
662 if (!session->service) {
669 r = seat_attach_session(seat, session);
674 r = session_start(session);
678 session->create_message = dbus_message_ref(message);
684 session_add_to_gc_queue(session);
687 user_add_to_gc_queue(user);
692 static bool valid_machine_name(const char *p) {
695 if (!filename_is_safe(p))
698 if (!ascii_is_valid(p))
709 static int bus_manager_create_machine(Manager *manager, DBusMessage *message) {
711 const char *name, *service, *class, *slice, *root_directory;
712 _cleanup_free_ char *p = NULL;
713 DBusMessageIter iter, sub;
724 if (!dbus_message_iter_init(message, &iter) ||
725 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
728 dbus_message_iter_get_basic(&iter, &name);
730 if (!valid_machine_name(name) ||
731 !dbus_message_iter_next(&iter) ||
732 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
733 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE)
736 dbus_message_iter_recurse(&iter, &sub);
737 dbus_message_iter_get_fixed_array(&sub, &v, &n);
746 if (!dbus_message_iter_next(&iter) ||
747 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
750 dbus_message_iter_get_basic(&iter, &service);
752 if (!dbus_message_iter_next(&iter) ||
753 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
756 dbus_message_iter_get_basic(&iter, &class);
759 c = _MACHINE_CLASS_INVALID;
761 c = machine_class_from_string(class);
766 if (!dbus_message_iter_next(&iter) ||
767 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
770 dbus_message_iter_get_basic(&iter, &leader);
771 if (!dbus_message_iter_next(&iter) ||
772 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
775 dbus_message_iter_get_basic(&iter, &slice);
776 if (!(isempty(slice) || (unit_name_is_valid(slice, false) && endswith(slice, ".slice"))) ||
777 !dbus_message_iter_next(&iter) ||
778 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
781 dbus_message_iter_get_basic(&iter, &root_directory);
783 if (!(isempty(root_directory) || path_is_absolute(root_directory)))
786 if (hashmap_get(manager->machines, name))
790 leader = bus_get_unix_process_id(manager->bus, dbus_message_get_sender(message), NULL);
795 r = manager_add_machine(manager, name, &m);
803 if (!isempty(service)) {
804 m->service = strdup(service);
811 if (!isempty(root_directory)) {
812 m->root_directory = strdup(root_directory);
813 if (!m->root_directory) {
819 r = machine_start(m);
823 m->create_message = dbus_message_ref(message);
829 machine_add_to_gc_queue(m);
834 static int bus_manager_inhibit(
836 DBusConnection *connection,
837 DBusMessage *message,
839 DBusMessage **_reply) {
843 const char *who, *why, *what, *mode;
849 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
857 if (!dbus_message_get_args(
860 DBUS_TYPE_STRING, &what,
861 DBUS_TYPE_STRING, &who,
862 DBUS_TYPE_STRING, &why,
863 DBUS_TYPE_STRING, &mode,
864 DBUS_TYPE_INVALID)) {
869 w = inhibit_what_from_string(what);
875 mm = inhibit_mode_from_string(mode);
881 /* Delay is only supported for shutdown/sleep */
882 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
887 /* Don't allow taking delay locks while we are already
888 * executing the operation. We shouldn't create the impression
889 * that the lock was successful if the machine is about to go
890 * down/suspend any moment. */
891 if (m->action_what & w) {
896 r = verify_polkit(connection, message,
897 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
898 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
899 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
900 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
901 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
902 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
903 "org.freedesktop.login1.inhibit-handle-lid-switch",
908 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
909 if (ul == (unsigned long) -1) {
914 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
924 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
928 } while (hashmap_get(m->inhibitors, id));
930 r = manager_add_inhibitor(m, id, &i);
940 i->why = strdup(why);
941 i->who = strdup(who);
943 if (!i->why || !i->who) {
948 fifo_fd = inhibitor_create_fifo(i);
954 reply = dbus_message_new_method_return(message);
960 if (!dbus_message_append_args(
962 DBUS_TYPE_UNIX_FD, &fifo_fd,
963 DBUS_TYPE_INVALID)) {
968 close_nointr_nofail(fifo_fd);
981 close_nointr_nofail(fifo_fd);
986 static int trigger_device(Manager *m, struct udev_device *d) {
987 struct udev_enumerate *e;
988 struct udev_list_entry *first, *item;
993 e = udev_enumerate_new(m->udev);
1000 if (udev_enumerate_add_match_parent(e, d) < 0) {
1006 if (udev_enumerate_scan_devices(e) < 0) {
1011 first = udev_enumerate_get_list_entry(e);
1012 udev_list_entry_foreach(item, first) {
1016 p = udev_list_entry_get_name(item);
1018 t = strappend(p, "/uevent");
1024 write_string_file(t, "change");
1032 udev_enumerate_unref(e);
1037 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
1038 struct udev_device *d;
1039 _cleanup_free_ char *rule = NULL, *file = NULL;
1040 const char *id_for_seat;
1047 d = udev_device_new_from_syspath(m->udev, sysfs);
1051 if (!udev_device_has_tag(d, "seat")) {
1056 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
1062 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
1067 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
1072 mkdir_p_label("/etc/udev/rules.d", 0755);
1074 r = write_string_file_atomic_label(file, rule);
1078 r = trigger_device(m, d);
1082 udev_device_unref(d);
1087 static int flush_devices(Manager *m) {
1088 _cleanup_closedir_ DIR *d;
1092 d = opendir("/etc/udev/rules.d");
1094 if (errno != ENOENT)
1095 log_warning("Failed to open /etc/udev/rules.d: %m");
1099 while ((de = readdir(d))) {
1101 if (!dirent_is_file(de))
1104 if (!startswith(de->d_name, "72-seat-"))
1107 if (!endswith(de->d_name, ".rules"))
1110 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
1111 log_warning("Failed to unlink %s: %m", de->d_name);
1115 return trigger_device(m, NULL);
1118 static int have_multiple_sessions(
1127 /* Check for other users' sessions. Greeter sessions do not
1128 * count, and non-login sessions do not count either. */
1129 HASHMAP_FOREACH(session, m->sessions, i)
1130 if (session->class == SESSION_USER &&
1131 session->user->uid != uid)
1137 static int bus_manager_log_shutdown(
1140 const char *unit_name) {
1147 if (w != INHIBIT_SHUTDOWN)
1150 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1151 p = "MESSAGE=System is powering down.";
1152 q = "SHUTDOWN=power-off";
1153 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1154 p = "MESSAGE=System is halting.";
1155 q = "SHUTDOWN=halt";
1156 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1157 p = "MESSAGE=System is rebooting.";
1158 q = "SHUTDOWN=reboot";
1159 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1160 p = "MESSAGE=System is rebooting with kexec.";
1161 q = "SHUTDOWN=kexec";
1163 p = "MESSAGE=System is shutting down.";
1167 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1172 static int execute_shutdown_or_sleep(
1175 const char *unit_name,
1178 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1179 const char *mode = "replace-irreversibly", *p;
1185 assert(w < _INHIBIT_WHAT_MAX);
1188 bus_manager_log_shutdown(m, w, unit_name);
1190 r = bus_method_call_with_reply(
1192 "org.freedesktop.systemd1",
1193 "/org/freedesktop/systemd1",
1194 "org.freedesktop.systemd1.Manager",
1198 DBUS_TYPE_STRING, &unit_name,
1199 DBUS_TYPE_STRING, &mode,
1204 if (!dbus_message_get_args(
1207 DBUS_TYPE_OBJECT_PATH, &p,
1215 m->action_unit = unit_name;
1216 free(m->action_job);
1223 static int delay_shutdown_or_sleep(
1226 const char *unit_name) {
1230 assert(w < _INHIBIT_WHAT_MAX);
1233 m->action_timestamp = now(CLOCK_MONOTONIC);
1234 m->action_unit = unit_name;
1240 static int bus_manager_can_shutdown_or_sleep(
1242 DBusConnection *connection,
1243 DBusMessage *message,
1246 const char *action_multiple_sessions,
1247 const char *action_ignore_inhibit,
1248 const char *sleep_verb,
1250 DBusMessage **_reply) {
1252 bool multiple_sessions, challenge, blocked, b;
1253 const char *result = NULL;
1254 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1262 assert(w <= _INHIBIT_WHAT_MAX);
1264 assert(action_multiple_sessions);
1265 assert(action_ignore_inhibit);
1270 r = can_sleep(sleep_verb);
1279 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1280 if (ul == (unsigned long) -1)
1283 r = have_multiple_sessions(m, (uid_t) ul);
1287 multiple_sessions = r > 0;
1288 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1290 if (multiple_sessions) {
1291 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1298 result = "challenge";
1304 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1308 if (r > 0 && !result)
1310 else if (challenge && (!result || streq(result, "yes")))
1311 result = "challenge";
1316 if (!multiple_sessions && !blocked) {
1317 /* If neither inhibit nor multiple sessions
1318 * apply then just check the normal policy */
1320 r = verify_polkit(connection, message, action, false, &challenge, error);
1327 result = "challenge";
1333 reply = dbus_message_new_method_return(message);
1337 b = dbus_message_append_args(
1339 DBUS_TYPE_STRING, &result,
1349 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1350 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1351 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1352 [INHIBIT_SLEEP] = "PrepareForSleep"
1355 dbus_bool_t active = _active;
1356 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1360 assert(w < _INHIBIT_WHAT_MAX);
1361 assert(signal_name[w]);
1363 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1367 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1368 !dbus_connection_send(m->bus, message, NULL))
1374 int bus_manager_shutdown_or_sleep_now_or_later(
1376 const char *unit_name,
1386 assert(w <= _INHIBIT_WHAT_MAX);
1387 assert(!m->action_job);
1389 /* Tell everybody to prepare for shutdown/sleep */
1390 send_prepare_for(m, w, true);
1393 m->inhibit_delay_max > 0 &&
1394 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1397 /* Shutdown is delayed, keep in mind what we
1398 * want to do, and start a timeout */
1399 r = delay_shutdown_or_sleep(m, w, unit_name);
1401 /* Shutdown is not delayed, execute it
1403 r = execute_shutdown_or_sleep(m, w, unit_name, error);
1408 static int bus_manager_do_shutdown_or_sleep(
1410 DBusConnection *connection,
1411 DBusMessage *message,
1412 const char *unit_name,
1415 const char *action_multiple_sessions,
1416 const char *action_ignore_inhibit,
1417 const char *sleep_verb,
1419 DBusMessage **_reply) {
1421 dbus_bool_t interactive;
1422 bool multiple_sessions, blocked;
1423 DBusMessage *reply = NULL;
1432 assert(w <= _INHIBIT_WHAT_MAX);
1434 assert(action_multiple_sessions);
1435 assert(action_ignore_inhibit);
1439 /* Don't allow multiple jobs being executed at the same time */
1443 if (!dbus_message_get_args(
1446 DBUS_TYPE_BOOLEAN, &interactive,
1451 r = can_sleep(sleep_verb);
1459 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1460 if (ul == (unsigned long) -1)
1463 r = have_multiple_sessions(m, (uid_t) ul);
1467 multiple_sessions = r > 0;
1468 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1470 if (multiple_sessions) {
1471 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1477 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1482 if (!multiple_sessions && !blocked) {
1483 r = verify_polkit(connection, message, action, interactive, NULL, error);
1488 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1492 reply = dbus_message_new_method_return(message);
1500 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1502 static const BusProperty bus_login_manager_properties[] = {
1503 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1504 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1505 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1506 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1507 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1508 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1509 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1510 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1511 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1512 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1513 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1514 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1515 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1516 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1517 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1518 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1519 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1520 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1524 static DBusHandlerResult manager_message_handler(
1525 DBusConnection *connection,
1526 DBusMessage *message,
1529 Manager *m = userdata;
1532 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1539 dbus_error_init(&error);
1541 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1547 if (!dbus_message_get_args(
1550 DBUS_TYPE_STRING, &name,
1552 return bus_send_error_reply(connection, message, &error, -EINVAL);
1554 session = hashmap_get(m->sessions, name);
1556 return bus_send_error_reply(connection, message, &error, -ENOENT);
1558 reply = dbus_message_new_method_return(message);
1562 p = session_bus_path(session);
1566 b = dbus_message_append_args(
1568 DBUS_TYPE_OBJECT_PATH, &p,
1575 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1581 if (!dbus_message_get_args(
1584 DBUS_TYPE_UINT32, &pid,
1586 return bus_send_error_reply(connection, message, &error, -EINVAL);
1588 r = manager_get_session_by_pid(m, pid, &session);
1590 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1592 reply = dbus_message_new_method_return(message);
1596 p = session_bus_path(session);
1600 b = dbus_message_append_args(
1602 DBUS_TYPE_OBJECT_PATH, &p,
1609 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1615 if (!dbus_message_get_args(
1618 DBUS_TYPE_UINT32, &uid,
1620 return bus_send_error_reply(connection, message, &error, -EINVAL);
1622 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1624 return bus_send_error_reply(connection, message, &error, -ENOENT);
1626 reply = dbus_message_new_method_return(message);
1630 p = user_bus_path(user);
1634 b = dbus_message_append_args(
1636 DBUS_TYPE_OBJECT_PATH, &p,
1643 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUserByPID")) {
1649 if (!dbus_message_get_args(
1652 DBUS_TYPE_UINT32, &pid,
1654 return bus_send_error_reply(connection, message, &error, -EINVAL);
1656 r = manager_get_user_by_pid(m, pid, &user);
1658 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1660 reply = dbus_message_new_method_return(message);
1664 p = user_bus_path(user);
1668 b = dbus_message_append_args(
1670 DBUS_TYPE_OBJECT_PATH, &p,
1676 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetMachine")) {
1682 if (!dbus_message_get_args(
1685 DBUS_TYPE_STRING, &name,
1687 return bus_send_error_reply(connection, message, &error, -EINVAL);
1689 machine = hashmap_get(m->machines, name);
1691 return bus_send_error_reply(connection, message, &error, -ENOENT);
1693 reply = dbus_message_new_method_return(message);
1697 p = machine_bus_path(machine);
1701 b = dbus_message_append_args(
1703 DBUS_TYPE_OBJECT_PATH, &p,
1710 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetMachineByPID")) {
1716 if (!dbus_message_get_args(
1719 DBUS_TYPE_UINT32, &pid,
1721 return bus_send_error_reply(connection, message, &error, -EINVAL);
1723 r = manager_get_machine_by_pid(m, pid, &machine);
1725 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1727 reply = dbus_message_new_method_return(message);
1731 p = machine_bus_path(machine);
1735 b = dbus_message_append_args(
1737 DBUS_TYPE_OBJECT_PATH, &p,
1744 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1750 if (!dbus_message_get_args(
1753 DBUS_TYPE_STRING, &name,
1755 return bus_send_error_reply(connection, message, &error, -EINVAL);
1757 seat = hashmap_get(m->seats, name);
1759 return bus_send_error_reply(connection, message, &error, -ENOENT);
1761 reply = dbus_message_new_method_return(message);
1765 p = seat_bus_path(seat);
1769 b = dbus_message_append_args(
1771 DBUS_TYPE_OBJECT_PATH, &p,
1778 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1782 DBusMessageIter iter, sub;
1783 const char *empty = "";
1785 reply = dbus_message_new_method_return(message);
1789 dbus_message_iter_init_append(reply, &iter);
1791 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1794 HASHMAP_FOREACH(session, m->sessions, i) {
1795 DBusMessageIter sub2;
1798 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1801 uid = session->user->uid;
1803 p = session_bus_path(session);
1807 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1808 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1809 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1810 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1811 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1818 if (!dbus_message_iter_close_container(&sub, &sub2))
1822 if (!dbus_message_iter_close_container(&iter, &sub))
1825 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1828 DBusMessageIter iter, sub;
1830 reply = dbus_message_new_method_return(message);
1834 dbus_message_iter_init_append(reply, &iter);
1836 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1839 HASHMAP_FOREACH(user, m->users, i) {
1840 _cleanup_free_ char *p = NULL;
1841 DBusMessageIter sub2;
1844 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1849 p = user_bus_path(user);
1853 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1854 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1855 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1860 if (!dbus_message_iter_close_container(&sub, &sub2))
1864 if (!dbus_message_iter_close_container(&iter, &sub))
1867 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1870 DBusMessageIter iter, sub;
1872 reply = dbus_message_new_method_return(message);
1876 dbus_message_iter_init_append(reply, &iter);
1878 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1881 HASHMAP_FOREACH(seat, m->seats, i) {
1882 _cleanup_free_ char *p = NULL;
1883 DBusMessageIter sub2;
1885 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1888 p = seat_bus_path(seat);
1892 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1893 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1898 if (!dbus_message_iter_close_container(&sub, &sub2))
1902 if (!dbus_message_iter_close_container(&iter, &sub))
1905 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1906 Inhibitor *inhibitor;
1908 DBusMessageIter iter, sub;
1910 reply = dbus_message_new_method_return(message);
1914 dbus_message_iter_init_append(reply, &iter);
1916 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1919 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1920 DBusMessageIter sub2;
1921 dbus_uint32_t uid, pid;
1922 const char *what, *who, *why, *mode;
1924 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1927 what = strempty(inhibit_what_to_string(inhibitor->what));
1928 who = strempty(inhibitor->who);
1929 why = strempty(inhibitor->why);
1930 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1931 uid = (dbus_uint32_t) inhibitor->uid;
1932 pid = (dbus_uint32_t) inhibitor->pid;
1934 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1935 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1936 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1937 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1938 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1939 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1942 if (!dbus_message_iter_close_container(&sub, &sub2))
1946 if (!dbus_message_iter_close_container(&iter, &sub))
1949 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListMachines")) {
1952 DBusMessageIter iter, sub;
1954 reply = dbus_message_new_method_return(message);
1958 dbus_message_iter_init_append(reply, &iter);
1960 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssso)", &sub))
1963 HASHMAP_FOREACH(machine, m->machines, i) {
1964 _cleanup_free_ char *p = NULL;
1965 DBusMessageIter sub2;
1968 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1971 p = machine_bus_path(machine);
1975 class = strempty(machine_class_to_string(machine->class));
1977 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &machine->name) ||
1978 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &class) ||
1979 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &machine->service) ||
1980 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1985 if (!dbus_message_iter_close_container(&sub, &sub2))
1989 if (!dbus_message_iter_close_container(&iter, &sub))
1992 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1994 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1997 return bus_send_error_reply(connection, message, &error, r);
2000 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
2002 r = bus_manager_create_session(m, message);
2004 /* Don't delay the work on OOM here, since it might be
2005 * triggered by a low RLIMIT_NOFILE here (since we
2006 * send a dupped fd to the client), and we'd rather
2007 * see this fail quickly then be retried later */
2010 return bus_send_error_reply(connection, message, NULL, r);
2012 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateMachine")) {
2014 r = bus_manager_create_machine(m, message);
2016 return bus_send_error_reply(connection, message, NULL, r);
2018 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
2022 if (!dbus_message_get_args(
2025 DBUS_TYPE_STRING, &name,
2027 return bus_send_error_reply(connection, message, &error, -EINVAL);
2029 session = hashmap_get(m->sessions, name);
2031 return bus_send_error_reply(connection, message, &error, -ENOENT);
2033 /* We use the FIFO to detect stray sessions where the
2034 process invoking PAM dies abnormally. We need to make
2035 sure that that process is not killed if at the clean
2036 end of the session it closes the FIFO. Hence, with
2037 this call explicitly turn off the FIFO logic, so that
2038 the PAM code can finish clean up on its own */
2039 session_remove_fifo(session);
2041 reply = dbus_message_new_method_return(message);
2045 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
2049 if (!dbus_message_get_args(
2052 DBUS_TYPE_STRING, &name,
2054 return bus_send_error_reply(connection, message, &error, -EINVAL);
2056 session = hashmap_get(m->sessions, name);
2058 return bus_send_error_reply(connection, message, &error, -ENOENT);
2060 r = session_activate(session);
2062 return bus_send_error_reply(connection, message, NULL, r);
2064 reply = dbus_message_new_method_return(message);
2068 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
2069 const char *session_name, *seat_name;
2073 /* Same as ActivateSession() but refuses to work if
2074 * the seat doesn't match */
2076 if (!dbus_message_get_args(
2079 DBUS_TYPE_STRING, &session_name,
2080 DBUS_TYPE_STRING, &seat_name,
2082 return bus_send_error_reply(connection, message, &error, -EINVAL);
2084 session = hashmap_get(m->sessions, session_name);
2086 return bus_send_error_reply(connection, message, &error, -ENOENT);
2088 seat = hashmap_get(m->seats, seat_name);
2090 return bus_send_error_reply(connection, message, &error, -ENOENT);
2092 if (session->seat != seat)
2093 return bus_send_error_reply(connection, message, &error, -EINVAL);
2095 r = session_activate(session);
2097 return bus_send_error_reply(connection, message, NULL, r);
2099 reply = dbus_message_new_method_return(message);
2103 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
2104 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
2108 if (!dbus_message_get_args(
2111 DBUS_TYPE_STRING, &name,
2113 return bus_send_error_reply(connection, message, &error, -EINVAL);
2115 session = hashmap_get(m->sessions, name);
2117 return bus_send_error_reply(connection, message, NULL, -ENOENT);
2119 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
2122 reply = dbus_message_new_method_return(message);
2126 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
2127 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
2129 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
2131 bus_send_error_reply(connection, message, NULL, r);
2133 reply = dbus_message_new_method_return(message);
2137 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
2144 if (!dbus_message_get_args(
2147 DBUS_TYPE_STRING, &name,
2148 DBUS_TYPE_STRING, &swho,
2149 DBUS_TYPE_INT32, &signo,
2151 return bus_send_error_reply(connection, message, &error, -EINVAL);
2156 who = kill_who_from_string(swho);
2158 return bus_send_error_reply(connection, message, &error, -EINVAL);
2161 if (signo <= 0 || signo >= _NSIG)
2162 return bus_send_error_reply(connection, message, &error, -EINVAL);
2164 session = hashmap_get(m->sessions, name);
2166 return bus_send_error_reply(connection, message, &error, -ENOENT);
2168 r = session_kill(session, who, signo);
2170 return bus_send_error_reply(connection, message, NULL, r);
2172 reply = dbus_message_new_method_return(message);
2176 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
2181 if (!dbus_message_get_args(
2184 DBUS_TYPE_UINT32, &uid,
2185 DBUS_TYPE_INT32, &signo,
2187 return bus_send_error_reply(connection, message, &error, -EINVAL);
2189 if (signo <= 0 || signo >= _NSIG)
2190 return bus_send_error_reply(connection, message, &error, -EINVAL);
2192 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2194 return bus_send_error_reply(connection, message, &error, -ENOENT);
2196 r = user_kill(user, signo);
2198 return bus_send_error_reply(connection, message, NULL, r);
2200 reply = dbus_message_new_method_return(message);
2204 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillMachine")) {
2211 if (!dbus_message_get_args(
2214 DBUS_TYPE_STRING, &name,
2215 DBUS_TYPE_STRING, &swho,
2216 DBUS_TYPE_INT32, &signo,
2218 return bus_send_error_reply(connection, message, &error, -EINVAL);
2223 who = kill_who_from_string(swho);
2225 return bus_send_error_reply(connection, message, &error, -EINVAL);
2228 if (signo <= 0 || signo >= _NSIG)
2229 return bus_send_error_reply(connection, message, &error, -EINVAL);
2231 machine = hashmap_get(m->machines, name);
2233 return bus_send_error_reply(connection, message, &error, -ENOENT);
2235 r = machine_kill(machine, who, signo);
2237 return bus_send_error_reply(connection, message, NULL, r);
2239 reply = dbus_message_new_method_return(message);
2243 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
2247 if (!dbus_message_get_args(
2250 DBUS_TYPE_STRING, &name,
2252 return bus_send_error_reply(connection, message, &error, -EINVAL);
2254 session = hashmap_get(m->sessions, name);
2256 return bus_send_error_reply(connection, message, &error, -ENOENT);
2258 r = session_stop(session);
2260 return bus_send_error_reply(connection, message, NULL, r);
2262 reply = dbus_message_new_method_return(message);
2266 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
2270 if (!dbus_message_get_args(
2273 DBUS_TYPE_UINT32, &uid,
2275 return bus_send_error_reply(connection, message, &error, -EINVAL);
2277 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2279 return bus_send_error_reply(connection, message, &error, -ENOENT);
2281 r = user_stop(user);
2283 return bus_send_error_reply(connection, message, NULL, r);
2285 reply = dbus_message_new_method_return(message);
2289 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
2293 if (!dbus_message_get_args(
2296 DBUS_TYPE_STRING, &name,
2298 return bus_send_error_reply(connection, message, &error, -EINVAL);
2300 seat = hashmap_get(m->seats, name);
2302 return bus_send_error_reply(connection, message, &error, -ENOENT);
2304 r = seat_stop_sessions(seat);
2306 return bus_send_error_reply(connection, message, NULL, r);
2308 reply = dbus_message_new_method_return(message);
2312 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateMachine")) {
2316 if (!dbus_message_get_args(
2319 DBUS_TYPE_STRING, &name,
2321 return bus_send_error_reply(connection, message, &error, -EINVAL);
2323 machine = hashmap_get(m->machines, name);
2325 return bus_send_error_reply(connection, message, &error, -ENOENT);
2327 r = machine_stop(machine);
2329 return bus_send_error_reply(connection, message, NULL, r);
2331 reply = dbus_message_new_method_return(message);
2335 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
2338 dbus_bool_t b, interactive;
2341 if (!dbus_message_get_args(
2344 DBUS_TYPE_UINT32, &uid,
2345 DBUS_TYPE_BOOLEAN, &b,
2346 DBUS_TYPE_BOOLEAN, &interactive,
2348 return bus_send_error_reply(connection, message, &error, -EINVAL);
2353 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2355 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2357 return bus_send_error_reply(connection, message, &error, r);
2359 mkdir_p_label("/var/lib/systemd", 0755);
2361 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2363 return bus_send_error_reply(connection, message, &error, r);
2365 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2376 return bus_send_error_reply(connection, message, &error, r);
2378 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2387 if (r < 0 && errno != ENOENT)
2388 return bus_send_error_reply(connection, message, &error, -errno);
2390 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2392 user_add_to_gc_queue(u);
2395 reply = dbus_message_new_method_return(message);
2399 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2400 const char *sysfs, *seat;
2401 dbus_bool_t interactive;
2403 if (!dbus_message_get_args(
2406 DBUS_TYPE_STRING, &seat,
2407 DBUS_TYPE_STRING, &sysfs,
2408 DBUS_TYPE_BOOLEAN, &interactive,
2410 return bus_send_error_reply(connection, message, &error, -EINVAL);
2412 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2413 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2415 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2417 return bus_send_error_reply(connection, message, &error, r);
2419 r = attach_device(m, seat, sysfs);
2421 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2423 reply = dbus_message_new_method_return(message);
2428 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2429 dbus_bool_t interactive;
2431 if (!dbus_message_get_args(
2434 DBUS_TYPE_BOOLEAN, &interactive,
2436 return bus_send_error_reply(connection, message, &error, -EINVAL);
2438 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2440 return bus_send_error_reply(connection, message, &error, r);
2442 r = flush_devices(m);
2444 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2446 reply = dbus_message_new_method_return(message);
2450 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2452 r = bus_manager_do_shutdown_or_sleep(
2453 m, connection, message,
2454 SPECIAL_POWEROFF_TARGET,
2456 "org.freedesktop.login1.power-off",
2457 "org.freedesktop.login1.power-off-multiple-sessions",
2458 "org.freedesktop.login1.power-off-ignore-inhibit",
2462 return bus_send_error_reply(connection, message, &error, r);
2463 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2464 r = bus_manager_do_shutdown_or_sleep(
2465 m, connection, message,
2466 SPECIAL_REBOOT_TARGET,
2468 "org.freedesktop.login1.reboot",
2469 "org.freedesktop.login1.reboot-multiple-sessions",
2470 "org.freedesktop.login1.reboot-ignore-inhibit",
2474 return bus_send_error_reply(connection, message, &error, r);
2476 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2477 r = bus_manager_do_shutdown_or_sleep(
2478 m, connection, message,
2479 SPECIAL_SUSPEND_TARGET,
2481 "org.freedesktop.login1.suspend",
2482 "org.freedesktop.login1.suspend-multiple-sessions",
2483 "org.freedesktop.login1.suspend-ignore-inhibit",
2487 return bus_send_error_reply(connection, message, &error, r);
2488 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2489 r = bus_manager_do_shutdown_or_sleep(
2490 m, connection, message,
2491 SPECIAL_HIBERNATE_TARGET,
2493 "org.freedesktop.login1.hibernate",
2494 "org.freedesktop.login1.hibernate-multiple-sessions",
2495 "org.freedesktop.login1.hibernate-ignore-inhibit",
2499 return bus_send_error_reply(connection, message, &error, r);
2501 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2502 r = bus_manager_do_shutdown_or_sleep(
2503 m, connection, message,
2504 SPECIAL_HYBRID_SLEEP_TARGET,
2506 "org.freedesktop.login1.hibernate",
2507 "org.freedesktop.login1.hibernate-multiple-sessions",
2508 "org.freedesktop.login1.hibernate-ignore-inhibit",
2512 return bus_send_error_reply(connection, message, &error, r);
2514 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2516 r = bus_manager_can_shutdown_or_sleep(
2517 m, connection, message,
2519 "org.freedesktop.login1.power-off",
2520 "org.freedesktop.login1.power-off-multiple-sessions",
2521 "org.freedesktop.login1.power-off-ignore-inhibit",
2525 return bus_send_error_reply(connection, message, &error, r);
2526 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2527 r = bus_manager_can_shutdown_or_sleep(
2528 m, connection, message,
2530 "org.freedesktop.login1.reboot",
2531 "org.freedesktop.login1.reboot-multiple-sessions",
2532 "org.freedesktop.login1.reboot-ignore-inhibit",
2536 return bus_send_error_reply(connection, message, &error, r);
2538 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2539 r = bus_manager_can_shutdown_or_sleep(
2540 m, connection, message,
2542 "org.freedesktop.login1.suspend",
2543 "org.freedesktop.login1.suspend-multiple-sessions",
2544 "org.freedesktop.login1.suspend-ignore-inhibit",
2548 return bus_send_error_reply(connection, message, &error, r);
2550 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2551 r = bus_manager_can_shutdown_or_sleep(
2552 m, connection, message,
2554 "org.freedesktop.login1.hibernate",
2555 "org.freedesktop.login1.hibernate-multiple-sessions",
2556 "org.freedesktop.login1.hibernate-ignore-inhibit",
2560 return bus_send_error_reply(connection, message, &error, r);
2562 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2563 r = bus_manager_can_shutdown_or_sleep(
2564 m, connection, message,
2566 "org.freedesktop.login1.hibernate",
2567 "org.freedesktop.login1.hibernate-multiple-sessions",
2568 "org.freedesktop.login1.hibernate-ignore-inhibit",
2572 return bus_send_error_reply(connection, message, &error, r);
2574 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2575 char *introspection = NULL;
2584 if (!(reply = dbus_message_new_method_return(message)))
2587 /* We roll our own introspection code here, instead of
2588 * relying on bus_default_message_handler() because we
2589 * need to generate our introspection string
2592 if (!(f = open_memstream(&introspection, &size)))
2595 fputs(INTROSPECTION_BEGIN, f);
2597 HASHMAP_FOREACH(seat, m->seats, i) {
2598 p = bus_path_escape(seat->id);
2601 fprintf(f, "<node name=\"seat/%s\"/>", p);
2606 HASHMAP_FOREACH(user, m->users, i)
2607 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2609 HASHMAP_FOREACH(session, m->sessions, i) {
2610 p = bus_path_escape(session->id);
2613 fprintf(f, "<node name=\"session/%s\"/>", p);
2618 fputs(INTROSPECTION_END, f);
2622 free(introspection);
2631 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2632 free(introspection);
2636 free(introspection);
2638 const BusBoundProperties bps[] = {
2639 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2642 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2646 if (!bus_maybe_send_reply(connection, message, reply))
2650 return DBUS_HANDLER_RESULT_HANDLED;
2653 dbus_error_free(&error);
2655 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2658 const DBusObjectPathVTable bus_manager_vtable = {
2659 .message_function = manager_message_handler
2662 DBusHandlerResult bus_message_filter(
2663 DBusConnection *connection,
2664 DBusMessage *message,
2667 Manager *m = userdata;
2674 dbus_error_init(&error);
2676 log_debug("Got message: %s %s %s", strna(dbus_message_get_sender(message)), strna(dbus_message_get_interface(message)), strna(dbus_message_get_member(message)));
2678 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2679 const char *path, *result, *unit;
2682 if (!dbus_message_get_args(message, &error,
2683 DBUS_TYPE_UINT32, &id,
2684 DBUS_TYPE_OBJECT_PATH, &path,
2685 DBUS_TYPE_STRING, &unit,
2686 DBUS_TYPE_STRING, &result,
2687 DBUS_TYPE_INVALID)) {
2688 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2692 if (m->action_job && streq(m->action_job, path)) {
2693 log_info("Operation finished.");
2695 /* Tell people that they now may take a lock again */
2696 send_prepare_for(m, m->action_what, false);
2698 free(m->action_job);
2699 m->action_job = NULL;
2700 m->action_unit = NULL;
2708 s = hashmap_get(m->session_units, unit);
2710 if (streq_ptr(path, s->scope_job)) {
2712 s->scope_job = NULL;
2715 if (streq(result, "done"))
2716 session_send_create_reply(s, NULL);
2718 dbus_set_error(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
2719 session_send_create_reply(s, &error);
2724 session_add_to_gc_queue(s);
2727 u = hashmap_get(m->user_units, unit);
2729 if (streq_ptr(path, u->service_job)) {
2730 free(u->service_job);
2731 u->service_job = NULL;
2734 if (streq_ptr(path, u->slice_job)) {
2736 u->slice_job = NULL;
2739 user_add_to_gc_queue(u);
2742 mm = hashmap_get(m->machine_units, unit);
2744 if (streq_ptr(path, mm->scope_job)) {
2745 free(mm->scope_job);
2746 mm->scope_job = NULL;
2749 if (streq(result, "done"))
2750 machine_send_create_reply(mm, NULL);
2752 dbus_set_error(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
2753 machine_send_create_reply(mm, &error);
2758 machine_add_to_gc_queue(mm);
2762 } else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
2764 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2765 _cleanup_free_ char *unit = NULL;
2768 path = dbus_message_get_path(message);
2772 unit_name_from_dbus_path(path, &unit);
2778 s = hashmap_get(m->session_units, unit);
2780 session_add_to_gc_queue(s);
2782 u = hashmap_get(m->user_units, unit);
2784 user_add_to_gc_queue(u);
2786 mm = hashmap_get(m->machine_units, unit);
2788 machine_add_to_gc_queue(mm);
2793 dbus_error_free(&error);
2795 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2798 int manager_send_changed(Manager *manager, const char *properties) {
2799 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
2803 m = bus_properties_changed_new("/org/freedesktop/login1",
2804 "org.freedesktop.login1.Manager",
2809 if (!dbus_connection_send(manager->bus, m, NULL))
2815 int manager_dispatch_delayed(Manager *manager) {
2821 if (manager->action_what == 0 || manager->action_job)
2824 /* Continue delay? */
2825 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
2827 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2830 log_info("Delay lock is active but inhibitor timeout is reached.");
2833 /* Actually do the operation */
2834 dbus_error_init(&error);
2835 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
2837 log_warning("Failed to send delayed message: %s", bus_error(&error, r));
2838 dbus_error_free(&error);
2840 manager->action_unit = NULL;
2841 manager->action_what = 0;
2848 int manager_start_scope(
2853 const char *description,
2857 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2858 DBusMessageIter iter, sub, sub2, sub3, sub4;
2859 const char *timeout_stop_property = "TimeoutStopUSec";
2860 const char *pids_property = "PIDs";
2861 uint64_t timeout = 500 * USEC_PER_MSEC;
2862 const char *fail = "fail";
2872 m = dbus_message_new_method_call(
2873 "org.freedesktop.systemd1",
2874 "/org/freedesktop/systemd1",
2875 "org.freedesktop.systemd1.Manager",
2876 "StartTransientUnit");
2880 dbus_message_iter_init_append(m, &iter);
2882 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &scope) ||
2883 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &fail) ||
2884 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub))
2887 if (!isempty(slice)) {
2888 const char *slice_property = "Slice";
2890 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2891 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &slice_property) ||
2892 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2893 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &slice) ||
2894 !dbus_message_iter_close_container(&sub2, &sub3) ||
2895 !dbus_message_iter_close_container(&sub, &sub2))
2899 if (!isempty(description)) {
2900 const char *description_property = "Description";
2902 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2903 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description_property) ||
2904 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2905 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &description) ||
2906 !dbus_message_iter_close_container(&sub2, &sub3) ||
2907 !dbus_message_iter_close_container(&sub, &sub2))
2911 /* cgroup empty notification is not available in containers
2912 * currently. To make this less problematic, let's shorten the
2913 * stop timeout for sessions, so that we don't wait
2916 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2917 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &timeout_stop_property) ||
2918 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "t", &sub3) ||
2919 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &timeout) ||
2920 !dbus_message_iter_close_container(&sub2, &sub3) ||
2921 !dbus_message_iter_close_container(&sub, &sub2))
2925 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2926 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &pids_property) ||
2927 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "au", &sub3) ||
2928 !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "u", &sub4) ||
2929 !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_UINT32, &u) ||
2930 !dbus_message_iter_close_container(&sub3, &sub4) ||
2931 !dbus_message_iter_close_container(&sub2, &sub3) ||
2932 !dbus_message_iter_close_container(&sub, &sub2) ||
2933 !dbus_message_iter_close_container(&iter, &sub))
2936 reply = dbus_connection_send_with_reply_and_block(manager->bus, m, -1, error);
2944 if (!dbus_message_get_args(reply, error, DBUS_TYPE_OBJECT_PATH, &j, DBUS_TYPE_INVALID))
2957 int manager_start_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
2958 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2959 const char *fail = "fail";
2965 r = bus_method_call_with_reply(
2967 "org.freedesktop.systemd1",
2968 "/org/freedesktop/systemd1",
2969 "org.freedesktop.systemd1.Manager",
2973 DBUS_TYPE_STRING, &unit,
2974 DBUS_TYPE_STRING, &fail,
2977 log_error("Failed to start unit %s: %s", unit, bus_error(error, r));
2985 if (!dbus_message_get_args(reply, error,
2986 DBUS_TYPE_OBJECT_PATH, &j,
2987 DBUS_TYPE_INVALID)) {
2988 log_error("Failed to parse reply.");
3002 int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
3003 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3004 const char *fail = "fail";
3010 r = bus_method_call_with_reply(
3012 "org.freedesktop.systemd1",
3013 "/org/freedesktop/systemd1",
3014 "org.freedesktop.systemd1.Manager",
3018 DBUS_TYPE_STRING, &unit,
3019 DBUS_TYPE_STRING, &fail,
3022 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
3030 if (!dbus_message_get_args(reply, error,
3031 DBUS_TYPE_OBJECT_PATH, &j,
3032 DBUS_TYPE_INVALID)) {
3033 log_error("Failed to parse reply.");
3047 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error) {
3048 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3055 w = who == KILL_LEADER ? "process" : "cgroup";
3056 assert_cc(sizeof(signo) == sizeof(int32_t));
3058 r = bus_method_call_with_reply(
3060 "org.freedesktop.systemd1",
3061 "/org/freedesktop/systemd1",
3062 "org.freedesktop.systemd1.Manager",
3066 DBUS_TYPE_STRING, &unit,
3067 DBUS_TYPE_STRING, &w,
3068 DBUS_TYPE_INT32, &signo,
3071 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
3078 int manager_unit_is_active(Manager *manager, const char *unit) {
3080 const char *interface = "org.freedesktop.systemd1.Unit";
3081 const char *property = "ActiveState";
3082 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3083 _cleanup_free_ char *path = NULL;
3084 DBusMessageIter iter, sub;
3092 dbus_error_init(&error);
3094 path = unit_dbus_path_from_name(unit);
3098 r = bus_method_call_with_reply(
3100 "org.freedesktop.systemd1",
3102 "org.freedesktop.DBus.Properties",
3106 DBUS_TYPE_STRING, &interface,
3107 DBUS_TYPE_STRING, &property,
3111 log_error("Failed to query ActiveState: %s", bus_error(&error, r));
3112 dbus_error_free(&error);
3116 if (!dbus_message_iter_init(reply, &iter) ||
3117 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
3118 log_error("Failed to parse reply.");
3122 dbus_message_iter_recurse(&iter, &sub);
3123 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
3124 log_error("Failed to parse reply.");
3128 dbus_message_iter_get_basic(&sub, &state);
3130 return !streq(state, "inactive") && !streq(state, "failed");