]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-dbus.c
sd-*.h: clean up exported (or to-be-exported) header files
[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 22#include <errno.h>
4f5dd394 23#include <pwd.h>
a185c5aa 24#include <string.h>
98a28fef 25#include <unistd.h>
a185c5aa 26
cc377381 27#include "sd-messages.h"
4f5dd394 28
cc377381 29#include "audit.h"
96aad8d1 30#include "bus-common-errors.h"
4f5dd394
LP
31#include "bus-error.h"
32#include "bus-util.h"
5bdf2243 33#include "efivars.h"
4f5dd394
LP
34#include "escape.h"
35#include "fileio-label.h"
6482f626 36#include "formats-util.h"
4f5dd394
LP
37#include "logind.h"
38#include "mkdir.h"
39#include "path-util.h"
0b452006 40#include "process-util.h"
4f5dd394
LP
41#include "selinux-util.h"
42#include "sleep-config.h"
43#include "special.h"
44#include "strv.h"
288a74cc 45#include "terminal-util.h"
4f5dd394
LP
46#include "udev-util.h"
47#include "unit-name.h"
e2fa5721 48#include "utmp-wtmp.h"
3f49d45a 49
309a29df
LP
50int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) {
51 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
52 Session *session;
53 int r;
54
55 assert(m);
56 assert(message);
57 assert(ret);
58
59 if (isempty(name)) {
60 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
61 if (r < 0)
62 return r;
63
64 r = sd_bus_creds_get_session(creds, &name);
65 if (r < 0)
66 return r;
67 }
68
69 session = hashmap_get(m->sessions, name);
70 if (!session)
71 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
72
73 *ret = session;
74 return 0;
75}
76
77int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, sd_bus_error *error, User **ret) {
78 User *user;
79 int r;
80
81 assert(m);
82 assert(message);
83 assert(ret);
84
85 if (uid == UID_INVALID) {
86 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
87
88 /* Note that we get the owner UID of the session, not the actual client UID here! */
89 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
90 if (r < 0)
91 return r;
92
93 r = sd_bus_creds_get_owner_uid(creds, &uid);
94 if (r < 0)
95 return r;
96 }
97
8cb4ab00 98 user = hashmap_get(m->users, UID_TO_PTR(uid));
309a29df
LP
99 if (!user)
100 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "No user "UID_FMT" known or logged in", uid);
101
102 *ret = user;
103 return 0;
104}
105
106int manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Seat **ret) {
107 Seat *seat;
108 int r;
109
110 assert(m);
111 assert(message);
112 assert(ret);
113
114 if (isempty(name)) {
115 Session *session;
116
117 r = manager_get_session_from_creds(m, message, NULL, error, &session);
118 if (r < 0)
119 return r;
120
121 seat = session->seat;
122
123 if (!seat)
124 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "Session has no seat.");
125 } else {
126 seat = hashmap_get(m->seats, name);
127 if (!seat)
128 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", name);
129 }
130
131 *ret = seat;
132 return 0;
133}
134
cc377381
LP
135static int property_get_idle_hint(
136 sd_bus *bus,
137 const char *path,
138 const char *interface,
139 const char *property,
140 sd_bus_message *reply,
ebcf1f97
LP
141 void *userdata,
142 sd_bus_error *error) {
a185c5aa 143
cc377381 144 Manager *m = userdata;
a185c5aa 145
cc377381
LP
146 assert(bus);
147 assert(reply);
148 assert(m);
149
150 return sd_bus_message_append(reply, "b", manager_get_idle_hint(m, NULL) > 0);
a185c5aa
LP
151}
152
cc377381
LP
153static int property_get_idle_since_hint(
154 sd_bus *bus,
155 const char *path,
156 const char *interface,
157 const char *property,
158 sd_bus_message *reply,
ebcf1f97
LP
159 void *userdata,
160 sd_bus_error *error) {
cc377381
LP
161
162 Manager *m = userdata;
5cb14b37 163 dual_timestamp t = DUAL_TIMESTAMP_NULL;
a185c5aa 164
cc377381
LP
165 assert(bus);
166 assert(reply);
a185c5aa
LP
167 assert(m);
168
169 manager_get_idle_hint(m, &t);
a185c5aa 170
cc377381 171 return sd_bus_message_append(reply, "t", streq(property, "IdleSinceHint") ? t.realtime : t.monotonic);
a185c5aa
LP
172}
173
cc377381
LP
174static int property_get_inhibited(
175 sd_bus *bus,
176 const char *path,
177 const char *interface,
178 const char *property,
179 sd_bus_message *reply,
ebcf1f97
LP
180 void *userdata,
181 sd_bus_error *error) {
cc377381
LP
182
183 Manager *m = userdata;
f8e2fb7b 184 InhibitWhat w;
f8e2fb7b 185
cc377381
LP
186 assert(bus);
187 assert(reply);
188 assert(m);
f8e2fb7b 189
cc377381 190 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
f8e2fb7b 191
cc377381 192 return sd_bus_message_append(reply, "s", inhibit_what_to_string(w));
f8e2fb7b
LP
193}
194
cc377381
LP
195static int property_get_preparing(
196 sd_bus *bus,
197 const char *path,
198 const char *interface,
199 const char *property,
200 sd_bus_message *reply,
ebcf1f97
LP
201 void *userdata,
202 sd_bus_error *error) {
cc377381
LP
203
204 Manager *m = userdata;
205 bool b;
5e4a79da 206
cc377381
LP
207 assert(bus);
208 assert(reply);
209 assert(m);
5e4a79da
LP
210
211 if (streq(property, "PreparingForShutdown"))
314b4b0a 212 b = !!(m->action_what & INHIBIT_SHUTDOWN);
5e4a79da 213 else
314b4b0a 214 b = !!(m->action_what & INHIBIT_SLEEP);
5e4a79da 215
cc377381 216 return sd_bus_message_append(reply, "b", b);
5e4a79da
LP
217}
218
8aaa023a
DM
219static int property_get_scheduled_shutdown(
220 sd_bus *bus,
221 const char *path,
222 const char *interface,
223 const char *property,
224 sd_bus_message *reply,
225 void *userdata,
226 sd_bus_error *error) {
227
228 Manager *m = userdata;
229 int r;
230
231 assert(bus);
232 assert(reply);
233 assert(m);
234
235 r = sd_bus_message_open_container(reply, 'r', "st");
236 if (r < 0)
237 return r;
238
239 r = sd_bus_message_append(reply, "st", m->scheduled_shutdown_type, m->scheduled_shutdown_timeout);
240 if (r < 0)
241 return r;
242
243 return sd_bus_message_close_container(reply);
244}
245
cc377381 246static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_handle_action, handle_action, HandleAction);
fb6becb4 247
14856079
LP
248static int property_get_docked(
249 sd_bus *bus,
250 const char *path,
251 const char *interface,
252 const char *property,
253 sd_bus_message *reply,
254 void *userdata,
255 sd_bus_error *error) {
256
257 Manager *m = userdata;
258
259 assert(bus);
260 assert(reply);
261 assert(m);
262
602a41c2 263 return sd_bus_message_append(reply, "b", manager_is_docked_or_external_displays(m));
14856079
LP
264}
265
19070062 266static int method_get_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
267 _cleanup_free_ char *p = NULL;
268 Manager *m = userdata;
269 const char *name;
270 Session *session;
271 int r;
272
cc377381
LP
273 assert(message);
274 assert(m);
275
276 r = sd_bus_message_read(message, "s", &name);
277 if (r < 0)
ebcf1f97 278 return r;
cc377381 279
309a29df
LP
280 r = manager_get_session_from_creds(m, message, name, error, &session);
281 if (r < 0)
282 return r;
cc377381
LP
283
284 p = session_bus_path(session);
285 if (!p)
ebcf1f97 286 return -ENOMEM;
cc377381 287
df2d202e 288 return sd_bus_reply_method_return(message, "o", p);
cc377381
LP
289}
290
19070062 291static int method_get_session_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 292 _cleanup_free_ char *p = NULL;
954449b8 293 Session *session = NULL;
cc377381 294 Manager *m = userdata;
4e724d9c 295 pid_t pid;
cc377381
LP
296 int r;
297
cc377381
LP
298 assert(message);
299 assert(m);
300
4e724d9c
LP
301 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
302
cc377381
LP
303 r = sd_bus_message_read(message, "u", &pid);
304 if (r < 0)
ebcf1f97 305 return r;
cc377381 306
309a29df
LP
307 if (pid <= 0) {
308 r = manager_get_session_from_creds(m, message, NULL, error, &session);
5b12334d
LP
309 if (r < 0)
310 return r;
309a29df
LP
311 } else {
312 r = manager_get_session_by_pid(m, pid, &session);
4e724d9c 313 if (r < 0)
ebcf1f97 314 return r;
4e724d9c 315
309a29df
LP
316 if (!session)
317 return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID, "PID "PID_FMT" does not belong to any known session", pid);
318 }
cc377381
LP
319
320 p = session_bus_path(session);
321 if (!p)
ebcf1f97 322 return -ENOMEM;
cc377381 323
df2d202e 324 return sd_bus_reply_method_return(message, "o", p);
cc377381
LP
325}
326
19070062 327static int method_get_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
328 _cleanup_free_ char *p = NULL;
329 Manager *m = userdata;
330 uint32_t uid;
331 User *user;
332 int r;
333
cc377381
LP
334 assert(message);
335 assert(m);
336
337 r = sd_bus_message_read(message, "u", &uid);
338 if (r < 0)
ebcf1f97 339 return r;
cc377381 340
309a29df
LP
341 r = manager_get_user_from_creds(m, message, uid, error, &user);
342 if (r < 0)
343 return r;
cc377381
LP
344
345 p = user_bus_path(user);
346 if (!p)
ebcf1f97 347 return -ENOMEM;
cc377381 348
df2d202e 349 return sd_bus_reply_method_return(message, "o", p);
cc377381
LP
350}
351
19070062 352static int method_get_user_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
353 _cleanup_free_ char *p = NULL;
354 Manager *m = userdata;
954449b8 355 User *user = NULL;
4e724d9c 356 pid_t pid;
fb6becb4 357 int r;
98a28fef 358
cc377381 359 assert(message);
98a28fef 360 assert(m);
cc377381 361
4e724d9c
LP
362 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
363
cc377381
LP
364 r = sd_bus_message_read(message, "u", &pid);
365 if (r < 0)
ebcf1f97 366 return r;
cc377381 367
309a29df
LP
368 if (pid <= 0) {
369 r = manager_get_user_from_creds(m, message, UID_INVALID, error, &user);
5b12334d
LP
370 if (r < 0)
371 return r;
309a29df
LP
372 } else {
373 r = manager_get_user_by_pid(m, pid, &user);
4e724d9c 374 if (r < 0)
ebcf1f97 375 return r;
309a29df
LP
376 if (!user)
377 return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID, "PID "PID_FMT" does not belong to any known or logged in user", pid);
4e724d9c
LP
378 }
379
cc377381
LP
380 p = user_bus_path(user);
381 if (!p)
ebcf1f97 382 return -ENOMEM;
cc377381 383
df2d202e 384 return sd_bus_reply_method_return(message, "o", p);
cc377381
LP
385}
386
19070062 387static int method_get_seat(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
388 _cleanup_free_ char *p = NULL;
389 Manager *m = userdata;
390 const char *name;
391 Seat *seat;
392 int r;
393
98a28fef 394 assert(message);
cc377381 395 assert(m);
98a28fef 396
cc377381
LP
397 r = sd_bus_message_read(message, "s", &name);
398 if (r < 0)
ebcf1f97 399 return r;
98a28fef 400
309a29df
LP
401 r = manager_get_seat_from_creds(m, message, name, error, &seat);
402 if (r < 0)
403 return r;
98a28fef 404
cc377381
LP
405 p = seat_bus_path(seat);
406 if (!p)
ebcf1f97 407 return -ENOMEM;
98a28fef 408
df2d202e 409 return sd_bus_reply_method_return(message, "o", p);
cc377381 410}
98a28fef 411
19070062 412static int method_list_sessions(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
413 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
414 Manager *m = userdata;
415 Session *session;
416 Iterator i;
417 int r;
418
cc377381
LP
419 assert(message);
420 assert(m);
98a28fef 421
df2d202e 422 r = sd_bus_message_new_method_return(message, &reply);
cc377381 423 if (r < 0)
ebcf1f97 424 return r;
98a28fef 425
cc377381
LP
426 r = sd_bus_message_open_container(reply, 'a', "(susso)");
427 if (r < 0)
ebcf1f97 428 return r;
cc377381
LP
429
430 HASHMAP_FOREACH(session, m->sessions, i) {
431 _cleanup_free_ char *p = NULL;
432
433 p = session_bus_path(session);
434 if (!p)
ebcf1f97 435 return -ENOMEM;
cc377381
LP
436
437 r = sd_bus_message_append(reply, "(susso)",
438 session->id,
439 (uint32_t) session->user->uid,
440 session->user->name,
441 session->seat ? session->seat->id : "",
442 p);
443 if (r < 0)
ebcf1f97 444 return r;
cc377381
LP
445 }
446
447 r = sd_bus_message_close_container(reply);
448 if (r < 0)
ebcf1f97 449 return r;
cc377381 450
9030ca46 451 return sd_bus_send(NULL, reply, NULL);
cc377381
LP
452}
453
19070062 454static int method_list_users(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
455 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
456 Manager *m = userdata;
457 User *user;
458 Iterator i;
459 int r;
460
cc377381
LP
461 assert(message);
462 assert(m);
463
df2d202e 464 r = sd_bus_message_new_method_return(message, &reply);
cc377381 465 if (r < 0)
ebcf1f97 466 return r;
cc377381
LP
467
468 r = sd_bus_message_open_container(reply, 'a', "(uso)");
469 if (r < 0)
ebcf1f97 470 return r;
cc377381
LP
471
472 HASHMAP_FOREACH(user, m->users, i) {
473 _cleanup_free_ char *p = NULL;
474
475 p = user_bus_path(user);
476 if (!p)
ebcf1f97 477 return -ENOMEM;
cc377381
LP
478
479 r = sd_bus_message_append(reply, "(uso)",
480 (uint32_t) user->uid,
481 user->name,
482 p);
483 if (r < 0)
ebcf1f97 484 return r;
cc377381
LP
485 }
486
487 r = sd_bus_message_close_container(reply);
488 if (r < 0)
ebcf1f97 489 return r;
cc377381 490
9030ca46 491 return sd_bus_send(NULL, reply, NULL);
cc377381
LP
492}
493
19070062 494static int method_list_seats(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
495 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
496 Manager *m = userdata;
497 Seat *seat;
498 Iterator i;
499 int r;
500
cc377381
LP
501 assert(message);
502 assert(m);
503
df2d202e 504 r = sd_bus_message_new_method_return(message, &reply);
cc377381 505 if (r < 0)
ebcf1f97 506 return r;
cc377381
LP
507
508 r = sd_bus_message_open_container(reply, 'a', "(so)");
509 if (r < 0)
ebcf1f97 510 return r;
cc377381
LP
511
512 HASHMAP_FOREACH(seat, m->seats, i) {
513 _cleanup_free_ char *p = NULL;
514
515 p = seat_bus_path(seat);
516 if (!p)
ebcf1f97 517 return -ENOMEM;
cc377381 518
b8358bce 519 r = sd_bus_message_append(reply, "(so)", seat->id, p);
cc377381 520 if (r < 0)
ebcf1f97 521 return r;
cc377381
LP
522 }
523
524 r = sd_bus_message_close_container(reply);
525 if (r < 0)
ebcf1f97 526 return r;
cc377381 527
9030ca46 528 return sd_bus_send(NULL, reply, NULL);
cc377381
LP
529}
530
19070062 531static int method_list_inhibitors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
532 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
533 Manager *m = userdata;
534 Inhibitor *inhibitor;
535 Iterator i;
536 int r;
537
19070062
LP
538 assert(message);
539 assert(m);
540
df2d202e 541 r = sd_bus_message_new_method_return(message, &reply);
cc377381 542 if (r < 0)
ebcf1f97 543 return r;
cc377381
LP
544
545 r = sd_bus_message_open_container(reply, 'a', "(ssssuu)");
546 if (r < 0)
ebcf1f97 547 return r;
cc377381
LP
548
549 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
550
dbfa3fbb 551 r = sd_bus_message_append(reply, "(ssssuu)",
cc377381
LP
552 strempty(inhibit_what_to_string(inhibitor->what)),
553 strempty(inhibitor->who),
554 strempty(inhibitor->why),
555 strempty(inhibit_mode_to_string(inhibitor->mode)),
556 (uint32_t) inhibitor->uid,
557 (uint32_t) inhibitor->pid);
558 if (r < 0)
ebcf1f97 559 return r;
cc377381
LP
560 }
561
562 r = sd_bus_message_close_container(reply);
563 if (r < 0)
ebcf1f97 564 return r;
cc377381 565
9030ca46 566 return sd_bus_send(NULL, reply, NULL);
cc377381
LP
567}
568
19070062 569static int method_create_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
a4cd87e9 570 const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
cc377381
LP
571 uint32_t uid, leader, audit_id = 0;
572 _cleanup_free_ char *id = NULL;
573 Session *session = NULL;
574 Manager *m = userdata;
575 User *user = NULL;
576 Seat *seat = NULL;
577 int remote;
578 uint32_t vtnr = 0;
579 SessionType t;
580 SessionClass c;
581 int r;
582
cc377381
LP
583 assert(message);
584 assert(m);
585
a4cd87e9 586 r = sd_bus_message_read(message, "uusssssussbss", &uid, &leader, &service, &type, &class, &desktop, &cseat, &vtnr, &tty, &display, &remote, &remote_user, &remote_host);
cc377381 587 if (r < 0)
ebcf1f97 588 return r;
cc377381
LP
589
590 if (leader == 1)
ebcf1f97 591 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
98a28fef 592
e2acb67b
LP
593 if (isempty(type))
594 t = _SESSION_TYPE_INVALID;
595 else {
596 t = session_type_from_string(type);
597 if (t < 0)
ebcf1f97 598 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid session type %s", type);
e2acb67b 599 }
98a28fef 600
55efac6c 601 if (isempty(class))
e2acb67b
LP
602 c = _SESSION_CLASS_INVALID;
603 else {
55efac6c 604 c = session_class_from_string(class);
e2acb67b 605 if (c < 0)
ebcf1f97 606 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid session class %s", class);
e2acb67b 607 }
55efac6c 608
a4cd87e9
LP
609 if (isempty(desktop))
610 desktop = NULL;
611 else {
612 if (!string_is_safe(desktop))
613 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid desktop string %s", desktop);
614 }
615
954449b8
LP
616 if (isempty(cseat))
617 seat = NULL;
98a28fef 618 else {
954449b8
LP
619 seat = hashmap_get(m->seats, cseat);
620 if (!seat)
d14ab08b 621 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", cseat);
98a28fef
LP
622 }
623
98a28fef 624 if (tty_is_vc(tty)) {
4d6d6518 625 int v;
98a28fef 626
954449b8 627 if (!seat)
92432fcc
DH
628 seat = m->seat0;
629 else if (seat != m->seat0)
d14ab08b 630 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "TTY %s is virtual console but seat %s is not seat0", tty, seat->id);
98a28fef 631
4d6d6518 632 v = vtnr_from_tty(tty);
4d6d6518 633 if (v <= 0)
ebcf1f97 634 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot determine VT number from virtual console TTY %s", tty);
98a28fef 635
92bd5ff3 636 if (!vtnr)
4d6d6518
LP
637 vtnr = (uint32_t) v;
638 else if (vtnr != (uint32_t) v)
ebcf1f97 639 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified TTY and VT number do not match");
cc377381 640
d1122ad5
LP
641 } else if (tty_is_console(tty)) {
642
954449b8 643 if (!seat)
92432fcc
DH
644 seat = m->seat0;
645 else if (seat != m->seat0)
ebcf1f97 646 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but seat is not seat0");
d1122ad5
LP
647
648 if (vtnr != 0)
ebcf1f97 649 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but VT number is not 0");
978cf3c7 650 }
98a28fef 651
954449b8 652 if (seat) {
bf7825ae 653 if (seat_has_vts(seat)) {
c506027a 654 if (!vtnr || vtnr > 63)
ebcf1f97 655 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "VT number out of range");
4d6d6518 656 } else {
d1122ad5 657 if (vtnr != 0)
ebcf1f97 658 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Seat has no VTs but VT number not 0");
4d6d6518
LP
659 }
660 }
661
cc377381
LP
662 r = sd_bus_message_enter_container(message, 'a', "(sv)");
663 if (r < 0)
ebcf1f97 664 return r;
98a28fef 665
e2acb67b
LP
666 if (t == _SESSION_TYPE_INVALID) {
667 if (!isempty(display))
668 t = SESSION_X11;
669 else if (!isempty(tty))
670 t = SESSION_TTY;
671 else
672 t = SESSION_UNSPECIFIED;
673 }
674
675 if (c == _SESSION_CLASS_INVALID) {
a4cd87e9 676 if (t == SESSION_UNSPECIFIED)
e2acb67b 677 c = SESSION_BACKGROUND;
a4cd87e9
LP
678 else
679 c = SESSION_USER;
e2acb67b
LP
680 }
681
9444b1f2 682 if (leader <= 0) {
5b12334d
LP
683 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
684
685 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
686 if (r < 0)
687 return r;
688
5b12334d 689 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
cc377381 690 if (r < 0)
ebcf1f97 691 return r;
9444b1f2
LP
692 }
693
b80120c4
DH
694 r = manager_get_session_by_pid(m, leader, NULL);
695 if (r > 0)
696 return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already running in a session");
697
698 /*
699 * Old gdm and lightdm start the user-session on the same VT as
700 * the greeter session. But they destroy the greeter session
701 * after the user-session and want the user-session to take
702 * over the VT. We need to support this for
703 * backwards-compatibility, so make sure we allow new sessions
cc85d562
DH
704 * on a VT that a greeter is running on. Furthermore, to allow
705 * re-logins, we have to allow a greeter to take over a used VT for
706 * the exact same reasons.
b80120c4 707 */
cc85d562
DH
708 if (c != SESSION_GREETER &&
709 vtnr > 0 &&
b80120c4
DH
710 vtnr < m->seat0->position_count &&
711 m->seat0->positions[vtnr] &&
712 m->seat0->positions[vtnr]->class != SESSION_GREETER)
713 return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already occupied by a session");
21c390cc 714
954449b8
LP
715 audit_session_from_pid(leader, &audit_id);
716 if (audit_id > 0) {
717 /* Keep our session IDs and the audit session IDs in sync */
21c390cc 718
de0671ee 719 if (asprintf(&id, "%"PRIu32, audit_id) < 0)
ebcf1f97 720 return -ENOMEM;
21c390cc 721
954449b8
LP
722 /* Wut? There's already a session by this name and we
723 * didn't find it above? Weird, then let's not trust
724 * the audit data and let's better register a new
725 * ID */
726 if (hashmap_get(m->sessions, id)) {
4b549144 727 log_warning("Existing logind session ID %s used by new audit session, ignoring", id);
954449b8 728 audit_id = 0;
8ea913b2 729
97b11eed 730 id = mfree(id);
07714753 731 }
954449b8 732 }
07714753 733
954449b8 734 if (!id) {
07714753 735 do {
97b11eed 736 id = mfree(id);
07714753 737
cc377381 738 if (asprintf(&id, "c%lu", ++m->session_counter) < 0)
ebcf1f97 739 return -ENOMEM;
07714753
LP
740
741 } while (hashmap_get(m->sessions, id));
98a28fef
LP
742 }
743
954449b8 744 r = manager_add_user_by_uid(m, uid, &user);
ebcf1f97 745 if (r < 0)
954449b8
LP
746 goto fail;
747
9444b1f2 748 r = manager_add_session(m, id, &session);
ebcf1f97 749 if (r < 0)
98a28fef
LP
750 goto fail;
751
9444b1f2
LP
752 session_set_user(session, user);
753
98a28fef
LP
754 session->leader = leader;
755 session->audit_id = audit_id;
756 session->type = t;
55efac6c 757 session->class = c;
98a28fef 758 session->remote = remote;
98a28fef
LP
759 session->vtnr = vtnr;
760
98a28fef
LP
761 if (!isempty(tty)) {
762 session->tty = strdup(tty);
763 if (!session->tty) {
ebcf1f97 764 r = -ENOMEM;
98a28fef
LP
765 goto fail;
766 }
767 }
768
769 if (!isempty(display)) {
770 session->display = strdup(display);
771 if (!session->display) {
ebcf1f97 772 r = -ENOMEM;
98a28fef
LP
773 goto fail;
774 }
775 }
776
777 if (!isempty(remote_user)) {
778 session->remote_user = strdup(remote_user);
779 if (!session->remote_user) {
ebcf1f97 780 r = -ENOMEM;
98a28fef
LP
781 goto fail;
782 }
783 }
784
785 if (!isempty(remote_host)) {
786 session->remote_host = strdup(remote_host);
787 if (!session->remote_host) {
ebcf1f97 788 r = -ENOMEM;
98a28fef
LP
789 goto fail;
790 }
791 }
792
793 if (!isempty(service)) {
794 session->service = strdup(service);
795 if (!session->service) {
ebcf1f97 796 r = -ENOMEM;
98a28fef
LP
797 goto fail;
798 }
799 }
800
a4cd87e9
LP
801 if (!isempty(desktop)) {
802 session->desktop = strdup(desktop);
803 if (!session->desktop) {
804 r = -ENOMEM;
805 goto fail;
806 }
807 }
808
954449b8
LP
809 if (seat) {
810 r = seat_attach_session(seat, session);
ebcf1f97 811 if (r < 0)
98a28fef
LP
812 goto fail;
813 }
814
815 r = session_start(session);
ebcf1f97 816 if (r < 0)
98a28fef
LP
817 goto fail;
818
cc377381 819 session->create_message = sd_bus_message_ref(message);
98a28fef 820
cba38758
LP
821 /* Now, let's wait until the slice unit and stuff got
822 * created. We send the reply back from
f7340ab2 823 * session_send_create_reply(). */
cba38758 824
cc377381 825 return 1;
98a28fef
LP
826
827fail:
98a28fef
LP
828 if (session)
829 session_add_to_gc_queue(session);
830
831 if (user)
832 user_add_to_gc_queue(user);
833
98a28fef
LP
834 return r;
835}
836
19070062 837static int method_release_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
838 Manager *m = userdata;
839 Session *session;
840 const char *name;
841 int r;
314b4b0a 842
cc377381
LP
843 assert(message);
844 assert(m);
845
846 r = sd_bus_message_read(message, "s", &name);
847 if (r < 0)
ebcf1f97 848 return r;
cc377381 849
309a29df
LP
850 r = manager_get_session_from_creds(m, message, name, error, &session);
851 if (r < 0)
852 return r;
cc377381 853
ad8780c9
ZJS
854 r = session_release(session);
855 if (r < 0)
856 return r;
cc377381 857
df2d202e 858 return sd_bus_reply_method_return(message, NULL);
cc377381
LP
859}
860
19070062 861static int method_activate_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
862 Manager *m = userdata;
863 Session *session;
864 const char *name;
865 int r;
f8e2fb7b 866
cc377381 867 assert(message);
f8e2fb7b 868 assert(m);
cc377381
LP
869
870 r = sd_bus_message_read(message, "s", &name);
871 if (r < 0)
ebcf1f97 872 return r;
cc377381 873
309a29df
LP
874 r = manager_get_session_from_creds(m, message, name, error, &session);
875 if (r < 0)
876 return r;
cc377381 877
19070062 878 return bus_session_method_activate(message, session, error);
cc377381
LP
879}
880
19070062 881static int method_activate_session_on_seat(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
882 const char *session_name, *seat_name;
883 Manager *m = userdata;
884 Session *session;
885 Seat *seat;
886 int r;
887
f8e2fb7b 888 assert(message);
cc377381 889 assert(m);
f8e2fb7b 890
cc377381
LP
891 /* Same as ActivateSession() but refuses to work if
892 * the seat doesn't match */
f8e2fb7b 893
cc377381
LP
894 r = sd_bus_message_read(message, "ss", &session_name, &seat_name);
895 if (r < 0)
ebcf1f97 896 return r;
eecd1362 897
309a29df
LP
898 r = manager_get_session_from_creds(m, message, session_name, error, &session);
899 if (r < 0)
900 return r;
beaafb2e 901
309a29df
LP
902 r = manager_get_seat_from_creds(m, message, seat_name, error, &seat);
903 if (r < 0)
904 return r;
314b4b0a 905
cc377381 906 if (session->seat != seat)
ebcf1f97 907 return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", session_name, seat_name);
cc377381
LP
908
909 r = session_activate(session);
f8e2fb7b 910 if (r < 0)
ebcf1f97 911 return r;
f8e2fb7b 912
df2d202e 913 return sd_bus_reply_method_return(message, NULL);
cc377381 914}
f8e2fb7b 915
19070062 916static int method_lock_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
917 Manager *m = userdata;
918 Session *session;
919 const char *name;
920 int r;
f8e2fb7b 921
cc377381
LP
922 assert(message);
923 assert(m);
f8e2fb7b 924
cc377381
LP
925 r = sd_bus_message_read(message, "s", &name);
926 if (r < 0)
ebcf1f97 927 return r;
f8e2fb7b 928
309a29df
LP
929 r = manager_get_session_from_creds(m, message, name, error, &session);
930 if (r < 0)
931 return r;
f8e2fb7b 932
19070062 933 return bus_session_method_lock(message, session, error);
cc377381 934}
f8e2fb7b 935
19070062 936static int method_lock_sessions(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
937 Manager *m = userdata;
938 int r;
f8e2fb7b 939
cc377381
LP
940 assert(message);
941 assert(m);
f8e2fb7b 942
c529695e
LP
943 r = bus_verify_polkit_async(
944 message,
945 CAP_SYS_ADMIN,
946 "org.freedesktop.login1.lock-sessions",
403ed0e5 947 NULL,
c529695e
LP
948 false,
949 UID_INVALID,
950 &m->polkit_registry,
951 error);
952 if (r < 0)
953 return r;
954 if (r == 0)
955 return 1; /* Will call us back */
956
cc377381
LP
957 r = session_send_lock_all(m, streq(sd_bus_message_get_member(message), "LockSessions"));
958 if (r < 0)
ebcf1f97 959 return r;
f8e2fb7b 960
df2d202e 961 return sd_bus_reply_method_return(message, NULL);
cc377381
LP
962}
963
19070062 964static int method_kill_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c529695e 965 const char *name;
cc377381
LP
966 Manager *m = userdata;
967 Session *session;
cc377381
LP
968 int r;
969
cc377381
LP
970 assert(message);
971 assert(m);
972
c529695e 973 r = sd_bus_message_read(message, "s", &name);
cc377381 974 if (r < 0)
ebcf1f97 975 return r;
cc377381 976
309a29df
LP
977 r = manager_get_session_from_creds(m, message, name, error, &session);
978 if (r < 0)
979 return r;
f8e2fb7b 980
19070062 981 return bus_session_method_kill(message, session, error);
cc377381 982}
f8e2fb7b 983
19070062 984static int method_kill_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
985 Manager *m = userdata;
986 uint32_t uid;
cc377381
LP
987 User *user;
988 int r;
f8e2fb7b 989
cc377381
LP
990 assert(message);
991 assert(m);
992
c529695e 993 r = sd_bus_message_read(message, "u", &uid);
cc377381 994 if (r < 0)
ebcf1f97 995 return r;
cc377381 996
309a29df
LP
997 r = manager_get_user_from_creds(m, message, uid, error, &user);
998 if (r < 0)
999 return r;
cc377381 1000
19070062 1001 return bus_user_method_kill(message, user, error);
cc377381
LP
1002}
1003
19070062 1004static int method_terminate_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
1005 Manager *m = userdata;
1006 const char *name;
1007 Session *session;
1008 int r;
1009
cc377381
LP
1010 assert(message);
1011 assert(m);
1012
1013 r = sd_bus_message_read(message, "s", &name);
1014 if (r < 0)
ebcf1f97 1015 return r;
cc377381 1016
309a29df
LP
1017 r = manager_get_session_from_creds(m, message, name, error, &session);
1018 if (r < 0)
1019 return r;
cc377381 1020
19070062 1021 return bus_session_method_terminate(message, session, error);
cc377381
LP
1022}
1023
19070062 1024static int method_terminate_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
1025 Manager *m = userdata;
1026 uint32_t uid;
1027 User *user;
1028 int r;
1029
cc377381
LP
1030 assert(message);
1031 assert(m);
1032
1033 r = sd_bus_message_read(message, "u", &uid);
1034 if (r < 0)
ebcf1f97 1035 return r;
cc377381 1036
309a29df
LP
1037 r = manager_get_user_from_creds(m, message, uid, error, &user);
1038 if (r < 0)
1039 return r;
cc377381 1040
19070062 1041 return bus_user_method_terminate(message, user, error);
cc377381
LP
1042}
1043
19070062 1044static int method_terminate_seat(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
1045 Manager *m = userdata;
1046 const char *name;
1047 Seat *seat;
1048 int r;
1049
cc377381
LP
1050 assert(message);
1051 assert(m);
1052
1053 r = sd_bus_message_read(message, "s", &name);
1054 if (r < 0)
ebcf1f97 1055 return r;
cc377381 1056
309a29df
LP
1057 r = manager_get_seat_from_creds(m, message, name, error, &seat);
1058 if (r < 0)
1059 return r;
cc377381 1060
19070062 1061 return bus_seat_method_terminate(message, seat, error);
cc377381
LP
1062}
1063
19070062 1064static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
1065 _cleanup_free_ char *cc = NULL;
1066 Manager *m = userdata;
1067 int b, r;
1068 struct passwd *pw;
1069 const char *path;
1070 uint32_t uid;
1071 int interactive;
1072
cc377381
LP
1073 assert(message);
1074 assert(m);
1075
1076 r = sd_bus_message_read(message, "ubb", &uid, &b, &interactive);
1077 if (r < 0)
ebcf1f97 1078 return r;
cc377381 1079
309a29df
LP
1080 if (uid == UID_INVALID) {
1081 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1082
1083 /* Note that we get the owner UID of the session, not the actual client UID here! */
1084 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
1085 if (r < 0)
1086 return r;
1087
1088 r = sd_bus_creds_get_owner_uid(creds, &uid);
1089 if (r < 0)
1090 return r;
1091 }
1092
cc377381
LP
1093 errno = 0;
1094 pw = getpwuid(uid);
1095 if (!pw)
ebcf1f97 1096 return errno ? -errno : -ENOENT;
cc377381 1097
f3885791
LP
1098 r = bus_verify_polkit_async(
1099 message,
1100 CAP_SYS_ADMIN,
1101 "org.freedesktop.login1.set-user-linger",
403ed0e5 1102 NULL,
f3885791 1103 interactive,
c529695e 1104 UID_INVALID,
f3885791
LP
1105 &m->polkit_registry,
1106 error);
cc377381 1107 if (r < 0)
ebcf1f97 1108 return r;
cc377381
LP
1109 if (r == 0)
1110 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1111
1112 mkdir_p_label("/var/lib/systemd", 0755);
1113
1114 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1115 if (r < 0)
ebcf1f97 1116 return r;
cc377381
LP
1117
1118 cc = cescape(pw->pw_name);
1119 if (!cc)
ebcf1f97 1120 return -ENOMEM;
cc377381 1121
63c372cb 1122 path = strjoina("/var/lib/systemd/linger/", cc);
cc377381
LP
1123 if (b) {
1124 User *u;
1125
1126 r = touch(path);
1127 if (r < 0)
ebcf1f97 1128 return r;
cc377381
LP
1129
1130 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1131 user_start(u);
1132
1133 } else {
1134 User *u;
1135
1136 r = unlink(path);
1137 if (r < 0 && errno != ENOENT)
ebcf1f97 1138 return -errno;
cc377381 1139
8cb4ab00 1140 u = hashmap_get(m->users, UID_TO_PTR(uid));
cc377381
LP
1141 if (u)
1142 user_add_to_gc_queue(u);
1143 }
1144
df2d202e 1145 return sd_bus_reply_method_return(message, NULL);
f8e2fb7b
LP
1146}
1147
2eb916cd 1148static int trigger_device(Manager *m, struct udev_device *d) {
06acf2d4 1149 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
b668e064
LP
1150 struct udev_list_entry *first, *item;
1151 int r;
1152
1153 assert(m);
1154
1155 e = udev_enumerate_new(m->udev);
06acf2d4
LP
1156 if (!e)
1157 return -ENOMEM;
b668e064 1158
2eb916cd 1159 if (d) {
06acf2d4
LP
1160 r = udev_enumerate_add_match_parent(e, d);
1161 if (r < 0)
1162 return r;
2eb916cd
LP
1163 }
1164
06acf2d4
LP
1165 r = udev_enumerate_scan_devices(e);
1166 if (r < 0)
1167 return r;
b668e064
LP
1168
1169 first = udev_enumerate_get_list_entry(e);
1170 udev_list_entry_foreach(item, first) {
cc377381 1171 _cleanup_free_ char *t = NULL;
b668e064
LP
1172 const char *p;
1173
1174 p = udev_list_entry_get_name(item);
1175
b668e064 1176 t = strappend(p, "/uevent");
06acf2d4
LP
1177 if (!t)
1178 return -ENOMEM;
b668e064 1179
4c1fc3e4 1180 write_string_file(t, "change", WRITE_STRING_FILE_CREATE);
b668e064
LP
1181 }
1182
06acf2d4 1183 return 0;
b668e064
LP
1184}
1185
47a26690 1186static int attach_device(Manager *m, const char *seat, const char *sysfs) {
06acf2d4 1187 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
7fd1b19b 1188 _cleanup_free_ char *rule = NULL, *file = NULL;
c28fa3d3 1189 const char *id_for_seat;
47a26690
LP
1190 int r;
1191
1192 assert(m);
1193 assert(seat);
1194 assert(sysfs);
1195
1196 d = udev_device_new_from_syspath(m->udev, sysfs);
1197 if (!d)
1198 return -ENODEV;
1199
06acf2d4
LP
1200 if (!udev_device_has_tag(d, "seat"))
1201 return -ENODEV;
47a26690 1202
c28fa3d3 1203 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
06acf2d4
LP
1204 if (!id_for_seat)
1205 return -ENODEV;
47a26690 1206
06acf2d4
LP
1207 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0)
1208 return -ENOMEM;
47a26690 1209
06acf2d4
LP
1210 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0)
1211 return -ENOMEM;
47a26690 1212
d2e54fae 1213 mkdir_p_label("/etc/udev/rules.d", 0755);
cc56fafe 1214 mac_selinux_init("/etc");
574d5f2d 1215 r = write_string_file_atomic_label(file, rule);
a0a0c7f1 1216 if (r < 0)
06acf2d4 1217 return r;
47a26690 1218
06acf2d4 1219 return trigger_device(m, d);
47a26690
LP
1220}
1221
b668e064 1222static int flush_devices(Manager *m) {
7fd1b19b 1223 _cleanup_closedir_ DIR *d;
b668e064
LP
1224
1225 assert(m);
1226
1227 d = opendir("/etc/udev/rules.d");
1228 if (!d) {
1229 if (errno != ENOENT)
56f64d95 1230 log_warning_errno(errno, "Failed to open /etc/udev/rules.d: %m");
b668e064
LP
1231 } else {
1232 struct dirent *de;
1233
1234 while ((de = readdir(d))) {
1235
1236 if (!dirent_is_file(de))
1237 continue;
1238
1239 if (!startswith(de->d_name, "72-seat-"))
1240 continue;
1241
1242 if (!endswith(de->d_name, ".rules"))
1243 continue;
1244
1245 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
56f64d95 1246 log_warning_errno(errno, "Failed to unlink %s: %m", de->d_name);
b668e064 1247 }
b668e064
LP
1248 }
1249
1250 return trigger_device(m, NULL);
1251}
1252
19070062 1253static int method_attach_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
1254 const char *sysfs, *seat;
1255 Manager *m = userdata;
1256 int interactive, r;
1257
cc377381
LP
1258 assert(message);
1259 assert(m);
1260
1261 r = sd_bus_message_read(message, "ssb", &seat, &sysfs, &interactive);
1262 if (r < 0)
ebcf1f97 1263 return r;
cc377381
LP
1264
1265 if (!path_startswith(sysfs, "/sys"))
ebcf1f97 1266 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not in /sys", sysfs);
cc377381
LP
1267
1268 if (!seat_name_is_valid(seat))
ebcf1f97 1269 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Seat %s is not valid", seat);
cc377381 1270
f3885791
LP
1271 r = bus_verify_polkit_async(
1272 message,
1273 CAP_SYS_ADMIN,
1274 "org.freedesktop.login1.attach-device",
403ed0e5 1275 NULL,
f3885791 1276 interactive,
c529695e 1277 UID_INVALID,
f3885791
LP
1278 &m->polkit_registry,
1279 error);
cc377381 1280 if (r < 0)
ebcf1f97 1281 return r;
cc377381
LP
1282 if (r == 0)
1283 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1284
1285 r = attach_device(m, seat, sysfs);
1286 if (r < 0)
ebcf1f97 1287 return r;
cc377381 1288
df2d202e 1289 return sd_bus_reply_method_return(message, NULL);
cc377381
LP
1290}
1291
19070062 1292static int method_flush_devices(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
1293 Manager *m = userdata;
1294 int interactive, r;
1295
cc377381
LP
1296 assert(message);
1297 assert(m);
1298
1299 r = sd_bus_message_read(message, "b", &interactive);
1300 if (r < 0)
ebcf1f97 1301 return r;
cc377381 1302
f3885791
LP
1303 r = bus_verify_polkit_async(
1304 message,
1305 CAP_SYS_ADMIN,
1306 "org.freedesktop.login1.flush-devices",
403ed0e5 1307 NULL,
f3885791 1308 interactive,
c529695e 1309 UID_INVALID,
f3885791
LP
1310 &m->polkit_registry,
1311 error);
cc377381 1312 if (r < 0)
ebcf1f97 1313 return r;
cc377381
LP
1314 if (r == 0)
1315 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1316
1317 r = flush_devices(m);
1318 if (r < 0)
ebcf1f97 1319 return r;
cc377381 1320
df2d202e 1321 return sd_bus_reply_method_return(message, NULL);
cc377381
LP
1322}
1323
89f13440 1324static int have_multiple_sessions(
89f13440 1325 Manager *m,
409133be 1326 uid_t uid) {
89f13440 1327
2154761f
MS
1328 Session *session;
1329 Iterator i;
89f13440
LP
1330
1331 assert(m);
1332
1ca04b87
LP
1333 /* Check for other users' sessions. Greeter sessions do not
1334 * count, and non-login sessions do not count either. */
2154761f 1335 HASHMAP_FOREACH(session, m->sessions, i)
1ca04b87 1336 if (session->class == SESSION_USER &&
1ca04b87 1337 session->user->uid != uid)
2154761f 1338 return true;
89f13440
LP
1339
1340 return false;
1341}
1342
314b4b0a
LP
1343static int bus_manager_log_shutdown(
1344 Manager *m,
1345 InhibitWhat w,
1346 const char *unit_name) {
1347
5744f59a 1348 const char *p, *q;
314b4b0a
LP
1349
1350 assert(m);
1351 assert(unit_name);
1352
1353 if (w != INHIBIT_SHUTDOWN)
1354 return 0;
1355
1356 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
f868cb58 1357 p = "MESSAGE=System is powering down";
314b4b0a
LP
1358 q = "SHUTDOWN=power-off";
1359 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
f868cb58 1360 p = "MESSAGE=System is halting";
314b4b0a
LP
1361 q = "SHUTDOWN=halt";
1362 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
f868cb58 1363 p = "MESSAGE=System is rebooting";
314b4b0a
LP
1364 q = "SHUTDOWN=reboot";
1365 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
f868cb58 1366 p = "MESSAGE=System is rebooting with kexec";
314b4b0a
LP
1367 q = "SHUTDOWN=kexec";
1368 } else {
f868cb58 1369 p = "MESSAGE=System is shutting down";
314b4b0a
LP
1370 q = NULL;
1371 }
1372
f868cb58
ZJS
1373 if (isempty(m->wall_message))
1374 p = strjoina(p, ".");
1375 else
1376 p = strjoina(p, " (", m->wall_message, ").");
9ef15026 1377
e2cc6eca
LP
1378 return log_struct(LOG_NOTICE,
1379 LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
314b4b0a 1380 p,
e2cc6eca
LP
1381 q,
1382 NULL);
314b4b0a
LP
1383}
1384
b5d3e168
KS
1385static int lid_switch_ignore_handler(sd_event_source *e, uint64_t usec, void *userdata) {
1386 Manager *m = userdata;
1387
1388 assert(e);
1389 assert(m);
1390
1391 m->lid_switch_ignore_event_source = sd_event_source_unref(m->lid_switch_ignore_event_source);
1392 return 0;
1393}
1394
1395int manager_set_lid_switch_ignore(Manager *m, usec_t until) {
1396 int r;
1397
1398 assert(m);
1399
1400 if (until <= now(CLOCK_MONOTONIC))
1401 return 0;
1402
1403 /* We want to ignore the lid switch for a while after each
1404 * suspend, and after boot-up. Hence let's install a timer for
1405 * this. As long as the event source exists we ignore the lid
1406 * switch. */
1407
1408 if (m->lid_switch_ignore_event_source) {
1409 usec_t u;
1410
1411 r = sd_event_source_get_time(m->lid_switch_ignore_event_source, &u);
1412 if (r < 0)
1413 return r;
1414
1415 if (until <= u)
1416 return 0;
1417
1418 r = sd_event_source_set_time(m->lid_switch_ignore_event_source, until);
1419 } else
6a0f1f6d
LP
1420 r = sd_event_add_time(
1421 m->event,
1422 &m->lid_switch_ignore_event_source,
1423 CLOCK_MONOTONIC,
1424 until, 0,
1425 lid_switch_ignore_handler, m);
b5d3e168
KS
1426
1427 return r;
1428}
1429
1389f4b9
DM
1430static void reset_scheduled_shutdown(Manager *m) {
1431 m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
1432 m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source);
1433 m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
1434 m->scheduled_shutdown_type = mfree(m->scheduled_shutdown_type);
1435 m->scheduled_shutdown_timeout = 0;
1436 m->shutdown_dry_run = false;
1437
1438 if (m->unlink_nologin) {
1439 (void) unlink("/run/nologin");
1440 m->unlink_nologin = false;
1441 }
1442}
1443
314b4b0a
LP
1444static int execute_shutdown_or_sleep(
1445 Manager *m,
1446 InhibitWhat w,
1447 const char *unit_name,
cc377381 1448 sd_bus_error *error) {
314b4b0a 1449
cc377381 1450 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1389f4b9 1451 char *c = NULL;
cc377381 1452 const char *p;
cc377381 1453 int r;
eecd1362 1454
af9792ac 1455 assert(m);
314b4b0a
LP
1456 assert(w >= 0);
1457 assert(w < _INHIBIT_WHAT_MAX);
d889a206 1458 assert(unit_name);
eecd1362 1459
314b4b0a
LP
1460 bus_manager_log_shutdown(m, w, unit_name);
1461
1389f4b9
DM
1462 if (m->shutdown_dry_run) {
1463 log_info("Running in dry run, suppressing action.");
1464 reset_scheduled_shutdown(m);
1465 } else {
1466 r = sd_bus_call_method(
1467 m->bus,
1468 "org.freedesktop.systemd1",
1469 "/org/freedesktop/systemd1",
1470 "org.freedesktop.systemd1.Manager",
1471 "StartUnit",
1472 error,
1473 &reply,
1474 "ss", unit_name, "replace-irreversibly");
1475 if (r < 0)
1476 return r;
af9792ac 1477
1389f4b9
DM
1478 r = sd_bus_message_read(reply, "o", &p);
1479 if (r < 0)
1480 return r;
af9792ac 1481
1389f4b9
DM
1482 c = strdup(p);
1483 if (!c)
1484 return -ENOMEM;
1485 }
af9792ac 1486
314b4b0a 1487 m->action_unit = unit_name;
af9792ac
LP
1488 free(m->action_job);
1489 m->action_job = c;
314b4b0a 1490 m->action_what = w;
af9792ac 1491
f9cd6be1 1492 /* Make sure the lid switch is ignored for a while */
9d10cbee 1493 manager_set_lid_switch_ignore(m, now(CLOCK_MONOTONIC) + m->holdoff_timeout_usec);
f9cd6be1 1494
af9792ac 1495 return 0;
eecd1362
LP
1496}
1497
418b22b8 1498int manager_dispatch_delayed(Manager *manager, bool timeout) {
c0f32805
DM
1499
1500 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1501 Inhibitor *offending = NULL;
c0f32805
DM
1502 int r;
1503
1504 assert(manager);
c0f32805
DM
1505
1506 if (manager->action_what == 0 || manager->action_job)
1507 return 0;
1508
1509 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) {
1510 _cleanup_free_ char *comm = NULL, *u = NULL;
1511
418b22b8
DM
1512 if (!timeout)
1513 return 0;
1514
c0f32805
DM
1515 (void) get_process_comm(offending->pid, &comm);
1516 u = uid_to_name(offending->uid);
1517
1518 log_notice("Delay lock is active (UID "UID_FMT"/%s, PID "PID_FMT"/%s) but inhibitor timeout is reached.",
1519 offending->uid, strna(u),
1520 offending->pid, strna(comm));
1521 }
1522
1523 /* Actually do the operation */
1524 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
1525 if (r < 0) {
1526 log_warning("Failed to send delayed message: %s", bus_error_message(&error, r));
1527
1528 manager->action_unit = NULL;
1529 manager->action_what = 0;
418b22b8 1530 return r;
c0f32805
DM
1531 }
1532
418b22b8
DM
1533 return 1;
1534}
1535
1536static int manager_inhibit_timeout_handler(
1537 sd_event_source *s,
1538 uint64_t usec,
1539 void *userdata) {
1540
1541 Manager *manager = userdata;
1542 int r;
1543
1544 assert(manager);
1545 assert(manager->inhibit_timeout_source == s);
1546
1547 r = manager_dispatch_delayed(manager, true);
1548 return (r < 0) ? r : 0;
c0f32805
DM
1549}
1550
314b4b0a
LP
1551static int delay_shutdown_or_sleep(
1552 Manager *m,
1553 InhibitWhat w,
1554 const char *unit_name) {
eecd1362 1555
c0f32805
DM
1556 int r;
1557 usec_t timeout_val;
1558
eecd1362 1559 assert(m);
d889a206
LP
1560 assert(w >= 0);
1561 assert(w < _INHIBIT_WHAT_MAX);
314b4b0a 1562 assert(unit_name);
eecd1362 1563
c0f32805
DM
1564 timeout_val = now(CLOCK_MONOTONIC) + m->inhibit_delay_max;
1565
1566 if (m->inhibit_timeout_source) {
1567 r = sd_event_source_set_time(m->inhibit_timeout_source, timeout_val);
1568 if (r < 0)
c2a23db0 1569 return log_error_errno(r, "sd_event_source_set_time() failed: %m");
c0f32805
DM
1570
1571 r = sd_event_source_set_enabled(m->inhibit_timeout_source, SD_EVENT_ONESHOT);
1572 if (r < 0)
c2a23db0 1573 return log_error_errno(r, "sd_event_source_set_enabled() failed: %m");
c0f32805
DM
1574 } else {
1575 r = sd_event_add_time(m->event, &m->inhibit_timeout_source, CLOCK_MONOTONIC,
1576 timeout_val, 0, manager_inhibit_timeout_handler, m);
1577 if (r < 0)
1578 return r;
1579 }
1580
314b4b0a
LP
1581 m->action_unit = unit_name;
1582 m->action_what = w;
d889a206
LP
1583
1584 return 0;
1585}
1586
cc377381 1587static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
d889a206 1588
cc377381
LP
1589 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1590 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1591 [INHIBIT_SLEEP] = "PrepareForSleep"
1592 };
1593
1594 int active = _active;
877d54e9
LP
1595
1596 assert(m);
314b4b0a
LP
1597 assert(w >= 0);
1598 assert(w < _INHIBIT_WHAT_MAX);
1599 assert(signal_name[w]);
877d54e9 1600
cc377381
LP
1601 return sd_bus_emit_signal(m->bus,
1602 "/org/freedesktop/login1",
1603 "org.freedesktop.login1.Manager",
1604 signal_name[w],
1605 "b",
dd9f0525 1606 active);
877d54e9
LP
1607}
1608
069cfc85
LP
1609int bus_manager_shutdown_or_sleep_now_or_later(
1610 Manager *m,
1611 const char *unit_name,
1612 InhibitWhat w,
cc377381 1613 sd_bus_error *error) {
069cfc85
LP
1614
1615 bool delayed;
1616 int r;
1617
1618 assert(m);
1619 assert(unit_name);
1620 assert(w >= 0);
1621 assert(w <= _INHIBIT_WHAT_MAX);
af9792ac 1622 assert(!m->action_job);
069cfc85 1623
314b4b0a
LP
1624 /* Tell everybody to prepare for shutdown/sleep */
1625 send_prepare_for(m, w, true);
1626
069cfc85
LP
1627 delayed =
1628 m->inhibit_delay_max > 0 &&
85a428c6 1629 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0, NULL);
069cfc85
LP
1630
1631 if (delayed)
1632 /* Shutdown is delayed, keep in mind what we
1633 * want to do, and start a timeout */
1634 r = delay_shutdown_or_sleep(m, w, unit_name);
314b4b0a 1635 else
069cfc85
LP
1636 /* Shutdown is not delayed, execute it
1637 * immediately */
314b4b0a 1638 r = execute_shutdown_or_sleep(m, w, unit_name, error);
069cfc85
LP
1639
1640 return r;
1641}
1642
b7aa9589 1643static int verify_shutdown_creds(
d889a206 1644 Manager *m,
cc377381 1645 sd_bus_message *message,
d889a206 1646 InhibitWhat w,
b7aa9589 1647 bool interactive,
d889a206
LP
1648 const char *action,
1649 const char *action_multiple_sessions,
1650 const char *action_ignore_inhibit,
ebcf1f97 1651 sd_bus_error *error) {
d889a206 1652
5b12334d 1653 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
069cfc85 1654 bool multiple_sessions, blocked;
cc377381 1655 uid_t uid;
b7aa9589 1656 int r;
d889a206
LP
1657
1658 assert(m);
d889a206 1659 assert(message);
d889a206
LP
1660 assert(w >= 0);
1661 assert(w <= _INHIBIT_WHAT_MAX);
6524990f 1662
05bae4a6 1663 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
5b12334d
LP
1664 if (r < 0)
1665 return r;
1666
05bae4a6 1667 r = sd_bus_creds_get_euid(creds, &uid);
cc377381 1668 if (r < 0)
ebcf1f97 1669 return r;
409133be 1670
cc377381 1671 r = have_multiple_sessions(m, uid);
d889a206 1672 if (r < 0)
ebcf1f97 1673 return r;
d889a206
LP
1674
1675 multiple_sessions = r > 0;
85a428c6 1676 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
d889a206 1677
b7aa9589 1678 if (multiple_sessions && action_multiple_sessions) {
403ed0e5 1679 r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
d889a206 1680 if (r < 0)
ebcf1f97 1681 return r;
055d4066
ZJS
1682 if (r == 0)
1683 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
d889a206
LP
1684 }
1685
b7aa9589 1686 if (blocked && action_ignore_inhibit) {
403ed0e5 1687 r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
d889a206 1688 if (r < 0)
ebcf1f97 1689 return r;
055d4066
ZJS
1690 if (r == 0)
1691 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
d889a206
LP
1692 }
1693
b7aa9589 1694 if (!multiple_sessions && !blocked && action) {
403ed0e5 1695 r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
d889a206 1696 if (r < 0)
ebcf1f97 1697 return r;
055d4066
ZJS
1698 if (r == 0)
1699 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
d889a206
LP
1700 }
1701
b7aa9589
DM
1702 return 0;
1703}
1704
1705static int method_do_shutdown_or_sleep(
1706 Manager *m,
1707 sd_bus_message *message,
1708 const char *unit_name,
1709 InhibitWhat w,
1710 const char *action,
1711 const char *action_multiple_sessions,
1712 const char *action_ignore_inhibit,
1713 const char *sleep_verb,
1714 sd_bus_error *error) {
1715
1716 int interactive, r;
1717
1718 assert(m);
1719 assert(message);
1720 assert(unit_name);
1721 assert(w >= 0);
1722 assert(w <= _INHIBIT_WHAT_MAX);
1723
1724 r = sd_bus_message_read(message, "b", &interactive);
1725 if (r < 0)
1726 return r;
1727
1728 /* Don't allow multiple jobs being executed at the same time */
1729 if (m->action_what)
1730 return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "There's already a shutdown or sleep operation in progress");
1731
1732 if (sleep_verb) {
1733 r = can_sleep(sleep_verb);
1734 if (r < 0)
1735 return r;
1736
1737 if (r == 0)
1738 return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, "Sleep verb not supported");
1739 }
1740
1741 r = verify_shutdown_creds(m, message, w, interactive, action, action_multiple_sessions,
1742 action_ignore_inhibit, error);
1743 if (r != 0)
1744 return r;
1745
ebcf1f97 1746 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
d889a206 1747 if (r < 0)
ebcf1f97 1748 return r;
d889a206 1749
df2d202e 1750 return sd_bus_reply_method_return(message, NULL);
eecd1362
LP
1751}
1752
19070062 1753static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error *error) {
3f49d45a
LP
1754 Manager *m = userdata;
1755
cc377381
LP
1756 return method_do_shutdown_or_sleep(
1757 m, message,
1758 SPECIAL_POWEROFF_TARGET,
1759 INHIBIT_SHUTDOWN,
1760 "org.freedesktop.login1.power-off",
1761 "org.freedesktop.login1.power-off-multiple-sessions",
1762 "org.freedesktop.login1.power-off-ignore-inhibit",
1763 NULL,
ebcf1f97 1764 error);
cc377381 1765}
88e3dc90 1766
19070062 1767static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 1768 Manager *m = userdata;
88e3dc90 1769
cc377381
LP
1770 return method_do_shutdown_or_sleep(
1771 m, message,
1772 SPECIAL_REBOOT_TARGET,
1773 INHIBIT_SHUTDOWN,
1774 "org.freedesktop.login1.reboot",
1775 "org.freedesktop.login1.reboot-multiple-sessions",
1776 "org.freedesktop.login1.reboot-ignore-inhibit",
1777 NULL,
ebcf1f97 1778 error);
cc377381 1779}
88e3dc90 1780
19070062 1781static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 1782 Manager *m = userdata;
88e3dc90 1783
cc377381
LP
1784 return method_do_shutdown_or_sleep(
1785 m, message,
1786 SPECIAL_SUSPEND_TARGET,
1787 INHIBIT_SLEEP,
1788 "org.freedesktop.login1.suspend",
1789 "org.freedesktop.login1.suspend-multiple-sessions",
1790 "org.freedesktop.login1.suspend-ignore-inhibit",
1791 "suspend",
ebcf1f97 1792 error);
cc377381 1793}
88e3dc90 1794
867c37f6
DM
1795static int nologin_timeout_handler(
1796 sd_event_source *s,
1797 uint64_t usec,
1798 void *userdata) {
1799
1800 Manager *m = userdata;
1801 int r;
1802
1803 log_info("Creating /run/nologin, blocking further logins...");
1804
6f566391 1805 r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
867c37f6
DM
1806 if (r < 0)
1807 log_error_errno(r, "Failed to create /run/nologin: %m");
1808 else
1809 m->unlink_nologin = true;
1810
1811 return 0;
1812}
1813
1814static int update_schedule_file(Manager *m) {
91b3e7fb 1815 _cleanup_free_ char *temp_path = NULL;
867c37f6 1816 _cleanup_fclose_ FILE *f = NULL;
91b3e7fb 1817 int r;
867c37f6
DM
1818
1819 assert(m);
1820
1821 r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
1822 if (r < 0)
1823 return log_error_errno(r, "Failed to create shutdown subdirectory: %m");
1824
867c37f6
DM
1825 r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
1826 if (r < 0)
1827 return log_error_errno(r, "Failed to save information about scheduled shutdowns: %m");
1828
1829 (void) fchmod(fileno(f), 0644);
1830
1831 fprintf(f,
1832 "USEC="USEC_FMT"\n"
1833 "WARN_WALL=%i\n"
1834 "MODE=%s\n",
1835 m->scheduled_shutdown_timeout,
1836 m->enable_wall_messages,
1837 m->scheduled_shutdown_type);
1838
91b3e7fb
LP
1839 if (!isempty(m->wall_message)) {
1840 _cleanup_free_ char *t;
1841
1842 t = cescape(m->wall_message);
1843 if (!t) {
1844 r = -ENOMEM;
1845 goto fail;
1846 }
1847
867c37f6 1848 fprintf(f, "WALL_MESSAGE=%s\n", t);
91b3e7fb 1849 }
867c37f6 1850
dacd6cee
LP
1851 r = fflush_and_check(f);
1852 if (r < 0)
1853 goto fail;
867c37f6 1854
dacd6cee 1855 if (rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
867c37f6 1856 r = -errno;
dacd6cee 1857 goto fail;
867c37f6
DM
1858 }
1859
dacd6cee
LP
1860 return 0;
1861
1862fail:
1863 (void) unlink(temp_path);
1864 (void) unlink("/run/systemd/shutdown/scheduled");
1865
1866 return log_error_errno(r, "Failed to write information about scheduled shutdowns: %m");
867c37f6
DM
1867}
1868
8aaa023a
DM
1869static int manager_scheduled_shutdown_handler(
1870 sd_event_source *s,
1871 uint64_t usec,
1872 void *userdata) {
1873
1874 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1875 Manager *m = userdata;
1876 const char *target;
1877 int r;
1878
1879 assert(m);
1880
1881 if (isempty(m->scheduled_shutdown_type))
1882 return 0;
1883
1884 if (streq(m->scheduled_shutdown_type, "halt"))
1885 target = SPECIAL_HALT_TARGET;
1886 else if (streq(m->scheduled_shutdown_type, "poweroff"))
1887 target = SPECIAL_POWEROFF_TARGET;
1888 else
1889 target = SPECIAL_REBOOT_TARGET;
1890
1891 r = execute_shutdown_or_sleep(m, 0, target, &error);
1892 if (r < 0)
c2a23db0 1893 return log_error_errno(r, "Unable to execute transition to %s: %m", target);
8aaa023a
DM
1894
1895 return 0;
1896}
1897
19070062 1898static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) {
8aaa023a 1899 Manager *m = userdata;
e2fa5721 1900 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
8aaa023a
DM
1901 const char *action_multiple_sessions = NULL;
1902 const char *action_ignore_inhibit = NULL;
1903 const char *action = NULL;
1904 uint64_t elapse;
1905 char *type;
1906 int r;
1907
1908 assert(m);
1909 assert(message);
1910
1911 r = sd_bus_message_read(message, "st", &type, &elapse);
1912 if (r < 0)
1913 return r;
1914
1389f4b9
DM
1915 if (startswith(type, "dry-")) {
1916 type += 4;
1917 m->shutdown_dry_run = true;
1918 }
1919
8aaa023a
DM
1920 if (streq(type, "reboot")) {
1921 action = "org.freedesktop.login1.reboot";
1922 action_multiple_sessions = "org.freedesktop.login1.reboot-multiple-sessions";
1923 action_ignore_inhibit = "org.freedesktop.login1.reboot-ignore-inhibit";
1924 } else if (streq(type, "halt")) {
1925 action = "org.freedesktop.login1.halt";
1926 action_multiple_sessions = "org.freedesktop.login1.halt-multiple-sessions";
1927 action_ignore_inhibit = "org.freedesktop.login1.halt-ignore-inhibit";
1928 } else if (streq(type, "poweroff")) {
1929 action = "org.freedesktop.login1.poweroff";
1930 action_multiple_sessions = "org.freedesktop.login1.poweroff-multiple-sessions";
1931 action_ignore_inhibit = "org.freedesktop.login1.poweroff-ignore-inhibit";
1932 } else
1933 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type");
1934
1935 r = verify_shutdown_creds(m, message, INHIBIT_SHUTDOWN, false,
1936 action, action_multiple_sessions, action_ignore_inhibit, error);
1937 if (r != 0)
1938 return r;
1939
1940 if (m->scheduled_shutdown_timeout_source) {
1941 r = sd_event_source_set_time(m->scheduled_shutdown_timeout_source, elapse);
1942 if (r < 0)
c2a23db0 1943 return log_error_errno(r, "sd_event_source_set_time() failed: %m");
8aaa023a
DM
1944
1945 r = sd_event_source_set_enabled(m->scheduled_shutdown_timeout_source, SD_EVENT_ONESHOT);
1946 if (r < 0)
c2a23db0 1947 return log_error_errno(r, "sd_event_source_set_enabled() failed: %m");
8aaa023a
DM
1948 } else {
1949 r = sd_event_add_time(m->event, &m->scheduled_shutdown_timeout_source,
1950 CLOCK_REALTIME, elapse, 0, manager_scheduled_shutdown_handler, m);
1951 if (r < 0)
c2a23db0 1952 return log_error_errno(r, "sd_event_add_time() failed: %m");
8aaa023a
DM
1953 }
1954
1955 r = free_and_strdup(&m->scheduled_shutdown_type, type);
1956 if (r < 0) {
1957 m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
1958 return log_oom();
1959 }
1960
867c37f6
DM
1961 if (m->nologin_timeout_source) {
1962 r = sd_event_source_set_time(m->nologin_timeout_source, elapse);
1963 if (r < 0)
c2a23db0 1964 return log_error_errno(r, "sd_event_source_set_time() failed: %m");
867c37f6
DM
1965
1966 r = sd_event_source_set_enabled(m->nologin_timeout_source, SD_EVENT_ONESHOT);
1967 if (r < 0)
c2a23db0 1968 return log_error_errno(r, "sd_event_source_set_enabled() failed: %m");
867c37f6
DM
1969 } else {
1970 r = sd_event_add_time(m->event, &m->nologin_timeout_source,
1971 CLOCK_REALTIME, elapse - 5 * USEC_PER_MINUTE, 0, nologin_timeout_handler, m);
1972 if (r < 0)
c2a23db0 1973 return log_error_errno(r, "sd_event_add_time() failed: %m");
867c37f6
DM
1974 }
1975
8aaa023a
DM
1976 m->scheduled_shutdown_timeout = elapse;
1977
e2fa5721
DM
1978 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_AUGMENT|SD_BUS_CREDS_TTY|SD_BUS_CREDS_UID, &creds);
1979 if (r >= 0) {
1980 const char *tty;
1981
1982 (void) sd_bus_creds_get_uid(creds, &m->scheduled_shutdown_uid);
1983 (void) sd_bus_creds_get_tty(creds, &tty);
1984
1985 r = free_and_strdup(&m->scheduled_shutdown_tty, tty);
1986 if (r < 0) {
1987 m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
1988 return log_oom();
1989 }
1990 }
1991
1992 r = manager_setup_wall_message_timer(m);
1993 if (r < 0)
1994 return r;
1995
867c37f6
DM
1996 if (!isempty(type)) {
1997 r = update_schedule_file(m);
1998 if (r < 0)
1999 return r;
2000 } else
2001 (void) unlink("/run/systemd/shutdown/scheduled");
2002
8aaa023a
DM
2003 return sd_bus_reply_method_return(message, NULL);
2004}
2005
19070062 2006static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) {
8aaa023a
DM
2007 Manager *m = userdata;
2008 bool cancelled;
2009
2010 assert(m);
2011 assert(message);
2012
2013 cancelled = m->scheduled_shutdown_type != NULL;
1389f4b9 2014 reset_scheduled_shutdown(m);
fb91034c 2015
e2fa5721
DM
2016 if (cancelled) {
2017 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
2018 const char *tty = NULL;
2019 uid_t uid = 0;
2020 int r;
2021
2022 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_AUGMENT|SD_BUS_CREDS_TTY|SD_BUS_CREDS_UID, &creds);
2023 if (r >= 0) {
2024 (void) sd_bus_creds_get_uid(creds, &uid);
2025 (void) sd_bus_creds_get_tty(creds, &tty);
2026 }
2027
2028 utmp_wall("The system shutdown has been cancelled",
2029 lookup_uid(uid), tty, logind_wall_tty_filter, m);
2030 }
2031
8aaa023a
DM
2032 return sd_bus_reply_method_return(message, "b", cancelled);
2033}
2034
19070062 2035static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 2036 Manager *m = userdata;
b6160029 2037
cc377381
LP
2038 return method_do_shutdown_or_sleep(
2039 m, message,
2040 SPECIAL_HIBERNATE_TARGET,
2041 INHIBIT_SLEEP,
2042 "org.freedesktop.login1.hibernate",
2043 "org.freedesktop.login1.hibernate-multiple-sessions",
2044 "org.freedesktop.login1.hibernate-ignore-inhibit",
2045 "hibernate",
ebcf1f97 2046 error);
cc377381 2047}
fa2b196d 2048
19070062 2049static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 2050 Manager *m = userdata;
fa2b196d 2051
cc377381
LP
2052 return method_do_shutdown_or_sleep(
2053 m, message,
2054 SPECIAL_HYBRID_SLEEP_TARGET,
2055 INHIBIT_SLEEP,
2056 "org.freedesktop.login1.hibernate",
2057 "org.freedesktop.login1.hibernate-multiple-sessions",
2058 "org.freedesktop.login1.hibernate-ignore-inhibit",
2059 "hybrid-sleep",
ebcf1f97 2060 error);
cc377381 2061}
de07ab16 2062
cc377381
LP
2063static int method_can_shutdown_or_sleep(
2064 Manager *m,
2065 sd_bus_message *message,
2066 InhibitWhat w,
2067 const char *action,
2068 const char *action_multiple_sessions,
2069 const char *action_ignore_inhibit,
ebcf1f97
LP
2070 const char *sleep_verb,
2071 sd_bus_error *error) {
de07ab16 2072
5b12334d 2073 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
cc377381
LP
2074 bool multiple_sessions, challenge, blocked;
2075 const char *result = NULL;
2076 uid_t uid;
2077 int r;
de07ab16 2078
cc377381
LP
2079 assert(m);
2080 assert(message);
2081 assert(w >= 0);
2082 assert(w <= _INHIBIT_WHAT_MAX);
2083 assert(action);
2084 assert(action_multiple_sessions);
2085 assert(action_ignore_inhibit);
de07ab16 2086
cc377381
LP
2087 if (sleep_verb) {
2088 r = can_sleep(sleep_verb);
de07ab16 2089 if (r < 0)
ebcf1f97 2090 return r;
cc377381 2091 if (r == 0)
df2d202e 2092 return sd_bus_reply_method_return(message, "s", "na");
cc377381 2093 }
de07ab16 2094
05bae4a6 2095 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
5b12334d
LP
2096 if (r < 0)
2097 return r;
2098
05bae4a6 2099 r = sd_bus_creds_get_euid(creds, &uid);
cc377381 2100 if (r < 0)
ebcf1f97 2101 return r;
de07ab16 2102
cc377381
LP
2103 r = have_multiple_sessions(m, uid);
2104 if (r < 0)
ebcf1f97 2105 return r;
de07ab16 2106
cc377381 2107 multiple_sessions = r > 0;
85a428c6 2108 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
de07ab16 2109
cc377381 2110 if (multiple_sessions) {
403ed0e5 2111 r = bus_test_polkit(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, UID_INVALID, &challenge, error);
de07ab16 2112 if (r < 0)
ebcf1f97 2113 return r;
bef422ae 2114
cc377381
LP
2115 if (r > 0)
2116 result = "yes";
2117 else if (challenge)
2118 result = "challenge";
2119 else
2120 result = "no";
2121 }
bef422ae 2122
cc377381 2123 if (blocked) {
403ed0e5 2124 r = bus_test_polkit(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, UID_INVALID, &challenge, error);
bef422ae 2125 if (r < 0)
ebcf1f97 2126 return r;
bef422ae 2127
cc377381
LP
2128 if (r > 0 && !result)
2129 result = "yes";
2130 else if (challenge && (!result || streq(result, "yes")))
2131 result = "challenge";
2132 else
2133 result = "no";
2134 }
bef422ae 2135
cc377381
LP
2136 if (!multiple_sessions && !blocked) {
2137 /* If neither inhibit nor multiple sessions
2138 * apply then just check the normal policy */
bef422ae 2139
403ed0e5 2140 r = bus_test_polkit(message, CAP_SYS_BOOT, action, NULL, UID_INVALID, &challenge, error);
bef422ae 2141 if (r < 0)
ebcf1f97 2142 return r;
bef422ae 2143
cc377381
LP
2144 if (r > 0)
2145 result = "yes";
2146 else if (challenge)
2147 result = "challenge";
2148 else
2149 result = "no";
2150 }
bef422ae 2151
df2d202e 2152 return sd_bus_reply_method_return(message, "s", result);
cc377381 2153}
bef422ae 2154
19070062 2155static int method_can_poweroff(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 2156 Manager *m = userdata;
bef422ae 2157
cc377381
LP
2158 return method_can_shutdown_or_sleep(
2159 m, message,
2160 INHIBIT_SHUTDOWN,
2161 "org.freedesktop.login1.power-off",
2162 "org.freedesktop.login1.power-off-multiple-sessions",
2163 "org.freedesktop.login1.power-off-ignore-inhibit",
ebcf1f97
LP
2164 NULL,
2165 error);
cc377381 2166}
bef422ae 2167
19070062 2168static int method_can_reboot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 2169 Manager *m = userdata;
bef422ae 2170
cc377381
LP
2171 return method_can_shutdown_or_sleep(
2172 m, message,
2173 INHIBIT_SHUTDOWN,
2174 "org.freedesktop.login1.reboot",
2175 "org.freedesktop.login1.reboot-multiple-sessions",
2176 "org.freedesktop.login1.reboot-ignore-inhibit",
ebcf1f97
LP
2177 NULL,
2178 error);
cc377381 2179}
bef422ae 2180
19070062 2181static int method_can_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 2182 Manager *m = userdata;
7f7bb946 2183
cc377381
LP
2184 return method_can_shutdown_or_sleep(
2185 m, message,
2186 INHIBIT_SLEEP,
2187 "org.freedesktop.login1.suspend",
2188 "org.freedesktop.login1.suspend-multiple-sessions",
2189 "org.freedesktop.login1.suspend-ignore-inhibit",
ebcf1f97
LP
2190 "suspend",
2191 error);
cc377381 2192}
7f7bb946 2193
19070062 2194static int method_can_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 2195 Manager *m = userdata;
02b16a19 2196
cc377381
LP
2197 return method_can_shutdown_or_sleep(
2198 m, message,
2199 INHIBIT_SLEEP,
2200 "org.freedesktop.login1.hibernate",
2201 "org.freedesktop.login1.hibernate-multiple-sessions",
2202 "org.freedesktop.login1.hibernate-ignore-inhibit",
ebcf1f97
LP
2203 "hibernate",
2204 error);
cc377381 2205}
7f7bb946 2206
19070062 2207static int method_can_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 2208 Manager *m = userdata;
7f7bb946 2209
cc377381
LP
2210 return method_can_shutdown_or_sleep(
2211 m, message,
2212 INHIBIT_SLEEP,
2213 "org.freedesktop.login1.hibernate",
2214 "org.freedesktop.login1.hibernate-multiple-sessions",
2215 "org.freedesktop.login1.hibernate-ignore-inhibit",
ebcf1f97
LP
2216 "hybrid-sleep",
2217 error);
cc377381 2218}
38f3fc7d 2219
5bdf2243
JJ
2220static int property_get_reboot_to_firmware_setup(
2221 sd_bus *bus,
2222 const char *path,
2223 const char *interface,
2224 const char *property,
2225 sd_bus_message *reply,
2226 void *userdata,
2227 sd_bus_error *error) {
2228 int r;
2229
2230 assert(bus);
2231 assert(reply);
2232 assert(userdata);
2233
2234 r = efi_get_reboot_to_firmware();
2235 if (r < 0 && r != -EOPNOTSUPP)
2236 return r;
2237
2238 return sd_bus_message_append(reply, "b", r > 0);
2239}
2240
2241static int method_set_reboot_to_firmware_setup(
5bdf2243
JJ
2242 sd_bus_message *message,
2243 void *userdata,
2244 sd_bus_error *error) {
2245
2246 int b, r;
5bdf2243
JJ
2247 Manager *m = userdata;
2248
5bdf2243
JJ
2249 assert(message);
2250 assert(m);
2251
889f25b2 2252 r = sd_bus_message_read(message, "b", &b);
5bdf2243
JJ
2253 if (r < 0)
2254 return r;
2255
2256 r = bus_verify_polkit_async(message,
2257 CAP_SYS_ADMIN,
2258 "org.freedesktop.login1.set-reboot-to-firmware-setup",
403ed0e5 2259 NULL,
889f25b2 2260 false,
5bdf2243
JJ
2261 UID_INVALID,
2262 &m->polkit_registry,
2263 error);
2264 if (r < 0)
2265 return r;
2266 if (r == 0)
2267 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
2268
2269 r = efi_set_reboot_to_firmware(b);
2270 if (r < 0)
2271 return r;
2272
2273 return sd_bus_reply_method_return(message, NULL);
2274}
2275
2276static int method_can_reboot_to_firmware_setup(
5bdf2243
JJ
2277 sd_bus_message *message,
2278 void *userdata,
2279 sd_bus_error *error) {
2280
2281 int r;
2282 bool challenge;
2283 const char *result;
2284 Manager *m = userdata;
2285
5bdf2243
JJ
2286 assert(message);
2287 assert(m);
2288
2289 r = efi_reboot_to_firmware_supported();
2290 if (r == -EOPNOTSUPP)
2291 return sd_bus_reply_method_return(message, "s", "na");
2292 else if (r < 0)
2293 return r;
2294
2295 r = bus_test_polkit(message,
2296 CAP_SYS_ADMIN,
2297 "org.freedesktop.login1.set-reboot-to-firmware-setup",
403ed0e5 2298 NULL,
5bdf2243
JJ
2299 UID_INVALID,
2300 &challenge,
2301 error);
2302 if (r < 0)
2303 return r;
2304
2305 if (r > 0)
2306 result = "yes";
2307 else if (challenge)
2308 result = "challenge";
2309 else
2310 result = "no";
2311
2312 return sd_bus_reply_method_return(message, "s", result);
2313}
2314
9ef15026
JS
2315static int method_set_wall_message(
2316 sd_bus_message *message,
2317 void *userdata,
2318 sd_bus_error *error) {
2319
2320 int r;
2321 Manager *m = userdata;
2322 char *wall_message;
2cf088b5 2323 int enable_wall_messages;
9ef15026
JS
2324
2325 assert(message);
2326 assert(m);
2327
2328 r = sd_bus_message_read(message, "sb", &wall_message, &enable_wall_messages);
2329 if (r < 0)
2330 return r;
2331
2332 r = bus_verify_polkit_async(message,
2333 CAP_SYS_ADMIN,
2334 "org.freedesktop.login1.set-wall-message",
403ed0e5 2335 NULL,
9ef15026
JS
2336 false,
2337 UID_INVALID,
2338 &m->polkit_registry,
2339 error);
9ef15026
JS
2340 if (r < 0)
2341 return r;
2342 if (r == 0)
2343 return 1; /* Will call us back */
2344
5744f59a
LP
2345 if (isempty(wall_message))
2346 m->wall_message = mfree(m->wall_message);
2347 else {
2348 r = free_and_strdup(&m->wall_message, wall_message);
2349 if (r < 0)
2350 return log_oom();
2351 }
2352
9ef15026
JS
2353 m->enable_wall_messages = enable_wall_messages;
2354
2355 return sd_bus_reply_method_return(message, NULL);
2356}
2357
19070062 2358static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
5b12334d 2359 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
cc377381
LP
2360 const char *who, *why, *what, *mode;
2361 _cleanup_free_ char *id = NULL;
2362 _cleanup_close_ int fifo_fd = -1;
2363 Manager *m = userdata;
2364 Inhibitor *i = NULL;
2365 InhibitMode mm;
2366 InhibitWhat w;
2367 pid_t pid;
2368 uid_t uid;
2369 int r;
7f7bb946 2370
cc377381
LP
2371 assert(message);
2372 assert(m);
38f3fc7d 2373
cc377381
LP
2374 r = sd_bus_message_read(message, "ssss", &what, &who, &why, &mode);
2375 if (r < 0)
ebcf1f97 2376 return r;
38f3fc7d 2377
cc377381
LP
2378 w = inhibit_what_from_string(what);
2379 if (w <= 0)
ebcf1f97 2380 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid what specification %s", what);
38f3fc7d 2381
cc377381
LP
2382 mm = inhibit_mode_from_string(mode);
2383 if (mm < 0)
ebcf1f97 2384 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid mode specification %s", mode);
7f7bb946 2385
cc377381
LP
2386 /* Delay is only supported for shutdown/sleep */
2387 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP)))
ebcf1f97 2388 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delay inhibitors only supported for shutdown and sleep");
38f3fc7d 2389
cc377381
LP
2390 /* Don't allow taking delay locks while we are already
2391 * executing the operation. We shouldn't create the impression
2392 * that the lock was successful if the machine is about to go
2393 * down/suspend any moment. */
2394 if (m->action_what & w)
ebcf1f97 2395 return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "The operation inhibition has been requested for is already running");
cc377381 2396
c529695e
LP
2397 r = bus_verify_polkit_async(
2398 message,
2399 CAP_SYS_BOOT,
2400 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
2401 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
2402 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
2403 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
2404 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
2405 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
2406 "org.freedesktop.login1.inhibit-handle-lid-switch",
403ed0e5 2407 NULL,
c529695e
LP
2408 false,
2409 UID_INVALID,
2410 &m->polkit_registry,
2411 error);
cc377381 2412 if (r < 0)
ebcf1f97 2413 return r;
cc377381
LP
2414 if (r == 0)
2415 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7f7bb946 2416
05bae4a6 2417 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID, &creds);
5b12334d
LP
2418 if (r < 0)
2419 return r;
2420
05bae4a6 2421 r = sd_bus_creds_get_euid(creds, &uid);
cc377381 2422 if (r < 0)
ebcf1f97 2423 return r;
7f7bb946 2424
5b12334d 2425 r = sd_bus_creds_get_pid(creds, &pid);
cc377381 2426 if (r < 0)
ebcf1f97 2427 return r;
47a26690 2428
cc377381 2429 do {
97b11eed 2430 id = mfree(id);
47a26690 2431
cc377381 2432 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0)
ebcf1f97 2433 return -ENOMEM;
47a26690 2434
cc377381 2435 } while (hashmap_get(m->inhibitors, id));
47a26690 2436
cc377381
LP
2437 r = manager_add_inhibitor(m, id, &i);
2438 if (r < 0)
ebcf1f97 2439 return r;
47a26690 2440
cc377381
LP
2441 i->what = w;
2442 i->mode = mm;
2443 i->pid = pid;
2444 i->uid = uid;
2445 i->why = strdup(why);
2446 i->who = strdup(who);
7f7bb946 2447
cc377381 2448 if (!i->why || !i->who) {
ebcf1f97 2449 r = -ENOMEM;
cc377381
LP
2450 goto fail;
2451 }
b668e064 2452
cc377381
LP
2453 fifo_fd = inhibitor_create_fifo(i);
2454 if (fifo_fd < 0) {
ebcf1f97 2455 r = fifo_fd;
cc377381
LP
2456 goto fail;
2457 }
b668e064 2458
cc377381 2459 inhibitor_start(i);
b668e064 2460
df2d202e 2461 return sd_bus_reply_method_return(message, "h", fifo_fd);
b668e064 2462
cc377381
LP
2463fail:
2464 if (i)
2465 inhibitor_free(i);
89f13440 2466
cc377381
LP
2467 return r;
2468}
3f49d45a 2469
cc377381
LP
2470const sd_bus_vtable manager_vtable[] = {
2471 SD_BUS_VTABLE_START(0),
2472
e2fa5721
DM
2473 SD_BUS_WRITABLE_PROPERTY("EnableWallMessages", "b", NULL, NULL, offsetof(Manager, enable_wall_messages), 0),
2474 SD_BUS_WRITABLE_PROPERTY("WallMessage", "s", NULL, NULL, offsetof(Manager, wall_message), 0),
2475
556089dc
LP
2476 SD_BUS_PROPERTY("NAutoVTs", "u", NULL, offsetof(Manager, n_autovts), SD_BUS_VTABLE_PROPERTY_CONST),
2477 SD_BUS_PROPERTY("KillOnlyUsers", "as", NULL, offsetof(Manager, kill_only_users), SD_BUS_VTABLE_PROPERTY_CONST),
2478 SD_BUS_PROPERTY("KillExcludeUsers", "as", NULL, offsetof(Manager, kill_exclude_users), SD_BUS_VTABLE_PROPERTY_CONST),
2479 SD_BUS_PROPERTY("KillUserProcesses", "b", NULL, offsetof(Manager, kill_user_processes), SD_BUS_VTABLE_PROPERTY_CONST),
5bdf2243 2480 SD_BUS_PROPERTY("RebootToFirmwareSetup", "b", property_get_reboot_to_firmware_setup, 0, SD_BUS_VTABLE_PROPERTY_CONST),
cc377381
LP
2481 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
2482 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
2483 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
2484 SD_BUS_PROPERTY("BlockInhibited", "s", property_get_inhibited, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
2485 SD_BUS_PROPERTY("DelayInhibited", "s", property_get_inhibited, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc
LP
2486 SD_BUS_PROPERTY("InhibitDelayMaxUSec", "t", NULL, offsetof(Manager, inhibit_delay_max), SD_BUS_VTABLE_PROPERTY_CONST),
2487 SD_BUS_PROPERTY("HandlePowerKey", "s", property_get_handle_action, offsetof(Manager, handle_power_key), SD_BUS_VTABLE_PROPERTY_CONST),
2488 SD_BUS_PROPERTY("HandleSuspendKey", "s", property_get_handle_action, offsetof(Manager, handle_suspend_key), SD_BUS_VTABLE_PROPERTY_CONST),
2489 SD_BUS_PROPERTY("HandleHibernateKey", "s", property_get_handle_action, offsetof(Manager, handle_hibernate_key), SD_BUS_VTABLE_PROPERTY_CONST),
2490 SD_BUS_PROPERTY("HandleLidSwitch", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch), SD_BUS_VTABLE_PROPERTY_CONST),
3c56cab4 2491 SD_BUS_PROPERTY("HandleLidSwitchDocked", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch_docked), SD_BUS_VTABLE_PROPERTY_CONST),
9d10cbee 2492 SD_BUS_PROPERTY("HoldoffTimeoutUSec", "t", NULL, offsetof(Manager, holdoff_timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST),
556089dc
LP
2493 SD_BUS_PROPERTY("IdleAction", "s", property_get_handle_action, offsetof(Manager, idle_action), SD_BUS_VTABLE_PROPERTY_CONST),
2494 SD_BUS_PROPERTY("IdleActionUSec", "t", NULL, offsetof(Manager, idle_action_usec), SD_BUS_VTABLE_PROPERTY_CONST),
cc377381
LP
2495 SD_BUS_PROPERTY("PreparingForShutdown", "b", property_get_preparing, 0, 0),
2496 SD_BUS_PROPERTY("PreparingForSleep", "b", property_get_preparing, 0, 0),
8aaa023a 2497 SD_BUS_PROPERTY("ScheduledShutdown", "(st)", property_get_scheduled_shutdown, 0, 0),
14856079 2498 SD_BUS_PROPERTY("Docked", "b", property_get_docked, 0, 0),
cc377381 2499
adacb957
LP
2500 SD_BUS_METHOD("GetSession", "s", "o", method_get_session, SD_BUS_VTABLE_UNPRIVILEGED),
2501 SD_BUS_METHOD("GetSessionByPID", "u", "o", method_get_session_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
2502 SD_BUS_METHOD("GetUser", "u", "o", method_get_user, SD_BUS_VTABLE_UNPRIVILEGED),
2503 SD_BUS_METHOD("GetUserByPID", "u", "o", method_get_user_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
2504 SD_BUS_METHOD("GetSeat", "s", "o", method_get_seat, SD_BUS_VTABLE_UNPRIVILEGED),
2505 SD_BUS_METHOD("ListSessions", NULL, "a(susso)", method_list_sessions, SD_BUS_VTABLE_UNPRIVILEGED),
2506 SD_BUS_METHOD("ListUsers", NULL, "a(uso)", method_list_users, SD_BUS_VTABLE_UNPRIVILEGED),
2507 SD_BUS_METHOD("ListSeats", NULL, "a(so)", method_list_seats, SD_BUS_VTABLE_UNPRIVILEGED),
2508 SD_BUS_METHOD("ListInhibitors", NULL, "a(ssssuu)", method_list_inhibitors, SD_BUS_VTABLE_UNPRIVILEGED),
a4cd87e9 2509 SD_BUS_METHOD("CreateSession", "uusssssussbssa(sv)", "soshusub", method_create_session, 0),
cc377381 2510 SD_BUS_METHOD("ReleaseSession", "s", NULL, method_release_session, 0),
adacb957
LP
2511 SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED),
2512 SD_BUS_METHOD("ActivateSessionOnSeat", "ss", NULL, method_activate_session_on_seat, SD_BUS_VTABLE_UNPRIVILEGED),
c529695e
LP
2513 SD_BUS_METHOD("LockSession", "s", NULL, method_lock_session, SD_BUS_VTABLE_UNPRIVILEGED),
2514 SD_BUS_METHOD("UnlockSession", "s", NULL, method_lock_session, SD_BUS_VTABLE_UNPRIVILEGED),
2515 SD_BUS_METHOD("LockSessions", NULL, NULL, method_lock_sessions, SD_BUS_VTABLE_UNPRIVILEGED),
2516 SD_BUS_METHOD("UnlockSessions", NULL, NULL, method_lock_sessions, SD_BUS_VTABLE_UNPRIVILEGED),
2517 SD_BUS_METHOD("KillSession", "ssi", NULL, method_kill_session, SD_BUS_VTABLE_UNPRIVILEGED),
2518 SD_BUS_METHOD("KillUser", "ui", NULL, method_kill_user, SD_BUS_VTABLE_UNPRIVILEGED),
2519 SD_BUS_METHOD("TerminateSession", "s", NULL, method_terminate_session, SD_BUS_VTABLE_UNPRIVILEGED),
2520 SD_BUS_METHOD("TerminateUser", "u", NULL, method_terminate_user, SD_BUS_VTABLE_UNPRIVILEGED),
2521 SD_BUS_METHOD("TerminateSeat", "s", NULL, method_terminate_seat, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957
LP
2522 SD_BUS_METHOD("SetUserLinger", "ubb", NULL, method_set_user_linger, SD_BUS_VTABLE_UNPRIVILEGED),
2523 SD_BUS_METHOD("AttachDevice", "ssb", NULL, method_attach_device, SD_BUS_VTABLE_UNPRIVILEGED),
2524 SD_BUS_METHOD("FlushDevices", "b", NULL, method_flush_devices, SD_BUS_VTABLE_UNPRIVILEGED),
2525 SD_BUS_METHOD("PowerOff", "b", NULL, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
2526 SD_BUS_METHOD("Reboot", "b", NULL, method_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
2527 SD_BUS_METHOD("Suspend", "b", NULL, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
2528 SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
2529 SD_BUS_METHOD("HybridSleep", "b", NULL, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
2530 SD_BUS_METHOD("CanPowerOff", NULL, "s", method_can_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
2531 SD_BUS_METHOD("CanReboot", NULL, "s", method_can_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
2532 SD_BUS_METHOD("CanSuspend", NULL, "s", method_can_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
2533 SD_BUS_METHOD("CanHibernate", NULL, "s", method_can_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
2534 SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
559b5cc2
LP
2535 SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
2536 SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957 2537 SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
5bdf2243 2538 SD_BUS_METHOD("CanRebootToFirmwareSetup", NULL, "s", method_can_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
889f25b2 2539 SD_BUS_METHOD("SetRebootToFirmwareSetup", "b", NULL, method_set_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
9ef15026 2540 SD_BUS_METHOD("SetWallMessage", "sb", NULL, method_set_wall_message, SD_BUS_VTABLE_UNPRIVILEGED),
cc377381
LP
2541
2542 SD_BUS_SIGNAL("SessionNew", "so", 0),
2543 SD_BUS_SIGNAL("SessionRemoved", "so", 0),
2544 SD_BUS_SIGNAL("UserNew", "uo", 0),
2545 SD_BUS_SIGNAL("UserRemoved", "uo", 0),
2546 SD_BUS_SIGNAL("SeatNew", "so", 0),
2547 SD_BUS_SIGNAL("SeatRemoved", "so", 0),
2548 SD_BUS_SIGNAL("PrepareForShutdown", "b", 0),
2549 SD_BUS_SIGNAL("PrepareForSleep", "b", 0),
2550
2551 SD_BUS_VTABLE_END
2552};
3f49d45a 2553
99e7e392
DH
2554static int session_jobs_reply(Session *s, const char *unit, const char *result) {
2555 int r = 0;
2556
2557 assert(s);
2558 assert(unit);
2559
2560 if (!s->started)
2561 return r;
2562
2563 if (streq(result, "done"))
2564 r = session_send_create_reply(s, NULL);
2565 else {
2566 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
2567
2568 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
2569 r = session_send_create_reply(s, &e);
2570 }
2571
2572 return r;
2573}
2574
19070062 2575int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
2576 const char *path, *result, *unit;
2577 Manager *m = userdata;
2578 Session *session;
2579 uint32_t id;
2580 User *user;
2581 int r;
3f49d45a 2582
cc377381
LP
2583 assert(message);
2584 assert(m);
3f49d45a 2585
cc377381
LP
2586 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
2587 if (r < 0) {
ebcf1f97 2588 bus_log_parse_error(r);
65d73cf0 2589 return 0;
cc377381 2590 }
3f49d45a 2591
cc377381 2592 if (m->action_job && streq(m->action_job, path)) {
af4efb51 2593 log_info("Operation '%s' finished.", inhibit_what_to_string(m->action_what));
3f49d45a 2594
cc377381
LP
2595 /* Tell people that they now may take a lock again */
2596 send_prepare_for(m, m->action_what, false);
3f49d45a 2597
491ac9f2 2598 m->action_job = mfree(m->action_job);
cc377381
LP
2599 m->action_unit = NULL;
2600 m->action_what = 0;
2601 return 0;
2602 }
3f49d45a 2603
cc377381
LP
2604 session = hashmap_get(m->session_units, unit);
2605 if (session) {
3f49d45a 2606
491ac9f2
LP
2607 if (streq_ptr(path, session->scope_job))
2608 session->scope_job = mfree(session->scope_job);
3f49d45a 2609
99e7e392 2610 session_jobs_reply(session, unit, result);
3f49d45a 2611
99e7e392 2612 session_save(session);
41dfeaa1 2613 user_save(session->user);
cc377381
LP
2614 session_add_to_gc_queue(session);
2615 }
3f49d45a 2616
cc377381
LP
2617 user = hashmap_get(m->user_units, unit);
2618 if (user) {
3f49d45a 2619
491ac9f2
LP
2620 if (streq_ptr(path, user->service_job))
2621 user->service_job = mfree(user->service_job);
3f49d45a 2622
491ac9f2
LP
2623 if (streq_ptr(path, user->slice_job))
2624 user->slice_job = mfree(user->slice_job);
3f49d45a 2625
491ac9f2 2626 LIST_FOREACH(sessions_by_user, session, user->sessions)
99e7e392 2627 session_jobs_reply(session, unit, result);
dd9b67aa 2628
cc377381
LP
2629 user_save(user);
2630 user_add_to_gc_queue(user);
3f49d45a
LP
2631 }
2632
cc377381 2633 return 0;
3f49d45a
LP
2634}
2635
19070062 2636int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 2637 const char *path, *unit;
1713813d 2638 Manager *m = userdata;
cc377381
LP
2639 Session *session;
2640 User *user;
2641 int r;
1713813d 2642
1713813d 2643 assert(message);
cc377381 2644 assert(m);
1713813d 2645
cc377381
LP
2646 r = sd_bus_message_read(message, "so", &unit, &path);
2647 if (r < 0) {
ebcf1f97 2648 bus_log_parse_error(r);
65d73cf0 2649 return 0;
cc377381 2650 }
fb6becb4 2651
cc377381
LP
2652 session = hashmap_get(m->session_units, unit);
2653 if (session)
2654 session_add_to_gc_queue(session);
fb6becb4 2655
cc377381
LP
2656 user = hashmap_get(m->user_units, unit);
2657 if (user)
2658 user_add_to_gc_queue(user);
fb6becb4 2659
cc377381
LP
2660 return 0;
2661}
fb6becb4 2662
19070062 2663int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
2664 _cleanup_free_ char *unit = NULL;
2665 Manager *m = userdata;
2666 const char *path;
2667 Session *session;
2668 User *user;
ebcf1f97 2669 int r;
fb6becb4 2670
cc377381
LP
2671 assert(message);
2672 assert(m);
fb6becb4 2673
cc377381
LP
2674 path = sd_bus_message_get_path(message);
2675 if (!path)
2676 return 0;
fb6becb4 2677
ebcf1f97 2678 r = unit_name_from_dbus_path(path, &unit);
e5f5b5b9
LP
2679 if (r == -EINVAL) /* not a unit */
2680 return 0;
65d73cf0
LP
2681 if (r < 0) {
2682 log_oom();
2683 return 0;
2684 }
fb6becb4 2685
cc377381
LP
2686 session = hashmap_get(m->session_units, unit);
2687 if (session)
2688 session_add_to_gc_queue(session);
fb6becb4 2689
cc377381
LP
2690 user = hashmap_get(m->user_units, unit);
2691 if (user)
2692 user_add_to_gc_queue(user);
fb6becb4 2693
cc377381
LP
2694 return 0;
2695}
6fa48533 2696
19070062 2697int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
2698 Manager *m = userdata;
2699 Session *session;
2700 Iterator i;
2701 int b, r;
943aca8e 2702
19070062
LP
2703 assert(message);
2704 assert(m);
943aca8e 2705
cc377381
LP
2706 r = sd_bus_message_read(message, "b", &b);
2707 if (r < 0) {
ebcf1f97 2708 bus_log_parse_error(r);
65d73cf0 2709 return 0;
cc377381 2710 }
943aca8e 2711
cc377381
LP
2712 if (b)
2713 return 0;
943aca8e 2714
cc377381
LP
2715 /* systemd finished reloading, let's recheck all our sessions */
2716 log_debug("System manager has been reloaded, rechecking sessions...");
6797c324 2717
cc377381
LP
2718 HASHMAP_FOREACH(session, m->sessions, i)
2719 session_add_to_gc_queue(session);
6797c324 2720
cc377381
LP
2721 return 0;
2722}
943aca8e 2723
cc377381
LP
2724int manager_send_changed(Manager *manager, const char *property, ...) {
2725 char **l;
9418f147
LP
2726
2727 assert(manager);
2728
cc377381 2729 l = strv_from_stdarg_alloca(property);
9418f147 2730
cc377381
LP
2731 return sd_bus_emit_properties_changed_strv(
2732 manager->bus,
2733 "/org/freedesktop/login1",
2734 "org.freedesktop.login1.Manager",
2735 l);
9418f147 2736}
eecd1362 2737
fb6becb4
LP
2738int manager_start_scope(
2739 Manager *manager,
2740 const char *scope,
2741 pid_t pid,
2742 const char *slice,
2743 const char *description,
ba4c5d93 2744 const char *after, const char *after2,
cc377381 2745 sd_bus_error *error,
fb6becb4
LP
2746 char **job) {
2747
cc377381
LP
2748 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
2749 int r;
fb6becb4
LP
2750
2751 assert(manager);
2752 assert(scope);
2753 assert(pid > 1);
2754
cc377381
LP
2755 r = sd_bus_message_new_method_call(
2756 manager->bus,
151b9b96 2757 &m,
fb6becb4
LP
2758 "org.freedesktop.systemd1",
2759 "/org/freedesktop/systemd1",
2760 "org.freedesktop.systemd1.Manager",
151b9b96 2761 "StartTransientUnit");
cc377381
LP
2762 if (r < 0)
2763 return r;
fb6becb4 2764
cc377381
LP
2765 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
2766 if (r < 0)
2767 return r;
fb6becb4 2768
cc377381
LP
2769 r = sd_bus_message_open_container(m, 'a', "(sv)");
2770 if (r < 0)
2771 return r;
fb6becb4
LP
2772
2773 if (!isempty(slice)) {
cc377381
LP
2774 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
2775 if (r < 0)
2776 return r;
fb6becb4
LP
2777 }
2778
2779 if (!isempty(description)) {
cc377381
LP
2780 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
2781 if (r < 0)
2782 return r;
fb6becb4
LP
2783 }
2784
ba4c5d93 2785 if (!isempty(after)) {
cc377381
LP
2786 r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after);
2787 if (r < 0)
2788 return r;
7fb3ee51
LP
2789 }
2790
ba4c5d93
LP
2791 if (!isempty(after2)) {
2792 r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after2);
2793 if (r < 0)
2794 return r;
2795 }
2796
fb6becb4
LP
2797 /* cgroup empty notification is not available in containers
2798 * currently. To make this less problematic, let's shorten the
2799 * stop timeout for sessions, so that we don't wait
2800 * forever. */
2801
743e8945
LP
2802 /* Make sure that the session shells are terminated with
2803 * SIGHUP since bash and friends tend to ignore SIGTERM */
cc377381
LP
2804 r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", true);
2805 if (r < 0)
2806 return r;
2807
2808 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
2809 if (r < 0)
2810 return r;
2811
2812 r = sd_bus_message_close_container(m);
2813 if (r < 0)
2814 return r;
86b8d289
LP
2815
2816 r = sd_bus_message_append(m, "a(sa(sv))", 0);
2817 if (r < 0)
2818 return r;
cc377381 2819
c49b30a2 2820 r = sd_bus_call(manager->bus, m, 0, error, &reply);
cc377381
LP
2821 if (r < 0)
2822 return r;
fb6becb4
LP
2823
2824 if (job) {
2825 const char *j;
2826 char *copy;
2827
cc377381
LP
2828 r = sd_bus_message_read(reply, "o", &j);
2829 if (r < 0)
2830 return r;
fb6becb4
LP
2831
2832 copy = strdup(j);
2833 if (!copy)
2834 return -ENOMEM;
2835
2836 *job = copy;
2837 }
2838
cc377381 2839 return 1;
fb6becb4
LP
2840}
2841
cc377381
LP
2842int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
2843 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
fb6becb4
LP
2844 int r;
2845
2846 assert(manager);
2847 assert(unit);
2848
cc377381 2849 r = sd_bus_call_method(
fb6becb4
LP
2850 manager->bus,
2851 "org.freedesktop.systemd1",
2852 "/org/freedesktop/systemd1",
2853 "org.freedesktop.systemd1.Manager",
2854 "StartUnit",
fb6becb4 2855 error,
cc377381
LP
2856 &reply,
2857 "ss", unit, "fail");
2858 if (r < 0)
fb6becb4 2859 return r;
fb6becb4
LP
2860
2861 if (job) {
2862 const char *j;
2863 char *copy;
2864
cc377381
LP
2865 r = sd_bus_message_read(reply, "o", &j);
2866 if (r < 0)
2867 return r;
fb6becb4
LP
2868
2869 copy = strdup(j);
2870 if (!copy)
2871 return -ENOMEM;
2872
2873 *job = copy;
2874 }
2875
cc377381 2876 return 1;
fb6becb4
LP
2877}
2878
cc377381
LP
2879int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
2880 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
fb6becb4
LP
2881 int r;
2882
2883 assert(manager);
2884 assert(unit);
2885
cc377381 2886 r = sd_bus_call_method(
fb6becb4
LP
2887 manager->bus,
2888 "org.freedesktop.systemd1",
2889 "/org/freedesktop/systemd1",
2890 "org.freedesktop.systemd1.Manager",
2891 "StopUnit",
fb6becb4 2892 error,
cc377381
LP
2893 &reply,
2894 "ss", unit, "fail");
fb6becb4 2895 if (r < 0) {
cc377381
LP
2896 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
2897 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
2898
2899 if (job)
2900 *job = NULL;
2901
cc377381 2902 sd_bus_error_free(error);
6797c324
LP
2903 return 0;
2904 }
2905
fb6becb4
LP
2906 return r;
2907 }
2908
2909 if (job) {
2910 const char *j;
2911 char *copy;
2912
cc377381
LP
2913 r = sd_bus_message_read(reply, "o", &j);
2914 if (r < 0)
2915 return r;
fb6becb4
LP
2916
2917 copy = strdup(j);
2918 if (!copy)
2919 return -ENOMEM;
2920
2921 *job = copy;
2922 }
2923
6797c324 2924 return 1;
fb6becb4
LP
2925}
2926
5f41d1f1 2927int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error) {
5f41d1f1
LP
2928 _cleanup_free_ char *path = NULL;
2929 int r;
2930
2931 assert(manager);
2932 assert(scope);
2933
2934 path = unit_dbus_path_from_name(scope);
2935 if (!path)
2936 return -ENOMEM;
2937
2938 r = sd_bus_call_method(
2939 manager->bus,
2940 "org.freedesktop.systemd1",
2941 path,
2942 "org.freedesktop.systemd1.Scope",
2943 "Abandon",
2944 error,
2945 NULL,
2946 NULL);
2947 if (r < 0) {
2948 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
4e2f8d27
LP
2949 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED) ||
2950 sd_bus_error_has_name(error, BUS_ERROR_SCOPE_NOT_RUNNING)) {
5f41d1f1
LP
2951 sd_bus_error_free(error);
2952 return 0;
2953 }
2954
2955 return r;
2956 }
2957
2958 return 1;
2959}
2960
cc377381 2961int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
fb6becb4
LP
2962 assert(manager);
2963 assert(unit);
2964
cc377381 2965 return sd_bus_call_method(
fb6becb4
LP
2966 manager->bus,
2967 "org.freedesktop.systemd1",
2968 "/org/freedesktop/systemd1",
2969 "org.freedesktop.systemd1.Manager",
2970 "KillUnit",
fb6becb4 2971 error,
cc377381
LP
2972 NULL,
2973 "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
fb6becb4
LP
2974}
2975
2976int manager_unit_is_active(Manager *manager, const char *unit) {
cc377381
LP
2977 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2978 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
fb6becb4 2979 _cleanup_free_ char *path = NULL;
fb6becb4 2980 const char *state;
fb6becb4
LP
2981 int r;
2982
2983 assert(manager);
2984 assert(unit);
2985
fb6becb4
LP
2986 path = unit_dbus_path_from_name(unit);
2987 if (!path)
2988 return -ENOMEM;
2989
cc377381 2990 r = sd_bus_get_property(
fb6becb4
LP
2991 manager->bus,
2992 "org.freedesktop.systemd1",
2993 path,
cc377381
LP
2994 "org.freedesktop.systemd1.Unit",
2995 "ActiveState",
fb6becb4 2996 &error,
cc377381
LP
2997 &reply,
2998 "s");
fb6becb4 2999 if (r < 0) {
cc377381
LP
3000 /* systemd might have droppped off momentarily, let's
3001 * not make this an error */
3002 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
3003 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 3004 return true;
6797c324 3005
cc377381
LP
3006 /* If the unit is already unloaded then it's not
3007 * active */
3008 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
3009 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 3010 return false;
6797c324 3011
fb6becb4
LP
3012 return r;
3013 }
3014
cc377381
LP
3015 r = sd_bus_message_read(reply, "s", &state);
3016 if (r < 0)
fb6becb4 3017 return -EINVAL;
fb6becb4 3018
cc377381
LP
3019 return !streq(state, "inactive") && !streq(state, "failed");
3020}
3021
3022int manager_job_is_active(Manager *manager, const char *path) {
3023 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
3024 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
3025 int r;
3026
3027 assert(manager);
3028 assert(path);
3029
3030 r = sd_bus_get_property(
3031 manager->bus,
3032 "org.freedesktop.systemd1",
3033 path,
3034 "org.freedesktop.systemd1.Job",
3035 "State",
3036 &error,
3037 &reply,
3038 "s");
3039 if (r < 0) {
3040 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
3041 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
3042 return true;
3043
3044 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
3045 return false;
3046
3047 return r;
fb6becb4
LP
3048 }
3049
cc377381
LP
3050 /* We don't actually care about the state really. The fact
3051 * that we could read the job state is enough for us */
fb6becb4 3052
cc377381 3053 return true;
fb6becb4 3054}