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 &&
960 session->user->uid != uid)
966 static int bus_manager_log_shutdown(
969 const char *unit_name) {
976 if (w != INHIBIT_SHUTDOWN)
979 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
980 p = "MESSAGE=System is powering down.";
981 q = "SHUTDOWN=power-off";
982 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
983 p = "MESSAGE=System is halting.";
985 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
986 p = "MESSAGE=System is rebooting.";
987 q = "SHUTDOWN=reboot";
988 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
989 p = "MESSAGE=System is rebooting with kexec.";
990 q = "SHUTDOWN=kexec";
992 p = "MESSAGE=System is shutting down.";
996 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1001 static int execute_shutdown_or_sleep(
1004 const char *unit_name,
1007 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1008 const char *mode = "replace-irreversibly", *p;
1014 assert(w < _INHIBIT_WHAT_MAX);
1017 bus_manager_log_shutdown(m, w, unit_name);
1019 r = bus_method_call_with_reply(
1021 "org.freedesktop.systemd1",
1022 "/org/freedesktop/systemd1",
1023 "org.freedesktop.systemd1.Manager",
1027 DBUS_TYPE_STRING, &unit_name,
1028 DBUS_TYPE_STRING, &mode,
1033 if (!dbus_message_get_args(
1036 DBUS_TYPE_OBJECT_PATH, &p,
1044 m->action_unit = unit_name;
1045 free(m->action_job);
1052 static int delay_shutdown_or_sleep(
1055 const char *unit_name) {
1059 assert(w < _INHIBIT_WHAT_MAX);
1062 m->action_timestamp = now(CLOCK_MONOTONIC);
1063 m->action_unit = unit_name;
1069 static int bus_manager_can_shutdown_or_sleep(
1071 DBusConnection *connection,
1072 DBusMessage *message,
1075 const char *action_multiple_sessions,
1076 const char *action_ignore_inhibit,
1077 const char *sleep_verb,
1079 DBusMessage **_reply) {
1081 bool multiple_sessions, challenge, blocked, b;
1082 const char *result = NULL;
1083 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1091 assert(w <= _INHIBIT_WHAT_MAX);
1093 assert(action_multiple_sessions);
1094 assert(action_ignore_inhibit);
1099 r = can_sleep(sleep_verb);
1108 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1109 if (ul == (unsigned long) -1)
1112 r = have_multiple_sessions(m, (uid_t) ul);
1116 multiple_sessions = r > 0;
1117 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1119 if (multiple_sessions) {
1120 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1127 result = "challenge";
1133 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1137 if (r > 0 && !result)
1139 else if (challenge && (!result || streq(result, "yes")))
1140 result = "challenge";
1145 if (!multiple_sessions && !blocked) {
1146 /* If neither inhibit nor multiple sessions
1147 * apply then just check the normal policy */
1149 r = verify_polkit(connection, message, action, false, &challenge, error);
1156 result = "challenge";
1162 reply = dbus_message_new_method_return(message);
1166 b = dbus_message_append_args(
1168 DBUS_TYPE_STRING, &result,
1178 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1179 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1180 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1181 [INHIBIT_SLEEP] = "PrepareForSleep"
1184 dbus_bool_t active = _active;
1185 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1189 assert(w < _INHIBIT_WHAT_MAX);
1190 assert(signal_name[w]);
1192 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1196 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1197 !dbus_connection_send(m->bus, message, NULL))
1203 int bus_manager_shutdown_or_sleep_now_or_later(
1205 const char *unit_name,
1215 assert(w <= _INHIBIT_WHAT_MAX);
1216 assert(!m->action_job);
1218 /* Tell everybody to prepare for shutdown/sleep */
1219 send_prepare_for(m, w, true);
1222 m->inhibit_delay_max > 0 &&
1223 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1226 /* Shutdown is delayed, keep in mind what we
1227 * want to do, and start a timeout */
1228 r = delay_shutdown_or_sleep(m, w, unit_name);
1230 /* Shutdown is not delayed, execute it
1232 r = execute_shutdown_or_sleep(m, w, unit_name, error);
1237 static int bus_manager_do_shutdown_or_sleep(
1239 DBusConnection *connection,
1240 DBusMessage *message,
1241 const char *unit_name,
1244 const char *action_multiple_sessions,
1245 const char *action_ignore_inhibit,
1246 const char *sleep_verb,
1248 DBusMessage **_reply) {
1250 dbus_bool_t interactive;
1251 bool multiple_sessions, blocked;
1252 DBusMessage *reply = NULL;
1261 assert(w <= _INHIBIT_WHAT_MAX);
1263 assert(action_multiple_sessions);
1264 assert(action_ignore_inhibit);
1268 /* Don't allow multiple jobs being executed at the same time */
1272 if (!dbus_message_get_args(
1275 DBUS_TYPE_BOOLEAN, &interactive,
1280 r = can_sleep(sleep_verb);
1288 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1289 if (ul == (unsigned long) -1)
1292 r = have_multiple_sessions(m, (uid_t) ul);
1296 multiple_sessions = r > 0;
1297 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1299 if (multiple_sessions) {
1300 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1306 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1311 if (!multiple_sessions && !blocked) {
1312 r = verify_polkit(connection, message, action, interactive, NULL, error);
1317 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1321 reply = dbus_message_new_method_return(message);
1329 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1331 static const BusProperty bus_login_manager_properties[] = {
1332 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1333 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1334 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1335 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1336 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1337 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1338 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1339 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1340 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1341 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1342 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1343 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1344 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1345 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1346 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1347 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1348 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1349 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1353 static DBusHandlerResult manager_message_handler(
1354 DBusConnection *connection,
1355 DBusMessage *message,
1358 Manager *m = userdata;
1361 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1368 dbus_error_init(&error);
1370 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1376 if (!dbus_message_get_args(
1379 DBUS_TYPE_STRING, &name,
1381 return bus_send_error_reply(connection, message, &error, -EINVAL);
1383 session = hashmap_get(m->sessions, name);
1385 return bus_send_error_reply(connection, message, &error, -ENOENT);
1387 reply = dbus_message_new_method_return(message);
1391 p = session_bus_path(session);
1395 b = dbus_message_append_args(
1397 DBUS_TYPE_OBJECT_PATH, &p,
1404 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1410 if (!dbus_message_get_args(
1413 DBUS_TYPE_UINT32, &pid,
1415 return bus_send_error_reply(connection, message, &error, -EINVAL);
1417 r = manager_get_session_by_pid(m, pid, &session);
1419 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1421 reply = dbus_message_new_method_return(message);
1425 p = session_bus_path(session);
1429 b = dbus_message_append_args(
1431 DBUS_TYPE_OBJECT_PATH, &p,
1438 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1444 if (!dbus_message_get_args(
1447 DBUS_TYPE_UINT32, &uid,
1449 return bus_send_error_reply(connection, message, &error, -EINVAL);
1451 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1453 return bus_send_error_reply(connection, message, &error, -ENOENT);
1455 reply = dbus_message_new_method_return(message);
1459 p = user_bus_path(user);
1463 b = dbus_message_append_args(
1465 DBUS_TYPE_OBJECT_PATH, &p,
1472 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUserByPID")) {
1478 if (!dbus_message_get_args(
1481 DBUS_TYPE_UINT32, &pid,
1483 return bus_send_error_reply(connection, message, &error, -EINVAL);
1485 r = manager_get_user_by_pid(m, pid, &user);
1487 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1489 reply = dbus_message_new_method_return(message);
1493 p = user_bus_path(user);
1497 b = dbus_message_append_args(
1499 DBUS_TYPE_OBJECT_PATH, &p,
1506 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1512 if (!dbus_message_get_args(
1515 DBUS_TYPE_STRING, &name,
1517 return bus_send_error_reply(connection, message, &error, -EINVAL);
1519 seat = hashmap_get(m->seats, name);
1521 return bus_send_error_reply(connection, message, &error, -ENOENT);
1523 reply = dbus_message_new_method_return(message);
1527 p = seat_bus_path(seat);
1531 b = dbus_message_append_args(
1533 DBUS_TYPE_OBJECT_PATH, &p,
1540 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1544 DBusMessageIter iter, sub;
1545 const char *empty = "";
1547 reply = dbus_message_new_method_return(message);
1551 dbus_message_iter_init_append(reply, &iter);
1553 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1556 HASHMAP_FOREACH(session, m->sessions, i) {
1557 DBusMessageIter sub2;
1560 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1563 uid = session->user->uid;
1565 p = session_bus_path(session);
1569 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1570 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1571 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1572 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1573 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1580 if (!dbus_message_iter_close_container(&sub, &sub2))
1584 if (!dbus_message_iter_close_container(&iter, &sub))
1587 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1590 DBusMessageIter iter, sub;
1592 reply = dbus_message_new_method_return(message);
1596 dbus_message_iter_init_append(reply, &iter);
1598 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1601 HASHMAP_FOREACH(user, m->users, i) {
1602 _cleanup_free_ char *p = NULL;
1603 DBusMessageIter sub2;
1606 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1611 p = user_bus_path(user);
1615 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1616 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1617 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1622 if (!dbus_message_iter_close_container(&sub, &sub2))
1626 if (!dbus_message_iter_close_container(&iter, &sub))
1629 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1632 DBusMessageIter iter, sub;
1634 reply = dbus_message_new_method_return(message);
1638 dbus_message_iter_init_append(reply, &iter);
1640 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1643 HASHMAP_FOREACH(seat, m->seats, i) {
1644 _cleanup_free_ char *p = NULL;
1645 DBusMessageIter sub2;
1647 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1650 p = seat_bus_path(seat);
1654 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1655 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1660 if (!dbus_message_iter_close_container(&sub, &sub2))
1664 if (!dbus_message_iter_close_container(&iter, &sub))
1667 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1668 Inhibitor *inhibitor;
1670 DBusMessageIter iter, sub;
1672 reply = dbus_message_new_method_return(message);
1676 dbus_message_iter_init_append(reply, &iter);
1678 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1681 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1682 DBusMessageIter sub2;
1683 dbus_uint32_t uid, pid;
1684 const char *what, *who, *why, *mode;
1686 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1689 what = strempty(inhibit_what_to_string(inhibitor->what));
1690 who = strempty(inhibitor->who);
1691 why = strempty(inhibitor->why);
1692 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1693 uid = (dbus_uint32_t) inhibitor->uid;
1694 pid = (dbus_uint32_t) inhibitor->pid;
1696 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1697 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1698 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1699 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1700 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1701 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1704 if (!dbus_message_iter_close_container(&sub, &sub2))
1708 if (!dbus_message_iter_close_container(&iter, &sub))
1712 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1714 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1717 return bus_send_error_reply(connection, message, &error, r);
1720 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1722 r = bus_manager_create_session(m, message);
1724 /* Don't delay the work on OOM here, since it might be
1725 * triggered by a low RLIMIT_NOFILE here (since we
1726 * send a dupped fd to the client), and we'd rather
1727 * see this fail quickly then be retried later */
1730 return bus_send_error_reply(connection, message, NULL, r);
1732 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1736 if (!dbus_message_get_args(
1739 DBUS_TYPE_STRING, &name,
1741 return bus_send_error_reply(connection, message, &error, -EINVAL);
1743 session = hashmap_get(m->sessions, name);
1745 return bus_send_error_reply(connection, message, &error, -ENOENT);
1747 /* We use the FIFO to detect stray sessions where the
1748 process invoking PAM dies abnormally. We need to make
1749 sure that that process is not killed if at the clean
1750 end of the session it closes the FIFO. Hence, with
1751 this call explicitly turn off the FIFO logic, so that
1752 the PAM code can finish clean up on its own */
1753 session_remove_fifo(session);
1755 reply = dbus_message_new_method_return(message);
1759 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1763 if (!dbus_message_get_args(
1766 DBUS_TYPE_STRING, &name,
1768 return bus_send_error_reply(connection, message, &error, -EINVAL);
1770 session = hashmap_get(m->sessions, name);
1772 return bus_send_error_reply(connection, message, &error, -ENOENT);
1774 r = session_activate(session);
1776 return bus_send_error_reply(connection, message, NULL, r);
1778 reply = dbus_message_new_method_return(message);
1782 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1783 const char *session_name, *seat_name;
1787 /* Same as ActivateSession() but refuses to work if
1788 * the seat doesn't match */
1790 if (!dbus_message_get_args(
1793 DBUS_TYPE_STRING, &session_name,
1794 DBUS_TYPE_STRING, &seat_name,
1796 return bus_send_error_reply(connection, message, &error, -EINVAL);
1798 session = hashmap_get(m->sessions, session_name);
1800 return bus_send_error_reply(connection, message, &error, -ENOENT);
1802 seat = hashmap_get(m->seats, seat_name);
1804 return bus_send_error_reply(connection, message, &error, -ENOENT);
1806 if (session->seat != seat)
1807 return bus_send_error_reply(connection, message, &error, -EINVAL);
1809 r = session_activate(session);
1811 return bus_send_error_reply(connection, message, NULL, r);
1813 reply = dbus_message_new_method_return(message);
1817 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1818 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1822 if (!dbus_message_get_args(
1825 DBUS_TYPE_STRING, &name,
1827 return bus_send_error_reply(connection, message, &error, -EINVAL);
1829 session = hashmap_get(m->sessions, name);
1831 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1833 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1836 reply = dbus_message_new_method_return(message);
1840 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1841 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1843 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
1845 bus_send_error_reply(connection, message, NULL, r);
1847 reply = dbus_message_new_method_return(message);
1851 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1858 if (!dbus_message_get_args(
1861 DBUS_TYPE_STRING, &name,
1862 DBUS_TYPE_STRING, &swho,
1863 DBUS_TYPE_INT32, &signo,
1865 return bus_send_error_reply(connection, message, &error, -EINVAL);
1870 who = kill_who_from_string(swho);
1872 return bus_send_error_reply(connection, message, &error, -EINVAL);
1875 if (signo <= 0 || signo >= _NSIG)
1876 return bus_send_error_reply(connection, message, &error, -EINVAL);
1878 session = hashmap_get(m->sessions, name);
1880 return bus_send_error_reply(connection, message, &error, -ENOENT);
1882 r = session_kill(session, who, signo);
1884 return bus_send_error_reply(connection, message, NULL, r);
1886 reply = dbus_message_new_method_return(message);
1890 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1895 if (!dbus_message_get_args(
1898 DBUS_TYPE_UINT32, &uid,
1899 DBUS_TYPE_INT32, &signo,
1901 return bus_send_error_reply(connection, message, &error, -EINVAL);
1903 if (signo <= 0 || signo >= _NSIG)
1904 return bus_send_error_reply(connection, message, &error, -EINVAL);
1906 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1908 return bus_send_error_reply(connection, message, &error, -ENOENT);
1910 r = user_kill(user, signo);
1912 return bus_send_error_reply(connection, message, NULL, r);
1914 reply = dbus_message_new_method_return(message);
1918 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1922 if (!dbus_message_get_args(
1925 DBUS_TYPE_STRING, &name,
1927 return bus_send_error_reply(connection, message, &error, -EINVAL);
1929 session = hashmap_get(m->sessions, name);
1931 return bus_send_error_reply(connection, message, &error, -ENOENT);
1933 r = session_stop(session);
1935 return bus_send_error_reply(connection, message, NULL, r);
1937 reply = dbus_message_new_method_return(message);
1941 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1945 if (!dbus_message_get_args(
1948 DBUS_TYPE_UINT32, &uid,
1950 return bus_send_error_reply(connection, message, &error, -EINVAL);
1952 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1954 return bus_send_error_reply(connection, message, &error, -ENOENT);
1956 r = user_stop(user);
1958 return bus_send_error_reply(connection, message, NULL, r);
1960 reply = dbus_message_new_method_return(message);
1964 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1968 if (!dbus_message_get_args(
1971 DBUS_TYPE_STRING, &name,
1973 return bus_send_error_reply(connection, message, &error, -EINVAL);
1975 seat = hashmap_get(m->seats, name);
1977 return bus_send_error_reply(connection, message, &error, -ENOENT);
1979 r = seat_stop_sessions(seat);
1981 return bus_send_error_reply(connection, message, NULL, r);
1983 reply = dbus_message_new_method_return(message);
1987 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1990 dbus_bool_t b, interactive;
1993 if (!dbus_message_get_args(
1996 DBUS_TYPE_UINT32, &uid,
1997 DBUS_TYPE_BOOLEAN, &b,
1998 DBUS_TYPE_BOOLEAN, &interactive,
2000 return bus_send_error_reply(connection, message, &error, -EINVAL);
2005 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2007 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2009 return bus_send_error_reply(connection, message, &error, r);
2011 mkdir_p_label("/var/lib/systemd", 0755);
2013 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2015 return bus_send_error_reply(connection, message, &error, r);
2017 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2028 return bus_send_error_reply(connection, message, &error, r);
2030 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2039 if (r < 0 && errno != ENOENT)
2040 return bus_send_error_reply(connection, message, &error, -errno);
2042 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2044 user_add_to_gc_queue(u);
2047 reply = dbus_message_new_method_return(message);
2051 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2052 const char *sysfs, *seat;
2053 dbus_bool_t interactive;
2055 if (!dbus_message_get_args(
2058 DBUS_TYPE_STRING, &seat,
2059 DBUS_TYPE_STRING, &sysfs,
2060 DBUS_TYPE_BOOLEAN, &interactive,
2062 return bus_send_error_reply(connection, message, &error, -EINVAL);
2064 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2065 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2067 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2069 return bus_send_error_reply(connection, message, &error, r);
2071 r = attach_device(m, seat, sysfs);
2073 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2075 reply = dbus_message_new_method_return(message);
2080 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2081 dbus_bool_t interactive;
2083 if (!dbus_message_get_args(
2086 DBUS_TYPE_BOOLEAN, &interactive,
2088 return bus_send_error_reply(connection, message, &error, -EINVAL);
2090 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2092 return bus_send_error_reply(connection, message, &error, r);
2094 r = flush_devices(m);
2096 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2098 reply = dbus_message_new_method_return(message);
2102 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2104 r = bus_manager_do_shutdown_or_sleep(
2105 m, connection, message,
2106 SPECIAL_POWEROFF_TARGET,
2108 "org.freedesktop.login1.power-off",
2109 "org.freedesktop.login1.power-off-multiple-sessions",
2110 "org.freedesktop.login1.power-off-ignore-inhibit",
2114 return bus_send_error_reply(connection, message, &error, r);
2115 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2116 r = bus_manager_do_shutdown_or_sleep(
2117 m, connection, message,
2118 SPECIAL_REBOOT_TARGET,
2120 "org.freedesktop.login1.reboot",
2121 "org.freedesktop.login1.reboot-multiple-sessions",
2122 "org.freedesktop.login1.reboot-ignore-inhibit",
2126 return bus_send_error_reply(connection, message, &error, r);
2128 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2129 r = bus_manager_do_shutdown_or_sleep(
2130 m, connection, message,
2131 SPECIAL_SUSPEND_TARGET,
2133 "org.freedesktop.login1.suspend",
2134 "org.freedesktop.login1.suspend-multiple-sessions",
2135 "org.freedesktop.login1.suspend-ignore-inhibit",
2139 return bus_send_error_reply(connection, message, &error, r);
2140 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2141 r = bus_manager_do_shutdown_or_sleep(
2142 m, connection, message,
2143 SPECIAL_HIBERNATE_TARGET,
2145 "org.freedesktop.login1.hibernate",
2146 "org.freedesktop.login1.hibernate-multiple-sessions",
2147 "org.freedesktop.login1.hibernate-ignore-inhibit",
2151 return bus_send_error_reply(connection, message, &error, r);
2153 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2154 r = bus_manager_do_shutdown_or_sleep(
2155 m, connection, message,
2156 SPECIAL_HYBRID_SLEEP_TARGET,
2158 "org.freedesktop.login1.hibernate",
2159 "org.freedesktop.login1.hibernate-multiple-sessions",
2160 "org.freedesktop.login1.hibernate-ignore-inhibit",
2164 return bus_send_error_reply(connection, message, &error, r);
2166 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2168 r = bus_manager_can_shutdown_or_sleep(
2169 m, connection, message,
2171 "org.freedesktop.login1.power-off",
2172 "org.freedesktop.login1.power-off-multiple-sessions",
2173 "org.freedesktop.login1.power-off-ignore-inhibit",
2177 return bus_send_error_reply(connection, message, &error, r);
2178 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2179 r = bus_manager_can_shutdown_or_sleep(
2180 m, connection, message,
2182 "org.freedesktop.login1.reboot",
2183 "org.freedesktop.login1.reboot-multiple-sessions",
2184 "org.freedesktop.login1.reboot-ignore-inhibit",
2188 return bus_send_error_reply(connection, message, &error, r);
2190 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2191 r = bus_manager_can_shutdown_or_sleep(
2192 m, connection, message,
2194 "org.freedesktop.login1.suspend",
2195 "org.freedesktop.login1.suspend-multiple-sessions",
2196 "org.freedesktop.login1.suspend-ignore-inhibit",
2200 return bus_send_error_reply(connection, message, &error, r);
2202 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2203 r = bus_manager_can_shutdown_or_sleep(
2204 m, connection, message,
2206 "org.freedesktop.login1.hibernate",
2207 "org.freedesktop.login1.hibernate-multiple-sessions",
2208 "org.freedesktop.login1.hibernate-ignore-inhibit",
2212 return bus_send_error_reply(connection, message, &error, r);
2214 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2215 r = bus_manager_can_shutdown_or_sleep(
2216 m, connection, message,
2218 "org.freedesktop.login1.hibernate",
2219 "org.freedesktop.login1.hibernate-multiple-sessions",
2220 "org.freedesktop.login1.hibernate-ignore-inhibit",
2224 return bus_send_error_reply(connection, message, &error, r);
2226 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2227 char *introspection = NULL;
2236 if (!(reply = dbus_message_new_method_return(message)))
2239 /* We roll our own introspection code here, instead of
2240 * relying on bus_default_message_handler() because we
2241 * need to generate our introspection string
2244 if (!(f = open_memstream(&introspection, &size)))
2247 fputs(INTROSPECTION_BEGIN, f);
2249 HASHMAP_FOREACH(seat, m->seats, i) {
2250 p = bus_path_escape(seat->id);
2253 fprintf(f, "<node name=\"seat/%s\"/>", p);
2258 HASHMAP_FOREACH(user, m->users, i)
2259 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2261 HASHMAP_FOREACH(session, m->sessions, i) {
2262 p = bus_path_escape(session->id);
2265 fprintf(f, "<node name=\"session/%s\"/>", p);
2270 fputs(INTROSPECTION_END, f);
2274 free(introspection);
2283 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2284 free(introspection);
2288 free(introspection);
2290 const BusBoundProperties bps[] = {
2291 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2294 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2298 if (!bus_maybe_send_reply(connection, message, reply))
2302 return DBUS_HANDLER_RESULT_HANDLED;
2305 dbus_error_free(&error);
2307 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2310 const DBusObjectPathVTable bus_manager_vtable = {
2311 .message_function = manager_message_handler
2314 DBusHandlerResult bus_message_filter(
2315 DBusConnection *connection,
2316 DBusMessage *message,
2319 Manager *m = userdata;
2326 dbus_error_init(&error);
2328 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)));
2330 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2331 const char *path, *result, *unit;
2334 if (!dbus_message_get_args(message, &error,
2335 DBUS_TYPE_UINT32, &id,
2336 DBUS_TYPE_OBJECT_PATH, &path,
2337 DBUS_TYPE_STRING, &unit,
2338 DBUS_TYPE_STRING, &result,
2339 DBUS_TYPE_INVALID)) {
2340 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2344 if (m->action_job && streq(m->action_job, path)) {
2345 log_info("Operation finished.");
2347 /* Tell people that they now may take a lock again */
2348 send_prepare_for(m, m->action_what, false);
2350 free(m->action_job);
2351 m->action_job = NULL;
2352 m->action_unit = NULL;
2359 s = hashmap_get(m->session_units, unit);
2361 if (streq_ptr(path, s->scope_job)) {
2363 s->scope_job = NULL;
2366 if (streq(result, "done"))
2367 session_send_create_reply(s, NULL);
2369 dbus_set_error(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
2370 session_send_create_reply(s, &error);
2376 session_add_to_gc_queue(s);
2379 u = hashmap_get(m->user_units, unit);
2381 if (streq_ptr(path, u->service_job)) {
2382 free(u->service_job);
2383 u->service_job = NULL;
2386 if (streq_ptr(path, u->slice_job)) {
2388 u->slice_job = NULL;
2392 user_add_to_gc_queue(u);
2396 } else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
2398 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
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");