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