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