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