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