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=\"ListSessions\">\n" \
67 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
69 " <method name=\"ListUsers\">\n" \
70 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
72 " <method name=\"ListSeats\">\n" \
73 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
75 " <method name=\"CreateSession\">\n" \
76 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
77 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
78 " <arg name=\"service\" type=\"s\" direction=\"in\"/>\n" \
79 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
80 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
81 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
82 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
83 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
84 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
85 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
86 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
87 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
88 " <arg name=\"scope_properties\" type=\"a(sv)\" direction=\"in\"/>\n" \
89 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
90 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
91 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
92 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
93 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
94 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
95 " <arg name=\"existing\" type=\"b\" direction=\"out\"/>\n" \
97 " <method name=\"ReleaseSession\">\n" \
98 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
100 " <method name=\"ActivateSession\">\n" \
101 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
103 " <method name=\"ActivateSessionOnSeat\">\n" \
104 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
105 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
107 " <method name=\"LockSession\">\n" \
108 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
110 " <method name=\"UnlockSession\">\n" \
111 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
113 " <method name=\"LockSessions\"/>\n" \
114 " <method name=\"UnlockSessions\"/>\n" \
115 " <method name=\"KillSession\">\n" \
116 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
117 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
118 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
120 " <method name=\"KillUser\">\n" \
121 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
122 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
124 " <method name=\"TerminateSession\">\n" \
125 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
127 " <method name=\"TerminateUser\">\n" \
128 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
130 " <method name=\"TerminateSeat\">\n" \
131 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
133 " <method name=\"SetUserLinger\">\n" \
134 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
135 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
136 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
138 " <method name=\"AttachDevice\">\n" \
139 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
140 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
141 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
143 " <method name=\"FlushDevices\">\n" \
144 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
146 " <method name=\"PowerOff\">\n" \
147 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
149 " <method name=\"Reboot\">\n" \
150 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
152 " <method name=\"Suspend\">\n" \
153 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
155 " <method name=\"Hibernate\">\n" \
156 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
158 " <method name=\"HybridSleep\">\n" \
159 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
161 " <method name=\"CanPowerOff\">\n" \
162 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
164 " <method name=\"CanReboot\">\n" \
165 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
167 " <method name=\"CanSuspend\">\n" \
168 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
170 " <method name=\"CanHibernate\">\n" \
171 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
173 " <method name=\"CanHybridSleep\">\n" \
174 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
176 " <method name=\"Inhibit\">\n" \
177 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
178 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
179 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
180 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
181 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
183 " <method name=\"ListInhibitors\">\n" \
184 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
186 " <signal name=\"SessionNew\">\n" \
187 " <arg name=\"id\" type=\"s\"/>\n" \
188 " <arg name=\"path\" type=\"o\"/>\n" \
190 " <signal name=\"SessionRemoved\">\n" \
191 " <arg name=\"id\" type=\"s\"/>\n" \
192 " <arg name=\"path\" type=\"o\"/>\n" \
194 " <signal name=\"UserNew\">\n" \
195 " <arg name=\"uid\" type=\"u\"/>\n" \
196 " <arg name=\"path\" type=\"o\"/>\n" \
198 " <signal name=\"UserRemoved\">\n" \
199 " <arg name=\"uid\" type=\"u\"/>\n" \
200 " <arg name=\"path\" type=\"o\"/>\n" \
202 " <signal name=\"SeatNew\">\n" \
203 " <arg name=\"id\" type=\"s\"/>\n" \
204 " <arg name=\"path\" type=\"o\"/>\n" \
206 " <signal name=\"SeatRemoved\">\n" \
207 " <arg name=\"id\" type=\"s\"/>\n" \
208 " <arg name=\"path\" type=\"o\"/>\n" \
210 " <signal name=\"PrepareForShutdown\">\n" \
211 " <arg name=\"active\" type=\"b\"/>\n" \
213 " <signal name=\"PrepareForSleep\">\n" \
214 " <arg name=\"active\" type=\"b\"/>\n" \
216 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
217 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
218 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
219 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
220 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
221 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
222 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
223 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
224 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
225 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
226 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
227 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
228 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
229 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
230 " <property name=\"IdleAction\" type=\"s\" access=\"read\"/>\n" \
231 " <property name=\"IdleActionUSec\" type=\"t\" access=\"read\"/>\n" \
232 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
233 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
236 #define INTROSPECTION_BEGIN \
237 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
239 BUS_MANAGER_INTERFACE \
240 BUS_PROPERTIES_INTERFACE \
242 BUS_INTROSPECTABLE_INTERFACE
244 #define INTROSPECTION_END \
247 #define INTERFACES_LIST \
248 BUS_GENERIC_INTERFACES_LIST \
249 "org.freedesktop.login1.Manager\0"
251 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
259 b = manager_get_idle_hint(m, NULL) > 0;
260 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
266 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
275 manager_get_idle_hint(m, &t);
276 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
278 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
284 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
289 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
290 p = inhibit_what_to_string(w);
292 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
298 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
305 if (streq(property, "PreparingForShutdown"))
306 b = !!(m->action_what & INHIBIT_SHUTDOWN);
308 b = !!(m->action_what & INHIBIT_SLEEP);
310 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
314 static int bus_manager_create_session(Manager *m, DBusMessage *message) {
316 const char *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *service;
317 uint32_t uid, leader, audit_id = 0;
318 _cleanup_free_ char *id = NULL;
319 Session *session = NULL;
322 DBusMessageIter iter;
333 if (!dbus_message_iter_init(message, &iter) ||
334 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
337 dbus_message_iter_get_basic(&iter, &uid);
339 if (!dbus_message_iter_next(&iter) ||
340 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
343 dbus_message_iter_get_basic(&iter, &leader);
345 if (!dbus_message_iter_next(&iter) ||
346 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
349 dbus_message_iter_get_basic(&iter, &service);
351 if (!dbus_message_iter_next(&iter) ||
352 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
355 dbus_message_iter_get_basic(&iter, &type);
357 t = _SESSION_TYPE_INVALID;
359 t = session_type_from_string(type);
364 if (!dbus_message_iter_next(&iter) ||
365 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
368 dbus_message_iter_get_basic(&iter, &class);
370 c = _SESSION_CLASS_INVALID;
372 c = session_class_from_string(class);
377 if (!dbus_message_iter_next(&iter) ||
378 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
381 dbus_message_iter_get_basic(&iter, &cseat);
386 seat = hashmap_get(m->seats, cseat);
391 if (!dbus_message_iter_next(&iter) ||
392 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
395 dbus_message_iter_get_basic(&iter, &vtnr);
397 if (!dbus_message_iter_next(&iter) ||
398 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
401 dbus_message_iter_get_basic(&iter, &tty);
403 if (tty_is_vc(tty)) {
408 else if (seat != m->vtconsole)
411 v = vtnr_from_tty(tty);
414 return v < 0 ? v : -EINVAL;
418 else if (vtnr != (uint32_t) v)
420 } else if (tty_is_console(tty)) {
424 else if (seat != m->vtconsole)
432 if (seat_can_multi_session(seat)) {
441 if (!dbus_message_iter_next(&iter) ||
442 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
445 dbus_message_iter_get_basic(&iter, &display);
447 if (!dbus_message_iter_next(&iter) ||
448 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
451 if (t == _SESSION_TYPE_INVALID) {
452 if (!isempty(display))
454 else if (!isempty(tty))
457 t = SESSION_UNSPECIFIED;
460 if (c == _SESSION_CLASS_INVALID) {
461 if (!isempty(display) || !isempty(tty))
464 c = SESSION_BACKGROUND;
467 dbus_message_iter_get_basic(&iter, &remote);
469 if (!dbus_message_iter_next(&iter) ||
470 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
473 dbus_message_iter_get_basic(&iter, &remote_user);
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, &remote_host);
482 leader = bus_get_unix_process_id(m->bus, dbus_message_get_sender(message), NULL);
487 r = manager_get_session_by_pid(m, leader, &session);
489 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
490 _cleanup_free_ char *path = NULL;
491 _cleanup_close_ int fifo_fd = -1;
494 /* Session already exists, client is probably
495 * something like "su" which changes uid but is still
496 * the same session */
498 fifo_fd = session_create_fifo(session);
504 path = session_bus_path(session);
510 reply = dbus_message_new_method_return(message);
516 cseat = session->seat ? session->seat->id : "";
517 vtnr = session->vtnr;
520 b = dbus_message_append_args(
522 DBUS_TYPE_STRING, &session->id,
523 DBUS_TYPE_OBJECT_PATH, &path,
524 DBUS_TYPE_STRING, &session->user->runtime_path,
525 DBUS_TYPE_UNIX_FD, &fifo_fd,
526 DBUS_TYPE_STRING, &cseat,
527 DBUS_TYPE_UINT32, &vtnr,
528 DBUS_TYPE_BOOLEAN, &exists,
535 if (!dbus_connection_send(m->bus, reply, NULL)) {
543 audit_session_from_pid(leader, &audit_id);
545 /* Keep our session IDs and the audit session IDs in sync */
547 if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0) {
552 /* Wut? There's already a session by this name and we
553 * didn't find it above? Weird, then let's not trust
554 * the audit data and let's better register a new
556 if (hashmap_get(m->sessions, id)) {
569 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
574 } while (hashmap_get(m->sessions, id));
577 r = manager_add_user_by_uid(m, uid, &user);
581 r = manager_add_session(m, id, &session);
585 session_set_user(session, user);
587 session->leader = leader;
588 session->audit_id = audit_id;
591 session->remote = remote;
592 session->vtnr = vtnr;
595 session->tty = strdup(tty);
602 if (!isempty(display)) {
603 session->display = strdup(display);
604 if (!session->display) {
610 if (!isempty(remote_user)) {
611 session->remote_user = strdup(remote_user);
612 if (!session->remote_user) {
618 if (!isempty(remote_host)) {
619 session->remote_host = strdup(remote_host);
620 if (!session->remote_host) {
626 if (!isempty(service)) {
627 session->service = strdup(service);
628 if (!session->service) {
635 r = seat_attach_session(seat, session);
640 r = session_start(session);
644 session->create_message = dbus_message_ref(message);
650 session_add_to_gc_queue(session);
653 user_add_to_gc_queue(user);
658 static int bus_manager_inhibit(
660 DBusConnection *connection,
661 DBusMessage *message,
663 DBusMessage **_reply) {
667 const char *who, *why, *what, *mode;
673 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
681 if (!dbus_message_get_args(
684 DBUS_TYPE_STRING, &what,
685 DBUS_TYPE_STRING, &who,
686 DBUS_TYPE_STRING, &why,
687 DBUS_TYPE_STRING, &mode,
688 DBUS_TYPE_INVALID)) {
693 w = inhibit_what_from_string(what);
699 mm = inhibit_mode_from_string(mode);
705 /* Delay is only supported for shutdown/sleep */
706 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
711 /* Don't allow taking delay locks while we are already
712 * executing the operation. We shouldn't create the impression
713 * that the lock was successful if the machine is about to go
714 * down/suspend any moment. */
715 if (m->action_what & w) {
720 r = verify_polkit(connection, message,
721 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
722 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
723 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
724 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
725 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
726 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
727 "org.freedesktop.login1.inhibit-handle-lid-switch",
732 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
733 if (ul == (unsigned long) -1) {
738 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
748 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
752 } while (hashmap_get(m->inhibitors, id));
754 r = manager_add_inhibitor(m, id, &i);
764 i->why = strdup(why);
765 i->who = strdup(who);
767 if (!i->why || !i->who) {
772 fifo_fd = inhibitor_create_fifo(i);
778 reply = dbus_message_new_method_return(message);
784 if (!dbus_message_append_args(
786 DBUS_TYPE_UNIX_FD, &fifo_fd,
787 DBUS_TYPE_INVALID)) {
792 close_nointr_nofail(fifo_fd);
805 close_nointr_nofail(fifo_fd);
810 static int trigger_device(Manager *m, struct udev_device *d) {
811 struct udev_enumerate *e;
812 struct udev_list_entry *first, *item;
817 e = udev_enumerate_new(m->udev);
824 if (udev_enumerate_add_match_parent(e, d) < 0) {
830 if (udev_enumerate_scan_devices(e) < 0) {
835 first = udev_enumerate_get_list_entry(e);
836 udev_list_entry_foreach(item, first) {
840 p = udev_list_entry_get_name(item);
842 t = strappend(p, "/uevent");
848 write_string_file(t, "change");
856 udev_enumerate_unref(e);
861 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
862 struct udev_device *d;
863 _cleanup_free_ char *rule = NULL, *file = NULL;
864 const char *id_for_seat;
871 d = udev_device_new_from_syspath(m->udev, sysfs);
875 if (!udev_device_has_tag(d, "seat")) {
880 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
886 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
891 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
896 mkdir_p_label("/etc/udev/rules.d", 0755);
898 r = write_string_file_atomic_label(file, rule);
902 r = trigger_device(m, d);
906 udev_device_unref(d);
911 static int flush_devices(Manager *m) {
912 _cleanup_closedir_ DIR *d;
916 d = opendir("/etc/udev/rules.d");
919 log_warning("Failed to open /etc/udev/rules.d: %m");
923 while ((de = readdir(d))) {
925 if (!dirent_is_file(de))
928 if (!startswith(de->d_name, "72-seat-"))
931 if (!endswith(de->d_name, ".rules"))
934 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
935 log_warning("Failed to unlink %s: %m", de->d_name);
939 return trigger_device(m, NULL);
942 static int have_multiple_sessions(
951 /* Check for other users' sessions. Greeter sessions do not
952 * count, and non-login sessions do not count either. */
953 HASHMAP_FOREACH(session, m->sessions, i)
954 if (session->class == SESSION_USER &&
955 session->user->uid != uid)
961 static int bus_manager_log_shutdown(
964 const char *unit_name) {
971 if (w != INHIBIT_SHUTDOWN)
974 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
975 p = "MESSAGE=System is powering down.";
976 q = "SHUTDOWN=power-off";
977 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
978 p = "MESSAGE=System is halting.";
980 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
981 p = "MESSAGE=System is rebooting.";
982 q = "SHUTDOWN=reboot";
983 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
984 p = "MESSAGE=System is rebooting with kexec.";
985 q = "SHUTDOWN=kexec";
987 p = "MESSAGE=System is shutting down.";
991 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
996 static int execute_shutdown_or_sleep(
999 const char *unit_name,
1002 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1003 const char *mode = "replace-irreversibly", *p;
1009 assert(w < _INHIBIT_WHAT_MAX);
1012 bus_manager_log_shutdown(m, w, unit_name);
1014 r = bus_method_call_with_reply(
1016 "org.freedesktop.systemd1",
1017 "/org/freedesktop/systemd1",
1018 "org.freedesktop.systemd1.Manager",
1022 DBUS_TYPE_STRING, &unit_name,
1023 DBUS_TYPE_STRING, &mode,
1028 if (!dbus_message_get_args(
1031 DBUS_TYPE_OBJECT_PATH, &p,
1039 m->action_unit = unit_name;
1040 free(m->action_job);
1047 static int delay_shutdown_or_sleep(
1050 const char *unit_name) {
1054 assert(w < _INHIBIT_WHAT_MAX);
1057 m->action_timestamp = now(CLOCK_MONOTONIC);
1058 m->action_unit = unit_name;
1064 static int bus_manager_can_shutdown_or_sleep(
1066 DBusConnection *connection,
1067 DBusMessage *message,
1070 const char *action_multiple_sessions,
1071 const char *action_ignore_inhibit,
1072 const char *sleep_verb,
1074 DBusMessage **_reply) {
1076 bool multiple_sessions, challenge, blocked, b;
1077 const char *result = NULL;
1078 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1086 assert(w <= _INHIBIT_WHAT_MAX);
1088 assert(action_multiple_sessions);
1089 assert(action_ignore_inhibit);
1094 r = can_sleep(sleep_verb);
1103 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1104 if (ul == (unsigned long) -1)
1107 r = have_multiple_sessions(m, (uid_t) ul);
1111 multiple_sessions = r > 0;
1112 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1114 if (multiple_sessions) {
1115 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1122 result = "challenge";
1128 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1132 if (r > 0 && !result)
1134 else if (challenge && (!result || streq(result, "yes")))
1135 result = "challenge";
1140 if (!multiple_sessions && !blocked) {
1141 /* If neither inhibit nor multiple sessions
1142 * apply then just check the normal policy */
1144 r = verify_polkit(connection, message, action, false, &challenge, error);
1151 result = "challenge";
1157 reply = dbus_message_new_method_return(message);
1161 b = dbus_message_append_args(
1163 DBUS_TYPE_STRING, &result,
1173 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1174 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1175 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1176 [INHIBIT_SLEEP] = "PrepareForSleep"
1179 dbus_bool_t active = _active;
1180 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1184 assert(w < _INHIBIT_WHAT_MAX);
1185 assert(signal_name[w]);
1187 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1191 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1192 !dbus_connection_send(m->bus, message, NULL))
1198 int bus_manager_shutdown_or_sleep_now_or_later(
1200 const char *unit_name,
1210 assert(w <= _INHIBIT_WHAT_MAX);
1211 assert(!m->action_job);
1213 /* Tell everybody to prepare for shutdown/sleep */
1214 send_prepare_for(m, w, true);
1217 m->inhibit_delay_max > 0 &&
1218 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1221 /* Shutdown is delayed, keep in mind what we
1222 * want to do, and start a timeout */
1223 r = delay_shutdown_or_sleep(m, w, unit_name);
1225 /* Shutdown is not delayed, execute it
1227 r = execute_shutdown_or_sleep(m, w, unit_name, error);
1232 static int bus_manager_do_shutdown_or_sleep(
1234 DBusConnection *connection,
1235 DBusMessage *message,
1236 const char *unit_name,
1239 const char *action_multiple_sessions,
1240 const char *action_ignore_inhibit,
1241 const char *sleep_verb,
1243 DBusMessage **_reply) {
1245 dbus_bool_t interactive;
1246 bool multiple_sessions, blocked;
1247 DBusMessage *reply = NULL;
1256 assert(w <= _INHIBIT_WHAT_MAX);
1258 assert(action_multiple_sessions);
1259 assert(action_ignore_inhibit);
1263 /* Don't allow multiple jobs being executed at the same time */
1267 if (!dbus_message_get_args(
1270 DBUS_TYPE_BOOLEAN, &interactive,
1275 r = can_sleep(sleep_verb);
1283 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1284 if (ul == (unsigned long) -1)
1287 r = have_multiple_sessions(m, (uid_t) ul);
1291 multiple_sessions = r > 0;
1292 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1294 if (multiple_sessions) {
1295 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1301 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1306 if (!multiple_sessions && !blocked) {
1307 r = verify_polkit(connection, message, action, interactive, NULL, error);
1312 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1316 reply = dbus_message_new_method_return(message);
1324 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1326 static const BusProperty bus_login_manager_properties[] = {
1327 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1328 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1329 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1330 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1331 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1332 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1333 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1334 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1335 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1336 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1337 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1338 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1339 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1340 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1341 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1342 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1343 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1344 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1348 static DBusHandlerResult manager_message_handler(
1349 DBusConnection *connection,
1350 DBusMessage *message,
1353 Manager *m = userdata;
1356 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1363 dbus_error_init(&error);
1365 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1371 if (!dbus_message_get_args(
1374 DBUS_TYPE_STRING, &name,
1376 return bus_send_error_reply(connection, message, &error, -EINVAL);
1378 session = hashmap_get(m->sessions, name);
1380 return bus_send_error_reply(connection, message, &error, -ENOENT);
1382 reply = dbus_message_new_method_return(message);
1386 p = session_bus_path(session);
1390 b = dbus_message_append_args(
1392 DBUS_TYPE_OBJECT_PATH, &p,
1399 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1405 if (!dbus_message_get_args(
1408 DBUS_TYPE_UINT32, &pid,
1410 return bus_send_error_reply(connection, message, &error, -EINVAL);
1412 r = manager_get_session_by_pid(m, pid, &session);
1414 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1416 reply = dbus_message_new_method_return(message);
1420 p = session_bus_path(session);
1424 b = dbus_message_append_args(
1426 DBUS_TYPE_OBJECT_PATH, &p,
1433 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1439 if (!dbus_message_get_args(
1442 DBUS_TYPE_UINT32, &uid,
1444 return bus_send_error_reply(connection, message, &error, -EINVAL);
1446 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1448 return bus_send_error_reply(connection, message, &error, -ENOENT);
1450 reply = dbus_message_new_method_return(message);
1454 p = user_bus_path(user);
1458 b = dbus_message_append_args(
1460 DBUS_TYPE_OBJECT_PATH, &p,
1467 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUserByPID")) {
1473 if (!dbus_message_get_args(
1476 DBUS_TYPE_UINT32, &pid,
1478 return bus_send_error_reply(connection, message, &error, -EINVAL);
1480 r = manager_get_user_by_pid(m, pid, &user);
1482 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1484 reply = dbus_message_new_method_return(message);
1488 p = user_bus_path(user);
1492 b = dbus_message_append_args(
1494 DBUS_TYPE_OBJECT_PATH, &p,
1501 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1507 if (!dbus_message_get_args(
1510 DBUS_TYPE_STRING, &name,
1512 return bus_send_error_reply(connection, message, &error, -EINVAL);
1514 seat = hashmap_get(m->seats, name);
1516 return bus_send_error_reply(connection, message, &error, -ENOENT);
1518 reply = dbus_message_new_method_return(message);
1522 p = seat_bus_path(seat);
1526 b = dbus_message_append_args(
1528 DBUS_TYPE_OBJECT_PATH, &p,
1535 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1539 DBusMessageIter iter, sub;
1540 const char *empty = "";
1542 reply = dbus_message_new_method_return(message);
1546 dbus_message_iter_init_append(reply, &iter);
1548 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1551 HASHMAP_FOREACH(session, m->sessions, i) {
1552 DBusMessageIter sub2;
1555 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1558 uid = session->user->uid;
1560 p = session_bus_path(session);
1564 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1565 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1566 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1567 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1568 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1575 if (!dbus_message_iter_close_container(&sub, &sub2))
1579 if (!dbus_message_iter_close_container(&iter, &sub))
1582 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1585 DBusMessageIter iter, sub;
1587 reply = dbus_message_new_method_return(message);
1591 dbus_message_iter_init_append(reply, &iter);
1593 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1596 HASHMAP_FOREACH(user, m->users, i) {
1597 _cleanup_free_ char *p = NULL;
1598 DBusMessageIter sub2;
1601 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1606 p = user_bus_path(user);
1610 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1611 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1612 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1617 if (!dbus_message_iter_close_container(&sub, &sub2))
1621 if (!dbus_message_iter_close_container(&iter, &sub))
1624 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1627 DBusMessageIter iter, sub;
1629 reply = dbus_message_new_method_return(message);
1633 dbus_message_iter_init_append(reply, &iter);
1635 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1638 HASHMAP_FOREACH(seat, m->seats, i) {
1639 _cleanup_free_ char *p = NULL;
1640 DBusMessageIter sub2;
1642 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1645 p = seat_bus_path(seat);
1649 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1650 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1655 if (!dbus_message_iter_close_container(&sub, &sub2))
1659 if (!dbus_message_iter_close_container(&iter, &sub))
1662 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1663 Inhibitor *inhibitor;
1665 DBusMessageIter iter, sub;
1667 reply = dbus_message_new_method_return(message);
1671 dbus_message_iter_init_append(reply, &iter);
1673 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1676 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1677 DBusMessageIter sub2;
1678 dbus_uint32_t uid, pid;
1679 const char *what, *who, *why, *mode;
1681 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1684 what = strempty(inhibit_what_to_string(inhibitor->what));
1685 who = strempty(inhibitor->who);
1686 why = strempty(inhibitor->why);
1687 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1688 uid = (dbus_uint32_t) inhibitor->uid;
1689 pid = (dbus_uint32_t) inhibitor->pid;
1691 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1692 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1693 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1694 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1695 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1696 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1699 if (!dbus_message_iter_close_container(&sub, &sub2))
1703 if (!dbus_message_iter_close_container(&iter, &sub))
1707 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1709 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1712 return bus_send_error_reply(connection, message, &error, r);
1715 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1717 r = bus_manager_create_session(m, message);
1719 /* Don't delay the work on OOM here, since it might be
1720 * triggered by a low RLIMIT_NOFILE here (since we
1721 * send a dupped fd to the client), and we'd rather
1722 * see this fail quickly then be retried later */
1725 return bus_send_error_reply(connection, message, NULL, r);
1727 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1731 if (!dbus_message_get_args(
1734 DBUS_TYPE_STRING, &name,
1736 return bus_send_error_reply(connection, message, &error, -EINVAL);
1738 session = hashmap_get(m->sessions, name);
1740 return bus_send_error_reply(connection, message, &error, -ENOENT);
1742 /* We use the FIFO to detect stray sessions where the
1743 process invoking PAM dies abnormally. We need to make
1744 sure that that process is not killed if at the clean
1745 end of the session it closes the FIFO. Hence, with
1746 this call explicitly turn off the FIFO logic, so that
1747 the PAM code can finish clean up on its own */
1748 session_remove_fifo(session);
1750 reply = dbus_message_new_method_return(message);
1754 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1758 if (!dbus_message_get_args(
1761 DBUS_TYPE_STRING, &name,
1763 return bus_send_error_reply(connection, message, &error, -EINVAL);
1765 session = hashmap_get(m->sessions, name);
1767 return bus_send_error_reply(connection, message, &error, -ENOENT);
1769 r = session_activate(session);
1771 return bus_send_error_reply(connection, message, NULL, r);
1773 reply = dbus_message_new_method_return(message);
1777 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1778 const char *session_name, *seat_name;
1782 /* Same as ActivateSession() but refuses to work if
1783 * the seat doesn't match */
1785 if (!dbus_message_get_args(
1788 DBUS_TYPE_STRING, &session_name,
1789 DBUS_TYPE_STRING, &seat_name,
1791 return bus_send_error_reply(connection, message, &error, -EINVAL);
1793 session = hashmap_get(m->sessions, session_name);
1795 return bus_send_error_reply(connection, message, &error, -ENOENT);
1797 seat = hashmap_get(m->seats, seat_name);
1799 return bus_send_error_reply(connection, message, &error, -ENOENT);
1801 if (session->seat != seat)
1802 return bus_send_error_reply(connection, message, &error, -EINVAL);
1804 r = session_activate(session);
1806 return bus_send_error_reply(connection, message, NULL, r);
1808 reply = dbus_message_new_method_return(message);
1812 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1813 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1817 if (!dbus_message_get_args(
1820 DBUS_TYPE_STRING, &name,
1822 return bus_send_error_reply(connection, message, &error, -EINVAL);
1824 session = hashmap_get(m->sessions, name);
1826 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1828 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1831 reply = dbus_message_new_method_return(message);
1835 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1836 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1838 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
1840 bus_send_error_reply(connection, message, NULL, r);
1842 reply = dbus_message_new_method_return(message);
1846 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1853 if (!dbus_message_get_args(
1856 DBUS_TYPE_STRING, &name,
1857 DBUS_TYPE_STRING, &swho,
1858 DBUS_TYPE_INT32, &signo,
1860 return bus_send_error_reply(connection, message, &error, -EINVAL);
1865 who = kill_who_from_string(swho);
1867 return bus_send_error_reply(connection, message, &error, -EINVAL);
1870 if (signo <= 0 || signo >= _NSIG)
1871 return bus_send_error_reply(connection, message, &error, -EINVAL);
1873 session = hashmap_get(m->sessions, name);
1875 return bus_send_error_reply(connection, message, &error, -ENOENT);
1877 r = session_kill(session, who, signo);
1879 return bus_send_error_reply(connection, message, NULL, r);
1881 reply = dbus_message_new_method_return(message);
1885 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1890 if (!dbus_message_get_args(
1893 DBUS_TYPE_UINT32, &uid,
1894 DBUS_TYPE_INT32, &signo,
1896 return bus_send_error_reply(connection, message, &error, -EINVAL);
1898 if (signo <= 0 || signo >= _NSIG)
1899 return bus_send_error_reply(connection, message, &error, -EINVAL);
1901 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1903 return bus_send_error_reply(connection, message, &error, -ENOENT);
1905 r = user_kill(user, signo);
1907 return bus_send_error_reply(connection, message, NULL, r);
1909 reply = dbus_message_new_method_return(message);
1913 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1917 if (!dbus_message_get_args(
1920 DBUS_TYPE_STRING, &name,
1922 return bus_send_error_reply(connection, message, &error, -EINVAL);
1924 session = hashmap_get(m->sessions, name);
1926 return bus_send_error_reply(connection, message, &error, -ENOENT);
1928 r = session_stop(session);
1930 return bus_send_error_reply(connection, message, NULL, r);
1932 reply = dbus_message_new_method_return(message);
1936 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1940 if (!dbus_message_get_args(
1943 DBUS_TYPE_UINT32, &uid,
1945 return bus_send_error_reply(connection, message, &error, -EINVAL);
1947 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1949 return bus_send_error_reply(connection, message, &error, -ENOENT);
1951 r = user_stop(user);
1953 return bus_send_error_reply(connection, message, NULL, r);
1955 reply = dbus_message_new_method_return(message);
1959 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1963 if (!dbus_message_get_args(
1966 DBUS_TYPE_STRING, &name,
1968 return bus_send_error_reply(connection, message, &error, -EINVAL);
1970 seat = hashmap_get(m->seats, name);
1972 return bus_send_error_reply(connection, message, &error, -ENOENT);
1974 r = seat_stop_sessions(seat);
1976 return bus_send_error_reply(connection, message, NULL, r);
1978 reply = dbus_message_new_method_return(message);
1982 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1985 dbus_bool_t b, interactive;
1988 if (!dbus_message_get_args(
1991 DBUS_TYPE_UINT32, &uid,
1992 DBUS_TYPE_BOOLEAN, &b,
1993 DBUS_TYPE_BOOLEAN, &interactive,
1995 return bus_send_error_reply(connection, message, &error, -EINVAL);
2000 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2002 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2004 return bus_send_error_reply(connection, message, &error, r);
2006 mkdir_p_label("/var/lib/systemd", 0755);
2008 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2010 return bus_send_error_reply(connection, message, &error, r);
2012 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2023 return bus_send_error_reply(connection, message, &error, r);
2025 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2034 if (r < 0 && errno != ENOENT)
2035 return bus_send_error_reply(connection, message, &error, -errno);
2037 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2039 user_add_to_gc_queue(u);
2042 reply = dbus_message_new_method_return(message);
2046 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2047 const char *sysfs, *seat;
2048 dbus_bool_t interactive;
2050 if (!dbus_message_get_args(
2053 DBUS_TYPE_STRING, &seat,
2054 DBUS_TYPE_STRING, &sysfs,
2055 DBUS_TYPE_BOOLEAN, &interactive,
2057 return bus_send_error_reply(connection, message, &error, -EINVAL);
2059 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2060 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2062 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2064 return bus_send_error_reply(connection, message, &error, r);
2066 r = attach_device(m, seat, sysfs);
2068 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2070 reply = dbus_message_new_method_return(message);
2075 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2076 dbus_bool_t interactive;
2078 if (!dbus_message_get_args(
2081 DBUS_TYPE_BOOLEAN, &interactive,
2083 return bus_send_error_reply(connection, message, &error, -EINVAL);
2085 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2087 return bus_send_error_reply(connection, message, &error, r);
2089 r = flush_devices(m);
2091 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2093 reply = dbus_message_new_method_return(message);
2097 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2099 r = bus_manager_do_shutdown_or_sleep(
2100 m, connection, message,
2101 SPECIAL_POWEROFF_TARGET,
2103 "org.freedesktop.login1.power-off",
2104 "org.freedesktop.login1.power-off-multiple-sessions",
2105 "org.freedesktop.login1.power-off-ignore-inhibit",
2109 return bus_send_error_reply(connection, message, &error, r);
2110 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2111 r = bus_manager_do_shutdown_or_sleep(
2112 m, connection, message,
2113 SPECIAL_REBOOT_TARGET,
2115 "org.freedesktop.login1.reboot",
2116 "org.freedesktop.login1.reboot-multiple-sessions",
2117 "org.freedesktop.login1.reboot-ignore-inhibit",
2121 return bus_send_error_reply(connection, message, &error, r);
2123 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2124 r = bus_manager_do_shutdown_or_sleep(
2125 m, connection, message,
2126 SPECIAL_SUSPEND_TARGET,
2128 "org.freedesktop.login1.suspend",
2129 "org.freedesktop.login1.suspend-multiple-sessions",
2130 "org.freedesktop.login1.suspend-ignore-inhibit",
2134 return bus_send_error_reply(connection, message, &error, r);
2135 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2136 r = bus_manager_do_shutdown_or_sleep(
2137 m, connection, message,
2138 SPECIAL_HIBERNATE_TARGET,
2140 "org.freedesktop.login1.hibernate",
2141 "org.freedesktop.login1.hibernate-multiple-sessions",
2142 "org.freedesktop.login1.hibernate-ignore-inhibit",
2146 return bus_send_error_reply(connection, message, &error, r);
2148 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2149 r = bus_manager_do_shutdown_or_sleep(
2150 m, connection, message,
2151 SPECIAL_HYBRID_SLEEP_TARGET,
2153 "org.freedesktop.login1.hibernate",
2154 "org.freedesktop.login1.hibernate-multiple-sessions",
2155 "org.freedesktop.login1.hibernate-ignore-inhibit",
2159 return bus_send_error_reply(connection, message, &error, r);
2161 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2163 r = bus_manager_can_shutdown_or_sleep(
2164 m, connection, message,
2166 "org.freedesktop.login1.power-off",
2167 "org.freedesktop.login1.power-off-multiple-sessions",
2168 "org.freedesktop.login1.power-off-ignore-inhibit",
2172 return bus_send_error_reply(connection, message, &error, r);
2173 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2174 r = bus_manager_can_shutdown_or_sleep(
2175 m, connection, message,
2177 "org.freedesktop.login1.reboot",
2178 "org.freedesktop.login1.reboot-multiple-sessions",
2179 "org.freedesktop.login1.reboot-ignore-inhibit",
2183 return bus_send_error_reply(connection, message, &error, r);
2185 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2186 r = bus_manager_can_shutdown_or_sleep(
2187 m, connection, message,
2189 "org.freedesktop.login1.suspend",
2190 "org.freedesktop.login1.suspend-multiple-sessions",
2191 "org.freedesktop.login1.suspend-ignore-inhibit",
2195 return bus_send_error_reply(connection, message, &error, r);
2197 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2198 r = bus_manager_can_shutdown_or_sleep(
2199 m, connection, message,
2201 "org.freedesktop.login1.hibernate",
2202 "org.freedesktop.login1.hibernate-multiple-sessions",
2203 "org.freedesktop.login1.hibernate-ignore-inhibit",
2207 return bus_send_error_reply(connection, message, &error, r);
2209 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2210 r = bus_manager_can_shutdown_or_sleep(
2211 m, connection, message,
2213 "org.freedesktop.login1.hibernate",
2214 "org.freedesktop.login1.hibernate-multiple-sessions",
2215 "org.freedesktop.login1.hibernate-ignore-inhibit",
2219 return bus_send_error_reply(connection, message, &error, r);
2221 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2222 char *introspection = NULL;
2231 if (!(reply = dbus_message_new_method_return(message)))
2234 /* We roll our own introspection code here, instead of
2235 * relying on bus_default_message_handler() because we
2236 * need to generate our introspection string
2239 if (!(f = open_memstream(&introspection, &size)))
2242 fputs(INTROSPECTION_BEGIN, f);
2244 HASHMAP_FOREACH(seat, m->seats, i) {
2245 p = bus_path_escape(seat->id);
2248 fprintf(f, "<node name=\"seat/%s\"/>", p);
2253 HASHMAP_FOREACH(user, m->users, i)
2254 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2256 HASHMAP_FOREACH(session, m->sessions, i) {
2257 p = bus_path_escape(session->id);
2260 fprintf(f, "<node name=\"session/%s\"/>", p);
2265 fputs(INTROSPECTION_END, f);
2269 free(introspection);
2278 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2279 free(introspection);
2283 free(introspection);
2285 const BusBoundProperties bps[] = {
2286 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2289 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2293 if (!bus_maybe_send_reply(connection, message, reply))
2297 return DBUS_HANDLER_RESULT_HANDLED;
2300 dbus_error_free(&error);
2302 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2305 const DBusObjectPathVTable bus_manager_vtable = {
2306 .message_function = manager_message_handler
2309 DBusHandlerResult bus_message_filter(
2310 DBusConnection *connection,
2311 DBusMessage *message,
2314 Manager *m = userdata;
2321 dbus_error_init(&error);
2323 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)));
2325 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2326 const char *path, *result, *unit;
2329 if (!dbus_message_get_args(message, &error,
2330 DBUS_TYPE_UINT32, &id,
2331 DBUS_TYPE_OBJECT_PATH, &path,
2332 DBUS_TYPE_STRING, &unit,
2333 DBUS_TYPE_STRING, &result,
2334 DBUS_TYPE_INVALID)) {
2335 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2339 if (m->action_job && streq(m->action_job, path)) {
2340 log_info("Operation finished.");
2342 /* Tell people that they now may take a lock again */
2343 send_prepare_for(m, m->action_what, false);
2345 free(m->action_job);
2346 m->action_job = NULL;
2347 m->action_unit = NULL;
2354 s = hashmap_get(m->session_units, unit);
2356 if (streq_ptr(path, s->scope_job)) {
2358 s->scope_job = NULL;
2362 if (streq(result, "done"))
2363 session_send_create_reply(s, NULL);
2365 dbus_set_error(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
2366 session_send_create_reply(s, &error);
2371 session_add_to_gc_queue(s);
2374 u = hashmap_get(m->user_units, unit);
2376 if (streq_ptr(path, u->service_job)) {
2377 free(u->service_job);
2378 u->service_job = NULL;
2381 if (streq_ptr(path, u->slice_job)) {
2383 u->slice_job = NULL;
2387 user_add_to_gc_queue(u);
2391 } else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
2393 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2394 _cleanup_free_ char *unit = NULL;
2397 path = dbus_message_get_path(message);
2401 unit_name_from_dbus_path(path, &unit);
2406 s = hashmap_get(m->session_units, unit);
2408 session_add_to_gc_queue(s);
2410 u = hashmap_get(m->user_units, unit);
2412 user_add_to_gc_queue(u);
2415 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitRemoved")) {
2417 const char *path, *unit;
2421 if (!dbus_message_get_args(message, &error,
2422 DBUS_TYPE_STRING, &unit,
2423 DBUS_TYPE_OBJECT_PATH, &path,
2424 DBUS_TYPE_INVALID)) {
2425 log_error("Failed to parse UnitRemoved message: %s", bus_error_message(&error));
2429 session = hashmap_get(m->session_units, unit);
2431 session_add_to_gc_queue(session);
2433 user = hashmap_get(m->user_units, unit);
2435 user_add_to_gc_queue(user);
2437 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "Reloading")) {
2440 if (!dbus_message_get_args(message, &error,
2441 DBUS_TYPE_BOOLEAN, &b,
2442 DBUS_TYPE_INVALID)) {
2443 log_error("Failed to parse Reloading message: %s", bus_error_message(&error));
2447 /* systemd finished reloading, let's recheck all our sessions */
2452 log_debug("System manager has been reloaded, rechecking sessions...");
2454 HASHMAP_FOREACH(session, m->sessions, i)
2455 session_add_to_gc_queue(session);
2460 dbus_error_free(&error);
2462 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2465 int manager_send_changed(Manager *manager, const char *properties) {
2466 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
2470 m = bus_properties_changed_new("/org/freedesktop/login1",
2471 "org.freedesktop.login1.Manager",
2476 if (!dbus_connection_send(manager->bus, m, NULL))
2482 int manager_dispatch_delayed(Manager *manager) {
2488 if (manager->action_what == 0 || manager->action_job)
2491 /* Continue delay? */
2492 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
2494 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2497 log_info("Delay lock is active but inhibitor timeout is reached.");
2500 /* Actually do the operation */
2501 dbus_error_init(&error);
2502 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
2504 log_warning("Failed to send delayed message: %s", bus_error(&error, r));
2505 dbus_error_free(&error);
2507 manager->action_unit = NULL;
2508 manager->action_what = 0;
2515 int manager_start_scope(
2520 const char *description,
2525 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2526 DBusMessageIter iter, sub, sub2, sub3, sub4;
2527 const char *timeout_stop_property = "TimeoutStopUSec";
2528 const char *pids_property = "PIDs";
2529 uint64_t timeout = 500 * USEC_PER_MSEC;
2530 const char *fail = "fail";
2540 m = dbus_message_new_method_call(
2541 "org.freedesktop.systemd1",
2542 "/org/freedesktop/systemd1",
2543 "org.freedesktop.systemd1.Manager",
2544 "StartTransientUnit");
2548 dbus_message_iter_init_append(m, &iter);
2550 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &scope) ||
2551 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &fail) ||
2552 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub))
2555 if (!isempty(slice)) {
2556 const char *slice_property = "Slice";
2558 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2559 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &slice_property) ||
2560 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2561 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &slice) ||
2562 !dbus_message_iter_close_container(&sub2, &sub3) ||
2563 !dbus_message_iter_close_container(&sub, &sub2))
2567 if (!isempty(description)) {
2568 const char *description_property = "Description";
2570 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2571 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description_property) ||
2572 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2573 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &description) ||
2574 !dbus_message_iter_close_container(&sub2, &sub3) ||
2575 !dbus_message_iter_close_container(&sub, &sub2))
2579 if (!isempty(after)) {
2580 const char *after_property = "After";
2582 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2583 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &after_property) ||
2584 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "as", &sub3) ||
2585 !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "s", &sub4) ||
2586 !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_STRING, &after) ||
2587 !dbus_message_iter_close_container(&sub3, &sub4) ||
2588 !dbus_message_iter_close_container(&sub2, &sub3) ||
2589 !dbus_message_iter_close_container(&sub, &sub2))
2593 /* cgroup empty notification is not available in containers
2594 * currently. To make this less problematic, let's shorten the
2595 * stop timeout for sessions, so that we don't wait
2598 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2599 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &timeout_stop_property) ||
2600 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "t", &sub3) ||
2601 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &timeout) ||
2602 !dbus_message_iter_close_container(&sub2, &sub3) ||
2603 !dbus_message_iter_close_container(&sub, &sub2))
2607 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2608 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &pids_property) ||
2609 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "au", &sub3) ||
2610 !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "u", &sub4) ||
2611 !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_UINT32, &u) ||
2612 !dbus_message_iter_close_container(&sub3, &sub4) ||
2613 !dbus_message_iter_close_container(&sub2, &sub3) ||
2614 !dbus_message_iter_close_container(&sub, &sub2) ||
2615 !dbus_message_iter_close_container(&iter, &sub))
2618 reply = dbus_connection_send_with_reply_and_block(manager->bus, m, -1, error);
2626 if (!dbus_message_get_args(reply, error, DBUS_TYPE_OBJECT_PATH, &j, DBUS_TYPE_INVALID))
2639 int manager_start_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
2640 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2641 const char *fail = "fail";
2647 r = bus_method_call_with_reply(
2649 "org.freedesktop.systemd1",
2650 "/org/freedesktop/systemd1",
2651 "org.freedesktop.systemd1.Manager",
2655 DBUS_TYPE_STRING, &unit,
2656 DBUS_TYPE_STRING, &fail,
2659 log_error("Failed to start unit %s: %s", unit, bus_error(error, r));
2667 if (!dbus_message_get_args(reply, error,
2668 DBUS_TYPE_OBJECT_PATH, &j,
2669 DBUS_TYPE_INVALID)) {
2670 log_error("Failed to parse reply.");
2684 int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
2685 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2686 const char *fail = "fail";
2692 r = bus_method_call_with_reply(
2694 "org.freedesktop.systemd1",
2695 "/org/freedesktop/systemd1",
2696 "org.freedesktop.systemd1.Manager",
2700 DBUS_TYPE_STRING, &unit,
2701 DBUS_TYPE_STRING, &fail,
2704 if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
2705 dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
2710 dbus_error_free(error);
2714 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
2722 if (!dbus_message_get_args(reply, error,
2723 DBUS_TYPE_OBJECT_PATH, &j,
2724 DBUS_TYPE_INVALID)) {
2725 log_error("Failed to parse reply.");
2739 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error) {
2740 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2747 w = who == KILL_LEADER ? "process" : "cgroup";
2748 assert_cc(sizeof(signo) == sizeof(int32_t));
2750 r = bus_method_call_with_reply(
2752 "org.freedesktop.systemd1",
2753 "/org/freedesktop/systemd1",
2754 "org.freedesktop.systemd1.Manager",
2758 DBUS_TYPE_STRING, &unit,
2759 DBUS_TYPE_STRING, &w,
2760 DBUS_TYPE_INT32, &signo,
2763 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
2770 int manager_unit_is_active(Manager *manager, const char *unit) {
2772 const char *interface = "org.freedesktop.systemd1.Unit";
2773 const char *property = "ActiveState";
2774 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2775 _cleanup_free_ char *path = NULL;
2776 DBusMessageIter iter, sub;
2784 dbus_error_init(&error);
2786 path = unit_dbus_path_from_name(unit);
2790 r = bus_method_call_with_reply(
2792 "org.freedesktop.systemd1",
2794 "org.freedesktop.DBus.Properties",
2798 DBUS_TYPE_STRING, &interface,
2799 DBUS_TYPE_STRING, &property,
2802 if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY) ||
2803 dbus_error_has_name(&error, DBUS_ERROR_DISCONNECTED)) {
2804 /* systemd might have droppped off
2805 * momentarily, let's not make this an
2808 dbus_error_free(&error);
2812 if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
2813 dbus_error_has_name(&error, BUS_ERROR_LOAD_FAILED)) {
2814 /* If the unit is already unloaded then it's
2817 dbus_error_free(&error);
2821 log_error("Failed to query ActiveState: %s", bus_error(&error, r));
2822 dbus_error_free(&error);
2826 if (!dbus_message_iter_init(reply, &iter) ||
2827 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
2828 log_error("Failed to parse reply.");
2832 dbus_message_iter_recurse(&iter, &sub);
2833 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
2834 log_error("Failed to parse reply.");
2838 dbus_message_iter_get_basic(&sub, &state);
2840 return !streq(state, "inactive") && !streq(state, "failed");