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