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