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