]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-dbus.c
hashmap: be a bit more conservative with pre-allocating hash tables and items
[thirdparty/systemd.git] / src / login / logind-dbus.c
CommitLineData
3f49d45a
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
3f49d45a
LP
11 (at your option) any later version.
12
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
5430f7f2 16 Lesser General Public License for more details.
3f49d45a 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
3f49d45a
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
a185c5aa
LP
22#include <errno.h>
23#include <string.h>
98a28fef 24#include <unistd.h>
7f7bb946 25#include <pwd.h>
a185c5aa 26
cc377381
LP
27#include "sd-id128.h"
28#include "sd-messages.h"
98a28fef 29#include "strv.h"
49e942b2 30#include "mkdir.h"
9eb977db 31#include "path-util.h"
55af3897 32#include "special.h"
19adb8a3 33#include "sleep-config.h"
a5c32cff
HH
34#include "fileio-label.h"
35#include "label.h"
9444b1f2
LP
36#include "utf8.h"
37#include "unit-name.h"
fb6becb4 38#include "virt.h"
cc377381
LP
39#include "audit.h"
40#include "bus-util.h"
41#include "bus-error.h"
42#include "logind.h"
3f49d45a 43
cc377381
LP
44static int property_get_idle_hint(
45 sd_bus *bus,
46 const char *path,
47 const char *interface,
48 const char *property,
49 sd_bus_message *reply,
50 sd_bus_error *error,
51 void *userdata) {
a185c5aa 52
cc377381 53 Manager *m = userdata;
a185c5aa 54
cc377381
LP
55 assert(bus);
56 assert(reply);
57 assert(m);
58
59 return sd_bus_message_append(reply, "b", manager_get_idle_hint(m, NULL) > 0);
a185c5aa
LP
60}
61
cc377381
LP
62static int property_get_idle_since_hint(
63 sd_bus *bus,
64 const char *path,
65 const char *interface,
66 const char *property,
67 sd_bus_message *reply,
68 sd_bus_error *error,
69 void *userdata) {
70
71 Manager *m = userdata;
a185c5aa 72 dual_timestamp t;
a185c5aa 73
cc377381
LP
74 assert(bus);
75 assert(reply);
a185c5aa
LP
76 assert(m);
77
78 manager_get_idle_hint(m, &t);
a185c5aa 79
cc377381 80 return sd_bus_message_append(reply, "t", streq(property, "IdleSinceHint") ? t.realtime : t.monotonic);
a185c5aa
LP
81}
82
cc377381
LP
83static int property_get_inhibited(
84 sd_bus *bus,
85 const char *path,
86 const char *interface,
87 const char *property,
88 sd_bus_message *reply,
89 sd_bus_error *error,
90 void *userdata) {
91
92 Manager *m = userdata;
f8e2fb7b 93 InhibitWhat w;
f8e2fb7b 94
cc377381
LP
95 assert(bus);
96 assert(reply);
97 assert(m);
f8e2fb7b 98
cc377381 99 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
f8e2fb7b 100
cc377381 101 return sd_bus_message_append(reply, "s", inhibit_what_to_string(w));
f8e2fb7b
LP
102}
103
cc377381
LP
104static int property_get_preparing(
105 sd_bus *bus,
106 const char *path,
107 const char *interface,
108 const char *property,
109 sd_bus_message *reply,
110 sd_bus_error *error,
111 void *userdata) {
112
113 Manager *m = userdata;
114 bool b;
5e4a79da 115
cc377381
LP
116 assert(bus);
117 assert(reply);
118 assert(m);
5e4a79da
LP
119
120 if (streq(property, "PreparingForShutdown"))
314b4b0a 121 b = !!(m->action_what & INHIBIT_SHUTDOWN);
5e4a79da 122 else
314b4b0a 123 b = !!(m->action_what & INHIBIT_SLEEP);
5e4a79da 124
cc377381 125 return sd_bus_message_append(reply, "b", b);
5e4a79da
LP
126}
127
cc377381 128static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_handle_action, handle_action, HandleAction);
fb6becb4 129
cc377381
LP
130static int method_get_session(sd_bus *bus, sd_bus_message *message, void *userdata) {
131 _cleanup_free_ char *p = NULL;
132 Manager *m = userdata;
133 const char *name;
134 Session *session;
135 int r;
136
137 assert(bus);
138 assert(message);
139 assert(m);
140
141 r = sd_bus_message_read(message, "s", &name);
142 if (r < 0)
143 return sd_bus_reply_method_errno(bus, message, r, NULL);
144
145 session = hashmap_get(m->sessions, name);
146 if (!session)
147 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
148
149 p = session_bus_path(session);
150 if (!p)
151 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
152
153 return sd_bus_reply_method_return(bus, message, "o", p);
154}
155
156static int method_get_session_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata) {
157 _cleanup_free_ char *p = NULL;
954449b8 158 Session *session = NULL;
cc377381 159 Manager *m = userdata;
4e724d9c 160 pid_t pid;
cc377381
LP
161 int r;
162
163 assert(bus);
164 assert(message);
165 assert(m);
166
4e724d9c
LP
167 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
168
cc377381
LP
169 r = sd_bus_message_read(message, "u", &pid);
170 if (r < 0)
171 return sd_bus_reply_method_errno(bus, message, r, NULL);
172
4e724d9c
LP
173 if (pid == 0) {
174 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
175 if (r < 0)
176 return sd_bus_reply_method_errno(bus, message, r, NULL);
177 }
178
cc377381
LP
179 r = manager_get_session_by_pid(m, pid, &session);
180 if (r < 0)
181 return sd_bus_reply_method_errno(bus, message, r, NULL);
182 if (!session)
183 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SESSION_FOR_PID, "PID %lu does not belong to any known session", (unsigned long) pid);
184
185 p = session_bus_path(session);
186 if (!p)
187 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
188
189 return sd_bus_reply_method_return(bus, message, "o", p);
190}
191
192static int method_get_user(sd_bus *bus, sd_bus_message *message, void *userdata) {
193 _cleanup_free_ char *p = NULL;
194 Manager *m = userdata;
195 uint32_t uid;
196 User *user;
197 int r;
198
199 assert(bus);
200 assert(message);
201 assert(m);
202
203 r = sd_bus_message_read(message, "u", &uid);
204 if (r < 0)
205 return sd_bus_reply_method_errno(bus, message, r, NULL);
206
207 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
208 if (!user)
209 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_USER, "No user '%lu' known or logged in", (unsigned long) uid);
210
211 p = user_bus_path(user);
212 if (!p)
213 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
214
215 return sd_bus_reply_method_return(bus, message, "o", p);
216}
217
218static int method_get_user_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata) {
219 _cleanup_free_ char *p = NULL;
220 Manager *m = userdata;
954449b8 221 User *user = NULL;
4e724d9c 222 pid_t pid;
fb6becb4 223 int r;
98a28fef 224
cc377381
LP
225 assert(bus);
226 assert(message);
98a28fef 227 assert(m);
cc377381 228
4e724d9c
LP
229 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
230
cc377381
LP
231 r = sd_bus_message_read(message, "u", &pid);
232 if (r < 0)
233 return sd_bus_reply_method_errno(bus, message, r, NULL);
234
4e724d9c
LP
235 if (pid == 0) {
236 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
237 if (r < 0)
238 return sd_bus_reply_method_errno(bus, message, r, NULL);
239 }
240
cc377381
LP
241 r = manager_get_user_by_pid(m, pid, &user);
242 if (r < 0)
243 return sd_bus_reply_method_errno(bus, message, r, NULL);
244 if (!user)
245 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_USER_FOR_PID, "PID %lu does not belong to any known or logged in user", (unsigned long) pid);
246
247 p = user_bus_path(user);
248 if (!p)
249 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
250
251 return sd_bus_reply_method_return(bus, message, "o", p);
252}
253
254static int method_get_seat(sd_bus *bus, sd_bus_message *message, void *userdata) {
255 _cleanup_free_ char *p = NULL;
256 Manager *m = userdata;
257 const char *name;
258 Seat *seat;
259 int r;
260
261 assert(bus);
98a28fef 262 assert(message);
cc377381 263 assert(m);
98a28fef 264
cc377381
LP
265 r = sd_bus_message_read(message, "s", &name);
266 if (r < 0)
267 return sd_bus_reply_method_errno(bus, message, r, NULL);
98a28fef 268
cc377381
LP
269 seat = hashmap_get(m->seats, name);
270 if (!seat)
271 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", name);
98a28fef 272
cc377381
LP
273 p = seat_bus_path(seat);
274 if (!p)
275 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
98a28fef 276
cc377381
LP
277 return sd_bus_reply_method_return(bus, message, "o", p);
278}
98a28fef 279
cc377381
LP
280static int method_list_sessions(sd_bus *bus, sd_bus_message *message, void *userdata) {
281 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
282 Manager *m = userdata;
283 Session *session;
284 Iterator i;
285 int r;
286
287 assert(bus);
288 assert(message);
289 assert(m);
98a28fef 290
cc377381
LP
291 r = sd_bus_message_new_method_return(bus, message, &reply);
292 if (r < 0)
293 return sd_bus_reply_method_errno(bus, message, r, NULL);
98a28fef 294
cc377381
LP
295 r = sd_bus_message_open_container(reply, 'a', "(susso)");
296 if (r < 0)
297 return sd_bus_reply_method_errno(bus, message, r, NULL);
298
299 HASHMAP_FOREACH(session, m->sessions, i) {
300 _cleanup_free_ char *p = NULL;
301
302 p = session_bus_path(session);
303 if (!p)
304 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
305
306 r = sd_bus_message_append(reply, "(susso)",
307 session->id,
308 (uint32_t) session->user->uid,
309 session->user->name,
310 session->seat ? session->seat->id : "",
311 p);
312 if (r < 0)
313 return sd_bus_reply_method_errno(bus, message, r, NULL);
314 }
315
316 r = sd_bus_message_close_container(reply);
317 if (r < 0)
318 return sd_bus_reply_method_errno(bus, message, r, NULL);
319
320 return sd_bus_send(bus, reply, NULL);
321}
322
323static int method_list_users(sd_bus *bus, sd_bus_message *message, void *userdata) {
324 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
325 Manager *m = userdata;
326 User *user;
327 Iterator i;
328 int r;
329
330 assert(bus);
331 assert(message);
332 assert(m);
333
334 r = sd_bus_message_new_method_return(bus, message, &reply);
335 if (r < 0)
336 return sd_bus_reply_method_errno(bus, message, r, NULL);
337
338 r = sd_bus_message_open_container(reply, 'a', "(uso)");
339 if (r < 0)
340 return sd_bus_reply_method_errno(bus, message, r, NULL);
341
342 HASHMAP_FOREACH(user, m->users, i) {
343 _cleanup_free_ char *p = NULL;
344
345 p = user_bus_path(user);
346 if (!p)
347 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
348
349 r = sd_bus_message_append(reply, "(uso)",
350 (uint32_t) user->uid,
351 user->name,
352 p);
353 if (r < 0)
354 return sd_bus_reply_method_errno(bus, message, r, NULL);
355 }
356
357 r = sd_bus_message_close_container(reply);
358 if (r < 0)
359 return sd_bus_reply_method_errno(bus, message, r, NULL);
360
361 return sd_bus_send(bus, reply, NULL);
362}
363
364static int method_list_seats(sd_bus *bus, sd_bus_message *message, void *userdata) {
365 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
366 Manager *m = userdata;
367 Seat *seat;
368 Iterator i;
369 int r;
370
371 assert(bus);
372 assert(message);
373 assert(m);
374
375 r = sd_bus_message_new_method_return(bus, message, &reply);
376 if (r < 0)
377 return sd_bus_reply_method_errno(bus, message, r, NULL);
378
379 r = sd_bus_message_open_container(reply, 'a', "(so)");
380 if (r < 0)
381 return sd_bus_reply_method_errno(bus, message, r, NULL);
382
383 HASHMAP_FOREACH(seat, m->seats, i) {
384 _cleanup_free_ char *p = NULL;
385
386 p = seat_bus_path(seat);
387 if (!p)
388 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
389
b8358bce 390 r = sd_bus_message_append(reply, "(so)", seat->id, p);
cc377381
LP
391 if (r < 0)
392 return sd_bus_reply_method_errno(bus, message, r, NULL);
393 }
394
395 r = sd_bus_message_close_container(reply);
396 if (r < 0)
397 return sd_bus_reply_method_errno(bus, message, r, NULL);
398
399 return sd_bus_send(bus, reply, NULL);
400}
401
402static int method_list_inhibitors(sd_bus *bus, sd_bus_message *message, void *userdata) {
403 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
404 Manager *m = userdata;
405 Inhibitor *inhibitor;
406 Iterator i;
407 int r;
408
409 r = sd_bus_message_new_method_return(bus, message, &reply);
410 if (r < 0)
411 return sd_bus_reply_method_errno(bus, message, r, NULL);
412
413 r = sd_bus_message_open_container(reply, 'a', "(ssssuu)");
414 if (r < 0)
415 return sd_bus_reply_method_errno(bus, message, r, NULL);
416
417 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
418
dbfa3fbb 419 r = sd_bus_message_append(reply, "(ssssuu)",
cc377381
LP
420 strempty(inhibit_what_to_string(inhibitor->what)),
421 strempty(inhibitor->who),
422 strempty(inhibitor->why),
423 strempty(inhibit_mode_to_string(inhibitor->mode)),
424 (uint32_t) inhibitor->uid,
425 (uint32_t) inhibitor->pid);
426 if (r < 0)
427 return sd_bus_reply_method_errno(bus, message, r, NULL);
428 }
429
430 r = sd_bus_message_close_container(reply);
431 if (r < 0)
432 return sd_bus_reply_method_errno(bus, message, r, NULL);
433
434 return sd_bus_send(bus, reply, NULL);
435}
436
437static int method_create_session(sd_bus *bus, sd_bus_message *message, void *userdata) {
438 const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host;
439 uint32_t uid, leader, audit_id = 0;
440 _cleanup_free_ char *id = NULL;
441 Session *session = NULL;
442 Manager *m = userdata;
443 User *user = NULL;
444 Seat *seat = NULL;
445 int remote;
446 uint32_t vtnr = 0;
447 SessionType t;
448 SessionClass c;
449 int r;
450
451 assert(bus);
452 assert(message);
453 assert(m);
454
455 r = sd_bus_message_read(message, "uussssussbss", &uid, &leader, &service, &type, &class, &cseat, &vtnr, &tty, &display, &remote, &remote_user, &remote_host);
456 if (r < 0)
457 return sd_bus_reply_method_errno(bus, message, r, NULL);
458
459 if (leader == 1)
460 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
98a28fef 461
e2acb67b
LP
462 if (isempty(type))
463 t = _SESSION_TYPE_INVALID;
464 else {
465 t = session_type_from_string(type);
466 if (t < 0)
cc377381 467 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid session type %s", type);
e2acb67b 468 }
98a28fef 469
55efac6c 470 if (isempty(class))
e2acb67b
LP
471 c = _SESSION_CLASS_INVALID;
472 else {
55efac6c 473 c = session_class_from_string(class);
e2acb67b 474 if (c < 0)
cc377381 475 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid session class %s", class);
e2acb67b 476 }
55efac6c 477
954449b8
LP
478 if (isempty(cseat))
479 seat = NULL;
98a28fef 480 else {
954449b8
LP
481 seat = hashmap_get(m->seats, cseat);
482 if (!seat)
cc377381 483 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", seat);
98a28fef
LP
484 }
485
98a28fef 486 if (tty_is_vc(tty)) {
4d6d6518 487 int v;
98a28fef 488
954449b8 489 if (!seat)
92432fcc
DH
490 seat = m->seat0;
491 else if (seat != m->seat0)
cc377381 492 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "TTY %s is virtual console but seat %s is not seat0", tty, seat);
98a28fef 493
4d6d6518 494 v = vtnr_from_tty(tty);
4d6d6518 495 if (v <= 0)
cc377381 496 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Cannot determine VT number from virtual console TTY %s", tty);
98a28fef
LP
497
498 if (vtnr <= 0)
4d6d6518
LP
499 vtnr = (uint32_t) v;
500 else if (vtnr != (uint32_t) v)
cc377381
LP
501 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Specified TTY and VT number do not match");
502
d1122ad5
LP
503 } else if (tty_is_console(tty)) {
504
954449b8 505 if (!seat)
92432fcc
DH
506 seat = m->seat0;
507 else if (seat != m->seat0)
cc377381 508 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but seat is not seat0");
d1122ad5
LP
509
510 if (vtnr != 0)
cc377381 511 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but VT number is not 0");
978cf3c7 512 }
98a28fef 513
954449b8 514 if (seat) {
bf7825ae 515 if (seat_has_vts(seat)) {
d1122ad5 516 if (vtnr > 63)
cc377381 517 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "VT number out of range");
4d6d6518 518 } else {
d1122ad5 519 if (vtnr != 0)
cc377381 520 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Seat has no VTs but VT number not 0");
4d6d6518
LP
521 }
522 }
523
cc377381
LP
524 r = sd_bus_message_enter_container(message, 'a', "(sv)");
525 if (r < 0)
526 return sd_bus_reply_method_errno(bus, message, r, NULL);
98a28fef 527
e2acb67b
LP
528 if (t == _SESSION_TYPE_INVALID) {
529 if (!isempty(display))
530 t = SESSION_X11;
531 else if (!isempty(tty))
532 t = SESSION_TTY;
533 else
534 t = SESSION_UNSPECIFIED;
535 }
536
537 if (c == _SESSION_CLASS_INVALID) {
538 if (!isempty(display) || !isempty(tty))
539 c = SESSION_USER;
540 else
541 c = SESSION_BACKGROUND;
542 }
543
9444b1f2 544 if (leader <= 0) {
cc377381
LP
545 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
546
547 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), (pid_t*) &leader);
548 if (r < 0)
549 return sd_bus_reply_method_errno(bus, message, r, NULL);
9444b1f2
LP
550 }
551
872c8faa 552 manager_get_session_by_pid(m, leader, &session);
fb6becb4 553 if (session) {
fb6becb4
LP
554 _cleanup_free_ char *path = NULL;
555 _cleanup_close_ int fifo_fd = -1;
98a28fef 556
fb6becb4
LP
557 /* Session already exists, client is probably
558 * something like "su" which changes uid but is still
559 * the same session */
98a28fef 560
954449b8 561 fifo_fd = session_create_fifo(session);
cc377381
LP
562 if (fifo_fd < 0)
563 return sd_bus_reply_method_errno(bus, message, fifo_fd, NULL);
98a28fef 564
fb6becb4 565 path = session_bus_path(session);
cc377381
LP
566 if (!path)
567 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
21c390cc 568
cc377381
LP
569 return sd_bus_reply_method_return(
570 bus, message, "soshsub",
571 session->id,
572 path,
573 session->user->runtime_path,
574 fifo_fd,
575 session->seat ? session->seat->id : "",
576 (uint32_t) session->vtnr,
577 true);
954449b8 578 }
21c390cc 579
954449b8
LP
580 audit_session_from_pid(leader, &audit_id);
581 if (audit_id > 0) {
582 /* Keep our session IDs and the audit session IDs in sync */
21c390cc 583
cc377381
LP
584 if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0)
585 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
21c390cc 586
954449b8
LP
587 /* Wut? There's already a session by this name and we
588 * didn't find it above? Weird, then let's not trust
589 * the audit data and let's better register a new
590 * ID */
591 if (hashmap_get(m->sessions, id)) {
4b549144 592 log_warning("Existing logind session ID %s used by new audit session, ignoring", id);
954449b8 593 audit_id = 0;
8ea913b2 594
954449b8
LP
595 free(id);
596 id = NULL;
07714753 597 }
954449b8 598 }
07714753 599
954449b8 600 if (!id) {
07714753
LP
601 do {
602 free(id);
f8e2fb7b 603 id = NULL;
07714753 604
cc377381
LP
605 if (asprintf(&id, "c%lu", ++m->session_counter) < 0)
606 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
07714753
LP
607
608 } while (hashmap_get(m->sessions, id));
98a28fef
LP
609 }
610
954449b8 611 r = manager_add_user_by_uid(m, uid, &user);
cc377381
LP
612 if (r < 0) {
613 r = sd_bus_reply_method_errno(bus, message, r, NULL);
954449b8 614 goto fail;
cc377381 615 }
954449b8 616
9444b1f2 617 r = manager_add_session(m, id, &session);
cc377381
LP
618 if (r < 0) {
619 r = sd_bus_reply_method_errno(bus, message, r, NULL);
98a28fef 620 goto fail;
cc377381 621 }
98a28fef 622
9444b1f2
LP
623 session_set_user(session, user);
624
98a28fef
LP
625 session->leader = leader;
626 session->audit_id = audit_id;
627 session->type = t;
55efac6c 628 session->class = c;
98a28fef 629 session->remote = remote;
98a28fef
LP
630 session->vtnr = vtnr;
631
98a28fef
LP
632 if (!isempty(tty)) {
633 session->tty = strdup(tty);
634 if (!session->tty) {
cc377381 635 r = sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
98a28fef
LP
636 goto fail;
637 }
638 }
639
640 if (!isempty(display)) {
641 session->display = strdup(display);
642 if (!session->display) {
cc377381 643 r = sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
98a28fef
LP
644 goto fail;
645 }
646 }
647
648 if (!isempty(remote_user)) {
649 session->remote_user = strdup(remote_user);
650 if (!session->remote_user) {
cc377381 651 r = sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
98a28fef
LP
652 goto fail;
653 }
654 }
655
656 if (!isempty(remote_host)) {
657 session->remote_host = strdup(remote_host);
658 if (!session->remote_host) {
cc377381 659 r = sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
98a28fef
LP
660 goto fail;
661 }
662 }
663
664 if (!isempty(service)) {
665 session->service = strdup(service);
666 if (!session->service) {
cc377381 667 r = sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
98a28fef
LP
668 goto fail;
669 }
670 }
671
954449b8
LP
672 if (seat) {
673 r = seat_attach_session(seat, session);
cc377381
LP
674 if (r < 0) {
675 r = sd_bus_reply_method_errno(bus, message, r, NULL);
98a28fef 676 goto fail;
cc377381 677 }
98a28fef
LP
678 }
679
680 r = session_start(session);
cc377381
LP
681 if (r < 0) {
682 r = sd_bus_reply_method_errno(bus, message, r, NULL);
98a28fef 683 goto fail;
cc377381 684 }
98a28fef 685
cc377381 686 session->create_message = sd_bus_message_ref(message);
98a28fef 687
cba38758
LP
688 /* Now, let's wait until the slice unit and stuff got
689 * created. We send the reply back from
690 * session_send_create_reply().*/
691
cc377381 692 return 1;
98a28fef
LP
693
694fail:
98a28fef
LP
695 if (session)
696 session_add_to_gc_queue(session);
697
698 if (user)
699 user_add_to_gc_queue(user);
700
98a28fef
LP
701 return r;
702}
703
cc377381
LP
704static int method_release_session(sd_bus *bus, sd_bus_message *message, void *userdata) {
705 Manager *m = userdata;
706 Session *session;
707 const char *name;
708 int r;
314b4b0a 709
cc377381
LP
710 assert(bus);
711 assert(message);
712 assert(m);
713
714 r = sd_bus_message_read(message, "s", &name);
715 if (r < 0)
716 return sd_bus_reply_method_errno(bus, message, r, NULL);
717
718 session = hashmap_get(m->sessions, name);
719 if (!session)
720 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
721
722 /* We use the FIFO to detect stray sessions where the process
723 invoking PAM dies abnormally. We need to make sure that
724 that process is not killed if at the clean end of the
725 session it closes the FIFO. Hence, with this call
726 explicitly turn off the FIFO logic, so that the PAM code
727 can finish clean up on its own */
728 session_remove_fifo(session);
729 session_save(session);
730 user_save(session->user);
731
732 return sd_bus_reply_method_return(bus, message, NULL);
733}
734
735static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *userdata) {
736 Manager *m = userdata;
737 Session *session;
738 const char *name;
739 int r;
f8e2fb7b 740
cc377381
LP
741 assert(bus);
742 assert(message);
f8e2fb7b 743 assert(m);
cc377381
LP
744
745 r = sd_bus_message_read(message, "s", &name);
746 if (r < 0)
747 return sd_bus_reply_method_errno(bus, message, r, NULL);
748
749 session = hashmap_get(m->sessions, name);
750 if (!session)
751 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
752
753 r = session_activate(session);
754 if (r < 0)
755 return sd_bus_reply_method_errno(bus, message, r, NULL);
756
757 return sd_bus_reply_method_return(bus, message, NULL);
758}
759
760static int method_activate_session_on_seat(sd_bus *bus, sd_bus_message *message, void *userdata) {
761 const char *session_name, *seat_name;
762 Manager *m = userdata;
763 Session *session;
764 Seat *seat;
765 int r;
766
767 assert(bus);
f8e2fb7b 768 assert(message);
cc377381 769 assert(m);
f8e2fb7b 770
cc377381
LP
771 /* Same as ActivateSession() but refuses to work if
772 * the seat doesn't match */
f8e2fb7b 773
cc377381
LP
774 r = sd_bus_message_read(message, "ss", &session_name, &seat_name);
775 if (r < 0)
776 return sd_bus_reply_method_errno(bus, message, r, NULL);
eecd1362 777
cc377381
LP
778 session = hashmap_get(m->sessions, session_name);
779 if (!session)
780 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", session_name);
beaafb2e 781
cc377381
LP
782 seat = hashmap_get(m->seats, seat_name);
783 if (!seat)
784 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", seat_name);
314b4b0a 785
cc377381
LP
786 if (session->seat != seat)
787 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", session_name, seat_name);
788
789 r = session_activate(session);
f8e2fb7b 790 if (r < 0)
cc377381 791 return sd_bus_reply_method_errno(bus, message, r, NULL);
f8e2fb7b 792
cc377381
LP
793 return sd_bus_reply_method_return(bus, message, NULL);
794}
f8e2fb7b 795
cc377381
LP
796static int method_lock_session(sd_bus *bus, sd_bus_message *message, void *userdata) {
797 Manager *m = userdata;
798 Session *session;
799 const char *name;
800 int r;
f8e2fb7b 801
cc377381
LP
802 assert(bus);
803 assert(message);
804 assert(m);
f8e2fb7b 805
cc377381
LP
806 r = sd_bus_message_read(message, "s", &name);
807 if (r < 0)
808 return sd_bus_reply_method_errno(bus, message, r, NULL);
f8e2fb7b 809
cc377381
LP
810 session = hashmap_get(m->sessions, name);
811 if (!session)
812 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
f8e2fb7b 813
cc377381 814 r = session_send_lock(session, streq(sd_bus_message_get_member(message), "LockSession"));
f8e2fb7b 815 if (r < 0)
cc377381 816 return sd_bus_reply_method_errno(bus, message, r, NULL);
f8e2fb7b 817
cc377381
LP
818 return sd_bus_reply_method_return(bus, message, NULL);
819}
f8e2fb7b 820
cc377381
LP
821static int method_lock_sessions(sd_bus *bus, sd_bus_message *message, void *userdata) {
822 Manager *m = userdata;
823 int r;
f8e2fb7b 824
cc377381
LP
825 assert(bus);
826 assert(message);
827 assert(m);
f8e2fb7b 828
cc377381
LP
829 r = session_send_lock_all(m, streq(sd_bus_message_get_member(message), "LockSessions"));
830 if (r < 0)
831 return sd_bus_reply_method_errno(bus, message, r, NULL);
f8e2fb7b 832
cc377381
LP
833 return sd_bus_reply_method_return(bus, message, NULL);
834}
835
836static int method_kill_session(sd_bus *bus, sd_bus_message *message, void *userdata) {
837 const char *name, *swho;
838 Manager *m = userdata;
839 Session *session;
840 int32_t signo;
841 KillWho who;
842 int r;
843
844 assert(bus);
845 assert(message);
846 assert(m);
847
848 r = sd_bus_message_read(message, "ssi", &name, &swho, &signo);
849 if (r < 0)
850 return sd_bus_reply_method_errno(bus, message, r, NULL);
851
852 if (isempty(swho))
853 who = KILL_ALL;
854 else {
855 who = kill_who_from_string(swho);
856 if (who < 0)
857 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
f8e2fb7b
LP
858 }
859
cc377381
LP
860 if (signo <= 0 || signo >= _NSIG)
861 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
f8e2fb7b 862
cc377381
LP
863 session = hashmap_get(m->sessions, name);
864 if (!session)
865 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
f8e2fb7b 866
cc377381
LP
867 r = session_kill(session, who, signo);
868 if (r < 0)
869 return sd_bus_reply_method_errno(bus, message, r, NULL);
f8e2fb7b 870
cc377381
LP
871 return sd_bus_reply_method_return(bus, message, NULL);
872}
f8e2fb7b 873
cc377381
LP
874static int method_kill_user(sd_bus *bus, sd_bus_message *message, void *userdata) {
875 Manager *m = userdata;
876 uint32_t uid;
877 int32_t signo;
878 User *user;
879 int r;
f8e2fb7b 880
cc377381
LP
881 assert(bus);
882 assert(message);
883 assert(m);
884
885 r = sd_bus_message_read(message, "ui", &uid, &signo);
886 if (r < 0)
887 return sd_bus_reply_method_errno(bus, message, r, NULL);
888
889 if (signo <= 0 || signo >= _NSIG)
890 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
891
892 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
893 if (!user)
894 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_USER, "No user '%lu' known or logged in", (unsigned long) uid);
895
896 r = user_kill(user, signo);
897 if (r < 0)
898 return sd_bus_reply_method_errno(bus, message, r, NULL);
899
900 return sd_bus_reply_method_return(bus, message, NULL);
901}
902
903static int method_terminate_session(sd_bus *bus, sd_bus_message *message, void *userdata) {
904 Manager *m = userdata;
905 const char *name;
906 Session *session;
907 int r;
908
909 assert(bus);
910 assert(message);
911 assert(m);
912
913 r = sd_bus_message_read(message, "s", &name);
914 if (r < 0)
915 return sd_bus_reply_method_errno(bus, message, r, NULL);
916
917 session = hashmap_get(m->sessions, name);
918 if (!session)
919 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
920
921 r = session_stop(session);
922 if (r < 0)
923 return sd_bus_reply_method_errno(bus, message, r, NULL);
924
925 return sd_bus_reply_method_return(bus, message, NULL);
926}
927
928static int method_terminate_user(sd_bus *bus, sd_bus_message *message, void *userdata) {
929 Manager *m = userdata;
930 uint32_t uid;
931 User *user;
932 int r;
933
934 assert(bus);
935 assert(message);
936 assert(m);
937
938 r = sd_bus_message_read(message, "u", &uid);
939 if (r < 0)
940 return sd_bus_reply_method_errno(bus, message, r, NULL);
941
942 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
943 if (!user)
944 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_USER, "No user '%lu' known or logged in", (unsigned long) uid);
945
946 r = user_stop(user);
947 if (r < 0)
948 return sd_bus_reply_method_errno(bus, message, r, NULL);
949
950 return sd_bus_reply_method_return(bus, message, NULL);
951}
952
953static int method_terminate_seat(sd_bus *bus, sd_bus_message *message, void *userdata) {
954 Manager *m = userdata;
955 const char *name;
956 Seat *seat;
957 int r;
958
959 assert(bus);
960 assert(message);
961 assert(m);
962
963 r = sd_bus_message_read(message, "s", &name);
964 if (r < 0)
965 return sd_bus_reply_method_errno(bus, message, r, NULL);
966
967 seat = hashmap_get(m->seats, name);
968 if (!seat)
969 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", name);
970
971 r = seat_stop_sessions(seat);
972 if (r < 0)
973 return sd_bus_reply_method_errno(bus, message, r, NULL);
974
975 return sd_bus_reply_method_return(bus, message, NULL);
976}
977
978static int method_set_user_linger(sd_bus *bus, sd_bus_message *message, void *userdata) {
979 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
980 _cleanup_free_ char *cc = NULL;
981 Manager *m = userdata;
982 int b, r;
983 struct passwd *pw;
984 const char *path;
985 uint32_t uid;
986 int interactive;
987
988 assert(bus);
989 assert(message);
990 assert(m);
991
992 r = sd_bus_message_read(message, "ubb", &uid, &b, &interactive);
993 if (r < 0)
994 return sd_bus_reply_method_errno(bus, message, r, NULL);
995
996 errno = 0;
997 pw = getpwuid(uid);
998 if (!pw)
999 return sd_bus_reply_method_errno(bus, message, errno ? errno : ENOENT, NULL);
1000
1001 r = bus_verify_polkit_async(bus,
1002 &m->polkit_registry,
1003 message,
1004 "org.freedesktop.login1.set-user-linger",
1005 interactive,
1006 &error,
1007 method_set_user_linger, m);
1008 if (r < 0)
1009 return sd_bus_reply_method_errno(bus, message, r, &error);
1010 if (r == 0)
1011 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1012
1013 mkdir_p_label("/var/lib/systemd", 0755);
1014
1015 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1016 if (r < 0)
1017 return sd_bus_reply_method_errno(bus, message, r, NULL);
1018
1019 cc = cescape(pw->pw_name);
1020 if (!cc)
1021 return sd_bus_reply_method_errno(bus, message, ENOMEM, NULL);
1022
1023 path = strappenda("/var/lib/systemd/linger/", cc);
1024 if (b) {
1025 User *u;
1026
1027 r = touch(path);
1028 if (r < 0)
1029 return sd_bus_reply_method_errno(bus, message, r, NULL);
1030
1031 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1032 user_start(u);
1033
1034 } else {
1035 User *u;
1036
1037 r = unlink(path);
1038 if (r < 0 && errno != ENOENT)
1039 return sd_bus_reply_method_errno(bus, message, errno, NULL);
1040
1041 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1042 if (u)
1043 user_add_to_gc_queue(u);
1044 }
1045
1046 return sd_bus_reply_method_return(bus, message, NULL);
f8e2fb7b
LP
1047}
1048
2eb916cd 1049static int trigger_device(Manager *m, struct udev_device *d) {
b668e064
LP
1050 struct udev_enumerate *e;
1051 struct udev_list_entry *first, *item;
1052 int r;
1053
1054 assert(m);
1055
1056 e = udev_enumerate_new(m->udev);
1057 if (!e) {
1058 r = -ENOMEM;
1059 goto finish;
1060 }
1061
2eb916cd
LP
1062 if (d) {
1063 if (udev_enumerate_add_match_parent(e, d) < 0) {
1064 r = -EIO;
1065 goto finish;
1066 }
1067 }
1068
b668e064
LP
1069 if (udev_enumerate_scan_devices(e) < 0) {
1070 r = -EIO;
1071 goto finish;
1072 }
1073
1074 first = udev_enumerate_get_list_entry(e);
1075 udev_list_entry_foreach(item, first) {
cc377381 1076 _cleanup_free_ char *t = NULL;
b668e064
LP
1077 const char *p;
1078
1079 p = udev_list_entry_get_name(item);
1080
b668e064
LP
1081 t = strappend(p, "/uevent");
1082 if (!t) {
1083 r = -ENOMEM;
1084 goto finish;
1085 }
1086
574d5f2d 1087 write_string_file(t, "change");
b668e064
LP
1088 }
1089
1090 r = 0;
1091
1092finish:
1093 if (e)
1094 udev_enumerate_unref(e);
1095
1096 return r;
1097}
1098
47a26690 1099static int attach_device(Manager *m, const char *seat, const char *sysfs) {
7fd1b19b 1100 _cleanup_free_ char *rule = NULL, *file = NULL;
c28fa3d3 1101 const char *id_for_seat;
cc377381 1102 struct udev_device *d;
47a26690
LP
1103 int r;
1104
1105 assert(m);
1106 assert(seat);
1107 assert(sysfs);
1108
1109 d = udev_device_new_from_syspath(m->udev, sysfs);
1110 if (!d)
1111 return -ENODEV;
1112
309c2a2c 1113 if (!udev_device_has_tag(d, "seat")) {
47a26690
LP
1114 r = -ENODEV;
1115 goto finish;
1116 }
1117
c28fa3d3
LP
1118 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
1119 if (!id_for_seat) {
47a26690
LP
1120 r = -ENODEV;
1121 goto finish;
1122 }
1123
c28fa3d3 1124 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
47a26690
LP
1125 r = -ENOMEM;
1126 goto finish;
1127 }
1128
c28fa3d3 1129 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
47a26690
LP
1130 r = -ENOMEM;
1131 goto finish;
1132 }
1133
d2e54fae 1134 mkdir_p_label("/etc/udev/rules.d", 0755);
a5c32cff 1135 label_init("/etc");
574d5f2d 1136 r = write_string_file_atomic_label(file, rule);
a0a0c7f1
LP
1137 if (r < 0)
1138 goto finish;
1139
2eb916cd 1140 r = trigger_device(m, d);
47a26690
LP
1141
1142finish:
47a26690
LP
1143 if (d)
1144 udev_device_unref(d);
1145
1146 return r;
1147}
1148
b668e064 1149static int flush_devices(Manager *m) {
7fd1b19b 1150 _cleanup_closedir_ DIR *d;
b668e064
LP
1151
1152 assert(m);
1153
1154 d = opendir("/etc/udev/rules.d");
1155 if (!d) {
1156 if (errno != ENOENT)
1157 log_warning("Failed to open /etc/udev/rules.d: %m");
1158 } else {
1159 struct dirent *de;
1160
1161 while ((de = readdir(d))) {
1162
1163 if (!dirent_is_file(de))
1164 continue;
1165
1166 if (!startswith(de->d_name, "72-seat-"))
1167 continue;
1168
1169 if (!endswith(de->d_name, ".rules"))
1170 continue;
1171
1172 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
1173 log_warning("Failed to unlink %s: %m", de->d_name);
1174 }
b668e064
LP
1175 }
1176
1177 return trigger_device(m, NULL);
1178}
1179
cc377381
LP
1180static int method_attach_device(sd_bus *bus, sd_bus_message *message, void *userdata) {
1181 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1182 const char *sysfs, *seat;
1183 Manager *m = userdata;
1184 int interactive, r;
1185
1186 assert(bus);
1187 assert(message);
1188 assert(m);
1189
1190 r = sd_bus_message_read(message, "ssb", &seat, &sysfs, &interactive);
1191 if (r < 0)
1192 return sd_bus_reply_method_errno(bus, message, r, NULL);
1193
1194 if (!path_startswith(sysfs, "/sys"))
1195 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not in /sys", sysfs);
1196
1197 if (!seat_name_is_valid(seat))
1198 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Seat %s is not valid", seat);
1199
1200 r = bus_verify_polkit_async(bus,
1201 &m->polkit_registry,
1202 message,
1203 "org.freedesktop.login1.attach-device",
1204 interactive,
1205 &error,
1206 method_attach_device, m);
1207 if (r < 0)
1208 return sd_bus_reply_method_errno(bus, message, r, &error);
1209 if (r == 0)
1210 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1211
1212 r = attach_device(m, seat, sysfs);
1213 if (r < 0)
1214 return sd_bus_reply_method_errno(bus, message, r, NULL);
1215
1216 return sd_bus_reply_method_return(bus, message, NULL);
1217}
1218
1219static int method_flush_devices(sd_bus *bus, sd_bus_message *message, void *userdata) {
1220 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1221 Manager *m = userdata;
1222 int interactive, r;
1223
1224 assert(bus);
1225 assert(message);
1226 assert(m);
1227
1228 r = sd_bus_message_read(message, "b", &interactive);
1229 if (r < 0)
1230 return sd_bus_reply_method_errno(bus, message, r, NULL);
1231
1232 r = bus_verify_polkit_async(bus,
1233 &m->polkit_registry,
1234 message,
1235 "org.freedesktop.login1.flush-devices",
1236 interactive,
1237 &error,
1238 method_flush_devices, m);
1239 if (r < 0)
1240 return sd_bus_reply_method_errno(bus, message, r, &error);
1241 if (r == 0)
1242 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1243
1244 r = flush_devices(m);
1245 if (r < 0)
1246 return sd_bus_reply_method_errno(bus, message, r, &error);
1247
1248 return sd_bus_reply_method_return(bus, message, NULL);
1249}
1250
89f13440 1251static int have_multiple_sessions(
89f13440 1252 Manager *m,
409133be 1253 uid_t uid) {
89f13440 1254
2154761f
MS
1255 Session *session;
1256 Iterator i;
89f13440
LP
1257
1258 assert(m);
1259
1ca04b87
LP
1260 /* Check for other users' sessions. Greeter sessions do not
1261 * count, and non-login sessions do not count either. */
2154761f 1262 HASHMAP_FOREACH(session, m->sessions, i)
1ca04b87 1263 if (session->class == SESSION_USER &&
c68ba912 1264 !session->closing &&
1ca04b87 1265 session->user->uid != uid)
2154761f 1266 return true;
89f13440
LP
1267
1268 return false;
1269}
1270
314b4b0a
LP
1271static int bus_manager_log_shutdown(
1272 Manager *m,
1273 InhibitWhat w,
1274 const char *unit_name) {
1275
1276 const char *p, *q;
1277
1278 assert(m);
1279 assert(unit_name);
1280
1281 if (w != INHIBIT_SHUTDOWN)
1282 return 0;
1283
1284 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1285 p = "MESSAGE=System is powering down.";
1286 q = "SHUTDOWN=power-off";
1287 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1288 p = "MESSAGE=System is halting.";
1289 q = "SHUTDOWN=halt";
1290 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1291 p = "MESSAGE=System is rebooting.";
1292 q = "SHUTDOWN=reboot";
1293 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1294 p = "MESSAGE=System is rebooting with kexec.";
1295 q = "SHUTDOWN=kexec";
1296 } else {
1297 p = "MESSAGE=System is shutting down.";
1298 q = NULL;
1299 }
1300
1301 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1302 p,
1303 q, NULL);
1304}
1305
1306static int execute_shutdown_or_sleep(
1307 Manager *m,
1308 InhibitWhat w,
1309 const char *unit_name,
cc377381 1310 sd_bus_error *error) {
314b4b0a 1311
cc377381
LP
1312 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1313 const char *p;
af9792ac 1314 char *c;
cc377381 1315 int r;
eecd1362 1316
af9792ac 1317 assert(m);
314b4b0a
LP
1318 assert(w >= 0);
1319 assert(w < _INHIBIT_WHAT_MAX);
d889a206 1320 assert(unit_name);
eecd1362 1321
314b4b0a
LP
1322 bus_manager_log_shutdown(m, w, unit_name);
1323
cc377381 1324 r = sd_bus_call_method(
af9792ac 1325 m->bus,
eecd1362
LP
1326 "org.freedesktop.systemd1",
1327 "/org/freedesktop/systemd1",
1328 "org.freedesktop.systemd1.Manager",
b9c26b41 1329 "StartUnit",
af9792ac 1330 error,
cc377381
LP
1331 &reply,
1332 "ss", unit_name, "replace-irreversibly");
af9792ac
LP
1333 if (r < 0)
1334 return r;
1335
cc377381
LP
1336 r = sd_bus_message_read(reply, "o", &p);
1337 if (r < 0)
1338 return r;
af9792ac
LP
1339
1340 c = strdup(p);
1341 if (!c)
1342 return -ENOMEM;
1343
314b4b0a 1344 m->action_unit = unit_name;
af9792ac
LP
1345 free(m->action_job);
1346 m->action_job = c;
314b4b0a 1347 m->action_what = w;
af9792ac
LP
1348
1349 return 0;
eecd1362
LP
1350}
1351
314b4b0a
LP
1352static int delay_shutdown_or_sleep(
1353 Manager *m,
1354 InhibitWhat w,
1355 const char *unit_name) {
eecd1362 1356
eecd1362 1357 assert(m);
d889a206
LP
1358 assert(w >= 0);
1359 assert(w < _INHIBIT_WHAT_MAX);
314b4b0a 1360 assert(unit_name);
eecd1362 1361
314b4b0a
LP
1362 m->action_timestamp = now(CLOCK_MONOTONIC);
1363 m->action_unit = unit_name;
1364 m->action_what = w;
d889a206
LP
1365
1366 return 0;
1367}
1368
cc377381 1369static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
d889a206 1370
cc377381
LP
1371 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1372 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1373 [INHIBIT_SLEEP] = "PrepareForSleep"
1374 };
1375
1376 int active = _active;
877d54e9
LP
1377
1378 assert(m);
314b4b0a
LP
1379 assert(w >= 0);
1380 assert(w < _INHIBIT_WHAT_MAX);
1381 assert(signal_name[w]);
877d54e9 1382
cc377381
LP
1383 return sd_bus_emit_signal(m->bus,
1384 "/org/freedesktop/login1",
1385 "org.freedesktop.login1.Manager",
1386 signal_name[w],
1387 "b",
dd9f0525 1388 active);
877d54e9
LP
1389}
1390
069cfc85
LP
1391int bus_manager_shutdown_or_sleep_now_or_later(
1392 Manager *m,
1393 const char *unit_name,
1394 InhibitWhat w,
cc377381 1395 sd_bus_error *error) {
069cfc85
LP
1396
1397 bool delayed;
1398 int r;
1399
1400 assert(m);
1401 assert(unit_name);
1402 assert(w >= 0);
1403 assert(w <= _INHIBIT_WHAT_MAX);
af9792ac 1404 assert(!m->action_job);
069cfc85 1405
314b4b0a
LP
1406 /* Tell everybody to prepare for shutdown/sleep */
1407 send_prepare_for(m, w, true);
1408
069cfc85
LP
1409 delayed =
1410 m->inhibit_delay_max > 0 &&
409133be 1411 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
069cfc85
LP
1412
1413 if (delayed)
1414 /* Shutdown is delayed, keep in mind what we
1415 * want to do, and start a timeout */
1416 r = delay_shutdown_or_sleep(m, w, unit_name);
314b4b0a 1417 else
069cfc85
LP
1418 /* Shutdown is not delayed, execute it
1419 * immediately */
314b4b0a 1420 r = execute_shutdown_or_sleep(m, w, unit_name, error);
069cfc85
LP
1421
1422 return r;
1423}
1424
cc377381 1425static int method_do_shutdown_or_sleep(
d889a206 1426 Manager *m,
cc377381 1427 sd_bus_message *message,
d889a206
LP
1428 const char *unit_name,
1429 InhibitWhat w,
1430 const char *action,
1431 const char *action_multiple_sessions,
1432 const char *action_ignore_inhibit,
19adb8a3 1433 const char *sleep_verb,
cc377381 1434 sd_bus_message_handler_t method) {
d889a206 1435
cc377381 1436 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
069cfc85 1437 bool multiple_sessions, blocked;
cc377381
LP
1438 int interactive, r;
1439 uid_t uid;
d889a206
LP
1440
1441 assert(m);
d889a206
LP
1442 assert(message);
1443 assert(unit_name);
1444 assert(w >= 0);
1445 assert(w <= _INHIBIT_WHAT_MAX);
1446 assert(action);
1447 assert(action_multiple_sessions);
1448 assert(action_ignore_inhibit);
cc377381
LP
1449 assert(method);
1450
1451 r = sd_bus_message_read(message, "b", &interactive);
1452 if (r < 0)
1453 return sd_bus_reply_method_errno(m->bus, message, r, NULL);
d889a206 1454
314b4b0a
LP
1455 /* Don't allow multiple jobs being executed at the same time */
1456 if (m->action_what)
cc377381 1457 return sd_bus_reply_method_errorf(m->bus, message, BUS_ERROR_OPERATION_IN_PROGRESS, "There's already a shutdown or sleep operation in progress");
d889a206 1458
19adb8a3
ZJS
1459 if (sleep_verb) {
1460 r = can_sleep(sleep_verb);
6524990f 1461 if (r < 0)
cc377381 1462 return sd_bus_reply_method_errno(m->bus, message, r, NULL);
6524990f
LP
1463
1464 if (r == 0)
cc377381 1465 return sd_bus_reply_method_errorf(m->bus, message, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, "Sleep verb not supported");
6524990f
LP
1466 }
1467
cc377381
LP
1468 r = sd_bus_get_owner_uid(m->bus, sd_bus_message_get_sender(message), &uid);
1469 if (r < 0)
1470 return sd_bus_reply_method_errno(m->bus, message, r, NULL);
409133be 1471
cc377381 1472 r = have_multiple_sessions(m, uid);
d889a206 1473 if (r < 0)
cc377381 1474 return sd_bus_reply_method_errno(m->bus, message, r, NULL);
d889a206
LP
1475
1476 multiple_sessions = r > 0;
cc377381 1477 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid);
d889a206
LP
1478
1479 if (multiple_sessions) {
cc377381
LP
1480 r = bus_verify_polkit_async(m->bus, &m->polkit_registry, message,
1481 action_multiple_sessions, interactive, &error, method, m);
d889a206 1482 if (r < 0)
cc377381 1483 return sd_bus_reply_method_errno(m->bus, message, r, &error);
d889a206
LP
1484 }
1485
1486 if (blocked) {
cc377381
LP
1487 r = bus_verify_polkit_async(m->bus, &m->polkit_registry, message,
1488 action_ignore_inhibit, interactive, &error, method, m);
d889a206 1489 if (r < 0)
cc377381 1490 return sd_bus_reply_method_errno(m->bus, message, r, &error);
d889a206
LP
1491 }
1492
1493 if (!multiple_sessions && !blocked) {
cc377381
LP
1494 r = bus_verify_polkit_async(m->bus, &m->polkit_registry, message,
1495 action, interactive, &error, method, m);
d889a206 1496 if (r < 0)
cc377381 1497 return sd_bus_reply_method_errno(m->bus, message, r, &error);
d889a206
LP
1498 }
1499
cc377381 1500 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, &error);
d889a206 1501 if (r < 0)
cc377381 1502 return sd_bus_reply_method_errno(m->bus, message, r, &error);
d889a206 1503
cc377381 1504 return sd_bus_reply_method_return(m->bus, message, NULL);
eecd1362
LP
1505}
1506
cc377381 1507static int method_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata) {
3f49d45a
LP
1508 Manager *m = userdata;
1509
cc377381
LP
1510 return method_do_shutdown_or_sleep(
1511 m, message,
1512 SPECIAL_POWEROFF_TARGET,
1513 INHIBIT_SHUTDOWN,
1514 "org.freedesktop.login1.power-off",
1515 "org.freedesktop.login1.power-off-multiple-sessions",
1516 "org.freedesktop.login1.power-off-ignore-inhibit",
1517 NULL,
1518 method_poweroff);
1519}
88e3dc90 1520
cc377381
LP
1521static int method_reboot(sd_bus *bus, sd_bus_message *message, void *userdata) {
1522 Manager *m = userdata;
88e3dc90 1523
cc377381
LP
1524 return method_do_shutdown_or_sleep(
1525 m, message,
1526 SPECIAL_REBOOT_TARGET,
1527 INHIBIT_SHUTDOWN,
1528 "org.freedesktop.login1.reboot",
1529 "org.freedesktop.login1.reboot-multiple-sessions",
1530 "org.freedesktop.login1.reboot-ignore-inhibit",
1531 NULL,
1532 method_reboot);
1533}
88e3dc90 1534
cc377381
LP
1535static int method_suspend(sd_bus *bus, sd_bus_message *message, void *userdata) {
1536 Manager *m = userdata;
88e3dc90 1537
cc377381
LP
1538 return method_do_shutdown_or_sleep(
1539 m, message,
1540 SPECIAL_SUSPEND_TARGET,
1541 INHIBIT_SLEEP,
1542 "org.freedesktop.login1.suspend",
1543 "org.freedesktop.login1.suspend-multiple-sessions",
1544 "org.freedesktop.login1.suspend-ignore-inhibit",
1545 "suspend",
1546 method_suspend);
1547}
88e3dc90 1548
cc377381
LP
1549static int method_hibernate(sd_bus *bus, sd_bus_message *message, void *userdata) {
1550 Manager *m = userdata;
b6160029 1551
cc377381
LP
1552 return method_do_shutdown_or_sleep(
1553 m, message,
1554 SPECIAL_HIBERNATE_TARGET,
1555 INHIBIT_SLEEP,
1556 "org.freedesktop.login1.hibernate",
1557 "org.freedesktop.login1.hibernate-multiple-sessions",
1558 "org.freedesktop.login1.hibernate-ignore-inhibit",
1559 "hibernate",
1560 method_hibernate);
1561}
fa2b196d 1562
cc377381
LP
1563static int method_hybrid_sleep(sd_bus *bus, sd_bus_message *message, void *userdata) {
1564 Manager *m = userdata;
fa2b196d 1565
cc377381
LP
1566 return method_do_shutdown_or_sleep(
1567 m, message,
1568 SPECIAL_HYBRID_SLEEP_TARGET,
1569 INHIBIT_SLEEP,
1570 "org.freedesktop.login1.hibernate",
1571 "org.freedesktop.login1.hibernate-multiple-sessions",
1572 "org.freedesktop.login1.hibernate-ignore-inhibit",
1573 "hybrid-sleep",
1574 method_hybrid_sleep);
1575}
de07ab16 1576
cc377381
LP
1577static int method_can_shutdown_or_sleep(
1578 Manager *m,
1579 sd_bus_message *message,
1580 InhibitWhat w,
1581 const char *action,
1582 const char *action_multiple_sessions,
1583 const char *action_ignore_inhibit,
1584 const char *sleep_verb) {
de07ab16 1585
cc377381
LP
1586 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1587 bool multiple_sessions, challenge, blocked;
1588 const char *result = NULL;
1589 uid_t uid;
1590 int r;
de07ab16 1591
cc377381
LP
1592 assert(m);
1593 assert(message);
1594 assert(w >= 0);
1595 assert(w <= _INHIBIT_WHAT_MAX);
1596 assert(action);
1597 assert(action_multiple_sessions);
1598 assert(action_ignore_inhibit);
de07ab16 1599
cc377381
LP
1600 if (sleep_verb) {
1601 r = can_sleep(sleep_verb);
de07ab16 1602 if (r < 0)
cc377381
LP
1603 return sd_bus_reply_method_errno(m->bus, message, r, NULL);
1604 if (r == 0)
1605 return sd_bus_reply_method_return(m->bus, message, "s", "na");
1606 }
de07ab16 1607
cc377381
LP
1608 r = sd_bus_get_owner_uid(m->bus, sd_bus_message_get_sender(message), &uid);
1609 if (r < 0)
1610 return sd_bus_reply_method_errno(m->bus, message, r, NULL);
de07ab16 1611
cc377381
LP
1612 r = have_multiple_sessions(m, uid);
1613 if (r < 0)
1614 return sd_bus_reply_method_errno(m->bus, message, r, NULL);
de07ab16 1615
cc377381
LP
1616 multiple_sessions = r > 0;
1617 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid);
de07ab16 1618
cc377381
LP
1619 if (multiple_sessions) {
1620 r = bus_verify_polkit(m->bus, message, action_multiple_sessions, false, &challenge, &error);
de07ab16 1621 if (r < 0)
cc377381 1622 return sd_bus_reply_method_errno(m->bus, message, r, &error);
bef422ae 1623
cc377381
LP
1624 if (r > 0)
1625 result = "yes";
1626 else if (challenge)
1627 result = "challenge";
1628 else
1629 result = "no";
1630 }
bef422ae 1631
cc377381
LP
1632 if (blocked) {
1633 r = bus_verify_polkit(m->bus, message, action_ignore_inhibit, false, &challenge, &error);
bef422ae 1634 if (r < 0)
cc377381 1635 return sd_bus_reply_method_errno(m->bus, message, r, &error);
bef422ae 1636
cc377381
LP
1637 if (r > 0 && !result)
1638 result = "yes";
1639 else if (challenge && (!result || streq(result, "yes")))
1640 result = "challenge";
1641 else
1642 result = "no";
1643 }
bef422ae 1644
cc377381
LP
1645 if (!multiple_sessions && !blocked) {
1646 /* If neither inhibit nor multiple sessions
1647 * apply then just check the normal policy */
bef422ae 1648
cc377381 1649 r = bus_verify_polkit(m->bus, message, action, false, &challenge, &error);
bef422ae 1650 if (r < 0)
cc377381 1651 return sd_bus_reply_method_errno(m->bus, message, r, &error);
bef422ae 1652
cc377381
LP
1653 if (r > 0)
1654 result = "yes";
1655 else if (challenge)
1656 result = "challenge";
1657 else
1658 result = "no";
1659 }
bef422ae 1660
cc377381
LP
1661 return sd_bus_reply_method_return(m->bus, message, "s", result);
1662}
bef422ae 1663
cc377381
LP
1664static int method_can_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata) {
1665 Manager *m = userdata;
bef422ae 1666
cc377381
LP
1667 return method_can_shutdown_or_sleep(
1668 m, message,
1669 INHIBIT_SHUTDOWN,
1670 "org.freedesktop.login1.power-off",
1671 "org.freedesktop.login1.power-off-multiple-sessions",
1672 "org.freedesktop.login1.power-off-ignore-inhibit",
1673 NULL);
1674}
bef422ae 1675
cc377381
LP
1676static int method_can_reboot(sd_bus *bus, sd_bus_message *message, void *userdata) {
1677 Manager *m = userdata;
bef422ae 1678
cc377381
LP
1679 return method_can_shutdown_or_sleep(
1680 m, message,
1681 INHIBIT_SHUTDOWN,
1682 "org.freedesktop.login1.reboot",
1683 "org.freedesktop.login1.reboot-multiple-sessions",
1684 "org.freedesktop.login1.reboot-ignore-inhibit",
1685 NULL);
1686}
bef422ae 1687
cc377381
LP
1688static int method_can_suspend(sd_bus *bus, sd_bus_message *message, void *userdata) {
1689 Manager *m = userdata;
7f7bb946 1690
cc377381
LP
1691 return method_can_shutdown_or_sleep(
1692 m, message,
1693 INHIBIT_SLEEP,
1694 "org.freedesktop.login1.suspend",
1695 "org.freedesktop.login1.suspend-multiple-sessions",
1696 "org.freedesktop.login1.suspend-ignore-inhibit",
1697 "suspend");
1698}
7f7bb946 1699
cc377381
LP
1700static int method_can_hibernate(sd_bus *bus, sd_bus_message *message, void *userdata) {
1701 Manager *m = userdata;
02b16a19 1702
cc377381
LP
1703 return method_can_shutdown_or_sleep(
1704 m, message,
1705 INHIBIT_SLEEP,
1706 "org.freedesktop.login1.hibernate",
1707 "org.freedesktop.login1.hibernate-multiple-sessions",
1708 "org.freedesktop.login1.hibernate-ignore-inhibit",
1709 "hibernate");
1710}
7f7bb946 1711
cc377381
LP
1712static int method_can_hybrid_sleep(sd_bus *bus, sd_bus_message *message, void *userdata) {
1713 Manager *m = userdata;
7f7bb946 1714
cc377381
LP
1715 return method_can_shutdown_or_sleep(
1716 m, message,
1717 INHIBIT_SLEEP,
1718 "org.freedesktop.login1.hibernate",
1719 "org.freedesktop.login1.hibernate-multiple-sessions",
1720 "org.freedesktop.login1.hibernate-ignore-inhibit",
1721 "hybrid-sleep");
1722}
38f3fc7d 1723
cc377381
LP
1724static int method_inhibit(sd_bus *bus, sd_bus_message *message, void *userdata) {
1725 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1726 const char *who, *why, *what, *mode;
1727 _cleanup_free_ char *id = NULL;
1728 _cleanup_close_ int fifo_fd = -1;
1729 Manager *m = userdata;
1730 Inhibitor *i = NULL;
1731 InhibitMode mm;
1732 InhibitWhat w;
1733 pid_t pid;
1734 uid_t uid;
1735 int r;
7f7bb946 1736
cc377381
LP
1737 assert(bus);
1738 assert(message);
1739 assert(m);
38f3fc7d 1740
cc377381
LP
1741 r = sd_bus_message_read(message, "ssss", &what, &who, &why, &mode);
1742 if (r < 0)
1743 return sd_bus_reply_method_errno(bus, message, r, NULL);
38f3fc7d 1744
cc377381
LP
1745 w = inhibit_what_from_string(what);
1746 if (w <= 0)
1747 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid what specification %s", what);
38f3fc7d 1748
cc377381
LP
1749 mm = inhibit_mode_from_string(mode);
1750 if (mm < 0)
1751 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid mode specification %s", mode);
7f7bb946 1752
cc377381
LP
1753 /* Delay is only supported for shutdown/sleep */
1754 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP)))
1755 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Delay inhibitors only supported for shutdown and sleep");
38f3fc7d 1756
cc377381
LP
1757 /* Don't allow taking delay locks while we are already
1758 * executing the operation. We shouldn't create the impression
1759 * that the lock was successful if the machine is about to go
1760 * down/suspend any moment. */
1761 if (m->action_what & w)
1762 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_OPERATION_IN_PROGRESS, "The operation inhibition has been requested for is already running");
1763
1764 r = bus_verify_polkit_async(bus, &m->polkit_registry, message,
1765 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
1766 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
1767 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
1768 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
1769 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
1770 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
1771 "org.freedesktop.login1.inhibit-handle-lid-switch",
1772 false, &error, method_inhibit, m);
1773 if (r < 0)
1774 return sd_bus_reply_method_errno(bus, message, r, &error);
1775 if (r == 0)
1776 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7f7bb946 1777
cc377381
LP
1778 r = sd_bus_get_owner_uid(m->bus, sd_bus_message_get_sender(message), &uid);
1779 if (r < 0)
1780 return sd_bus_reply_method_errno(bus, message, r, NULL);
7f7bb946 1781
cc377381
LP
1782 r = sd_bus_get_owner_pid(m->bus, sd_bus_message_get_sender(message), &pid);
1783 if (r < 0)
1784 return sd_bus_reply_method_errno(bus, message, r, NULL);
47a26690 1785
cc377381
LP
1786 do {
1787 free(id);
1788 id = NULL;
47a26690 1789
cc377381
LP
1790 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0)
1791 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
47a26690 1792
cc377381 1793 } while (hashmap_get(m->inhibitors, id));
47a26690 1794
cc377381
LP
1795 r = manager_add_inhibitor(m, id, &i);
1796 if (r < 0)
1797 return sd_bus_reply_method_errno(bus, message, r, NULL);
47a26690 1798
cc377381
LP
1799 i->what = w;
1800 i->mode = mm;
1801 i->pid = pid;
1802 i->uid = uid;
1803 i->why = strdup(why);
1804 i->who = strdup(who);
7f7bb946 1805
cc377381
LP
1806 if (!i->why || !i->who) {
1807 r = sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
1808 goto fail;
1809 }
b668e064 1810
cc377381
LP
1811 fifo_fd = inhibitor_create_fifo(i);
1812 if (fifo_fd < 0) {
1813 r = sd_bus_reply_method_errno(bus, message, fifo_fd, NULL);
1814 goto fail;
1815 }
b668e064 1816
cc377381 1817 inhibitor_start(i);
b668e064 1818
cc377381 1819 return sd_bus_reply_method_return(bus, message, "h", fifo_fd);
b668e064 1820
cc377381
LP
1821fail:
1822 if (i)
1823 inhibitor_free(i);
89f13440 1824
cc377381
LP
1825 return r;
1826}
3f49d45a 1827
cc377381
LP
1828const sd_bus_vtable manager_vtable[] = {
1829 SD_BUS_VTABLE_START(0),
1830
1831 SD_BUS_PROPERTY("NAutoVTs", "u", NULL, offsetof(Manager, n_autovts), 0),
1832 SD_BUS_PROPERTY("KillOnlyUsers", "as", NULL, offsetof(Manager, kill_only_users), 0),
1833 SD_BUS_PROPERTY("KillExcludeUsers", "as", NULL, offsetof(Manager, kill_exclude_users), 0),
1834 SD_BUS_PROPERTY("KillUserProcesses", "b", NULL, offsetof(Manager, kill_user_processes), 0),
1835 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1836 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1837 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1838 SD_BUS_PROPERTY("BlockInhibited", "s", property_get_inhibited, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1839 SD_BUS_PROPERTY("DelayInhibited", "s", property_get_inhibited, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1840 SD_BUS_PROPERTY("InhibitDelayMaxUSec", "t", NULL, offsetof(Manager, inhibit_delay_max), 0),
1841 SD_BUS_PROPERTY("HandlePowerKey", "s", property_get_handle_action, offsetof(Manager, handle_power_key), 0),
1842 SD_BUS_PROPERTY("HandleSuspendKey", "s", property_get_handle_action, offsetof(Manager, handle_suspend_key), 0),
1843 SD_BUS_PROPERTY("HandleHibernateKey", "s", property_get_handle_action, offsetof(Manager, handle_hibernate_key), 0),
1844 SD_BUS_PROPERTY("HandleLidSwitch", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch), 0),
1845 SD_BUS_PROPERTY("IdleAction", "s", property_get_handle_action, offsetof(Manager, idle_action), 0),
1846 SD_BUS_PROPERTY("IdleActionUSec", "t", NULL, offsetof(Manager, idle_action_usec), 0),
1847 SD_BUS_PROPERTY("PreparingForShutdown", "b", property_get_preparing, 0, 0),
1848 SD_BUS_PROPERTY("PreparingForSleep", "b", property_get_preparing, 0, 0),
1849
1850 SD_BUS_METHOD("GetSession", "s", "o", method_get_session, 0),
1851 SD_BUS_METHOD("GetSessionByPID", "u", "o", method_get_session_by_pid, 0),
1852 SD_BUS_METHOD("GetUser", "u", "o", method_get_user, 0),
1853 SD_BUS_METHOD("GetUserByPID", "u", "o", method_get_user_by_pid, 0),
1854 SD_BUS_METHOD("GetSeat", "s", "o", method_get_seat, 0),
1855 SD_BUS_METHOD("ListSessions", NULL, "a(susso)", method_list_sessions, 0),
1856 SD_BUS_METHOD("ListUsers", NULL, "a(uso)", method_list_users, 0),
1857 SD_BUS_METHOD("ListSeats", NULL, "a(so)", method_list_seats, 0),
1858 SD_BUS_METHOD("ListInhibitors", NULL, "a(ssssuu)", method_list_inhibitors, 0),
1859 SD_BUS_METHOD("CreateSession", "uussssussbssa(sv)", "soshsub", method_create_session, 0),
1860 SD_BUS_METHOD("ReleaseSession", "s", NULL, method_release_session, 0),
1861 SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, 0),
1862 SD_BUS_METHOD("ActivateSessionOnSeat", "ss", NULL, method_activate_session_on_seat, 0),
1863 SD_BUS_METHOD("LockSession", "s", NULL, method_lock_session, 0),
1864 SD_BUS_METHOD("UnlockSession", "s", NULL, method_lock_session, 0),
1865 SD_BUS_METHOD("LockSessions", NULL, NULL, method_lock_sessions, 0),
1866 SD_BUS_METHOD("UnlockSessions", NULL, NULL, method_lock_sessions, 0),
1867 SD_BUS_METHOD("KillSession", "ssi", NULL, method_kill_session, 0),
1868 SD_BUS_METHOD("KillUser", "ui", NULL, method_kill_user, 0),
1869 SD_BUS_METHOD("TerminateSession", "s", NULL, method_terminate_session, 0),
1870 SD_BUS_METHOD("TerminateUser", "u", NULL, method_terminate_user, 0),
1871 SD_BUS_METHOD("TerminateSeat", "s", NULL, method_terminate_seat, 0),
1872 SD_BUS_METHOD("SetUserLinger", "ubb", NULL, method_set_user_linger, 0),
1873 SD_BUS_METHOD("AttachDevice", "ssb", NULL, method_attach_device, 0),
1874 SD_BUS_METHOD("FlushDevices", "b", NULL, method_flush_devices, 0),
1875 SD_BUS_METHOD("PowerOff", "b", NULL, method_poweroff, 0),
1876 SD_BUS_METHOD("Reboot", "b", NULL, method_reboot, 0),
1877 SD_BUS_METHOD("Suspend", "b", NULL, method_suspend, 0),
1878 SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, 0),
1879 SD_BUS_METHOD("HybridSleep", "b", NULL, method_hybrid_sleep, 0),
1880 SD_BUS_METHOD("CanPowerOff", NULL, "s", method_can_poweroff, 0),
1881 SD_BUS_METHOD("CanReboot", NULL, "s", method_can_reboot, 0),
1882 SD_BUS_METHOD("CanSuspend", NULL, "s", method_can_suspend, 0),
1883 SD_BUS_METHOD("CanHibernate", NULL, "s", method_can_hibernate, 0),
1884 SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, 0),
1885 SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, 0),
1886
1887 SD_BUS_SIGNAL("SessionNew", "so", 0),
1888 SD_BUS_SIGNAL("SessionRemoved", "so", 0),
1889 SD_BUS_SIGNAL("UserNew", "uo", 0),
1890 SD_BUS_SIGNAL("UserRemoved", "uo", 0),
1891 SD_BUS_SIGNAL("SeatNew", "so", 0),
1892 SD_BUS_SIGNAL("SeatRemoved", "so", 0),
1893 SD_BUS_SIGNAL("PrepareForShutdown", "b", 0),
1894 SD_BUS_SIGNAL("PrepareForSleep", "b", 0),
1895
1896 SD_BUS_VTABLE_END
1897};
3f49d45a 1898
cc377381
LP
1899int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata) {
1900 const char *path, *result, *unit;
1901 Manager *m = userdata;
1902 Session *session;
1903 uint32_t id;
1904 User *user;
1905 int r;
3f49d45a 1906
cc377381
LP
1907 assert(bus);
1908 assert(message);
1909 assert(m);
3f49d45a 1910
cc377381
LP
1911 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
1912 if (r < 0) {
1913 log_error("Failed to parse JobRemoved message: %s", strerror(-r));
1914 return 0;
1915 }
3f49d45a 1916
cc377381
LP
1917 if (m->action_job && streq(m->action_job, path)) {
1918 log_info("Operation finished.");
3f49d45a 1919
cc377381
LP
1920 /* Tell people that they now may take a lock again */
1921 send_prepare_for(m, m->action_what, false);
3f49d45a 1922
cc377381
LP
1923 free(m->action_job);
1924 m->action_job = NULL;
1925 m->action_unit = NULL;
1926 m->action_what = 0;
1927 return 0;
1928 }
3f49d45a 1929
cc377381
LP
1930 session = hashmap_get(m->session_units, unit);
1931 if (session) {
3f49d45a 1932
cc377381
LP
1933 if (streq_ptr(path, session->scope_job)) {
1934 free(session->scope_job);
1935 session->scope_job = NULL;
3f49d45a
LP
1936 }
1937
cc377381
LP
1938 if (session->started) {
1939 if (streq(result, "done"))
1940 session_send_create_reply(session, NULL);
1941 else {
1942 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
3f49d45a 1943
cc377381
LP
1944 sd_bus_error_setf(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
1945 session_send_create_reply(session, &error);
1946 }
1947 } else
1948 session_save(session);
3f49d45a 1949
cc377381
LP
1950 session_add_to_gc_queue(session);
1951 }
3f49d45a 1952
cc377381
LP
1953 user = hashmap_get(m->user_units, unit);
1954 if (user) {
3f49d45a 1955
cc377381
LP
1956 if (streq_ptr(path, user->service_job)) {
1957 free(user->service_job);
1958 user->service_job = NULL;
3f49d45a
LP
1959 }
1960
cc377381
LP
1961 if (streq_ptr(path, user->slice_job)) {
1962 free(user->slice_job);
1963 user->slice_job = NULL;
1964 }
3f49d45a 1965
cc377381
LP
1966 user_save(user);
1967 user_add_to_gc_queue(user);
3f49d45a
LP
1968 }
1969
cc377381 1970 return 0;
3f49d45a
LP
1971}
1972
cc377381
LP
1973int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata) {
1974 const char *path, *unit;
1713813d 1975 Manager *m = userdata;
cc377381
LP
1976 Session *session;
1977 User *user;
1978 int r;
1713813d 1979
cc377381 1980 assert(bus);
1713813d 1981 assert(message);
cc377381 1982 assert(m);
1713813d 1983
cc377381
LP
1984 r = sd_bus_message_read(message, "so", &unit, &path);
1985 if (r < 0) {
1986 log_error("Failed to parse UnitRemoved message: %s", strerror(-r));
1987 return 0;
1988 }
fb6becb4 1989
cc377381
LP
1990 session = hashmap_get(m->session_units, unit);
1991 if (session)
1992 session_add_to_gc_queue(session);
fb6becb4 1993
cc377381
LP
1994 user = hashmap_get(m->user_units, unit);
1995 if (user)
1996 user_add_to_gc_queue(user);
fb6becb4 1997
cc377381
LP
1998 return 0;
1999}
fb6becb4 2000
cc377381
LP
2001int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata) {
2002 _cleanup_free_ char *unit = NULL;
2003 Manager *m = userdata;
2004 const char *path;
2005 Session *session;
2006 User *user;
fb6becb4 2007
cc377381
LP
2008 assert(bus);
2009 assert(message);
2010 assert(m);
fb6becb4 2011
cc377381
LP
2012 path = sd_bus_message_get_path(message);
2013 if (!path)
2014 return 0;
fb6becb4 2015
cc377381
LP
2016 unit_name_from_dbus_path(path, &unit);
2017 if (!unit)
2018 return 0;
fb6becb4 2019
cc377381
LP
2020 session = hashmap_get(m->session_units, unit);
2021 if (session)
2022 session_add_to_gc_queue(session);
fb6becb4 2023
cc377381
LP
2024 user = hashmap_get(m->user_units, unit);
2025 if (user)
2026 user_add_to_gc_queue(user);
fb6becb4 2027
cc377381
LP
2028 return 0;
2029}
6fa48533 2030
cc377381
LP
2031int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata) {
2032 Manager *m = userdata;
2033 Session *session;
2034 Iterator i;
2035 int b, r;
943aca8e 2036
cc377381 2037 assert(bus);
943aca8e 2038
cc377381
LP
2039 r = sd_bus_message_read(message, "b", &b);
2040 if (r < 0) {
2041 log_error("Failed to parse Reloading message: %s", strerror(-r));
2042 return 0;
2043 }
943aca8e 2044
cc377381
LP
2045 if (b)
2046 return 0;
943aca8e 2047
cc377381
LP
2048 /* systemd finished reloading, let's recheck all our sessions */
2049 log_debug("System manager has been reloaded, rechecking sessions...");
6797c324 2050
cc377381
LP
2051 HASHMAP_FOREACH(session, m->sessions, i)
2052 session_add_to_gc_queue(session);
6797c324 2053
cc377381
LP
2054 return 0;
2055}
943aca8e 2056
cc377381
LP
2057int match_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata) {
2058 const char *name, *old, *new;
2059 Manager *m = userdata;
2060 Session *session;
2061 Iterator i;
2062 int r;
943aca8e 2063
6797c324 2064
cc377381 2065 char *key;
e8b212fe 2066
cc377381
LP
2067 r = sd_bus_message_read(message, "sss", &name, &old, &new);
2068 if (r < 0) {
2069 log_error("Failed to parse NameOwnerChanged message: %s", strerror(-r));
2070 return 0;
2071 }
e8b212fe 2072
cc377381
LP
2073 if (isempty(old) || !isempty(new))
2074 return 0;
e8b212fe 2075
cc377381
LP
2076 key = set_remove(m->busnames, (char*) old);
2077 if (!key)
2078 return 0;
ae5e06bd 2079
cc377381 2080 /* Drop all controllers owned by this name */
ae5e06bd 2081
cc377381 2082 free(key);
1713813d 2083
cc377381
LP
2084 HASHMAP_FOREACH(session, m->sessions, i)
2085 if (session_is_controller(session, old))
2086 session_drop_controller(session);
1713813d 2087
cc377381 2088 return 0;
1713813d
LP
2089}
2090
cc377381
LP
2091int manager_send_changed(Manager *manager, const char *property, ...) {
2092 char **l;
9418f147
LP
2093
2094 assert(manager);
2095
cc377381 2096 l = strv_from_stdarg_alloca(property);
9418f147 2097
cc377381
LP
2098 return sd_bus_emit_properties_changed_strv(
2099 manager->bus,
2100 "/org/freedesktop/login1",
2101 "org.freedesktop.login1.Manager",
2102 l);
9418f147 2103}
eecd1362 2104
d889a206 2105int manager_dispatch_delayed(Manager *manager) {
cc377381 2106 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
eecd1362
LP
2107 int r;
2108
2109 assert(manager);
2110
84286536 2111 if (manager->action_what == 0 || manager->action_job)
eecd1362
LP
2112 return 0;
2113
2114 /* Continue delay? */
314b4b0a 2115 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
eecd1362 2116
314b4b0a
LP
2117 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2118 return 0;
af9792ac 2119
314b4b0a
LP
2120 log_info("Delay lock is active but inhibitor timeout is reached.");
2121 }
eecd1362 2122
314b4b0a 2123 /* Actually do the operation */
314b4b0a 2124 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
eecd1362 2125 if (r < 0) {
cc377381 2126 log_warning("Failed to send delayed message: %s", bus_error_message(&error, r));
314b4b0a
LP
2127
2128 manager->action_unit = NULL;
2129 manager->action_what = 0;
eecd1362
LP
2130 return r;
2131 }
2132
eecd1362
LP
2133 return 1;
2134}
fb6becb4
LP
2135
2136int manager_start_scope(
2137 Manager *manager,
2138 const char *scope,
2139 pid_t pid,
2140 const char *slice,
2141 const char *description,
7fb3ee51 2142 const char *after,
405e0255 2143 const char *kill_mode,
cc377381 2144 sd_bus_error *error,
fb6becb4
LP
2145 char **job) {
2146
cc377381
LP
2147 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
2148 int r;
fb6becb4
LP
2149
2150 assert(manager);
2151 assert(scope);
2152 assert(pid > 1);
2153
cc377381
LP
2154 r = sd_bus_message_new_method_call(
2155 manager->bus,
fb6becb4
LP
2156 "org.freedesktop.systemd1",
2157 "/org/freedesktop/systemd1",
2158 "org.freedesktop.systemd1.Manager",
cc377381
LP
2159 "StartTransientUnit",
2160 &m);
2161 if (r < 0)
2162 return r;
fb6becb4 2163
cc377381
LP
2164 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
2165 if (r < 0)
2166 return r;
fb6becb4 2167
cc377381
LP
2168 r = sd_bus_message_open_container(m, 'a', "(sv)");
2169 if (r < 0)
2170 return r;
fb6becb4
LP
2171
2172 if (!isempty(slice)) {
cc377381
LP
2173 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
2174 if (r < 0)
2175 return r;
fb6becb4
LP
2176 }
2177
2178 if (!isempty(description)) {
cc377381
LP
2179 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
2180 if (r < 0)
2181 return r;
fb6becb4
LP
2182 }
2183
cc377381
LP
2184 if (!isempty(description)) {
2185 r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after);
2186 if (r < 0)
2187 return r;
7fb3ee51
LP
2188 }
2189
405e0255 2190 if (!isempty(kill_mode)) {
cc377381
LP
2191 r = sd_bus_message_append(m, "(sv)", "KillMode", "s", kill_mode);
2192 if (r < 0)
2193 return r;
405e0255
LP
2194 }
2195
fb6becb4
LP
2196 /* cgroup empty notification is not available in containers
2197 * currently. To make this less problematic, let's shorten the
2198 * stop timeout for sessions, so that we don't wait
2199 * forever. */
2200
cc377381
LP
2201 r = sd_bus_message_append(m, "(sv)", "TimeoutStopUSec", "t", 500 * USEC_PER_MSEC);
2202 if (r < 0)
2203 return r;
fb6becb4 2204
743e8945
LP
2205 /* Make sure that the session shells are terminated with
2206 * SIGHUP since bash and friends tend to ignore SIGTERM */
cc377381
LP
2207 r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", true);
2208 if (r < 0)
2209 return r;
2210
2211 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
2212 if (r < 0)
2213 return r;
2214
2215 r = sd_bus_message_close_container(m);
2216 if (r < 0)
2217 return r;
2218
c49b30a2 2219 r = sd_bus_call(manager->bus, m, 0, error, &reply);
cc377381
LP
2220 if (r < 0)
2221 return r;
fb6becb4
LP
2222
2223 if (job) {
2224 const char *j;
2225 char *copy;
2226
cc377381
LP
2227 r = sd_bus_message_read(reply, "o", &j);
2228 if (r < 0)
2229 return r;
fb6becb4
LP
2230
2231 copy = strdup(j);
2232 if (!copy)
2233 return -ENOMEM;
2234
2235 *job = copy;
2236 }
2237
cc377381 2238 return 1;
fb6becb4
LP
2239}
2240
cc377381
LP
2241int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
2242 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
fb6becb4
LP
2243 int r;
2244
2245 assert(manager);
2246 assert(unit);
2247
cc377381 2248 r = sd_bus_call_method(
fb6becb4
LP
2249 manager->bus,
2250 "org.freedesktop.systemd1",
2251 "/org/freedesktop/systemd1",
2252 "org.freedesktop.systemd1.Manager",
2253 "StartUnit",
fb6becb4 2254 error,
cc377381
LP
2255 &reply,
2256 "ss", unit, "fail");
2257 if (r < 0)
fb6becb4 2258 return r;
fb6becb4
LP
2259
2260 if (job) {
2261 const char *j;
2262 char *copy;
2263
cc377381
LP
2264 r = sd_bus_message_read(reply, "o", &j);
2265 if (r < 0)
2266 return r;
fb6becb4
LP
2267
2268 copy = strdup(j);
2269 if (!copy)
2270 return -ENOMEM;
2271
2272 *job = copy;
2273 }
2274
cc377381 2275 return 1;
fb6becb4
LP
2276}
2277
cc377381
LP
2278int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
2279 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
fb6becb4
LP
2280 int r;
2281
2282 assert(manager);
2283 assert(unit);
2284
cc377381 2285 r = sd_bus_call_method(
fb6becb4
LP
2286 manager->bus,
2287 "org.freedesktop.systemd1",
2288 "/org/freedesktop/systemd1",
2289 "org.freedesktop.systemd1.Manager",
2290 "StopUnit",
fb6becb4 2291 error,
cc377381
LP
2292 &reply,
2293 "ss", unit, "fail");
fb6becb4 2294 if (r < 0) {
cc377381
LP
2295 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
2296 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
2297
2298 if (job)
2299 *job = NULL;
2300
cc377381 2301 sd_bus_error_free(error);
6797c324
LP
2302 return 0;
2303 }
2304
fb6becb4
LP
2305 return r;
2306 }
2307
2308 if (job) {
2309 const char *j;
2310 char *copy;
2311
cc377381
LP
2312 r = sd_bus_message_read(reply, "o", &j);
2313 if (r < 0)
2314 return r;
fb6becb4
LP
2315
2316 copy = strdup(j);
2317 if (!copy)
2318 return -ENOMEM;
2319
2320 *job = copy;
2321 }
2322
6797c324 2323 return 1;
fb6becb4
LP
2324}
2325
cc377381 2326int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
fb6becb4
LP
2327 assert(manager);
2328 assert(unit);
2329
cc377381 2330 return sd_bus_call_method(
fb6becb4
LP
2331 manager->bus,
2332 "org.freedesktop.systemd1",
2333 "/org/freedesktop/systemd1",
2334 "org.freedesktop.systemd1.Manager",
2335 "KillUnit",
fb6becb4 2336 error,
cc377381
LP
2337 NULL,
2338 "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
fb6becb4
LP
2339}
2340
2341int manager_unit_is_active(Manager *manager, const char *unit) {
cc377381
LP
2342 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2343 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
fb6becb4 2344 _cleanup_free_ char *path = NULL;
fb6becb4 2345 const char *state;
fb6becb4
LP
2346 int r;
2347
2348 assert(manager);
2349 assert(unit);
2350
fb6becb4
LP
2351 path = unit_dbus_path_from_name(unit);
2352 if (!path)
2353 return -ENOMEM;
2354
cc377381 2355 r = sd_bus_get_property(
fb6becb4
LP
2356 manager->bus,
2357 "org.freedesktop.systemd1",
2358 path,
cc377381
LP
2359 "org.freedesktop.systemd1.Unit",
2360 "ActiveState",
fb6becb4 2361 &error,
cc377381
LP
2362 &reply,
2363 "s");
fb6becb4 2364 if (r < 0) {
cc377381
LP
2365 /* systemd might have droppped off momentarily, let's
2366 * not make this an error */
2367 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
2368 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 2369 return true;
6797c324 2370
cc377381
LP
2371 /* If the unit is already unloaded then it's not
2372 * active */
2373 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
2374 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 2375 return false;
6797c324 2376
fb6becb4
LP
2377 return r;
2378 }
2379
cc377381
LP
2380 r = sd_bus_message_read(reply, "s", &state);
2381 if (r < 0)
fb6becb4 2382 return -EINVAL;
fb6becb4 2383
cc377381
LP
2384 return !streq(state, "inactive") && !streq(state, "failed");
2385}
2386
2387int manager_job_is_active(Manager *manager, const char *path) {
2388 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2389 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
2390 int r;
2391
2392 assert(manager);
2393 assert(path);
2394
2395 r = sd_bus_get_property(
2396 manager->bus,
2397 "org.freedesktop.systemd1",
2398 path,
2399 "org.freedesktop.systemd1.Job",
2400 "State",
2401 &error,
2402 &reply,
2403 "s");
2404 if (r < 0) {
2405 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
2406 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
2407 return true;
2408
2409 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
2410 return false;
2411
2412 return r;
fb6becb4
LP
2413 }
2414
cc377381
LP
2415 /* We don't actually care about the state really. The fact
2416 * that we could read the job state is enough for us */
fb6becb4 2417
cc377381 2418 return true;
fb6becb4 2419}