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