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