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);
646 /* Now, let's wait until the slice unit and stuff got
647 * created. We send the reply back from
648 * session_send_create_reply().*/
654 session_add_to_gc_queue(session);
657 user_add_to_gc_queue(user);
662 static int bus_manager_inhibit(
664 DBusConnection *connection,
665 DBusMessage *message,
667 DBusMessage **_reply) {
671 const char *who, *why, *what, *mode;
677 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
685 if (!dbus_message_get_args(
688 DBUS_TYPE_STRING, &what,
689 DBUS_TYPE_STRING, &who,
690 DBUS_TYPE_STRING, &why,
691 DBUS_TYPE_STRING, &mode,
692 DBUS_TYPE_INVALID)) {
697 w = inhibit_what_from_string(what);
703 mm = inhibit_mode_from_string(mode);
709 /* Delay is only supported for shutdown/sleep */
710 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
715 /* Don't allow taking delay locks while we are already
716 * executing the operation. We shouldn't create the impression
717 * that the lock was successful if the machine is about to go
718 * down/suspend any moment. */
719 if (m->action_what & w) {
724 r = verify_polkit(connection, message,
725 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
726 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
727 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
728 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
729 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
730 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
731 "org.freedesktop.login1.inhibit-handle-lid-switch",
736 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
737 if (ul == (unsigned long) -1) {
742 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
752 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
756 } while (hashmap_get(m->inhibitors, id));
758 r = manager_add_inhibitor(m, id, &i);
768 i->why = strdup(why);
769 i->who = strdup(who);
771 if (!i->why || !i->who) {
776 fifo_fd = inhibitor_create_fifo(i);
782 reply = dbus_message_new_method_return(message);
788 if (!dbus_message_append_args(
790 DBUS_TYPE_UNIX_FD, &fifo_fd,
791 DBUS_TYPE_INVALID)) {
796 close_nointr_nofail(fifo_fd);
809 close_nointr_nofail(fifo_fd);
814 static int trigger_device(Manager *m, struct udev_device *d) {
815 struct udev_enumerate *e;
816 struct udev_list_entry *first, *item;
821 e = udev_enumerate_new(m->udev);
828 if (udev_enumerate_add_match_parent(e, d) < 0) {
834 if (udev_enumerate_scan_devices(e) < 0) {
839 first = udev_enumerate_get_list_entry(e);
840 udev_list_entry_foreach(item, first) {
844 p = udev_list_entry_get_name(item);
846 t = strappend(p, "/uevent");
852 write_string_file(t, "change");
860 udev_enumerate_unref(e);
865 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
866 struct udev_device *d;
867 _cleanup_free_ char *rule = NULL, *file = NULL;
868 const char *id_for_seat;
875 d = udev_device_new_from_syspath(m->udev, sysfs);
879 if (!udev_device_has_tag(d, "seat")) {
884 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
890 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
895 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
900 mkdir_p_label("/etc/udev/rules.d", 0755);
902 r = write_string_file_atomic_label(file, rule);
906 r = trigger_device(m, d);
910 udev_device_unref(d);
915 static int flush_devices(Manager *m) {
916 _cleanup_closedir_ DIR *d;
920 d = opendir("/etc/udev/rules.d");
923 log_warning("Failed to open /etc/udev/rules.d: %m");
927 while ((de = readdir(d))) {
929 if (!dirent_is_file(de))
932 if (!startswith(de->d_name, "72-seat-"))
935 if (!endswith(de->d_name, ".rules"))
938 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
939 log_warning("Failed to unlink %s: %m", de->d_name);
943 return trigger_device(m, NULL);
946 static int have_multiple_sessions(
955 /* Check for other users' sessions. Greeter sessions do not
956 * count, and non-login sessions do not count either. */
957 HASHMAP_FOREACH(session, m->sessions, i)
958 if (session->class == SESSION_USER &&
959 session->user->uid != uid)
965 static int bus_manager_log_shutdown(
968 const char *unit_name) {
975 if (w != INHIBIT_SHUTDOWN)
978 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
979 p = "MESSAGE=System is powering down.";
980 q = "SHUTDOWN=power-off";
981 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
982 p = "MESSAGE=System is halting.";
984 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
985 p = "MESSAGE=System is rebooting.";
986 q = "SHUTDOWN=reboot";
987 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
988 p = "MESSAGE=System is rebooting with kexec.";
989 q = "SHUTDOWN=kexec";
991 p = "MESSAGE=System is shutting down.";
995 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1000 static int execute_shutdown_or_sleep(
1003 const char *unit_name,
1006 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1007 const char *mode = "replace-irreversibly", *p;
1013 assert(w < _INHIBIT_WHAT_MAX);
1016 bus_manager_log_shutdown(m, w, unit_name);
1018 r = bus_method_call_with_reply(
1020 "org.freedesktop.systemd1",
1021 "/org/freedesktop/systemd1",
1022 "org.freedesktop.systemd1.Manager",
1026 DBUS_TYPE_STRING, &unit_name,
1027 DBUS_TYPE_STRING, &mode,
1032 if (!dbus_message_get_args(
1035 DBUS_TYPE_OBJECT_PATH, &p,
1043 m->action_unit = unit_name;
1044 free(m->action_job);
1051 static int delay_shutdown_or_sleep(
1054 const char *unit_name) {
1058 assert(w < _INHIBIT_WHAT_MAX);
1061 m->action_timestamp = now(CLOCK_MONOTONIC);
1062 m->action_unit = unit_name;
1068 static int bus_manager_can_shutdown_or_sleep(
1070 DBusConnection *connection,
1071 DBusMessage *message,
1074 const char *action_multiple_sessions,
1075 const char *action_ignore_inhibit,
1076 const char *sleep_verb,
1078 DBusMessage **_reply) {
1080 bool multiple_sessions, challenge, blocked, b;
1081 const char *result = NULL;
1082 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1090 assert(w <= _INHIBIT_WHAT_MAX);
1092 assert(action_multiple_sessions);
1093 assert(action_ignore_inhibit);
1098 r = can_sleep(sleep_verb);
1107 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1108 if (ul == (unsigned long) -1)
1111 r = have_multiple_sessions(m, (uid_t) ul);
1115 multiple_sessions = r > 0;
1116 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1118 if (multiple_sessions) {
1119 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1126 result = "challenge";
1132 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1136 if (r > 0 && !result)
1138 else if (challenge && (!result || streq(result, "yes")))
1139 result = "challenge";
1144 if (!multiple_sessions && !blocked) {
1145 /* If neither inhibit nor multiple sessions
1146 * apply then just check the normal policy */
1148 r = verify_polkit(connection, message, action, false, &challenge, error);
1155 result = "challenge";
1161 reply = dbus_message_new_method_return(message);
1165 b = dbus_message_append_args(
1167 DBUS_TYPE_STRING, &result,
1177 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1178 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1179 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1180 [INHIBIT_SLEEP] = "PrepareForSleep"
1183 dbus_bool_t active = _active;
1184 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1188 assert(w < _INHIBIT_WHAT_MAX);
1189 assert(signal_name[w]);
1191 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1195 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1196 !dbus_connection_send(m->bus, message, NULL))
1202 int bus_manager_shutdown_or_sleep_now_or_later(
1204 const char *unit_name,
1214 assert(w <= _INHIBIT_WHAT_MAX);
1215 assert(!m->action_job);
1217 /* Tell everybody to prepare for shutdown/sleep */
1218 send_prepare_for(m, w, true);
1221 m->inhibit_delay_max > 0 &&
1222 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1225 /* Shutdown is delayed, keep in mind what we
1226 * want to do, and start a timeout */
1227 r = delay_shutdown_or_sleep(m, w, unit_name);
1229 /* Shutdown is not delayed, execute it
1231 r = execute_shutdown_or_sleep(m, w, unit_name, error);
1236 static int bus_manager_do_shutdown_or_sleep(
1238 DBusConnection *connection,
1239 DBusMessage *message,
1240 const char *unit_name,
1243 const char *action_multiple_sessions,
1244 const char *action_ignore_inhibit,
1245 const char *sleep_verb,
1247 DBusMessage **_reply) {
1249 dbus_bool_t interactive;
1250 bool multiple_sessions, blocked;
1251 DBusMessage *reply = NULL;
1260 assert(w <= _INHIBIT_WHAT_MAX);
1262 assert(action_multiple_sessions);
1263 assert(action_ignore_inhibit);
1267 /* Don't allow multiple jobs being executed at the same time */
1271 if (!dbus_message_get_args(
1274 DBUS_TYPE_BOOLEAN, &interactive,
1279 r = can_sleep(sleep_verb);
1287 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1288 if (ul == (unsigned long) -1)
1291 r = have_multiple_sessions(m, (uid_t) ul);
1295 multiple_sessions = r > 0;
1296 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1298 if (multiple_sessions) {
1299 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1305 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1310 if (!multiple_sessions && !blocked) {
1311 r = verify_polkit(connection, message, action, interactive, NULL, error);
1316 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1320 reply = dbus_message_new_method_return(message);
1328 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1330 static const BusProperty bus_login_manager_properties[] = {
1331 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1332 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1333 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1334 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1335 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1336 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1337 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1338 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1339 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1340 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1341 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1342 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1343 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1344 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1345 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1346 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1347 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1348 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1352 static DBusHandlerResult manager_message_handler(
1353 DBusConnection *connection,
1354 DBusMessage *message,
1357 Manager *m = userdata;
1360 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1367 dbus_error_init(&error);
1369 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1375 if (!dbus_message_get_args(
1378 DBUS_TYPE_STRING, &name,
1380 return bus_send_error_reply(connection, message, &error, -EINVAL);
1382 session = hashmap_get(m->sessions, name);
1384 return bus_send_error_reply(connection, message, &error, -ENOENT);
1386 reply = dbus_message_new_method_return(message);
1390 p = session_bus_path(session);
1394 b = dbus_message_append_args(
1396 DBUS_TYPE_OBJECT_PATH, &p,
1403 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1409 if (!dbus_message_get_args(
1412 DBUS_TYPE_UINT32, &pid,
1414 return bus_send_error_reply(connection, message, &error, -EINVAL);
1416 r = manager_get_session_by_pid(m, pid, &session);
1418 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1420 reply = dbus_message_new_method_return(message);
1424 p = session_bus_path(session);
1428 b = dbus_message_append_args(
1430 DBUS_TYPE_OBJECT_PATH, &p,
1437 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1443 if (!dbus_message_get_args(
1446 DBUS_TYPE_UINT32, &uid,
1448 return bus_send_error_reply(connection, message, &error, -EINVAL);
1450 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1452 return bus_send_error_reply(connection, message, &error, -ENOENT);
1454 reply = dbus_message_new_method_return(message);
1458 p = user_bus_path(user);
1462 b = dbus_message_append_args(
1464 DBUS_TYPE_OBJECT_PATH, &p,
1471 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUserByPID")) {
1477 if (!dbus_message_get_args(
1480 DBUS_TYPE_UINT32, &pid,
1482 return bus_send_error_reply(connection, message, &error, -EINVAL);
1484 r = manager_get_user_by_pid(m, pid, &user);
1486 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1488 reply = dbus_message_new_method_return(message);
1492 p = user_bus_path(user);
1496 b = dbus_message_append_args(
1498 DBUS_TYPE_OBJECT_PATH, &p,
1505 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1511 if (!dbus_message_get_args(
1514 DBUS_TYPE_STRING, &name,
1516 return bus_send_error_reply(connection, message, &error, -EINVAL);
1518 seat = hashmap_get(m->seats, name);
1520 return bus_send_error_reply(connection, message, &error, -ENOENT);
1522 reply = dbus_message_new_method_return(message);
1526 p = seat_bus_path(seat);
1530 b = dbus_message_append_args(
1532 DBUS_TYPE_OBJECT_PATH, &p,
1539 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1543 DBusMessageIter iter, sub;
1544 const char *empty = "";
1546 reply = dbus_message_new_method_return(message);
1550 dbus_message_iter_init_append(reply, &iter);
1552 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1555 HASHMAP_FOREACH(session, m->sessions, i) {
1556 DBusMessageIter sub2;
1559 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1562 uid = session->user->uid;
1564 p = session_bus_path(session);
1568 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1569 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1570 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1571 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1572 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1579 if (!dbus_message_iter_close_container(&sub, &sub2))
1583 if (!dbus_message_iter_close_container(&iter, &sub))
1586 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1589 DBusMessageIter iter, sub;
1591 reply = dbus_message_new_method_return(message);
1595 dbus_message_iter_init_append(reply, &iter);
1597 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1600 HASHMAP_FOREACH(user, m->users, i) {
1601 _cleanup_free_ char *p = NULL;
1602 DBusMessageIter sub2;
1605 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1610 p = user_bus_path(user);
1614 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1615 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1616 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1621 if (!dbus_message_iter_close_container(&sub, &sub2))
1625 if (!dbus_message_iter_close_container(&iter, &sub))
1628 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1631 DBusMessageIter iter, sub;
1633 reply = dbus_message_new_method_return(message);
1637 dbus_message_iter_init_append(reply, &iter);
1639 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1642 HASHMAP_FOREACH(seat, m->seats, i) {
1643 _cleanup_free_ char *p = NULL;
1644 DBusMessageIter sub2;
1646 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1649 p = seat_bus_path(seat);
1653 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1654 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1659 if (!dbus_message_iter_close_container(&sub, &sub2))
1663 if (!dbus_message_iter_close_container(&iter, &sub))
1666 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1667 Inhibitor *inhibitor;
1669 DBusMessageIter iter, sub;
1671 reply = dbus_message_new_method_return(message);
1675 dbus_message_iter_init_append(reply, &iter);
1677 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1680 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1681 DBusMessageIter sub2;
1682 dbus_uint32_t uid, pid;
1683 const char *what, *who, *why, *mode;
1685 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1688 what = strempty(inhibit_what_to_string(inhibitor->what));
1689 who = strempty(inhibitor->who);
1690 why = strempty(inhibitor->why);
1691 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1692 uid = (dbus_uint32_t) inhibitor->uid;
1693 pid = (dbus_uint32_t) inhibitor->pid;
1695 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1696 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1697 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1698 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1699 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1700 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1703 if (!dbus_message_iter_close_container(&sub, &sub2))
1707 if (!dbus_message_iter_close_container(&iter, &sub))
1711 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1713 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1716 return bus_send_error_reply(connection, message, &error, r);
1719 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1721 r = bus_manager_create_session(m, message);
1723 /* Don't delay the work on OOM here, since it might be
1724 * triggered by a low RLIMIT_NOFILE here (since we
1725 * send a dupped fd to the client), and we'd rather
1726 * see this fail quickly then be retried later */
1729 return bus_send_error_reply(connection, message, NULL, r);
1731 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1735 if (!dbus_message_get_args(
1738 DBUS_TYPE_STRING, &name,
1740 return bus_send_error_reply(connection, message, &error, -EINVAL);
1742 session = hashmap_get(m->sessions, name);
1744 return bus_send_error_reply(connection, message, &error, -ENOENT);
1746 /* We use the FIFO to detect stray sessions where the
1747 process invoking PAM dies abnormally. We need to make
1748 sure that that process is not killed if at the clean
1749 end of the session it closes the FIFO. Hence, with
1750 this call explicitly turn off the FIFO logic, so that
1751 the PAM code can finish clean up on its own */
1752 session_remove_fifo(session);
1754 reply = dbus_message_new_method_return(message);
1758 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1762 if (!dbus_message_get_args(
1765 DBUS_TYPE_STRING, &name,
1767 return bus_send_error_reply(connection, message, &error, -EINVAL);
1769 session = hashmap_get(m->sessions, name);
1771 return bus_send_error_reply(connection, message, &error, -ENOENT);
1773 r = session_activate(session);
1775 return bus_send_error_reply(connection, message, NULL, r);
1777 reply = dbus_message_new_method_return(message);
1781 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1782 const char *session_name, *seat_name;
1786 /* Same as ActivateSession() but refuses to work if
1787 * the seat doesn't match */
1789 if (!dbus_message_get_args(
1792 DBUS_TYPE_STRING, &session_name,
1793 DBUS_TYPE_STRING, &seat_name,
1795 return bus_send_error_reply(connection, message, &error, -EINVAL);
1797 session = hashmap_get(m->sessions, session_name);
1799 return bus_send_error_reply(connection, message, &error, -ENOENT);
1801 seat = hashmap_get(m->seats, seat_name);
1803 return bus_send_error_reply(connection, message, &error, -ENOENT);
1805 if (session->seat != seat)
1806 return bus_send_error_reply(connection, message, &error, -EINVAL);
1808 r = session_activate(session);
1810 return bus_send_error_reply(connection, message, NULL, r);
1812 reply = dbus_message_new_method_return(message);
1816 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1817 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1821 if (!dbus_message_get_args(
1824 DBUS_TYPE_STRING, &name,
1826 return bus_send_error_reply(connection, message, &error, -EINVAL);
1828 session = hashmap_get(m->sessions, name);
1830 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1832 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1835 reply = dbus_message_new_method_return(message);
1839 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1840 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1842 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
1844 bus_send_error_reply(connection, message, NULL, r);
1846 reply = dbus_message_new_method_return(message);
1850 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1857 if (!dbus_message_get_args(
1860 DBUS_TYPE_STRING, &name,
1861 DBUS_TYPE_STRING, &swho,
1862 DBUS_TYPE_INT32, &signo,
1864 return bus_send_error_reply(connection, message, &error, -EINVAL);
1869 who = kill_who_from_string(swho);
1871 return bus_send_error_reply(connection, message, &error, -EINVAL);
1874 if (signo <= 0 || signo >= _NSIG)
1875 return bus_send_error_reply(connection, message, &error, -EINVAL);
1877 session = hashmap_get(m->sessions, name);
1879 return bus_send_error_reply(connection, message, &error, -ENOENT);
1881 r = session_kill(session, who, signo);
1883 return bus_send_error_reply(connection, message, NULL, r);
1885 reply = dbus_message_new_method_return(message);
1889 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1894 if (!dbus_message_get_args(
1897 DBUS_TYPE_UINT32, &uid,
1898 DBUS_TYPE_INT32, &signo,
1900 return bus_send_error_reply(connection, message, &error, -EINVAL);
1902 if (signo <= 0 || signo >= _NSIG)
1903 return bus_send_error_reply(connection, message, &error, -EINVAL);
1905 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1907 return bus_send_error_reply(connection, message, &error, -ENOENT);
1909 r = user_kill(user, signo);
1911 return bus_send_error_reply(connection, message, NULL, r);
1913 reply = dbus_message_new_method_return(message);
1917 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1921 if (!dbus_message_get_args(
1924 DBUS_TYPE_STRING, &name,
1926 return bus_send_error_reply(connection, message, &error, -EINVAL);
1928 session = hashmap_get(m->sessions, name);
1930 return bus_send_error_reply(connection, message, &error, -ENOENT);
1932 r = session_stop(session);
1934 return bus_send_error_reply(connection, message, NULL, r);
1936 reply = dbus_message_new_method_return(message);
1940 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1944 if (!dbus_message_get_args(
1947 DBUS_TYPE_UINT32, &uid,
1949 return bus_send_error_reply(connection, message, &error, -EINVAL);
1951 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1953 return bus_send_error_reply(connection, message, &error, -ENOENT);
1955 r = user_stop(user);
1957 return bus_send_error_reply(connection, message, NULL, r);
1959 reply = dbus_message_new_method_return(message);
1963 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1967 if (!dbus_message_get_args(
1970 DBUS_TYPE_STRING, &name,
1972 return bus_send_error_reply(connection, message, &error, -EINVAL);
1974 seat = hashmap_get(m->seats, name);
1976 return bus_send_error_reply(connection, message, &error, -ENOENT);
1978 r = seat_stop_sessions(seat);
1980 return bus_send_error_reply(connection, message, NULL, r);
1982 reply = dbus_message_new_method_return(message);
1986 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1989 dbus_bool_t b, interactive;
1992 if (!dbus_message_get_args(
1995 DBUS_TYPE_UINT32, &uid,
1996 DBUS_TYPE_BOOLEAN, &b,
1997 DBUS_TYPE_BOOLEAN, &interactive,
1999 return bus_send_error_reply(connection, message, &error, -EINVAL);
2004 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2006 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2008 return bus_send_error_reply(connection, message, &error, r);
2010 mkdir_p_label("/var/lib/systemd", 0755);
2012 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2014 return bus_send_error_reply(connection, message, &error, r);
2016 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2027 return bus_send_error_reply(connection, message, &error, r);
2029 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2038 if (r < 0 && errno != ENOENT)
2039 return bus_send_error_reply(connection, message, &error, -errno);
2041 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2043 user_add_to_gc_queue(u);
2046 reply = dbus_message_new_method_return(message);
2050 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2051 const char *sysfs, *seat;
2052 dbus_bool_t interactive;
2054 if (!dbus_message_get_args(
2057 DBUS_TYPE_STRING, &seat,
2058 DBUS_TYPE_STRING, &sysfs,
2059 DBUS_TYPE_BOOLEAN, &interactive,
2061 return bus_send_error_reply(connection, message, &error, -EINVAL);
2063 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2064 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2066 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2068 return bus_send_error_reply(connection, message, &error, r);
2070 r = attach_device(m, seat, sysfs);
2072 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2074 reply = dbus_message_new_method_return(message);
2079 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2080 dbus_bool_t interactive;
2082 if (!dbus_message_get_args(
2085 DBUS_TYPE_BOOLEAN, &interactive,
2087 return bus_send_error_reply(connection, message, &error, -EINVAL);
2089 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2091 return bus_send_error_reply(connection, message, &error, r);
2093 r = flush_devices(m);
2095 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2097 reply = dbus_message_new_method_return(message);
2101 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2103 r = bus_manager_do_shutdown_or_sleep(
2104 m, connection, message,
2105 SPECIAL_POWEROFF_TARGET,
2107 "org.freedesktop.login1.power-off",
2108 "org.freedesktop.login1.power-off-multiple-sessions",
2109 "org.freedesktop.login1.power-off-ignore-inhibit",
2113 return bus_send_error_reply(connection, message, &error, r);
2114 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2115 r = bus_manager_do_shutdown_or_sleep(
2116 m, connection, message,
2117 SPECIAL_REBOOT_TARGET,
2119 "org.freedesktop.login1.reboot",
2120 "org.freedesktop.login1.reboot-multiple-sessions",
2121 "org.freedesktop.login1.reboot-ignore-inhibit",
2125 return bus_send_error_reply(connection, message, &error, r);
2127 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2128 r = bus_manager_do_shutdown_or_sleep(
2129 m, connection, message,
2130 SPECIAL_SUSPEND_TARGET,
2132 "org.freedesktop.login1.suspend",
2133 "org.freedesktop.login1.suspend-multiple-sessions",
2134 "org.freedesktop.login1.suspend-ignore-inhibit",
2138 return bus_send_error_reply(connection, message, &error, r);
2139 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2140 r = bus_manager_do_shutdown_or_sleep(
2141 m, connection, message,
2142 SPECIAL_HIBERNATE_TARGET,
2144 "org.freedesktop.login1.hibernate",
2145 "org.freedesktop.login1.hibernate-multiple-sessions",
2146 "org.freedesktop.login1.hibernate-ignore-inhibit",
2150 return bus_send_error_reply(connection, message, &error, r);
2152 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2153 r = bus_manager_do_shutdown_or_sleep(
2154 m, connection, message,
2155 SPECIAL_HYBRID_SLEEP_TARGET,
2157 "org.freedesktop.login1.hibernate",
2158 "org.freedesktop.login1.hibernate-multiple-sessions",
2159 "org.freedesktop.login1.hibernate-ignore-inhibit",
2163 return bus_send_error_reply(connection, message, &error, r);
2165 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2167 r = bus_manager_can_shutdown_or_sleep(
2168 m, connection, message,
2170 "org.freedesktop.login1.power-off",
2171 "org.freedesktop.login1.power-off-multiple-sessions",
2172 "org.freedesktop.login1.power-off-ignore-inhibit",
2176 return bus_send_error_reply(connection, message, &error, r);
2177 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2178 r = bus_manager_can_shutdown_or_sleep(
2179 m, connection, message,
2181 "org.freedesktop.login1.reboot",
2182 "org.freedesktop.login1.reboot-multiple-sessions",
2183 "org.freedesktop.login1.reboot-ignore-inhibit",
2187 return bus_send_error_reply(connection, message, &error, r);
2189 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2190 r = bus_manager_can_shutdown_or_sleep(
2191 m, connection, message,
2193 "org.freedesktop.login1.suspend",
2194 "org.freedesktop.login1.suspend-multiple-sessions",
2195 "org.freedesktop.login1.suspend-ignore-inhibit",
2199 return bus_send_error_reply(connection, message, &error, r);
2201 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2202 r = bus_manager_can_shutdown_or_sleep(
2203 m, connection, message,
2205 "org.freedesktop.login1.hibernate",
2206 "org.freedesktop.login1.hibernate-multiple-sessions",
2207 "org.freedesktop.login1.hibernate-ignore-inhibit",
2211 return bus_send_error_reply(connection, message, &error, r);
2213 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2214 r = bus_manager_can_shutdown_or_sleep(
2215 m, connection, message,
2217 "org.freedesktop.login1.hibernate",
2218 "org.freedesktop.login1.hibernate-multiple-sessions",
2219 "org.freedesktop.login1.hibernate-ignore-inhibit",
2223 return bus_send_error_reply(connection, message, &error, r);
2225 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2226 char *introspection = NULL;
2235 if (!(reply = dbus_message_new_method_return(message)))
2238 /* We roll our own introspection code here, instead of
2239 * relying on bus_default_message_handler() because we
2240 * need to generate our introspection string
2243 if (!(f = open_memstream(&introspection, &size)))
2246 fputs(INTROSPECTION_BEGIN, f);
2248 HASHMAP_FOREACH(seat, m->seats, i) {
2249 p = bus_path_escape(seat->id);
2252 fprintf(f, "<node name=\"seat/%s\"/>", p);
2257 HASHMAP_FOREACH(user, m->users, i)
2258 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2260 HASHMAP_FOREACH(session, m->sessions, i) {
2261 p = bus_path_escape(session->id);
2264 fprintf(f, "<node name=\"session/%s\"/>", p);
2269 fputs(INTROSPECTION_END, f);
2273 free(introspection);
2282 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2283 free(introspection);
2287 free(introspection);
2289 const BusBoundProperties bps[] = {
2290 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2293 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2297 if (!bus_maybe_send_reply(connection, message, reply))
2301 return DBUS_HANDLER_RESULT_HANDLED;
2304 dbus_error_free(&error);
2306 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2309 const DBusObjectPathVTable bus_manager_vtable = {
2310 .message_function = manager_message_handler
2313 DBusHandlerResult bus_message_filter(
2314 DBusConnection *connection,
2315 DBusMessage *message,
2318 Manager *m = userdata;
2325 dbus_error_init(&error);
2327 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)));
2329 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2330 const char *path, *result, *unit;
2333 if (!dbus_message_get_args(message, &error,
2334 DBUS_TYPE_UINT32, &id,
2335 DBUS_TYPE_OBJECT_PATH, &path,
2336 DBUS_TYPE_STRING, &unit,
2337 DBUS_TYPE_STRING, &result,
2338 DBUS_TYPE_INVALID)) {
2339 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2343 if (m->action_job && streq(m->action_job, path)) {
2344 log_info("Operation finished.");
2346 /* Tell people that they now may take a lock again */
2347 send_prepare_for(m, m->action_what, false);
2349 free(m->action_job);
2350 m->action_job = NULL;
2351 m->action_unit = NULL;
2358 s = hashmap_get(m->session_units, unit);
2360 if (streq_ptr(path, s->scope_job)) {
2362 s->scope_job = NULL;
2365 if (streq(result, "done"))
2366 session_send_create_reply(s, NULL);
2368 dbus_set_error(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
2369 session_send_create_reply(s, &error);
2375 session_add_to_gc_queue(s);
2378 u = hashmap_get(m->user_units, unit);
2380 if (streq_ptr(path, u->service_job)) {
2381 free(u->service_job);
2382 u->service_job = NULL;
2385 if (streq_ptr(path, u->slice_job)) {
2387 u->slice_job = NULL;
2391 user_add_to_gc_queue(u);
2395 } else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
2397 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2398 _cleanup_free_ char *unit = NULL;
2401 path = dbus_message_get_path(message);
2405 unit_name_from_dbus_path(path, &unit);
2410 s = hashmap_get(m->session_units, unit);
2412 session_add_to_gc_queue(s);
2414 u = hashmap_get(m->user_units, unit);
2416 user_add_to_gc_queue(u);
2419 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitRemoved")) {
2421 const char *path, *unit;
2425 if (!dbus_message_get_args(message, &error,
2426 DBUS_TYPE_STRING, &unit,
2427 DBUS_TYPE_OBJECT_PATH, &path,
2428 DBUS_TYPE_INVALID)) {
2429 log_error("Failed to parse UnitRemoved message: %s", bus_error_message(&error));
2433 session = hashmap_get(m->session_units, unit);
2435 session_add_to_gc_queue(session);
2437 user = hashmap_get(m->user_units, unit);
2439 user_add_to_gc_queue(user);
2441 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "Reloading")) {
2444 if (!dbus_message_get_args(message, &error,
2445 DBUS_TYPE_BOOLEAN, &b,
2446 DBUS_TYPE_INVALID)) {
2447 log_error("Failed to parse Reloading message: %s", bus_error_message(&error));
2451 /* systemd finished reloading, let's recheck all our sessions */
2456 log_debug("System manager has been reloaded, rechecking sessions...");
2458 HASHMAP_FOREACH(session, m->sessions, i)
2459 session_add_to_gc_queue(session);
2464 dbus_error_free(&error);
2466 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2469 int manager_send_changed(Manager *manager, const char *properties) {
2470 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
2474 m = bus_properties_changed_new("/org/freedesktop/login1",
2475 "org.freedesktop.login1.Manager",
2480 if (!dbus_connection_send(manager->bus, m, NULL))
2486 int manager_dispatch_delayed(Manager *manager) {
2492 if (manager->action_what == 0 || manager->action_job)
2495 /* Continue delay? */
2496 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
2498 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2501 log_info("Delay lock is active but inhibitor timeout is reached.");
2504 /* Actually do the operation */
2505 dbus_error_init(&error);
2506 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
2508 log_warning("Failed to send delayed message: %s", bus_error(&error, r));
2509 dbus_error_free(&error);
2511 manager->action_unit = NULL;
2512 manager->action_what = 0;
2519 int manager_start_scope(
2524 const char *description,
2526 const char *kill_mode,
2530 const char *timeout_stop_property = "TimeoutStopUSec", *send_sighup_property = "SendSIGHUP", *pids_property = "PIDs";
2531 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2532 DBusMessageIter iter, sub, sub2, sub3, sub4;
2533 uint64_t timeout = 500 * USEC_PER_MSEC;
2534 dbus_bool_t send_sighup = true;
2535 const char *fail = "fail";
2545 m = dbus_message_new_method_call(
2546 "org.freedesktop.systemd1",
2547 "/org/freedesktop/systemd1",
2548 "org.freedesktop.systemd1.Manager",
2549 "StartTransientUnit");
2553 dbus_message_iter_init_append(m, &iter);
2555 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &scope) ||
2556 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &fail) ||
2557 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub))
2560 if (!isempty(slice)) {
2561 const char *slice_property = "Slice";
2563 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2564 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &slice_property) ||
2565 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2566 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &slice) ||
2567 !dbus_message_iter_close_container(&sub2, &sub3) ||
2568 !dbus_message_iter_close_container(&sub, &sub2))
2572 if (!isempty(description)) {
2573 const char *description_property = "Description";
2575 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2576 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description_property) ||
2577 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2578 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &description) ||
2579 !dbus_message_iter_close_container(&sub2, &sub3) ||
2580 !dbus_message_iter_close_container(&sub, &sub2))
2584 if (!isempty(after)) {
2585 const char *after_property = "After";
2587 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2588 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &after_property) ||
2589 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "as", &sub3) ||
2590 !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "s", &sub4) ||
2591 !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_STRING, &after) ||
2592 !dbus_message_iter_close_container(&sub3, &sub4) ||
2593 !dbus_message_iter_close_container(&sub2, &sub3) ||
2594 !dbus_message_iter_close_container(&sub, &sub2))
2598 if (!isempty(kill_mode)) {
2599 const char *kill_mode_property = "KillMode";
2601 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2602 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &kill_mode_property) ||
2603 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2604 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &kill_mode) ||
2605 !dbus_message_iter_close_container(&sub2, &sub3) ||
2606 !dbus_message_iter_close_container(&sub, &sub2))
2610 /* cgroup empty notification is not available in containers
2611 * currently. To make this less problematic, let's shorten the
2612 * stop timeout for sessions, so that we don't wait
2615 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2616 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &timeout_stop_property) ||
2617 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "t", &sub3) ||
2618 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &timeout) ||
2619 !dbus_message_iter_close_container(&sub2, &sub3) ||
2620 !dbus_message_iter_close_container(&sub, &sub2))
2623 /* Make sure that the session shells are terminated with
2624 * SIGHUP since bash and friends tend to ignore SIGTERM */
2625 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2626 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &send_sighup_property) ||
2627 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "b", &sub3) ||
2628 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_BOOLEAN, &send_sighup) ||
2629 !dbus_message_iter_close_container(&sub2, &sub3) ||
2630 !dbus_message_iter_close_container(&sub, &sub2))
2634 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2635 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &pids_property) ||
2636 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "au", &sub3) ||
2637 !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "u", &sub4) ||
2638 !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_UINT32, &u) ||
2639 !dbus_message_iter_close_container(&sub3, &sub4) ||
2640 !dbus_message_iter_close_container(&sub2, &sub3) ||
2641 !dbus_message_iter_close_container(&sub, &sub2))
2644 if (!dbus_message_iter_close_container(&iter, &sub))
2647 reply = dbus_connection_send_with_reply_and_block(manager->bus, m, -1, error);
2655 if (!dbus_message_get_args(reply, error, DBUS_TYPE_OBJECT_PATH, &j, DBUS_TYPE_INVALID))
2668 int manager_start_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
2669 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2670 const char *fail = "fail";
2676 r = bus_method_call_with_reply(
2678 "org.freedesktop.systemd1",
2679 "/org/freedesktop/systemd1",
2680 "org.freedesktop.systemd1.Manager",
2684 DBUS_TYPE_STRING, &unit,
2685 DBUS_TYPE_STRING, &fail,
2688 log_error("Failed to start unit %s: %s", unit, bus_error(error, r));
2696 if (!dbus_message_get_args(reply, error,
2697 DBUS_TYPE_OBJECT_PATH, &j,
2698 DBUS_TYPE_INVALID)) {
2699 log_error("Failed to parse reply.");
2713 int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
2714 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2715 const char *fail = "fail";
2721 r = bus_method_call_with_reply(
2723 "org.freedesktop.systemd1",
2724 "/org/freedesktop/systemd1",
2725 "org.freedesktop.systemd1.Manager",
2729 DBUS_TYPE_STRING, &unit,
2730 DBUS_TYPE_STRING, &fail,
2733 if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
2734 dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
2739 dbus_error_free(error);
2743 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
2751 if (!dbus_message_get_args(reply, error,
2752 DBUS_TYPE_OBJECT_PATH, &j,
2753 DBUS_TYPE_INVALID)) {
2754 log_error("Failed to parse reply.");
2768 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error) {
2769 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2776 w = who == KILL_LEADER ? "process" : "cgroup";
2777 assert_cc(sizeof(signo) == sizeof(int32_t));
2779 r = bus_method_call_with_reply(
2781 "org.freedesktop.systemd1",
2782 "/org/freedesktop/systemd1",
2783 "org.freedesktop.systemd1.Manager",
2787 DBUS_TYPE_STRING, &unit,
2788 DBUS_TYPE_STRING, &w,
2789 DBUS_TYPE_INT32, &signo,
2792 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
2799 int manager_unit_is_active(Manager *manager, const char *unit) {
2801 const char *interface = "org.freedesktop.systemd1.Unit";
2802 const char *property = "ActiveState";
2803 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2804 _cleanup_free_ char *path = NULL;
2805 DBusMessageIter iter, sub;
2813 dbus_error_init(&error);
2815 path = unit_dbus_path_from_name(unit);
2819 r = bus_method_call_with_reply(
2821 "org.freedesktop.systemd1",
2823 "org.freedesktop.DBus.Properties",
2827 DBUS_TYPE_STRING, &interface,
2828 DBUS_TYPE_STRING, &property,
2831 if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY) ||
2832 dbus_error_has_name(&error, DBUS_ERROR_DISCONNECTED)) {
2833 /* systemd might have droppped off
2834 * momentarily, let's not make this an
2837 dbus_error_free(&error);
2841 if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
2842 dbus_error_has_name(&error, BUS_ERROR_LOAD_FAILED)) {
2843 /* If the unit is already unloaded then it's
2846 dbus_error_free(&error);
2850 log_error("Failed to query ActiveState: %s", bus_error(&error, r));
2851 dbus_error_free(&error);
2855 if (!dbus_message_iter_init(reply, &iter) ||
2856 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
2857 log_error("Failed to parse reply.");
2861 dbus_message_iter_recurse(&iter, &sub);
2862 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
2863 log_error("Failed to parse reply.");
2867 dbus_message_iter_get_basic(&sub, &state);
2869 return !streq(state, "inactive") && !streq(state, "failed");