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->seat0)
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->seat0)
432 if (seat_has_vts(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)) {
557 log_warning("Existing logind session ID %s used by new audit session, ignoring", id);
570 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
575 } while (hashmap_get(m->sessions, id));
578 r = manager_add_user_by_uid(m, uid, &user);
582 r = manager_add_session(m, id, &session);
586 session_set_user(session, user);
588 session->leader = leader;
589 session->audit_id = audit_id;
592 session->remote = remote;
593 session->vtnr = vtnr;
596 session->tty = strdup(tty);
603 if (!isempty(display)) {
604 session->display = strdup(display);
605 if (!session->display) {
611 if (!isempty(remote_user)) {
612 session->remote_user = strdup(remote_user);
613 if (!session->remote_user) {
619 if (!isempty(remote_host)) {
620 session->remote_host = strdup(remote_host);
621 if (!session->remote_host) {
627 if (!isempty(service)) {
628 session->service = strdup(service);
629 if (!session->service) {
636 r = seat_attach_session(seat, session);
641 r = session_start(session);
645 session->create_message = dbus_message_ref(message);
647 /* Now, let's wait until the slice unit and stuff got
648 * created. We send the reply back from
649 * session_send_create_reply().*/
655 session_add_to_gc_queue(session);
658 user_add_to_gc_queue(user);
663 static int bus_manager_inhibit(
665 DBusConnection *connection,
666 DBusMessage *message,
668 DBusMessage **_reply) {
672 const char *who, *why, *what, *mode;
678 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
686 if (!dbus_message_get_args(
689 DBUS_TYPE_STRING, &what,
690 DBUS_TYPE_STRING, &who,
691 DBUS_TYPE_STRING, &why,
692 DBUS_TYPE_STRING, &mode,
693 DBUS_TYPE_INVALID)) {
698 w = inhibit_what_from_string(what);
704 mm = inhibit_mode_from_string(mode);
710 /* Delay is only supported for shutdown/sleep */
711 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
716 /* Don't allow taking delay locks while we are already
717 * executing the operation. We shouldn't create the impression
718 * that the lock was successful if the machine is about to go
719 * down/suspend any moment. */
720 if (m->action_what & w) {
725 r = verify_polkit(connection, message,
726 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
727 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
728 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
729 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
730 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
731 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
732 "org.freedesktop.login1.inhibit-handle-lid-switch",
737 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
738 if (ul == (unsigned long) -1) {
743 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
753 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
757 } while (hashmap_get(m->inhibitors, id));
759 r = manager_add_inhibitor(m, id, &i);
769 i->why = strdup(why);
770 i->who = strdup(who);
772 if (!i->why || !i->who) {
777 fifo_fd = inhibitor_create_fifo(i);
783 reply = dbus_message_new_method_return(message);
789 if (!dbus_message_append_args(
791 DBUS_TYPE_UNIX_FD, &fifo_fd,
792 DBUS_TYPE_INVALID)) {
797 close_nointr_nofail(fifo_fd);
810 close_nointr_nofail(fifo_fd);
815 static int trigger_device(Manager *m, struct udev_device *d) {
816 struct udev_enumerate *e;
817 struct udev_list_entry *first, *item;
822 e = udev_enumerate_new(m->udev);
829 if (udev_enumerate_add_match_parent(e, d) < 0) {
835 if (udev_enumerate_scan_devices(e) < 0) {
840 first = udev_enumerate_get_list_entry(e);
841 udev_list_entry_foreach(item, first) {
845 p = udev_list_entry_get_name(item);
847 t = strappend(p, "/uevent");
853 write_string_file(t, "change");
861 udev_enumerate_unref(e);
866 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
867 struct udev_device *d;
868 _cleanup_free_ char *rule = NULL, *file = NULL;
869 const char *id_for_seat;
876 d = udev_device_new_from_syspath(m->udev, sysfs);
880 if (!udev_device_has_tag(d, "seat")) {
885 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
891 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
896 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
901 mkdir_p_label("/etc/udev/rules.d", 0755);
903 r = write_string_file_atomic_label(file, rule);
907 r = trigger_device(m, d);
911 udev_device_unref(d);
916 static int flush_devices(Manager *m) {
917 _cleanup_closedir_ DIR *d;
921 d = opendir("/etc/udev/rules.d");
924 log_warning("Failed to open /etc/udev/rules.d: %m");
928 while ((de = readdir(d))) {
930 if (!dirent_is_file(de))
933 if (!startswith(de->d_name, "72-seat-"))
936 if (!endswith(de->d_name, ".rules"))
939 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
940 log_warning("Failed to unlink %s: %m", de->d_name);
944 return trigger_device(m, NULL);
947 static int have_multiple_sessions(
956 /* Check for other users' sessions. Greeter sessions do not
957 * count, and non-login sessions do not count either. */
958 HASHMAP_FOREACH(session, m->sessions, i)
959 if (session->class == SESSION_USER &&
961 session->user->uid != uid)
967 static int bus_manager_log_shutdown(
970 const char *unit_name) {
977 if (w != INHIBIT_SHUTDOWN)
980 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
981 p = "MESSAGE=System is powering down.";
982 q = "SHUTDOWN=power-off";
983 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
984 p = "MESSAGE=System is halting.";
986 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
987 p = "MESSAGE=System is rebooting.";
988 q = "SHUTDOWN=reboot";
989 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
990 p = "MESSAGE=System is rebooting with kexec.";
991 q = "SHUTDOWN=kexec";
993 p = "MESSAGE=System is shutting down.";
997 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1002 static int execute_shutdown_or_sleep(
1005 const char *unit_name,
1008 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1009 const char *mode = "replace-irreversibly", *p;
1015 assert(w < _INHIBIT_WHAT_MAX);
1018 bus_manager_log_shutdown(m, w, unit_name);
1020 r = bus_method_call_with_reply(
1022 "org.freedesktop.systemd1",
1023 "/org/freedesktop/systemd1",
1024 "org.freedesktop.systemd1.Manager",
1028 DBUS_TYPE_STRING, &unit_name,
1029 DBUS_TYPE_STRING, &mode,
1034 if (!dbus_message_get_args(
1037 DBUS_TYPE_OBJECT_PATH, &p,
1045 m->action_unit = unit_name;
1046 free(m->action_job);
1053 static int delay_shutdown_or_sleep(
1056 const char *unit_name) {
1060 assert(w < _INHIBIT_WHAT_MAX);
1063 m->action_timestamp = now(CLOCK_MONOTONIC);
1064 m->action_unit = unit_name;
1070 static int bus_manager_can_shutdown_or_sleep(
1072 DBusConnection *connection,
1073 DBusMessage *message,
1076 const char *action_multiple_sessions,
1077 const char *action_ignore_inhibit,
1078 const char *sleep_verb,
1080 DBusMessage **_reply) {
1082 bool multiple_sessions, challenge, blocked, b;
1083 const char *result = NULL;
1084 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1092 assert(w <= _INHIBIT_WHAT_MAX);
1094 assert(action_multiple_sessions);
1095 assert(action_ignore_inhibit);
1100 r = can_sleep(sleep_verb);
1109 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1110 if (ul == (unsigned long) -1)
1113 r = have_multiple_sessions(m, (uid_t) ul);
1117 multiple_sessions = r > 0;
1118 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1120 if (multiple_sessions) {
1121 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1128 result = "challenge";
1134 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1138 if (r > 0 && !result)
1140 else if (challenge && (!result || streq(result, "yes")))
1141 result = "challenge";
1146 if (!multiple_sessions && !blocked) {
1147 /* If neither inhibit nor multiple sessions
1148 * apply then just check the normal policy */
1150 r = verify_polkit(connection, message, action, false, &challenge, error);
1157 result = "challenge";
1163 reply = dbus_message_new_method_return(message);
1167 b = dbus_message_append_args(
1169 DBUS_TYPE_STRING, &result,
1179 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1180 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1181 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1182 [INHIBIT_SLEEP] = "PrepareForSleep"
1185 dbus_bool_t active = _active;
1186 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1190 assert(w < _INHIBIT_WHAT_MAX);
1191 assert(signal_name[w]);
1193 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1197 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1198 !dbus_connection_send(m->bus, message, NULL))
1204 int bus_manager_shutdown_or_sleep_now_or_later(
1206 const char *unit_name,
1216 assert(w <= _INHIBIT_WHAT_MAX);
1217 assert(!m->action_job);
1219 /* Tell everybody to prepare for shutdown/sleep */
1220 send_prepare_for(m, w, true);
1223 m->inhibit_delay_max > 0 &&
1224 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1227 /* Shutdown is delayed, keep in mind what we
1228 * want to do, and start a timeout */
1229 r = delay_shutdown_or_sleep(m, w, unit_name);
1231 /* Shutdown is not delayed, execute it
1233 r = execute_shutdown_or_sleep(m, w, unit_name, error);
1238 static int bus_manager_do_shutdown_or_sleep(
1240 DBusConnection *connection,
1241 DBusMessage *message,
1242 const char *unit_name,
1245 const char *action_multiple_sessions,
1246 const char *action_ignore_inhibit,
1247 const char *sleep_verb,
1249 DBusMessage **_reply) {
1251 dbus_bool_t interactive;
1252 bool multiple_sessions, blocked;
1253 DBusMessage *reply = NULL;
1262 assert(w <= _INHIBIT_WHAT_MAX);
1264 assert(action_multiple_sessions);
1265 assert(action_ignore_inhibit);
1269 /* Don't allow multiple jobs being executed at the same time */
1273 if (!dbus_message_get_args(
1276 DBUS_TYPE_BOOLEAN, &interactive,
1281 r = can_sleep(sleep_verb);
1289 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1290 if (ul == (unsigned long) -1)
1293 r = have_multiple_sessions(m, (uid_t) ul);
1297 multiple_sessions = r > 0;
1298 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1300 if (multiple_sessions) {
1301 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1307 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1312 if (!multiple_sessions && !blocked) {
1313 r = verify_polkit(connection, message, action, interactive, NULL, error);
1318 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1322 reply = dbus_message_new_method_return(message);
1330 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1332 static const BusProperty bus_login_manager_properties[] = {
1333 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1334 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1335 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1336 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1337 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1338 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1339 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1340 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1341 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1342 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1343 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1344 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1345 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1346 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1347 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1348 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1349 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1350 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1354 static DBusHandlerResult manager_message_handler(
1355 DBusConnection *connection,
1356 DBusMessage *message,
1359 Manager *m = userdata;
1362 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1369 dbus_error_init(&error);
1371 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1377 if (!dbus_message_get_args(
1380 DBUS_TYPE_STRING, &name,
1382 return bus_send_error_reply(connection, message, &error, -EINVAL);
1384 session = hashmap_get(m->sessions, name);
1386 return bus_send_error_reply(connection, message, &error, -ENOENT);
1388 reply = dbus_message_new_method_return(message);
1392 p = session_bus_path(session);
1396 b = dbus_message_append_args(
1398 DBUS_TYPE_OBJECT_PATH, &p,
1405 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1411 if (!dbus_message_get_args(
1414 DBUS_TYPE_UINT32, &pid,
1416 return bus_send_error_reply(connection, message, &error, -EINVAL);
1418 r = manager_get_session_by_pid(m, pid, &session);
1420 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1422 reply = dbus_message_new_method_return(message);
1426 p = session_bus_path(session);
1430 b = dbus_message_append_args(
1432 DBUS_TYPE_OBJECT_PATH, &p,
1439 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1445 if (!dbus_message_get_args(
1448 DBUS_TYPE_UINT32, &uid,
1450 return bus_send_error_reply(connection, message, &error, -EINVAL);
1452 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1454 return bus_send_error_reply(connection, message, &error, -ENOENT);
1456 reply = dbus_message_new_method_return(message);
1460 p = user_bus_path(user);
1464 b = dbus_message_append_args(
1466 DBUS_TYPE_OBJECT_PATH, &p,
1473 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUserByPID")) {
1479 if (!dbus_message_get_args(
1482 DBUS_TYPE_UINT32, &pid,
1484 return bus_send_error_reply(connection, message, &error, -EINVAL);
1486 r = manager_get_user_by_pid(m, pid, &user);
1488 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1490 reply = dbus_message_new_method_return(message);
1494 p = user_bus_path(user);
1498 b = dbus_message_append_args(
1500 DBUS_TYPE_OBJECT_PATH, &p,
1507 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1513 if (!dbus_message_get_args(
1516 DBUS_TYPE_STRING, &name,
1518 return bus_send_error_reply(connection, message, &error, -EINVAL);
1520 seat = hashmap_get(m->seats, name);
1522 return bus_send_error_reply(connection, message, &error, -ENOENT);
1524 reply = dbus_message_new_method_return(message);
1528 p = seat_bus_path(seat);
1532 b = dbus_message_append_args(
1534 DBUS_TYPE_OBJECT_PATH, &p,
1541 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1545 DBusMessageIter iter, sub;
1546 const char *empty = "";
1548 reply = dbus_message_new_method_return(message);
1552 dbus_message_iter_init_append(reply, &iter);
1554 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1557 HASHMAP_FOREACH(session, m->sessions, i) {
1558 DBusMessageIter sub2;
1561 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1564 uid = session->user->uid;
1566 p = session_bus_path(session);
1570 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1571 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1572 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1573 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1574 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1581 if (!dbus_message_iter_close_container(&sub, &sub2))
1585 if (!dbus_message_iter_close_container(&iter, &sub))
1588 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1591 DBusMessageIter iter, sub;
1593 reply = dbus_message_new_method_return(message);
1597 dbus_message_iter_init_append(reply, &iter);
1599 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1602 HASHMAP_FOREACH(user, m->users, i) {
1603 _cleanup_free_ char *p = NULL;
1604 DBusMessageIter sub2;
1607 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1612 p = user_bus_path(user);
1616 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1617 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1618 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1623 if (!dbus_message_iter_close_container(&sub, &sub2))
1627 if (!dbus_message_iter_close_container(&iter, &sub))
1630 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1633 DBusMessageIter iter, sub;
1635 reply = dbus_message_new_method_return(message);
1639 dbus_message_iter_init_append(reply, &iter);
1641 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1644 HASHMAP_FOREACH(seat, m->seats, i) {
1645 _cleanup_free_ char *p = NULL;
1646 DBusMessageIter sub2;
1648 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1651 p = seat_bus_path(seat);
1655 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1656 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1661 if (!dbus_message_iter_close_container(&sub, &sub2))
1665 if (!dbus_message_iter_close_container(&iter, &sub))
1668 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1669 Inhibitor *inhibitor;
1671 DBusMessageIter iter, sub;
1673 reply = dbus_message_new_method_return(message);
1677 dbus_message_iter_init_append(reply, &iter);
1679 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1682 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1683 DBusMessageIter sub2;
1684 dbus_uint32_t uid, pid;
1685 const char *what, *who, *why, *mode;
1687 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1690 what = strempty(inhibit_what_to_string(inhibitor->what));
1691 who = strempty(inhibitor->who);
1692 why = strempty(inhibitor->why);
1693 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1694 uid = (dbus_uint32_t) inhibitor->uid;
1695 pid = (dbus_uint32_t) inhibitor->pid;
1697 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1698 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1699 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1700 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1701 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1702 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1705 if (!dbus_message_iter_close_container(&sub, &sub2))
1709 if (!dbus_message_iter_close_container(&iter, &sub))
1713 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1715 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1718 return bus_send_error_reply(connection, message, &error, r);
1721 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1723 r = bus_manager_create_session(m, message);
1725 /* Don't delay the work on OOM here, since it might be
1726 * triggered by a low RLIMIT_NOFILE here (since we
1727 * send a dupped fd to the client), and we'd rather
1728 * see this fail quickly then be retried later */
1731 return bus_send_error_reply(connection, message, NULL, r);
1733 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1737 if (!dbus_message_get_args(
1740 DBUS_TYPE_STRING, &name,
1742 return bus_send_error_reply(connection, message, &error, -EINVAL);
1744 session = hashmap_get(m->sessions, name);
1746 return bus_send_error_reply(connection, message, &error, -ENOENT);
1748 /* We use the FIFO to detect stray sessions where the
1749 process invoking PAM dies abnormally. We need to make
1750 sure that that process is not killed if at the clean
1751 end of the session it closes the FIFO. Hence, with
1752 this call explicitly turn off the FIFO logic, so that
1753 the PAM code can finish clean up on its own */
1754 session_remove_fifo(session);
1756 reply = dbus_message_new_method_return(message);
1760 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1764 if (!dbus_message_get_args(
1767 DBUS_TYPE_STRING, &name,
1769 return bus_send_error_reply(connection, message, &error, -EINVAL);
1771 session = hashmap_get(m->sessions, name);
1773 return bus_send_error_reply(connection, message, &error, -ENOENT);
1775 r = session_activate(session);
1777 return bus_send_error_reply(connection, message, NULL, r);
1779 reply = dbus_message_new_method_return(message);
1783 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1784 const char *session_name, *seat_name;
1788 /* Same as ActivateSession() but refuses to work if
1789 * the seat doesn't match */
1791 if (!dbus_message_get_args(
1794 DBUS_TYPE_STRING, &session_name,
1795 DBUS_TYPE_STRING, &seat_name,
1797 return bus_send_error_reply(connection, message, &error, -EINVAL);
1799 session = hashmap_get(m->sessions, session_name);
1801 return bus_send_error_reply(connection, message, &error, -ENOENT);
1803 seat = hashmap_get(m->seats, seat_name);
1805 return bus_send_error_reply(connection, message, &error, -ENOENT);
1807 if (session->seat != seat)
1808 return bus_send_error_reply(connection, message, &error, -EINVAL);
1810 r = session_activate(session);
1812 return bus_send_error_reply(connection, message, NULL, r);
1814 reply = dbus_message_new_method_return(message);
1818 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1819 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1823 if (!dbus_message_get_args(
1826 DBUS_TYPE_STRING, &name,
1828 return bus_send_error_reply(connection, message, &error, -EINVAL);
1830 session = hashmap_get(m->sessions, name);
1832 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1834 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1837 reply = dbus_message_new_method_return(message);
1841 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1842 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1844 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
1846 bus_send_error_reply(connection, message, NULL, r);
1848 reply = dbus_message_new_method_return(message);
1852 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1859 if (!dbus_message_get_args(
1862 DBUS_TYPE_STRING, &name,
1863 DBUS_TYPE_STRING, &swho,
1864 DBUS_TYPE_INT32, &signo,
1866 return bus_send_error_reply(connection, message, &error, -EINVAL);
1871 who = kill_who_from_string(swho);
1873 return bus_send_error_reply(connection, message, &error, -EINVAL);
1876 if (signo <= 0 || signo >= _NSIG)
1877 return bus_send_error_reply(connection, message, &error, -EINVAL);
1879 session = hashmap_get(m->sessions, name);
1881 return bus_send_error_reply(connection, message, &error, -ENOENT);
1883 r = session_kill(session, who, signo);
1885 return bus_send_error_reply(connection, message, NULL, r);
1887 reply = dbus_message_new_method_return(message);
1891 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1896 if (!dbus_message_get_args(
1899 DBUS_TYPE_UINT32, &uid,
1900 DBUS_TYPE_INT32, &signo,
1902 return bus_send_error_reply(connection, message, &error, -EINVAL);
1904 if (signo <= 0 || signo >= _NSIG)
1905 return bus_send_error_reply(connection, message, &error, -EINVAL);
1907 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1909 return bus_send_error_reply(connection, message, &error, -ENOENT);
1911 r = user_kill(user, signo);
1913 return bus_send_error_reply(connection, message, NULL, r);
1915 reply = dbus_message_new_method_return(message);
1919 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1923 if (!dbus_message_get_args(
1926 DBUS_TYPE_STRING, &name,
1928 return bus_send_error_reply(connection, message, &error, -EINVAL);
1930 session = hashmap_get(m->sessions, name);
1932 return bus_send_error_reply(connection, message, &error, -ENOENT);
1934 r = session_stop(session);
1936 return bus_send_error_reply(connection, message, NULL, r);
1938 reply = dbus_message_new_method_return(message);
1942 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1946 if (!dbus_message_get_args(
1949 DBUS_TYPE_UINT32, &uid,
1951 return bus_send_error_reply(connection, message, &error, -EINVAL);
1953 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1955 return bus_send_error_reply(connection, message, &error, -ENOENT);
1957 r = user_stop(user);
1959 return bus_send_error_reply(connection, message, NULL, r);
1961 reply = dbus_message_new_method_return(message);
1965 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1969 if (!dbus_message_get_args(
1972 DBUS_TYPE_STRING, &name,
1974 return bus_send_error_reply(connection, message, &error, -EINVAL);
1976 seat = hashmap_get(m->seats, name);
1978 return bus_send_error_reply(connection, message, &error, -ENOENT);
1980 r = seat_stop_sessions(seat);
1982 return bus_send_error_reply(connection, message, NULL, r);
1984 reply = dbus_message_new_method_return(message);
1988 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1991 dbus_bool_t b, interactive;
1994 if (!dbus_message_get_args(
1997 DBUS_TYPE_UINT32, &uid,
1998 DBUS_TYPE_BOOLEAN, &b,
1999 DBUS_TYPE_BOOLEAN, &interactive,
2001 return bus_send_error_reply(connection, message, &error, -EINVAL);
2006 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2008 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2010 return bus_send_error_reply(connection, message, &error, r);
2012 mkdir_p_label("/var/lib/systemd", 0755);
2014 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2016 return bus_send_error_reply(connection, message, &error, r);
2018 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2029 return bus_send_error_reply(connection, message, &error, r);
2031 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2040 if (r < 0 && errno != ENOENT)
2041 return bus_send_error_reply(connection, message, &error, -errno);
2043 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2045 user_add_to_gc_queue(u);
2048 reply = dbus_message_new_method_return(message);
2052 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2053 const char *sysfs, *seat;
2054 dbus_bool_t interactive;
2056 if (!dbus_message_get_args(
2059 DBUS_TYPE_STRING, &seat,
2060 DBUS_TYPE_STRING, &sysfs,
2061 DBUS_TYPE_BOOLEAN, &interactive,
2063 return bus_send_error_reply(connection, message, &error, -EINVAL);
2065 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2066 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2068 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2070 return bus_send_error_reply(connection, message, &error, r);
2072 r = attach_device(m, seat, sysfs);
2074 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2076 reply = dbus_message_new_method_return(message);
2081 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2082 dbus_bool_t interactive;
2084 if (!dbus_message_get_args(
2087 DBUS_TYPE_BOOLEAN, &interactive,
2089 return bus_send_error_reply(connection, message, &error, -EINVAL);
2091 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2093 return bus_send_error_reply(connection, message, &error, r);
2095 r = flush_devices(m);
2097 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2099 reply = dbus_message_new_method_return(message);
2103 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2105 r = bus_manager_do_shutdown_or_sleep(
2106 m, connection, message,
2107 SPECIAL_POWEROFF_TARGET,
2109 "org.freedesktop.login1.power-off",
2110 "org.freedesktop.login1.power-off-multiple-sessions",
2111 "org.freedesktop.login1.power-off-ignore-inhibit",
2115 return bus_send_error_reply(connection, message, &error, r);
2116 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2117 r = bus_manager_do_shutdown_or_sleep(
2118 m, connection, message,
2119 SPECIAL_REBOOT_TARGET,
2121 "org.freedesktop.login1.reboot",
2122 "org.freedesktop.login1.reboot-multiple-sessions",
2123 "org.freedesktop.login1.reboot-ignore-inhibit",
2127 return bus_send_error_reply(connection, message, &error, r);
2129 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2130 r = bus_manager_do_shutdown_or_sleep(
2131 m, connection, message,
2132 SPECIAL_SUSPEND_TARGET,
2134 "org.freedesktop.login1.suspend",
2135 "org.freedesktop.login1.suspend-multiple-sessions",
2136 "org.freedesktop.login1.suspend-ignore-inhibit",
2140 return bus_send_error_reply(connection, message, &error, r);
2141 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2142 r = bus_manager_do_shutdown_or_sleep(
2143 m, connection, message,
2144 SPECIAL_HIBERNATE_TARGET,
2146 "org.freedesktop.login1.hibernate",
2147 "org.freedesktop.login1.hibernate-multiple-sessions",
2148 "org.freedesktop.login1.hibernate-ignore-inhibit",
2152 return bus_send_error_reply(connection, message, &error, r);
2154 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2155 r = bus_manager_do_shutdown_or_sleep(
2156 m, connection, message,
2157 SPECIAL_HYBRID_SLEEP_TARGET,
2159 "org.freedesktop.login1.hibernate",
2160 "org.freedesktop.login1.hibernate-multiple-sessions",
2161 "org.freedesktop.login1.hibernate-ignore-inhibit",
2165 return bus_send_error_reply(connection, message, &error, r);
2167 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2169 r = bus_manager_can_shutdown_or_sleep(
2170 m, connection, message,
2172 "org.freedesktop.login1.power-off",
2173 "org.freedesktop.login1.power-off-multiple-sessions",
2174 "org.freedesktop.login1.power-off-ignore-inhibit",
2178 return bus_send_error_reply(connection, message, &error, r);
2179 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2180 r = bus_manager_can_shutdown_or_sleep(
2181 m, connection, message,
2183 "org.freedesktop.login1.reboot",
2184 "org.freedesktop.login1.reboot-multiple-sessions",
2185 "org.freedesktop.login1.reboot-ignore-inhibit",
2189 return bus_send_error_reply(connection, message, &error, r);
2191 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2192 r = bus_manager_can_shutdown_or_sleep(
2193 m, connection, message,
2195 "org.freedesktop.login1.suspend",
2196 "org.freedesktop.login1.suspend-multiple-sessions",
2197 "org.freedesktop.login1.suspend-ignore-inhibit",
2201 return bus_send_error_reply(connection, message, &error, r);
2203 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2204 r = bus_manager_can_shutdown_or_sleep(
2205 m, connection, message,
2207 "org.freedesktop.login1.hibernate",
2208 "org.freedesktop.login1.hibernate-multiple-sessions",
2209 "org.freedesktop.login1.hibernate-ignore-inhibit",
2213 return bus_send_error_reply(connection, message, &error, r);
2215 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2216 r = bus_manager_can_shutdown_or_sleep(
2217 m, connection, message,
2219 "org.freedesktop.login1.hibernate",
2220 "org.freedesktop.login1.hibernate-multiple-sessions",
2221 "org.freedesktop.login1.hibernate-ignore-inhibit",
2225 return bus_send_error_reply(connection, message, &error, r);
2227 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2228 char *introspection = NULL;
2237 if (!(reply = dbus_message_new_method_return(message)))
2240 /* We roll our own introspection code here, instead of
2241 * relying on bus_default_message_handler() because we
2242 * need to generate our introspection string
2245 if (!(f = open_memstream(&introspection, &size)))
2248 fputs(INTROSPECTION_BEGIN, f);
2250 HASHMAP_FOREACH(seat, m->seats, i) {
2251 p = bus_path_escape(seat->id);
2254 fprintf(f, "<node name=\"seat/%s\"/>", p);
2259 HASHMAP_FOREACH(user, m->users, i)
2260 fprintf(f, "<node name=\"user/_%llu\"/>", (unsigned long long) user->uid);
2262 HASHMAP_FOREACH(session, m->sessions, i) {
2263 p = bus_path_escape(session->id);
2266 fprintf(f, "<node name=\"session/%s\"/>", p);
2271 fputs(INTROSPECTION_END, f);
2275 free(introspection);
2284 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2285 free(introspection);
2289 free(introspection);
2291 const BusBoundProperties bps[] = {
2292 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2295 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2299 if (!bus_maybe_send_reply(connection, message, reply))
2303 return DBUS_HANDLER_RESULT_HANDLED;
2306 dbus_error_free(&error);
2308 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2311 const DBusObjectPathVTable bus_manager_vtable = {
2312 .message_function = manager_message_handler
2315 DBusHandlerResult bus_message_filter(
2316 DBusConnection *connection,
2317 DBusMessage *message,
2320 Manager *m = userdata;
2327 dbus_error_init(&error);
2329 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)));
2331 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2332 const char *path, *result, *unit;
2335 if (!dbus_message_get_args(message, &error,
2336 DBUS_TYPE_UINT32, &id,
2337 DBUS_TYPE_OBJECT_PATH, &path,
2338 DBUS_TYPE_STRING, &unit,
2339 DBUS_TYPE_STRING, &result,
2340 DBUS_TYPE_INVALID)) {
2341 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2345 if (m->action_job && streq(m->action_job, path)) {
2346 log_info("Operation finished.");
2348 /* Tell people that they now may take a lock again */
2349 send_prepare_for(m, m->action_what, false);
2351 free(m->action_job);
2352 m->action_job = NULL;
2353 m->action_unit = NULL;
2360 s = hashmap_get(m->session_units, unit);
2362 if (streq_ptr(path, s->scope_job)) {
2364 s->scope_job = NULL;
2367 if (streq(result, "done"))
2368 session_send_create_reply(s, NULL);
2370 dbus_set_error(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
2371 session_send_create_reply(s, &error);
2377 session_add_to_gc_queue(s);
2380 u = hashmap_get(m->user_units, unit);
2382 if (streq_ptr(path, u->service_job)) {
2383 free(u->service_job);
2384 u->service_job = NULL;
2387 if (streq_ptr(path, u->slice_job)) {
2389 u->slice_job = NULL;
2393 user_add_to_gc_queue(u);
2397 } else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
2399 _cleanup_free_ char *unit = NULL;
2402 path = dbus_message_get_path(message);
2406 unit_name_from_dbus_path(path, &unit);
2411 s = hashmap_get(m->session_units, unit);
2413 session_add_to_gc_queue(s);
2415 u = hashmap_get(m->user_units, unit);
2417 user_add_to_gc_queue(u);
2420 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitRemoved")) {
2422 const char *path, *unit;
2426 if (!dbus_message_get_args(message, &error,
2427 DBUS_TYPE_STRING, &unit,
2428 DBUS_TYPE_OBJECT_PATH, &path,
2429 DBUS_TYPE_INVALID)) {
2430 log_error("Failed to parse UnitRemoved message: %s", bus_error_message(&error));
2434 session = hashmap_get(m->session_units, unit);
2436 session_add_to_gc_queue(session);
2438 user = hashmap_get(m->user_units, unit);
2440 user_add_to_gc_queue(user);
2442 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "Reloading")) {
2445 if (!dbus_message_get_args(message, &error,
2446 DBUS_TYPE_BOOLEAN, &b,
2447 DBUS_TYPE_INVALID)) {
2448 log_error("Failed to parse Reloading message: %s", bus_error_message(&error));
2452 /* systemd finished reloading, let's recheck all our sessions */
2457 log_debug("System manager has been reloaded, rechecking sessions...");
2459 HASHMAP_FOREACH(session, m->sessions, i)
2460 session_add_to_gc_queue(session);
2463 } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
2464 const char *name, *old, *new;
2467 if (!dbus_message_get_args(message, &error,
2468 DBUS_TYPE_STRING, &name,
2469 DBUS_TYPE_STRING, &old,
2470 DBUS_TYPE_STRING, &new,
2471 DBUS_TYPE_INVALID)) {
2472 log_error("Failed to parse NameOwnerChanged message: %s", bus_error_message(&error));
2476 /* drop all controllers owned by this name */
2477 if (*old && !*new && (key = hashmap_remove(m->busnames, old))) {
2483 HASHMAP_FOREACH(session, m->sessions, i)
2484 if (session_is_controller(session, old))
2485 session_drop_controller(session);
2490 dbus_error_free(&error);
2492 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2495 int manager_send_changed(Manager *manager, const char *properties) {
2496 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
2500 m = bus_properties_changed_new("/org/freedesktop/login1",
2501 "org.freedesktop.login1.Manager",
2506 if (!dbus_connection_send(manager->bus, m, NULL))
2512 int manager_dispatch_delayed(Manager *manager) {
2518 if (manager->action_what == 0 || manager->action_job)
2521 /* Continue delay? */
2522 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
2524 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2527 log_info("Delay lock is active but inhibitor timeout is reached.");
2530 /* Actually do the operation */
2531 dbus_error_init(&error);
2532 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
2534 log_warning("Failed to send delayed message: %s", bus_error(&error, r));
2535 dbus_error_free(&error);
2537 manager->action_unit = NULL;
2538 manager->action_what = 0;
2545 int manager_start_scope(
2550 const char *description,
2552 const char *kill_mode,
2556 const char *timeout_stop_property = "TimeoutStopUSec", *send_sighup_property = "SendSIGHUP", *pids_property = "PIDs";
2557 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2558 DBusMessageIter iter, sub, sub2, sub3, sub4;
2559 uint64_t timeout = 500 * USEC_PER_MSEC;
2560 dbus_bool_t send_sighup = true;
2561 const char *fail = "fail";
2571 m = dbus_message_new_method_call(
2572 "org.freedesktop.systemd1",
2573 "/org/freedesktop/systemd1",
2574 "org.freedesktop.systemd1.Manager",
2575 "StartTransientUnit");
2579 dbus_message_iter_init_append(m, &iter);
2581 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &scope) ||
2582 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &fail) ||
2583 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub))
2586 if (!isempty(slice)) {
2587 const char *slice_property = "Slice";
2589 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2590 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &slice_property) ||
2591 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2592 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &slice) ||
2593 !dbus_message_iter_close_container(&sub2, &sub3) ||
2594 !dbus_message_iter_close_container(&sub, &sub2))
2598 if (!isempty(description)) {
2599 const char *description_property = "Description";
2601 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2602 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description_property) ||
2603 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2604 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &description) ||
2605 !dbus_message_iter_close_container(&sub2, &sub3) ||
2606 !dbus_message_iter_close_container(&sub, &sub2))
2610 if (!isempty(after)) {
2611 const char *after_property = "After";
2613 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2614 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &after_property) ||
2615 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "as", &sub3) ||
2616 !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "s", &sub4) ||
2617 !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_STRING, &after) ||
2618 !dbus_message_iter_close_container(&sub3, &sub4) ||
2619 !dbus_message_iter_close_container(&sub2, &sub3) ||
2620 !dbus_message_iter_close_container(&sub, &sub2))
2624 if (!isempty(kill_mode)) {
2625 const char *kill_mode_property = "KillMode";
2627 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2628 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &kill_mode_property) ||
2629 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2630 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &kill_mode) ||
2631 !dbus_message_iter_close_container(&sub2, &sub3) ||
2632 !dbus_message_iter_close_container(&sub, &sub2))
2636 /* cgroup empty notification is not available in containers
2637 * currently. To make this less problematic, let's shorten the
2638 * stop timeout for sessions, so that we don't wait
2641 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2642 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &timeout_stop_property) ||
2643 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "t", &sub3) ||
2644 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &timeout) ||
2645 !dbus_message_iter_close_container(&sub2, &sub3) ||
2646 !dbus_message_iter_close_container(&sub, &sub2))
2649 /* Make sure that the session shells are terminated with
2650 * SIGHUP since bash and friends tend to ignore SIGTERM */
2651 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2652 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &send_sighup_property) ||
2653 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "b", &sub3) ||
2654 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_BOOLEAN, &send_sighup) ||
2655 !dbus_message_iter_close_container(&sub2, &sub3) ||
2656 !dbus_message_iter_close_container(&sub, &sub2))
2660 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2661 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &pids_property) ||
2662 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "au", &sub3) ||
2663 !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "u", &sub4) ||
2664 !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_UINT32, &u) ||
2665 !dbus_message_iter_close_container(&sub3, &sub4) ||
2666 !dbus_message_iter_close_container(&sub2, &sub3) ||
2667 !dbus_message_iter_close_container(&sub, &sub2))
2670 if (!dbus_message_iter_close_container(&iter, &sub))
2673 reply = dbus_connection_send_with_reply_and_block(manager->bus, m, -1, error);
2681 if (!dbus_message_get_args(reply, error, DBUS_TYPE_OBJECT_PATH, &j, DBUS_TYPE_INVALID))
2694 int manager_start_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
2695 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2696 const char *fail = "fail";
2702 r = bus_method_call_with_reply(
2704 "org.freedesktop.systemd1",
2705 "/org/freedesktop/systemd1",
2706 "org.freedesktop.systemd1.Manager",
2710 DBUS_TYPE_STRING, &unit,
2711 DBUS_TYPE_STRING, &fail,
2714 log_error("Failed to start 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_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
2740 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2741 const char *fail = "fail";
2747 r = bus_method_call_with_reply(
2749 "org.freedesktop.systemd1",
2750 "/org/freedesktop/systemd1",
2751 "org.freedesktop.systemd1.Manager",
2755 DBUS_TYPE_STRING, &unit,
2756 DBUS_TYPE_STRING, &fail,
2759 if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
2760 dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
2765 dbus_error_free(error);
2769 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
2777 if (!dbus_message_get_args(reply, error,
2778 DBUS_TYPE_OBJECT_PATH, &j,
2779 DBUS_TYPE_INVALID)) {
2780 log_error("Failed to parse reply.");
2794 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error) {
2795 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2802 w = who == KILL_LEADER ? "process" : "cgroup";
2803 assert_cc(sizeof(signo) == sizeof(int32_t));
2805 r = bus_method_call_with_reply(
2807 "org.freedesktop.systemd1",
2808 "/org/freedesktop/systemd1",
2809 "org.freedesktop.systemd1.Manager",
2813 DBUS_TYPE_STRING, &unit,
2814 DBUS_TYPE_STRING, &w,
2815 DBUS_TYPE_INT32, &signo,
2818 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
2825 int manager_unit_is_active(Manager *manager, const char *unit) {
2827 const char *interface = "org.freedesktop.systemd1.Unit";
2828 const char *property = "ActiveState";
2829 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2830 _cleanup_free_ char *path = NULL;
2831 DBusMessageIter iter, sub;
2839 dbus_error_init(&error);
2841 path = unit_dbus_path_from_name(unit);
2845 r = bus_method_call_with_reply(
2847 "org.freedesktop.systemd1",
2849 "org.freedesktop.DBus.Properties",
2853 DBUS_TYPE_STRING, &interface,
2854 DBUS_TYPE_STRING, &property,
2857 if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY) ||
2858 dbus_error_has_name(&error, DBUS_ERROR_DISCONNECTED)) {
2859 /* systemd might have droppped off
2860 * momentarily, let's not make this an
2863 dbus_error_free(&error);
2867 if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
2868 dbus_error_has_name(&error, BUS_ERROR_LOAD_FAILED)) {
2869 /* If the unit is already unloaded then it's
2872 dbus_error_free(&error);
2876 log_error("Failed to query ActiveState: %s", bus_error(&error, r));
2877 dbus_error_free(&error);
2881 if (!dbus_message_iter_init(reply, &iter) ||
2882 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
2883 log_error("Failed to parse reply.");
2887 dbus_message_iter_recurse(&iter, &sub);
2888 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
2889 log_error("Failed to parse reply.");
2893 dbus_message_iter_get_basic(&sub, &state);
2895 return !streq(state, "inactive") && !streq(state, "failed");