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