]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-dbus.c
log: fix order of log_unit_struct() to match other logging calls
[thirdparty/systemd.git] / src / login / logind-dbus.c
CommitLineData
3f49d45a
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
3f49d45a
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
3f49d45a 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
3f49d45a
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
a185c5aa
LP
22#include <errno.h>
23#include <string.h>
98a28fef 24#include <unistd.h>
7f7bb946 25#include <pwd.h>
adacb957 26#include <sys/capability.h>
a185c5aa 27
cc377381
LP
28#include "sd-id128.h"
29#include "sd-messages.h"
98a28fef 30#include "strv.h"
49e942b2 31#include "mkdir.h"
9eb977db 32#include "path-util.h"
55af3897 33#include "special.h"
19adb8a3 34#include "sleep-config.h"
a5c32cff
HH
35#include "fileio-label.h"
36#include "label.h"
9444b1f2
LP
37#include "utf8.h"
38#include "unit-name.h"
fb6becb4 39#include "virt.h"
cc377381
LP
40#include "audit.h"
41#include "bus-util.h"
42#include "bus-error.h"
43#include "logind.h"
718db961 44#include "bus-errors.h"
06acf2d4 45#include "udev-util.h"
3f49d45a 46
cc377381
LP
47static int property_get_idle_hint(
48 sd_bus *bus,
49 const char *path,
50 const char *interface,
51 const char *property,
52 sd_bus_message *reply,
ebcf1f97
LP
53 void *userdata,
54 sd_bus_error *error) {
a185c5aa 55
cc377381 56 Manager *m = userdata;
a185c5aa 57
cc377381
LP
58 assert(bus);
59 assert(reply);
60 assert(m);
61
62 return sd_bus_message_append(reply, "b", manager_get_idle_hint(m, NULL) > 0);
a185c5aa
LP
63}
64
cc377381
LP
65static int property_get_idle_since_hint(
66 sd_bus *bus,
67 const char *path,
68 const char *interface,
69 const char *property,
70 sd_bus_message *reply,
ebcf1f97
LP
71 void *userdata,
72 sd_bus_error *error) {
cc377381
LP
73
74 Manager *m = userdata;
a185c5aa 75 dual_timestamp t;
a185c5aa 76
cc377381
LP
77 assert(bus);
78 assert(reply);
a185c5aa
LP
79 assert(m);
80
81 manager_get_idle_hint(m, &t);
a185c5aa 82
cc377381 83 return sd_bus_message_append(reply, "t", streq(property, "IdleSinceHint") ? t.realtime : t.monotonic);
a185c5aa
LP
84}
85
cc377381
LP
86static int property_get_inhibited(
87 sd_bus *bus,
88 const char *path,
89 const char *interface,
90 const char *property,
91 sd_bus_message *reply,
ebcf1f97
LP
92 void *userdata,
93 sd_bus_error *error) {
cc377381
LP
94
95 Manager *m = userdata;
f8e2fb7b 96 InhibitWhat w;
f8e2fb7b 97
cc377381
LP
98 assert(bus);
99 assert(reply);
100 assert(m);
f8e2fb7b 101
cc377381 102 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
f8e2fb7b 103
cc377381 104 return sd_bus_message_append(reply, "s", inhibit_what_to_string(w));
f8e2fb7b
LP
105}
106
cc377381
LP
107static int property_get_preparing(
108 sd_bus *bus,
109 const char *path,
110 const char *interface,
111 const char *property,
112 sd_bus_message *reply,
ebcf1f97
LP
113 void *userdata,
114 sd_bus_error *error) {
cc377381
LP
115
116 Manager *m = userdata;
117 bool b;
5e4a79da 118
cc377381
LP
119 assert(bus);
120 assert(reply);
121 assert(m);
5e4a79da
LP
122
123 if (streq(property, "PreparingForShutdown"))
314b4b0a 124 b = !!(m->action_what & INHIBIT_SHUTDOWN);
5e4a79da 125 else
314b4b0a 126 b = !!(m->action_what & INHIBIT_SLEEP);
5e4a79da 127
cc377381 128 return sd_bus_message_append(reply, "b", b);
5e4a79da
LP
129}
130
cc377381 131static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_handle_action, handle_action, HandleAction);
fb6becb4 132
ebcf1f97 133static int method_get_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
134 _cleanup_free_ char *p = NULL;
135 Manager *m = userdata;
136 const char *name;
137 Session *session;
138 int r;
139
140 assert(bus);
141 assert(message);
142 assert(m);
143
144 r = sd_bus_message_read(message, "s", &name);
145 if (r < 0)
ebcf1f97 146 return r;
cc377381
LP
147
148 session = hashmap_get(m->sessions, name);
149 if (!session)
ebcf1f97 150 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
cc377381
LP
151
152 p = session_bus_path(session);
153 if (!p)
ebcf1f97 154 return -ENOMEM;
cc377381 155
df2d202e 156 return sd_bus_reply_method_return(message, "o", p);
cc377381
LP
157}
158
ebcf1f97 159static int method_get_session_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 160 _cleanup_free_ char *p = NULL;
954449b8 161 Session *session = NULL;
cc377381 162 Manager *m = userdata;
4e724d9c 163 pid_t pid;
cc377381
LP
164 int r;
165
166 assert(bus);
167 assert(message);
168 assert(m);
169
4e724d9c
LP
170 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
171
cc377381
LP
172 r = sd_bus_message_read(message, "u", &pid);
173 if (r < 0)
ebcf1f97 174 return r;
cc377381 175
4e724d9c 176 if (pid == 0) {
5b12334d
LP
177 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
178
179 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
180 if (r < 0)
181 return r;
182
183 r = sd_bus_creds_get_pid(creds, &pid);
4e724d9c 184 if (r < 0)
ebcf1f97 185 return r;
4e724d9c
LP
186 }
187
cc377381
LP
188 r = manager_get_session_by_pid(m, pid, &session);
189 if (r < 0)
ebcf1f97 190 return r;
cc377381 191 if (!session)
de0671ee 192 return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID, "PID "PID_FMT" does not belong to any known session", pid);
cc377381
LP
193
194 p = session_bus_path(session);
195 if (!p)
ebcf1f97 196 return -ENOMEM;
cc377381 197
df2d202e 198 return sd_bus_reply_method_return(message, "o", p);
cc377381
LP
199}
200
ebcf1f97 201static int method_get_user(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
202 _cleanup_free_ char *p = NULL;
203 Manager *m = userdata;
204 uint32_t uid;
205 User *user;
206 int r;
207
208 assert(bus);
209 assert(message);
210 assert(m);
211
212 r = sd_bus_message_read(message, "u", &uid);
213 if (r < 0)
ebcf1f97 214 return r;
cc377381
LP
215
216 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
217 if (!user)
de0671ee 218 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "No user "UID_FMT" known or logged in", uid);
cc377381
LP
219
220 p = user_bus_path(user);
221 if (!p)
ebcf1f97 222 return -ENOMEM;
cc377381 223
df2d202e 224 return sd_bus_reply_method_return(message, "o", p);
cc377381
LP
225}
226
ebcf1f97 227static int method_get_user_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
228 _cleanup_free_ char *p = NULL;
229 Manager *m = userdata;
954449b8 230 User *user = NULL;
4e724d9c 231 pid_t pid;
fb6becb4 232 int r;
98a28fef 233
cc377381
LP
234 assert(bus);
235 assert(message);
98a28fef 236 assert(m);
cc377381 237
4e724d9c
LP
238 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
239
cc377381
LP
240 r = sd_bus_message_read(message, "u", &pid);
241 if (r < 0)
ebcf1f97 242 return r;
cc377381 243
4e724d9c 244 if (pid == 0) {
5b12334d
LP
245 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
246
247 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
248 if (r < 0)
249 return r;
250
251 r = sd_bus_creds_get_pid(creds, &pid);
4e724d9c 252 if (r < 0)
ebcf1f97 253 return r;
4e724d9c
LP
254 }
255
cc377381
LP
256 r = manager_get_user_by_pid(m, pid, &user);
257 if (r < 0)
ebcf1f97 258 return r;
cc377381 259 if (!user)
de0671ee 260 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);
cc377381
LP
261
262 p = user_bus_path(user);
263 if (!p)
ebcf1f97 264 return -ENOMEM;
cc377381 265
df2d202e 266 return sd_bus_reply_method_return(message, "o", p);
cc377381
LP
267}
268
ebcf1f97 269static int method_get_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
270 _cleanup_free_ char *p = NULL;
271 Manager *m = userdata;
272 const char *name;
273 Seat *seat;
274 int r;
275
276 assert(bus);
98a28fef 277 assert(message);
cc377381 278 assert(m);
98a28fef 279
cc377381
LP
280 r = sd_bus_message_read(message, "s", &name);
281 if (r < 0)
ebcf1f97 282 return r;
98a28fef 283
cc377381
LP
284 seat = hashmap_get(m->seats, name);
285 if (!seat)
ebcf1f97 286 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", name);
98a28fef 287
cc377381
LP
288 p = seat_bus_path(seat);
289 if (!p)
ebcf1f97 290 return -ENOMEM;
98a28fef 291
df2d202e 292 return sd_bus_reply_method_return(message, "o", p);
cc377381 293}
98a28fef 294
ebcf1f97 295static int method_list_sessions(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
296 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
297 Manager *m = userdata;
298 Session *session;
299 Iterator i;
300 int r;
301
302 assert(bus);
303 assert(message);
304 assert(m);
98a28fef 305
df2d202e 306 r = sd_bus_message_new_method_return(message, &reply);
cc377381 307 if (r < 0)
ebcf1f97 308 return r;
98a28fef 309
cc377381
LP
310 r = sd_bus_message_open_container(reply, 'a', "(susso)");
311 if (r < 0)
ebcf1f97 312 return r;
cc377381
LP
313
314 HASHMAP_FOREACH(session, m->sessions, i) {
315 _cleanup_free_ char *p = NULL;
316
317 p = session_bus_path(session);
318 if (!p)
ebcf1f97 319 return -ENOMEM;
cc377381
LP
320
321 r = sd_bus_message_append(reply, "(susso)",
322 session->id,
323 (uint32_t) session->user->uid,
324 session->user->name,
325 session->seat ? session->seat->id : "",
326 p);
327 if (r < 0)
ebcf1f97 328 return r;
cc377381
LP
329 }
330
331 r = sd_bus_message_close_container(reply);
332 if (r < 0)
ebcf1f97 333 return r;
cc377381
LP
334
335 return sd_bus_send(bus, reply, NULL);
336}
337
ebcf1f97 338static int method_list_users(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
339 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
340 Manager *m = userdata;
341 User *user;
342 Iterator i;
343 int r;
344
345 assert(bus);
346 assert(message);
347 assert(m);
348
df2d202e 349 r = sd_bus_message_new_method_return(message, &reply);
cc377381 350 if (r < 0)
ebcf1f97 351 return r;
cc377381
LP
352
353 r = sd_bus_message_open_container(reply, 'a', "(uso)");
354 if (r < 0)
ebcf1f97 355 return r;
cc377381
LP
356
357 HASHMAP_FOREACH(user, m->users, i) {
358 _cleanup_free_ char *p = NULL;
359
360 p = user_bus_path(user);
361 if (!p)
ebcf1f97 362 return -ENOMEM;
cc377381
LP
363
364 r = sd_bus_message_append(reply, "(uso)",
365 (uint32_t) user->uid,
366 user->name,
367 p);
368 if (r < 0)
ebcf1f97 369 return r;
cc377381
LP
370 }
371
372 r = sd_bus_message_close_container(reply);
373 if (r < 0)
ebcf1f97 374 return r;
cc377381
LP
375
376 return sd_bus_send(bus, reply, NULL);
377}
378
ebcf1f97 379static int method_list_seats(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
380 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
381 Manager *m = userdata;
382 Seat *seat;
383 Iterator i;
384 int r;
385
386 assert(bus);
387 assert(message);
388 assert(m);
389
df2d202e 390 r = sd_bus_message_new_method_return(message, &reply);
cc377381 391 if (r < 0)
ebcf1f97 392 return r;
cc377381
LP
393
394 r = sd_bus_message_open_container(reply, 'a', "(so)");
395 if (r < 0)
ebcf1f97 396 return r;
cc377381
LP
397
398 HASHMAP_FOREACH(seat, m->seats, i) {
399 _cleanup_free_ char *p = NULL;
400
401 p = seat_bus_path(seat);
402 if (!p)
ebcf1f97 403 return -ENOMEM;
cc377381 404
b8358bce 405 r = sd_bus_message_append(reply, "(so)", seat->id, p);
cc377381 406 if (r < 0)
ebcf1f97 407 return r;
cc377381
LP
408 }
409
410 r = sd_bus_message_close_container(reply);
411 if (r < 0)
ebcf1f97 412 return r;
cc377381
LP
413
414 return sd_bus_send(bus, reply, NULL);
415}
416
ebcf1f97 417static int method_list_inhibitors(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
418 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
419 Manager *m = userdata;
420 Inhibitor *inhibitor;
421 Iterator i;
422 int r;
423
df2d202e 424 r = sd_bus_message_new_method_return(message, &reply);
cc377381 425 if (r < 0)
ebcf1f97 426 return r;
cc377381
LP
427
428 r = sd_bus_message_open_container(reply, 'a', "(ssssuu)");
429 if (r < 0)
ebcf1f97 430 return r;
cc377381
LP
431
432 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
433
dbfa3fbb 434 r = sd_bus_message_append(reply, "(ssssuu)",
cc377381
LP
435 strempty(inhibit_what_to_string(inhibitor->what)),
436 strempty(inhibitor->who),
437 strempty(inhibitor->why),
438 strempty(inhibit_mode_to_string(inhibitor->mode)),
439 (uint32_t) inhibitor->uid,
440 (uint32_t) inhibitor->pid);
441 if (r < 0)
ebcf1f97 442 return r;
cc377381
LP
443 }
444
445 r = sd_bus_message_close_container(reply);
446 if (r < 0)
ebcf1f97 447 return r;
cc377381
LP
448
449 return sd_bus_send(bus, reply, NULL);
450}
451
ebcf1f97 452static int method_create_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
a4cd87e9 453 const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
cc377381
LP
454 uint32_t uid, leader, audit_id = 0;
455 _cleanup_free_ char *id = NULL;
456 Session *session = NULL;
457 Manager *m = userdata;
458 User *user = NULL;
459 Seat *seat = NULL;
460 int remote;
461 uint32_t vtnr = 0;
462 SessionType t;
463 SessionClass c;
464 int r;
465
466 assert(bus);
467 assert(message);
468 assert(m);
469
a4cd87e9 470 r = sd_bus_message_read(message, "uusssssussbss", &uid, &leader, &service, &type, &class, &desktop, &cseat, &vtnr, &tty, &display, &remote, &remote_user, &remote_host);
cc377381 471 if (r < 0)
ebcf1f97 472 return r;
cc377381
LP
473
474 if (leader == 1)
ebcf1f97 475 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
98a28fef 476
e2acb67b
LP
477 if (isempty(type))
478 t = _SESSION_TYPE_INVALID;
479 else {
480 t = session_type_from_string(type);
481 if (t < 0)
ebcf1f97 482 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid session type %s", type);
e2acb67b 483 }
98a28fef 484
55efac6c 485 if (isempty(class))
e2acb67b
LP
486 c = _SESSION_CLASS_INVALID;
487 else {
55efac6c 488 c = session_class_from_string(class);
e2acb67b 489 if (c < 0)
ebcf1f97 490 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid session class %s", class);
e2acb67b 491 }
55efac6c 492
a4cd87e9
LP
493 if (isempty(desktop))
494 desktop = NULL;
495 else {
496 if (!string_is_safe(desktop))
497 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid desktop string %s", desktop);
498 }
499
954449b8
LP
500 if (isempty(cseat))
501 seat = NULL;
98a28fef 502 else {
954449b8
LP
503 seat = hashmap_get(m->seats, cseat);
504 if (!seat)
d14ab08b 505 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", cseat);
98a28fef
LP
506 }
507
98a28fef 508 if (tty_is_vc(tty)) {
4d6d6518 509 int v;
98a28fef 510
954449b8 511 if (!seat)
92432fcc
DH
512 seat = m->seat0;
513 else if (seat != m->seat0)
d14ab08b 514 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 515
4d6d6518 516 v = vtnr_from_tty(tty);
4d6d6518 517 if (v <= 0)
ebcf1f97 518 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot determine VT number from virtual console TTY %s", tty);
98a28fef 519
92bd5ff3 520 if (!vtnr)
4d6d6518
LP
521 vtnr = (uint32_t) v;
522 else if (vtnr != (uint32_t) v)
ebcf1f97 523 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified TTY and VT number do not match");
cc377381 524
d1122ad5
LP
525 } else if (tty_is_console(tty)) {
526
954449b8 527 if (!seat)
92432fcc
DH
528 seat = m->seat0;
529 else if (seat != m->seat0)
ebcf1f97 530 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but seat is not seat0");
d1122ad5
LP
531
532 if (vtnr != 0)
ebcf1f97 533 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but VT number is not 0");
978cf3c7 534 }
98a28fef 535
954449b8 536 if (seat) {
bf7825ae 537 if (seat_has_vts(seat)) {
c506027a 538 if (!vtnr || vtnr > 63)
ebcf1f97 539 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "VT number out of range");
4d6d6518 540 } else {
d1122ad5 541 if (vtnr != 0)
ebcf1f97 542 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Seat has no VTs but VT number not 0");
4d6d6518
LP
543 }
544 }
545
cc377381
LP
546 r = sd_bus_message_enter_container(message, 'a', "(sv)");
547 if (r < 0)
ebcf1f97 548 return r;
98a28fef 549
e2acb67b
LP
550 if (t == _SESSION_TYPE_INVALID) {
551 if (!isempty(display))
552 t = SESSION_X11;
553 else if (!isempty(tty))
554 t = SESSION_TTY;
555 else
556 t = SESSION_UNSPECIFIED;
557 }
558
559 if (c == _SESSION_CLASS_INVALID) {
a4cd87e9 560 if (t == SESSION_UNSPECIFIED)
e2acb67b 561 c = SESSION_BACKGROUND;
a4cd87e9
LP
562 else
563 c = SESSION_USER;
e2acb67b
LP
564 }
565
9444b1f2 566 if (leader <= 0) {
5b12334d
LP
567 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
568
569 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
570 if (r < 0)
571 return r;
572
cc377381
LP
573 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
574
5b12334d 575 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
cc377381 576 if (r < 0)
ebcf1f97 577 return r;
9444b1f2
LP
578 }
579
872c8faa 580 manager_get_session_by_pid(m, leader, &session);
fb6becb4 581 if (session) {
fb6becb4
LP
582 _cleanup_free_ char *path = NULL;
583 _cleanup_close_ int fifo_fd = -1;
98a28fef 584
fb6becb4
LP
585 /* Session already exists, client is probably
586 * something like "su" which changes uid but is still
587 * the same session */
98a28fef 588
954449b8 589 fifo_fd = session_create_fifo(session);
cc377381 590 if (fifo_fd < 0)
ebcf1f97 591 return fifo_fd;
98a28fef 592
fb6becb4 593 path = session_bus_path(session);
cc377381 594 if (!path)
ebcf1f97 595 return -ENOMEM;
21c390cc 596
236af516
DH
597 log_debug("Sending reply about an existing session: "
598 "id=%s object_path=%s uid=%u runtime_path=%s "
599 "session_fd=%d seat=%s vtnr=%u",
600 session->id,
601 path,
602 (uint32_t) session->user->uid,
603 session->user->runtime_path,
604 fifo_fd,
605 session->seat ? session->seat->id : "",
606 (uint32_t) session->vtnr);
607
cc377381 608 return sd_bus_reply_method_return(
baae0358 609 message, "soshusub",
cc377381
LP
610 session->id,
611 path,
612 session->user->runtime_path,
613 fifo_fd,
baae0358 614 (uint32_t) session->user->uid,
cc377381
LP
615 session->seat ? session->seat->id : "",
616 (uint32_t) session->vtnr,
617 true);
954449b8 618 }
21c390cc 619
954449b8
LP
620 audit_session_from_pid(leader, &audit_id);
621 if (audit_id > 0) {
622 /* Keep our session IDs and the audit session IDs in sync */
21c390cc 623
de0671ee 624 if (asprintf(&id, "%"PRIu32, audit_id) < 0)
ebcf1f97 625 return -ENOMEM;
21c390cc 626
954449b8
LP
627 /* Wut? There's already a session by this name and we
628 * didn't find it above? Weird, then let's not trust
629 * the audit data and let's better register a new
630 * ID */
631 if (hashmap_get(m->sessions, id)) {
4b549144 632 log_warning("Existing logind session ID %s used by new audit session, ignoring", id);
954449b8 633 audit_id = 0;
8ea913b2 634
954449b8
LP
635 free(id);
636 id = NULL;
07714753 637 }
954449b8 638 }
07714753 639
954449b8 640 if (!id) {
07714753
LP
641 do {
642 free(id);
f8e2fb7b 643 id = NULL;
07714753 644
cc377381 645 if (asprintf(&id, "c%lu", ++m->session_counter) < 0)
ebcf1f97 646 return -ENOMEM;
07714753
LP
647
648 } while (hashmap_get(m->sessions, id));
98a28fef
LP
649 }
650
954449b8 651 r = manager_add_user_by_uid(m, uid, &user);
ebcf1f97 652 if (r < 0)
954449b8
LP
653 goto fail;
654
9444b1f2 655 r = manager_add_session(m, id, &session);
ebcf1f97 656 if (r < 0)
98a28fef
LP
657 goto fail;
658
9444b1f2
LP
659 session_set_user(session, user);
660
98a28fef
LP
661 session->leader = leader;
662 session->audit_id = audit_id;
663 session->type = t;
55efac6c 664 session->class = c;
98a28fef 665 session->remote = remote;
98a28fef
LP
666 session->vtnr = vtnr;
667
98a28fef
LP
668 if (!isempty(tty)) {
669 session->tty = strdup(tty);
670 if (!session->tty) {
ebcf1f97 671 r = -ENOMEM;
98a28fef
LP
672 goto fail;
673 }
674 }
675
676 if (!isempty(display)) {
677 session->display = strdup(display);
678 if (!session->display) {
ebcf1f97 679 r = -ENOMEM;
98a28fef
LP
680 goto fail;
681 }
682 }
683
684 if (!isempty(remote_user)) {
685 session->remote_user = strdup(remote_user);
686 if (!session->remote_user) {
ebcf1f97 687 r = -ENOMEM;
98a28fef
LP
688 goto fail;
689 }
690 }
691
692 if (!isempty(remote_host)) {
693 session->remote_host = strdup(remote_host);
694 if (!session->remote_host) {
ebcf1f97 695 r = -ENOMEM;
98a28fef
LP
696 goto fail;
697 }
698 }
699
700 if (!isempty(service)) {
701 session->service = strdup(service);
702 if (!session->service) {
ebcf1f97 703 r = -ENOMEM;
98a28fef
LP
704 goto fail;
705 }
706 }
707
a4cd87e9
LP
708 if (!isempty(desktop)) {
709 session->desktop = strdup(desktop);
710 if (!session->desktop) {
711 r = -ENOMEM;
712 goto fail;
713 }
714 }
715
954449b8
LP
716 if (seat) {
717 r = seat_attach_session(seat, session);
ebcf1f97 718 if (r < 0)
98a28fef
LP
719 goto fail;
720 }
721
722 r = session_start(session);
ebcf1f97 723 if (r < 0)
98a28fef
LP
724 goto fail;
725
cc377381 726 session->create_message = sd_bus_message_ref(message);
98a28fef 727
cba38758
LP
728 /* Now, let's wait until the slice unit and stuff got
729 * created. We send the reply back from
730 * session_send_create_reply().*/
731
cc377381 732 return 1;
98a28fef
LP
733
734fail:
98a28fef
LP
735 if (session)
736 session_add_to_gc_queue(session);
737
738 if (user)
739 user_add_to_gc_queue(user);
740
98a28fef
LP
741 return r;
742}
743
ebcf1f97 744static int method_release_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
745 Manager *m = userdata;
746 Session *session;
747 const char *name;
748 int r;
314b4b0a 749
cc377381
LP
750 assert(bus);
751 assert(message);
752 assert(m);
753
754 r = sd_bus_message_read(message, "s", &name);
755 if (r < 0)
ebcf1f97 756 return r;
cc377381
LP
757
758 session = hashmap_get(m->sessions, name);
759 if (!session)
ebcf1f97 760 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
cc377381 761
5f41d1f1 762 session_release(session);
cc377381 763
df2d202e 764 return sd_bus_reply_method_return(message, NULL);
cc377381
LP
765}
766
ebcf1f97 767static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
768 Manager *m = userdata;
769 Session *session;
770 const char *name;
771 int r;
f8e2fb7b 772
cc377381
LP
773 assert(bus);
774 assert(message);
f8e2fb7b 775 assert(m);
cc377381
LP
776
777 r = sd_bus_message_read(message, "s", &name);
778 if (r < 0)
ebcf1f97 779 return r;
cc377381
LP
780
781 session = hashmap_get(m->sessions, name);
782 if (!session)
ebcf1f97 783 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
cc377381
LP
784
785 r = session_activate(session);
786 if (r < 0)
ebcf1f97 787 return r;
cc377381 788
df2d202e 789 return sd_bus_reply_method_return(message, NULL);
cc377381
LP
790}
791
ebcf1f97 792static int method_activate_session_on_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
793 const char *session_name, *seat_name;
794 Manager *m = userdata;
795 Session *session;
796 Seat *seat;
797 int r;
798
799 assert(bus);
f8e2fb7b 800 assert(message);
cc377381 801 assert(m);
f8e2fb7b 802
cc377381
LP
803 /* Same as ActivateSession() but refuses to work if
804 * the seat doesn't match */
f8e2fb7b 805
cc377381
LP
806 r = sd_bus_message_read(message, "ss", &session_name, &seat_name);
807 if (r < 0)
ebcf1f97 808 return r;
eecd1362 809
cc377381
LP
810 session = hashmap_get(m->sessions, session_name);
811 if (!session)
ebcf1f97 812 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", session_name);
beaafb2e 813
cc377381
LP
814 seat = hashmap_get(m->seats, seat_name);
815 if (!seat)
ebcf1f97 816 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", seat_name);
314b4b0a 817
cc377381 818 if (session->seat != seat)
ebcf1f97 819 return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", session_name, seat_name);
cc377381
LP
820
821 r = session_activate(session);
f8e2fb7b 822 if (r < 0)
ebcf1f97 823 return r;
f8e2fb7b 824
df2d202e 825 return sd_bus_reply_method_return(message, NULL);
cc377381 826}
f8e2fb7b 827
ebcf1f97 828static int method_lock_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
829 Manager *m = userdata;
830 Session *session;
831 const char *name;
832 int r;
f8e2fb7b 833
cc377381
LP
834 assert(bus);
835 assert(message);
836 assert(m);
f8e2fb7b 837
cc377381
LP
838 r = sd_bus_message_read(message, "s", &name);
839 if (r < 0)
ebcf1f97 840 return r;
f8e2fb7b 841
cc377381
LP
842 session = hashmap_get(m->sessions, name);
843 if (!session)
ebcf1f97 844 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
f8e2fb7b 845
cc377381 846 r = session_send_lock(session, streq(sd_bus_message_get_member(message), "LockSession"));
f8e2fb7b 847 if (r < 0)
ebcf1f97 848 return r;
f8e2fb7b 849
df2d202e 850 return sd_bus_reply_method_return(message, NULL);
cc377381 851}
f8e2fb7b 852
ebcf1f97 853static int method_lock_sessions(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
854 Manager *m = userdata;
855 int r;
f8e2fb7b 856
cc377381
LP
857 assert(bus);
858 assert(message);
859 assert(m);
f8e2fb7b 860
cc377381
LP
861 r = session_send_lock_all(m, streq(sd_bus_message_get_member(message), "LockSessions"));
862 if (r < 0)
ebcf1f97 863 return r;
f8e2fb7b 864
df2d202e 865 return sd_bus_reply_method_return(message, NULL);
cc377381
LP
866}
867
ebcf1f97 868static int method_kill_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
869 const char *name, *swho;
870 Manager *m = userdata;
871 Session *session;
872 int32_t signo;
873 KillWho who;
874 int r;
875
876 assert(bus);
877 assert(message);
878 assert(m);
879
880 r = sd_bus_message_read(message, "ssi", &name, &swho, &signo);
881 if (r < 0)
ebcf1f97 882 return r;
cc377381
LP
883
884 if (isempty(swho))
885 who = KILL_ALL;
886 else {
887 who = kill_who_from_string(swho);
888 if (who < 0)
ebcf1f97 889 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
f8e2fb7b
LP
890 }
891
cc377381 892 if (signo <= 0 || signo >= _NSIG)
ebcf1f97 893 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
f8e2fb7b 894
cc377381
LP
895 session = hashmap_get(m->sessions, name);
896 if (!session)
ebcf1f97 897 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
f8e2fb7b 898
cc377381
LP
899 r = session_kill(session, who, signo);
900 if (r < 0)
ebcf1f97 901 return r;
f8e2fb7b 902
df2d202e 903 return sd_bus_reply_method_return(message, NULL);
cc377381 904}
f8e2fb7b 905
ebcf1f97 906static int method_kill_user(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
907 Manager *m = userdata;
908 uint32_t uid;
909 int32_t signo;
910 User *user;
911 int r;
f8e2fb7b 912
cc377381
LP
913 assert(bus);
914 assert(message);
915 assert(m);
916
917 r = sd_bus_message_read(message, "ui", &uid, &signo);
918 if (r < 0)
ebcf1f97 919 return r;
cc377381
LP
920
921 if (signo <= 0 || signo >= _NSIG)
ebcf1f97 922 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
cc377381
LP
923
924 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
925 if (!user)
de0671ee 926 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "No user "UID_FMT" known or logged in", uid);
cc377381
LP
927
928 r = user_kill(user, signo);
929 if (r < 0)
ebcf1f97 930 return r;
cc377381 931
df2d202e 932 return sd_bus_reply_method_return(message, NULL);
cc377381
LP
933}
934
ebcf1f97 935static int method_terminate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
936 Manager *m = userdata;
937 const char *name;
938 Session *session;
939 int r;
940
941 assert(bus);
942 assert(message);
943 assert(m);
944
945 r = sd_bus_message_read(message, "s", &name);
946 if (r < 0)
ebcf1f97 947 return r;
cc377381
LP
948
949 session = hashmap_get(m->sessions, name);
950 if (!session)
ebcf1f97 951 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
cc377381 952
9bb69af4 953 r = session_stop(session, true);
cc377381 954 if (r < 0)
ebcf1f97 955 return r;
cc377381 956
df2d202e 957 return sd_bus_reply_method_return(message, NULL);
cc377381
LP
958}
959
ebcf1f97 960static int method_terminate_user(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
961 Manager *m = userdata;
962 uint32_t uid;
963 User *user;
964 int r;
965
966 assert(bus);
967 assert(message);
968 assert(m);
969
970 r = sd_bus_message_read(message, "u", &uid);
971 if (r < 0)
ebcf1f97 972 return r;
cc377381
LP
973
974 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
975 if (!user)
de0671ee 976 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "No user "UID_FMT" known or logged in", uid);
cc377381 977
9bb69af4 978 r = user_stop(user, true);
cc377381 979 if (r < 0)
ebcf1f97 980 return r;
cc377381 981
df2d202e 982 return sd_bus_reply_method_return(message, NULL);
cc377381
LP
983}
984
ebcf1f97 985static int method_terminate_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
986 Manager *m = userdata;
987 const char *name;
988 Seat *seat;
989 int r;
990
991 assert(bus);
992 assert(message);
993 assert(m);
994
995 r = sd_bus_message_read(message, "s", &name);
996 if (r < 0)
ebcf1f97 997 return r;
cc377381
LP
998
999 seat = hashmap_get(m->seats, name);
1000 if (!seat)
ebcf1f97 1001 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", name);
cc377381 1002
9bb69af4 1003 r = seat_stop_sessions(seat, true);
cc377381 1004 if (r < 0)
ebcf1f97 1005 return r;
cc377381 1006
df2d202e 1007 return sd_bus_reply_method_return(message, NULL);
cc377381
LP
1008}
1009
ebcf1f97 1010static int method_set_user_linger(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
1011 _cleanup_free_ char *cc = NULL;
1012 Manager *m = userdata;
1013 int b, r;
1014 struct passwd *pw;
1015 const char *path;
1016 uint32_t uid;
1017 int interactive;
1018
1019 assert(bus);
1020 assert(message);
1021 assert(m);
1022
1023 r = sd_bus_message_read(message, "ubb", &uid, &b, &interactive);
1024 if (r < 0)
ebcf1f97 1025 return r;
cc377381
LP
1026
1027 errno = 0;
1028 pw = getpwuid(uid);
1029 if (!pw)
ebcf1f97 1030 return errno ? -errno : -ENOENT;
cc377381 1031
f3885791
LP
1032 r = bus_verify_polkit_async(
1033 message,
1034 CAP_SYS_ADMIN,
1035 "org.freedesktop.login1.set-user-linger",
1036 interactive,
1037 &m->polkit_registry,
1038 error);
cc377381 1039 if (r < 0)
ebcf1f97 1040 return r;
cc377381
LP
1041 if (r == 0)
1042 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1043
1044 mkdir_p_label("/var/lib/systemd", 0755);
1045
1046 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1047 if (r < 0)
ebcf1f97 1048 return r;
cc377381
LP
1049
1050 cc = cescape(pw->pw_name);
1051 if (!cc)
ebcf1f97 1052 return -ENOMEM;
cc377381
LP
1053
1054 path = strappenda("/var/lib/systemd/linger/", cc);
1055 if (b) {
1056 User *u;
1057
1058 r = touch(path);
1059 if (r < 0)
ebcf1f97 1060 return r;
cc377381
LP
1061
1062 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1063 user_start(u);
1064
1065 } else {
1066 User *u;
1067
1068 r = unlink(path);
1069 if (r < 0 && errno != ENOENT)
ebcf1f97 1070 return -errno;
cc377381
LP
1071
1072 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1073 if (u)
1074 user_add_to_gc_queue(u);
1075 }
1076
df2d202e 1077 return sd_bus_reply_method_return(message, NULL);
f8e2fb7b
LP
1078}
1079
2eb916cd 1080static int trigger_device(Manager *m, struct udev_device *d) {
06acf2d4 1081 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
b668e064
LP
1082 struct udev_list_entry *first, *item;
1083 int r;
1084
1085 assert(m);
1086
1087 e = udev_enumerate_new(m->udev);
06acf2d4
LP
1088 if (!e)
1089 return -ENOMEM;
b668e064 1090
2eb916cd 1091 if (d) {
06acf2d4
LP
1092 r = udev_enumerate_add_match_parent(e, d);
1093 if (r < 0)
1094 return r;
2eb916cd
LP
1095 }
1096
06acf2d4
LP
1097 r = udev_enumerate_scan_devices(e);
1098 if (r < 0)
1099 return r;
b668e064
LP
1100
1101 first = udev_enumerate_get_list_entry(e);
1102 udev_list_entry_foreach(item, first) {
cc377381 1103 _cleanup_free_ char *t = NULL;
b668e064
LP
1104 const char *p;
1105
1106 p = udev_list_entry_get_name(item);
1107
b668e064 1108 t = strappend(p, "/uevent");
06acf2d4
LP
1109 if (!t)
1110 return -ENOMEM;
b668e064 1111
574d5f2d 1112 write_string_file(t, "change");
b668e064
LP
1113 }
1114
06acf2d4 1115 return 0;
b668e064
LP
1116}
1117
47a26690 1118static int attach_device(Manager *m, const char *seat, const char *sysfs) {
06acf2d4 1119 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
7fd1b19b 1120 _cleanup_free_ char *rule = NULL, *file = NULL;
c28fa3d3 1121 const char *id_for_seat;
47a26690
LP
1122 int r;
1123
1124 assert(m);
1125 assert(seat);
1126 assert(sysfs);
1127
1128 d = udev_device_new_from_syspath(m->udev, sysfs);
1129 if (!d)
1130 return -ENODEV;
1131
06acf2d4
LP
1132 if (!udev_device_has_tag(d, "seat"))
1133 return -ENODEV;
47a26690 1134
c28fa3d3 1135 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
06acf2d4
LP
1136 if (!id_for_seat)
1137 return -ENODEV;
47a26690 1138
06acf2d4
LP
1139 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0)
1140 return -ENOMEM;
47a26690 1141
06acf2d4
LP
1142 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0)
1143 return -ENOMEM;
47a26690 1144
d2e54fae 1145 mkdir_p_label("/etc/udev/rules.d", 0755);
cc56fafe 1146 mac_selinux_init("/etc");
574d5f2d 1147 r = write_string_file_atomic_label(file, rule);
a0a0c7f1 1148 if (r < 0)
06acf2d4 1149 return r;
47a26690 1150
06acf2d4 1151 return trigger_device(m, d);
47a26690
LP
1152}
1153
b668e064 1154static int flush_devices(Manager *m) {
7fd1b19b 1155 _cleanup_closedir_ DIR *d;
b668e064
LP
1156
1157 assert(m);
1158
1159 d = opendir("/etc/udev/rules.d");
1160 if (!d) {
1161 if (errno != ENOENT)
1162 log_warning("Failed to open /etc/udev/rules.d: %m");
1163 } else {
1164 struct dirent *de;
1165
1166 while ((de = readdir(d))) {
1167
1168 if (!dirent_is_file(de))
1169 continue;
1170
1171 if (!startswith(de->d_name, "72-seat-"))
1172 continue;
1173
1174 if (!endswith(de->d_name, ".rules"))
1175 continue;
1176
1177 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
1178 log_warning("Failed to unlink %s: %m", de->d_name);
1179 }
b668e064
LP
1180 }
1181
1182 return trigger_device(m, NULL);
1183}
1184
ebcf1f97 1185static int method_attach_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
1186 const char *sysfs, *seat;
1187 Manager *m = userdata;
1188 int interactive, r;
1189
1190 assert(bus);
1191 assert(message);
1192 assert(m);
1193
1194 r = sd_bus_message_read(message, "ssb", &seat, &sysfs, &interactive);
1195 if (r < 0)
ebcf1f97 1196 return r;
cc377381
LP
1197
1198 if (!path_startswith(sysfs, "/sys"))
ebcf1f97 1199 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not in /sys", sysfs);
cc377381
LP
1200
1201 if (!seat_name_is_valid(seat))
ebcf1f97 1202 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Seat %s is not valid", seat);
cc377381 1203
f3885791
LP
1204 r = bus_verify_polkit_async(
1205 message,
1206 CAP_SYS_ADMIN,
1207 "org.freedesktop.login1.attach-device",
1208 interactive,
1209 &m->polkit_registry,
1210 error);
cc377381 1211 if (r < 0)
ebcf1f97 1212 return r;
cc377381
LP
1213 if (r == 0)
1214 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1215
1216 r = attach_device(m, seat, sysfs);
1217 if (r < 0)
ebcf1f97 1218 return r;
cc377381 1219
df2d202e 1220 return sd_bus_reply_method_return(message, NULL);
cc377381
LP
1221}
1222
ebcf1f97 1223static int method_flush_devices(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
1224 Manager *m = userdata;
1225 int interactive, r;
1226
1227 assert(bus);
1228 assert(message);
1229 assert(m);
1230
1231 r = sd_bus_message_read(message, "b", &interactive);
1232 if (r < 0)
ebcf1f97 1233 return r;
cc377381 1234
f3885791
LP
1235 r = bus_verify_polkit_async(
1236 message,
1237 CAP_SYS_ADMIN,
1238 "org.freedesktop.login1.flush-devices",
1239 interactive,
1240 &m->polkit_registry,
1241 error);
cc377381 1242 if (r < 0)
ebcf1f97 1243 return r;
cc377381
LP
1244 if (r == 0)
1245 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1246
1247 r = flush_devices(m);
1248 if (r < 0)
ebcf1f97 1249 return r;
cc377381 1250
df2d202e 1251 return sd_bus_reply_method_return(message, NULL);
cc377381
LP
1252}
1253
89f13440 1254static int have_multiple_sessions(
89f13440 1255 Manager *m,
409133be 1256 uid_t uid) {
89f13440 1257
2154761f
MS
1258 Session *session;
1259 Iterator i;
89f13440
LP
1260
1261 assert(m);
1262
1ca04b87
LP
1263 /* Check for other users' sessions. Greeter sessions do not
1264 * count, and non-login sessions do not count either. */
2154761f 1265 HASHMAP_FOREACH(session, m->sessions, i)
1ca04b87 1266 if (session->class == SESSION_USER &&
1ca04b87 1267 session->user->uid != uid)
2154761f 1268 return true;
89f13440
LP
1269
1270 return false;
1271}
1272
314b4b0a
LP
1273static int bus_manager_log_shutdown(
1274 Manager *m,
1275 InhibitWhat w,
1276 const char *unit_name) {
1277
1278 const char *p, *q;
1279
1280 assert(m);
1281 assert(unit_name);
1282
1283 if (w != INHIBIT_SHUTDOWN)
1284 return 0;
1285
1286 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1287 p = "MESSAGE=System is powering down.";
1288 q = "SHUTDOWN=power-off";
1289 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1290 p = "MESSAGE=System is halting.";
1291 q = "SHUTDOWN=halt";
1292 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1293 p = "MESSAGE=System is rebooting.";
1294 q = "SHUTDOWN=reboot";
1295 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1296 p = "MESSAGE=System is rebooting with kexec.";
1297 q = "SHUTDOWN=kexec";
1298 } else {
1299 p = "MESSAGE=System is shutting down.";
1300 q = NULL;
1301 }
1302
e2cc6eca
LP
1303 return log_struct(LOG_NOTICE,
1304 LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
314b4b0a 1305 p,
e2cc6eca
LP
1306 q,
1307 NULL);
314b4b0a
LP
1308}
1309
b5d3e168
KS
1310static int lid_switch_ignore_handler(sd_event_source *e, uint64_t usec, void *userdata) {
1311 Manager *m = userdata;
1312
1313 assert(e);
1314 assert(m);
1315
1316 m->lid_switch_ignore_event_source = sd_event_source_unref(m->lid_switch_ignore_event_source);
1317 return 0;
1318}
1319
1320int manager_set_lid_switch_ignore(Manager *m, usec_t until) {
1321 int r;
1322
1323 assert(m);
1324
1325 if (until <= now(CLOCK_MONOTONIC))
1326 return 0;
1327
1328 /* We want to ignore the lid switch for a while after each
1329 * suspend, and after boot-up. Hence let's install a timer for
1330 * this. As long as the event source exists we ignore the lid
1331 * switch. */
1332
1333 if (m->lid_switch_ignore_event_source) {
1334 usec_t u;
1335
1336 r = sd_event_source_get_time(m->lid_switch_ignore_event_source, &u);
1337 if (r < 0)
1338 return r;
1339
1340 if (until <= u)
1341 return 0;
1342
1343 r = sd_event_source_set_time(m->lid_switch_ignore_event_source, until);
1344 } else
6a0f1f6d
LP
1345 r = sd_event_add_time(
1346 m->event,
1347 &m->lid_switch_ignore_event_source,
1348 CLOCK_MONOTONIC,
1349 until, 0,
1350 lid_switch_ignore_handler, m);
b5d3e168
KS
1351
1352 return r;
1353}
1354
314b4b0a
LP
1355static int execute_shutdown_or_sleep(
1356 Manager *m,
1357 InhibitWhat w,
1358 const char *unit_name,
cc377381 1359 sd_bus_error *error) {
314b4b0a 1360
cc377381
LP
1361 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1362 const char *p;
af9792ac 1363 char *c;
cc377381 1364 int r;
eecd1362 1365
af9792ac 1366 assert(m);
314b4b0a
LP
1367 assert(w >= 0);
1368 assert(w < _INHIBIT_WHAT_MAX);
d889a206 1369 assert(unit_name);
eecd1362 1370
314b4b0a
LP
1371 bus_manager_log_shutdown(m, w, unit_name);
1372
cc377381 1373 r = sd_bus_call_method(
af9792ac 1374 m->bus,
eecd1362
LP
1375 "org.freedesktop.systemd1",
1376 "/org/freedesktop/systemd1",
1377 "org.freedesktop.systemd1.Manager",
b9c26b41 1378 "StartUnit",
af9792ac 1379 error,
cc377381
LP
1380 &reply,
1381 "ss", unit_name, "replace-irreversibly");
af9792ac
LP
1382 if (r < 0)
1383 return r;
1384
cc377381
LP
1385 r = sd_bus_message_read(reply, "o", &p);
1386 if (r < 0)
1387 return r;
af9792ac
LP
1388
1389 c = strdup(p);
1390 if (!c)
1391 return -ENOMEM;
1392
314b4b0a 1393 m->action_unit = unit_name;
af9792ac
LP
1394 free(m->action_job);
1395 m->action_job = c;
314b4b0a 1396 m->action_what = w;
af9792ac 1397
f9cd6be1
LP
1398 /* Make sure the lid switch is ignored for a while */
1399 manager_set_lid_switch_ignore(m, now(CLOCK_MONOTONIC) + IGNORE_LID_SWITCH_SUSPEND_USEC);
1400
af9792ac 1401 return 0;
eecd1362
LP
1402}
1403
314b4b0a
LP
1404static int delay_shutdown_or_sleep(
1405 Manager *m,
1406 InhibitWhat w,
1407 const char *unit_name) {
eecd1362 1408
eecd1362 1409 assert(m);
d889a206
LP
1410 assert(w >= 0);
1411 assert(w < _INHIBIT_WHAT_MAX);
314b4b0a 1412 assert(unit_name);
eecd1362 1413
314b4b0a
LP
1414 m->action_timestamp = now(CLOCK_MONOTONIC);
1415 m->action_unit = unit_name;
1416 m->action_what = w;
d889a206
LP
1417
1418 return 0;
1419}
1420
cc377381 1421static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
d889a206 1422
cc377381
LP
1423 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1424 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1425 [INHIBIT_SLEEP] = "PrepareForSleep"
1426 };
1427
1428 int active = _active;
877d54e9
LP
1429
1430 assert(m);
314b4b0a
LP
1431 assert(w >= 0);
1432 assert(w < _INHIBIT_WHAT_MAX);
1433 assert(signal_name[w]);
877d54e9 1434
cc377381
LP
1435 return sd_bus_emit_signal(m->bus,
1436 "/org/freedesktop/login1",
1437 "org.freedesktop.login1.Manager",
1438 signal_name[w],
1439 "b",
dd9f0525 1440 active);
877d54e9
LP
1441}
1442
069cfc85
LP
1443int bus_manager_shutdown_or_sleep_now_or_later(
1444 Manager *m,
1445 const char *unit_name,
1446 InhibitWhat w,
cc377381 1447 sd_bus_error *error) {
069cfc85
LP
1448
1449 bool delayed;
1450 int r;
1451
1452 assert(m);
1453 assert(unit_name);
1454 assert(w >= 0);
1455 assert(w <= _INHIBIT_WHAT_MAX);
af9792ac 1456 assert(!m->action_job);
069cfc85 1457
314b4b0a
LP
1458 /* Tell everybody to prepare for shutdown/sleep */
1459 send_prepare_for(m, w, true);
1460
069cfc85
LP
1461 delayed =
1462 m->inhibit_delay_max > 0 &&
85a428c6 1463 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0, NULL);
069cfc85
LP
1464
1465 if (delayed)
1466 /* Shutdown is delayed, keep in mind what we
1467 * want to do, and start a timeout */
1468 r = delay_shutdown_or_sleep(m, w, unit_name);
314b4b0a 1469 else
069cfc85
LP
1470 /* Shutdown is not delayed, execute it
1471 * immediately */
314b4b0a 1472 r = execute_shutdown_or_sleep(m, w, unit_name, error);
069cfc85
LP
1473
1474 return r;
1475}
1476
cc377381 1477static int method_do_shutdown_or_sleep(
d889a206 1478 Manager *m,
cc377381 1479 sd_bus_message *message,
d889a206
LP
1480 const char *unit_name,
1481 InhibitWhat w,
1482 const char *action,
1483 const char *action_multiple_sessions,
1484 const char *action_ignore_inhibit,
19adb8a3 1485 const char *sleep_verb,
ebcf1f97
LP
1486 sd_bus_message_handler_t method,
1487 sd_bus_error *error) {
d889a206 1488
5b12334d 1489 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
069cfc85 1490 bool multiple_sessions, blocked;
cc377381
LP
1491 int interactive, r;
1492 uid_t uid;
d889a206
LP
1493
1494 assert(m);
d889a206
LP
1495 assert(message);
1496 assert(unit_name);
1497 assert(w >= 0);
1498 assert(w <= _INHIBIT_WHAT_MAX);
1499 assert(action);
1500 assert(action_multiple_sessions);
1501 assert(action_ignore_inhibit);
cc377381
LP
1502 assert(method);
1503
1504 r = sd_bus_message_read(message, "b", &interactive);
1505 if (r < 0)
ebcf1f97 1506 return r;
d889a206 1507
314b4b0a
LP
1508 /* Don't allow multiple jobs being executed at the same time */
1509 if (m->action_what)
ebcf1f97 1510 return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "There's already a shutdown or sleep operation in progress");
d889a206 1511
19adb8a3
ZJS
1512 if (sleep_verb) {
1513 r = can_sleep(sleep_verb);
6524990f 1514 if (r < 0)
ebcf1f97 1515 return r;
6524990f
LP
1516
1517 if (r == 0)
ebcf1f97 1518 return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, "Sleep verb not supported");
6524990f
LP
1519 }
1520
5b12334d
LP
1521 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds);
1522 if (r < 0)
1523 return r;
1524
1525 r = sd_bus_creds_get_uid(creds, &uid);
cc377381 1526 if (r < 0)
ebcf1f97 1527 return r;
409133be 1528
cc377381 1529 r = have_multiple_sessions(m, uid);
d889a206 1530 if (r < 0)
ebcf1f97 1531 return r;
d889a206
LP
1532
1533 multiple_sessions = r > 0;
85a428c6 1534 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
d889a206
LP
1535
1536 if (multiple_sessions) {
f3885791 1537 r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_multiple_sessions, interactive, &m->polkit_registry, error);
d889a206 1538 if (r < 0)
ebcf1f97 1539 return r;
055d4066
ZJS
1540 if (r == 0)
1541 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
d889a206
LP
1542 }
1543
1544 if (blocked) {
f3885791 1545 r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, interactive, &m->polkit_registry, error);
d889a206 1546 if (r < 0)
ebcf1f97 1547 return r;
055d4066
ZJS
1548 if (r == 0)
1549 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
d889a206
LP
1550 }
1551
1552 if (!multiple_sessions && !blocked) {
f3885791 1553 r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action, interactive, &m->polkit_registry, error);
d889a206 1554 if (r < 0)
ebcf1f97 1555 return r;
055d4066
ZJS
1556 if (r == 0)
1557 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
d889a206
LP
1558 }
1559
ebcf1f97 1560 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
d889a206 1561 if (r < 0)
ebcf1f97 1562 return r;
d889a206 1563
df2d202e 1564 return sd_bus_reply_method_return(message, NULL);
eecd1362
LP
1565}
1566
ebcf1f97 1567static int method_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
3f49d45a
LP
1568 Manager *m = userdata;
1569
cc377381
LP
1570 return method_do_shutdown_or_sleep(
1571 m, message,
1572 SPECIAL_POWEROFF_TARGET,
1573 INHIBIT_SHUTDOWN,
1574 "org.freedesktop.login1.power-off",
1575 "org.freedesktop.login1.power-off-multiple-sessions",
1576 "org.freedesktop.login1.power-off-ignore-inhibit",
1577 NULL,
ebcf1f97
LP
1578 method_poweroff,
1579 error);
cc377381 1580}
88e3dc90 1581
ebcf1f97 1582static int method_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 1583 Manager *m = userdata;
88e3dc90 1584
cc377381
LP
1585 return method_do_shutdown_or_sleep(
1586 m, message,
1587 SPECIAL_REBOOT_TARGET,
1588 INHIBIT_SHUTDOWN,
1589 "org.freedesktop.login1.reboot",
1590 "org.freedesktop.login1.reboot-multiple-sessions",
1591 "org.freedesktop.login1.reboot-ignore-inhibit",
1592 NULL,
ebcf1f97
LP
1593 method_reboot,
1594 error);
cc377381 1595}
88e3dc90 1596
ebcf1f97 1597static int method_suspend(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 1598 Manager *m = userdata;
88e3dc90 1599
cc377381
LP
1600 return method_do_shutdown_or_sleep(
1601 m, message,
1602 SPECIAL_SUSPEND_TARGET,
1603 INHIBIT_SLEEP,
1604 "org.freedesktop.login1.suspend",
1605 "org.freedesktop.login1.suspend-multiple-sessions",
1606 "org.freedesktop.login1.suspend-ignore-inhibit",
1607 "suspend",
ebcf1f97
LP
1608 method_suspend,
1609 error);
cc377381 1610}
88e3dc90 1611
ebcf1f97 1612static int method_hibernate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 1613 Manager *m = userdata;
b6160029 1614
cc377381
LP
1615 return method_do_shutdown_or_sleep(
1616 m, message,
1617 SPECIAL_HIBERNATE_TARGET,
1618 INHIBIT_SLEEP,
1619 "org.freedesktop.login1.hibernate",
1620 "org.freedesktop.login1.hibernate-multiple-sessions",
1621 "org.freedesktop.login1.hibernate-ignore-inhibit",
1622 "hibernate",
ebcf1f97
LP
1623 method_hibernate,
1624 error);
cc377381 1625}
fa2b196d 1626
ebcf1f97 1627static int method_hybrid_sleep(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 1628 Manager *m = userdata;
fa2b196d 1629
cc377381
LP
1630 return method_do_shutdown_or_sleep(
1631 m, message,
1632 SPECIAL_HYBRID_SLEEP_TARGET,
1633 INHIBIT_SLEEP,
1634 "org.freedesktop.login1.hibernate",
1635 "org.freedesktop.login1.hibernate-multiple-sessions",
1636 "org.freedesktop.login1.hibernate-ignore-inhibit",
1637 "hybrid-sleep",
ebcf1f97
LP
1638 method_hybrid_sleep,
1639 error);
cc377381 1640}
de07ab16 1641
cc377381
LP
1642static int method_can_shutdown_or_sleep(
1643 Manager *m,
1644 sd_bus_message *message,
1645 InhibitWhat w,
1646 const char *action,
1647 const char *action_multiple_sessions,
1648 const char *action_ignore_inhibit,
ebcf1f97
LP
1649 const char *sleep_verb,
1650 sd_bus_error *error) {
de07ab16 1651
5b12334d 1652 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
cc377381
LP
1653 bool multiple_sessions, challenge, blocked;
1654 const char *result = NULL;
1655 uid_t uid;
1656 int r;
de07ab16 1657
cc377381
LP
1658 assert(m);
1659 assert(message);
1660 assert(w >= 0);
1661 assert(w <= _INHIBIT_WHAT_MAX);
1662 assert(action);
1663 assert(action_multiple_sessions);
1664 assert(action_ignore_inhibit);
de07ab16 1665
cc377381
LP
1666 if (sleep_verb) {
1667 r = can_sleep(sleep_verb);
de07ab16 1668 if (r < 0)
ebcf1f97 1669 return r;
cc377381 1670 if (r == 0)
df2d202e 1671 return sd_bus_reply_method_return(message, "s", "na");
cc377381 1672 }
de07ab16 1673
5b12334d
LP
1674 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds);
1675 if (r < 0)
1676 return r;
1677
1678 r = sd_bus_creds_get_uid(creds, &uid);
cc377381 1679 if (r < 0)
ebcf1f97 1680 return r;
de07ab16 1681
cc377381
LP
1682 r = have_multiple_sessions(m, uid);
1683 if (r < 0)
ebcf1f97 1684 return r;
de07ab16 1685
cc377381 1686 multiple_sessions = r > 0;
85a428c6 1687 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
de07ab16 1688
cc377381 1689 if (multiple_sessions) {
f3885791 1690 r = bus_verify_polkit(message, CAP_SYS_BOOT, action_multiple_sessions, false, &challenge, error);
de07ab16 1691 if (r < 0)
ebcf1f97 1692 return r;
bef422ae 1693
cc377381
LP
1694 if (r > 0)
1695 result = "yes";
1696 else if (challenge)
1697 result = "challenge";
1698 else
1699 result = "no";
1700 }
bef422ae 1701
cc377381 1702 if (blocked) {
f3885791 1703 r = bus_verify_polkit(message, CAP_SYS_BOOT, action_ignore_inhibit, false, &challenge, error);
bef422ae 1704 if (r < 0)
ebcf1f97 1705 return r;
bef422ae 1706
cc377381
LP
1707 if (r > 0 && !result)
1708 result = "yes";
1709 else if (challenge && (!result || streq(result, "yes")))
1710 result = "challenge";
1711 else
1712 result = "no";
1713 }
bef422ae 1714
cc377381
LP
1715 if (!multiple_sessions && !blocked) {
1716 /* If neither inhibit nor multiple sessions
1717 * apply then just check the normal policy */
bef422ae 1718
f3885791 1719 r = bus_verify_polkit(message, CAP_SYS_BOOT, action, false, &challenge, error);
bef422ae 1720 if (r < 0)
ebcf1f97 1721 return r;
bef422ae 1722
cc377381
LP
1723 if (r > 0)
1724 result = "yes";
1725 else if (challenge)
1726 result = "challenge";
1727 else
1728 result = "no";
1729 }
bef422ae 1730
df2d202e 1731 return sd_bus_reply_method_return(message, "s", result);
cc377381 1732}
bef422ae 1733
ebcf1f97 1734static int method_can_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 1735 Manager *m = userdata;
bef422ae 1736
cc377381
LP
1737 return method_can_shutdown_or_sleep(
1738 m, message,
1739 INHIBIT_SHUTDOWN,
1740 "org.freedesktop.login1.power-off",
1741 "org.freedesktop.login1.power-off-multiple-sessions",
1742 "org.freedesktop.login1.power-off-ignore-inhibit",
ebcf1f97
LP
1743 NULL,
1744 error);
cc377381 1745}
bef422ae 1746
ebcf1f97 1747static int method_can_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 1748 Manager *m = userdata;
bef422ae 1749
cc377381
LP
1750 return method_can_shutdown_or_sleep(
1751 m, message,
1752 INHIBIT_SHUTDOWN,
1753 "org.freedesktop.login1.reboot",
1754 "org.freedesktop.login1.reboot-multiple-sessions",
1755 "org.freedesktop.login1.reboot-ignore-inhibit",
ebcf1f97
LP
1756 NULL,
1757 error);
cc377381 1758}
bef422ae 1759
ebcf1f97 1760static int method_can_suspend(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 1761 Manager *m = userdata;
7f7bb946 1762
cc377381
LP
1763 return method_can_shutdown_or_sleep(
1764 m, message,
1765 INHIBIT_SLEEP,
1766 "org.freedesktop.login1.suspend",
1767 "org.freedesktop.login1.suspend-multiple-sessions",
1768 "org.freedesktop.login1.suspend-ignore-inhibit",
ebcf1f97
LP
1769 "suspend",
1770 error);
cc377381 1771}
7f7bb946 1772
ebcf1f97 1773static int method_can_hibernate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 1774 Manager *m = userdata;
02b16a19 1775
cc377381
LP
1776 return method_can_shutdown_or_sleep(
1777 m, message,
1778 INHIBIT_SLEEP,
1779 "org.freedesktop.login1.hibernate",
1780 "org.freedesktop.login1.hibernate-multiple-sessions",
1781 "org.freedesktop.login1.hibernate-ignore-inhibit",
ebcf1f97
LP
1782 "hibernate",
1783 error);
cc377381 1784}
7f7bb946 1785
ebcf1f97 1786static int method_can_hybrid_sleep(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 1787 Manager *m = userdata;
7f7bb946 1788
cc377381
LP
1789 return method_can_shutdown_or_sleep(
1790 m, message,
1791 INHIBIT_SLEEP,
1792 "org.freedesktop.login1.hibernate",
1793 "org.freedesktop.login1.hibernate-multiple-sessions",
1794 "org.freedesktop.login1.hibernate-ignore-inhibit",
ebcf1f97
LP
1795 "hybrid-sleep",
1796 error);
cc377381 1797}
38f3fc7d 1798
ebcf1f97 1799static int method_inhibit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
5b12334d 1800 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
cc377381
LP
1801 const char *who, *why, *what, *mode;
1802 _cleanup_free_ char *id = NULL;
1803 _cleanup_close_ int fifo_fd = -1;
1804 Manager *m = userdata;
1805 Inhibitor *i = NULL;
1806 InhibitMode mm;
1807 InhibitWhat w;
1808 pid_t pid;
1809 uid_t uid;
1810 int r;
7f7bb946 1811
cc377381
LP
1812 assert(bus);
1813 assert(message);
1814 assert(m);
38f3fc7d 1815
cc377381
LP
1816 r = sd_bus_message_read(message, "ssss", &what, &who, &why, &mode);
1817 if (r < 0)
ebcf1f97 1818 return r;
38f3fc7d 1819
cc377381
LP
1820 w = inhibit_what_from_string(what);
1821 if (w <= 0)
ebcf1f97 1822 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid what specification %s", what);
38f3fc7d 1823
cc377381
LP
1824 mm = inhibit_mode_from_string(mode);
1825 if (mm < 0)
ebcf1f97 1826 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid mode specification %s", mode);
7f7bb946 1827
cc377381
LP
1828 /* Delay is only supported for shutdown/sleep */
1829 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP)))
ebcf1f97 1830 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delay inhibitors only supported for shutdown and sleep");
38f3fc7d 1831
cc377381
LP
1832 /* Don't allow taking delay locks while we are already
1833 * executing the operation. We shouldn't create the impression
1834 * that the lock was successful if the machine is about to go
1835 * down/suspend any moment. */
1836 if (m->action_what & w)
ebcf1f97 1837 return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "The operation inhibition has been requested for is already running");
cc377381 1838
f3885791 1839 r = bus_verify_polkit_async(message, CAP_SYS_BOOT,
cc377381
LP
1840 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
1841 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
1842 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
1843 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
1844 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
1845 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
1846 "org.freedesktop.login1.inhibit-handle-lid-switch",
f3885791 1847 false, &m->polkit_registry, error);
cc377381 1848 if (r < 0)
ebcf1f97 1849 return r;
cc377381
LP
1850 if (r == 0)
1851 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7f7bb946 1852
5b12334d
LP
1853 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID, &creds);
1854 if (r < 0)
1855 return r;
1856
1857 r = sd_bus_creds_get_uid(creds, &uid);
cc377381 1858 if (r < 0)
ebcf1f97 1859 return r;
7f7bb946 1860
5b12334d 1861 r = sd_bus_creds_get_pid(creds, &pid);
cc377381 1862 if (r < 0)
ebcf1f97 1863 return r;
47a26690 1864
cc377381
LP
1865 do {
1866 free(id);
1867 id = NULL;
47a26690 1868
cc377381 1869 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0)
ebcf1f97 1870 return -ENOMEM;
47a26690 1871
cc377381 1872 } while (hashmap_get(m->inhibitors, id));
47a26690 1873
cc377381
LP
1874 r = manager_add_inhibitor(m, id, &i);
1875 if (r < 0)
ebcf1f97 1876 return r;
47a26690 1877
cc377381
LP
1878 i->what = w;
1879 i->mode = mm;
1880 i->pid = pid;
1881 i->uid = uid;
1882 i->why = strdup(why);
1883 i->who = strdup(who);
7f7bb946 1884
cc377381 1885 if (!i->why || !i->who) {
ebcf1f97 1886 r = -ENOMEM;
cc377381
LP
1887 goto fail;
1888 }
b668e064 1889
cc377381
LP
1890 fifo_fd = inhibitor_create_fifo(i);
1891 if (fifo_fd < 0) {
ebcf1f97 1892 r = fifo_fd;
cc377381
LP
1893 goto fail;
1894 }
b668e064 1895
cc377381 1896 inhibitor_start(i);
b668e064 1897
df2d202e 1898 return sd_bus_reply_method_return(message, "h", fifo_fd);
b668e064 1899
cc377381
LP
1900fail:
1901 if (i)
1902 inhibitor_free(i);
89f13440 1903
cc377381
LP
1904 return r;
1905}
3f49d45a 1906
cc377381
LP
1907const sd_bus_vtable manager_vtable[] = {
1908 SD_BUS_VTABLE_START(0),
1909
556089dc
LP
1910 SD_BUS_PROPERTY("NAutoVTs", "u", NULL, offsetof(Manager, n_autovts), SD_BUS_VTABLE_PROPERTY_CONST),
1911 SD_BUS_PROPERTY("KillOnlyUsers", "as", NULL, offsetof(Manager, kill_only_users), SD_BUS_VTABLE_PROPERTY_CONST),
1912 SD_BUS_PROPERTY("KillExcludeUsers", "as", NULL, offsetof(Manager, kill_exclude_users), SD_BUS_VTABLE_PROPERTY_CONST),
1913 SD_BUS_PROPERTY("KillUserProcesses", "b", NULL, offsetof(Manager, kill_user_processes), SD_BUS_VTABLE_PROPERTY_CONST),
cc377381
LP
1914 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1915 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1916 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1917 SD_BUS_PROPERTY("BlockInhibited", "s", property_get_inhibited, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1918 SD_BUS_PROPERTY("DelayInhibited", "s", property_get_inhibited, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc
LP
1919 SD_BUS_PROPERTY("InhibitDelayMaxUSec", "t", NULL, offsetof(Manager, inhibit_delay_max), SD_BUS_VTABLE_PROPERTY_CONST),
1920 SD_BUS_PROPERTY("HandlePowerKey", "s", property_get_handle_action, offsetof(Manager, handle_power_key), SD_BUS_VTABLE_PROPERTY_CONST),
1921 SD_BUS_PROPERTY("HandleSuspendKey", "s", property_get_handle_action, offsetof(Manager, handle_suspend_key), SD_BUS_VTABLE_PROPERTY_CONST),
1922 SD_BUS_PROPERTY("HandleHibernateKey", "s", property_get_handle_action, offsetof(Manager, handle_hibernate_key), SD_BUS_VTABLE_PROPERTY_CONST),
1923 SD_BUS_PROPERTY("HandleLidSwitch", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch), SD_BUS_VTABLE_PROPERTY_CONST),
3c56cab4 1924 SD_BUS_PROPERTY("HandleLidSwitchDocked", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch_docked), SD_BUS_VTABLE_PROPERTY_CONST),
556089dc
LP
1925 SD_BUS_PROPERTY("IdleAction", "s", property_get_handle_action, offsetof(Manager, idle_action), SD_BUS_VTABLE_PROPERTY_CONST),
1926 SD_BUS_PROPERTY("IdleActionUSec", "t", NULL, offsetof(Manager, idle_action_usec), SD_BUS_VTABLE_PROPERTY_CONST),
cc377381
LP
1927 SD_BUS_PROPERTY("PreparingForShutdown", "b", property_get_preparing, 0, 0),
1928 SD_BUS_PROPERTY("PreparingForSleep", "b", property_get_preparing, 0, 0),
1929
adacb957
LP
1930 SD_BUS_METHOD("GetSession", "s", "o", method_get_session, SD_BUS_VTABLE_UNPRIVILEGED),
1931 SD_BUS_METHOD("GetSessionByPID", "u", "o", method_get_session_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
1932 SD_BUS_METHOD("GetUser", "u", "o", method_get_user, SD_BUS_VTABLE_UNPRIVILEGED),
1933 SD_BUS_METHOD("GetUserByPID", "u", "o", method_get_user_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
1934 SD_BUS_METHOD("GetSeat", "s", "o", method_get_seat, SD_BUS_VTABLE_UNPRIVILEGED),
1935 SD_BUS_METHOD("ListSessions", NULL, "a(susso)", method_list_sessions, SD_BUS_VTABLE_UNPRIVILEGED),
1936 SD_BUS_METHOD("ListUsers", NULL, "a(uso)", method_list_users, SD_BUS_VTABLE_UNPRIVILEGED),
1937 SD_BUS_METHOD("ListSeats", NULL, "a(so)", method_list_seats, SD_BUS_VTABLE_UNPRIVILEGED),
1938 SD_BUS_METHOD("ListInhibitors", NULL, "a(ssssuu)", method_list_inhibitors, SD_BUS_VTABLE_UNPRIVILEGED),
a4cd87e9 1939 SD_BUS_METHOD("CreateSession", "uusssssussbssa(sv)", "soshusub", method_create_session, 0),
cc377381 1940 SD_BUS_METHOD("ReleaseSession", "s", NULL, method_release_session, 0),
adacb957
LP
1941 SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED),
1942 SD_BUS_METHOD("ActivateSessionOnSeat", "ss", NULL, method_activate_session_on_seat, SD_BUS_VTABLE_UNPRIVILEGED),
cc377381
LP
1943 SD_BUS_METHOD("LockSession", "s", NULL, method_lock_session, 0),
1944 SD_BUS_METHOD("UnlockSession", "s", NULL, method_lock_session, 0),
1945 SD_BUS_METHOD("LockSessions", NULL, NULL, method_lock_sessions, 0),
1946 SD_BUS_METHOD("UnlockSessions", NULL, NULL, method_lock_sessions, 0),
adacb957
LP
1947 SD_BUS_METHOD("KillSession", "ssi", NULL, method_kill_session, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
1948 SD_BUS_METHOD("KillUser", "ui", NULL, method_kill_user, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
1949 SD_BUS_METHOD("TerminateSession", "s", NULL, method_terminate_session, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
1950 SD_BUS_METHOD("TerminateUser", "u", NULL, method_terminate_user, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
1951 SD_BUS_METHOD("TerminateSeat", "s", NULL, method_terminate_seat, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
1952 SD_BUS_METHOD("SetUserLinger", "ubb", NULL, method_set_user_linger, SD_BUS_VTABLE_UNPRIVILEGED),
1953 SD_BUS_METHOD("AttachDevice", "ssb", NULL, method_attach_device, SD_BUS_VTABLE_UNPRIVILEGED),
1954 SD_BUS_METHOD("FlushDevices", "b", NULL, method_flush_devices, SD_BUS_VTABLE_UNPRIVILEGED),
1955 SD_BUS_METHOD("PowerOff", "b", NULL, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
1956 SD_BUS_METHOD("Reboot", "b", NULL, method_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
1957 SD_BUS_METHOD("Suspend", "b", NULL, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
1958 SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
1959 SD_BUS_METHOD("HybridSleep", "b", NULL, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
1960 SD_BUS_METHOD("CanPowerOff", NULL, "s", method_can_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
1961 SD_BUS_METHOD("CanReboot", NULL, "s", method_can_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
1962 SD_BUS_METHOD("CanSuspend", NULL, "s", method_can_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
1963 SD_BUS_METHOD("CanHibernate", NULL, "s", method_can_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
1964 SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
1965 SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
cc377381
LP
1966
1967 SD_BUS_SIGNAL("SessionNew", "so", 0),
1968 SD_BUS_SIGNAL("SessionRemoved", "so", 0),
1969 SD_BUS_SIGNAL("UserNew", "uo", 0),
1970 SD_BUS_SIGNAL("UserRemoved", "uo", 0),
1971 SD_BUS_SIGNAL("SeatNew", "so", 0),
1972 SD_BUS_SIGNAL("SeatRemoved", "so", 0),
1973 SD_BUS_SIGNAL("PrepareForShutdown", "b", 0),
1974 SD_BUS_SIGNAL("PrepareForSleep", "b", 0),
1975
1976 SD_BUS_VTABLE_END
1977};
3f49d45a 1978
99e7e392
DH
1979static int session_jobs_reply(Session *s, const char *unit, const char *result) {
1980 int r = 0;
1981
1982 assert(s);
1983 assert(unit);
1984
1985 if (!s->started)
1986 return r;
1987
1988 if (streq(result, "done"))
1989 r = session_send_create_reply(s, NULL);
1990 else {
1991 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
1992
1993 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
1994 r = session_send_create_reply(s, &e);
1995 }
1996
1997 return r;
1998}
1999
ebcf1f97 2000int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
2001 const char *path, *result, *unit;
2002 Manager *m = userdata;
2003 Session *session;
2004 uint32_t id;
2005 User *user;
2006 int r;
3f49d45a 2007
cc377381
LP
2008 assert(bus);
2009 assert(message);
2010 assert(m);
3f49d45a 2011
cc377381
LP
2012 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
2013 if (r < 0) {
ebcf1f97
LP
2014 bus_log_parse_error(r);
2015 return r;
cc377381 2016 }
3f49d45a 2017
cc377381
LP
2018 if (m->action_job && streq(m->action_job, path)) {
2019 log_info("Operation finished.");
3f49d45a 2020
cc377381
LP
2021 /* Tell people that they now may take a lock again */
2022 send_prepare_for(m, m->action_what, false);
3f49d45a 2023
cc377381
LP
2024 free(m->action_job);
2025 m->action_job = NULL;
2026 m->action_unit = NULL;
2027 m->action_what = 0;
2028 return 0;
2029 }
3f49d45a 2030
cc377381
LP
2031 session = hashmap_get(m->session_units, unit);
2032 if (session) {
3f49d45a 2033
cc377381
LP
2034 if (streq_ptr(path, session->scope_job)) {
2035 free(session->scope_job);
2036 session->scope_job = NULL;
3f49d45a
LP
2037 }
2038
99e7e392 2039 session_jobs_reply(session, unit, result);
3f49d45a 2040
99e7e392 2041 session_save(session);
cc377381
LP
2042 session_add_to_gc_queue(session);
2043 }
3f49d45a 2044
cc377381
LP
2045 user = hashmap_get(m->user_units, unit);
2046 if (user) {
3f49d45a 2047
cc377381
LP
2048 if (streq_ptr(path, user->service_job)) {
2049 free(user->service_job);
2050 user->service_job = NULL;
3f49d45a
LP
2051 }
2052
cc377381
LP
2053 if (streq_ptr(path, user->slice_job)) {
2054 free(user->slice_job);
2055 user->slice_job = NULL;
2056 }
3f49d45a 2057
dd9b67aa 2058 LIST_FOREACH(sessions_by_user, session, user->sessions) {
99e7e392 2059 session_jobs_reply(session, unit, result);
dd9b67aa
LP
2060 }
2061
cc377381
LP
2062 user_save(user);
2063 user_add_to_gc_queue(user);
3f49d45a
LP
2064 }
2065
cc377381 2066 return 0;
3f49d45a
LP
2067}
2068
ebcf1f97 2069int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 2070 const char *path, *unit;
1713813d 2071 Manager *m = userdata;
cc377381
LP
2072 Session *session;
2073 User *user;
2074 int r;
1713813d 2075
cc377381 2076 assert(bus);
1713813d 2077 assert(message);
cc377381 2078 assert(m);
1713813d 2079
cc377381
LP
2080 r = sd_bus_message_read(message, "so", &unit, &path);
2081 if (r < 0) {
ebcf1f97
LP
2082 bus_log_parse_error(r);
2083 return r;
cc377381 2084 }
fb6becb4 2085
cc377381
LP
2086 session = hashmap_get(m->session_units, unit);
2087 if (session)
2088 session_add_to_gc_queue(session);
fb6becb4 2089
cc377381
LP
2090 user = hashmap_get(m->user_units, unit);
2091 if (user)
2092 user_add_to_gc_queue(user);
fb6becb4 2093
cc377381
LP
2094 return 0;
2095}
fb6becb4 2096
ebcf1f97 2097int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
2098 _cleanup_free_ char *unit = NULL;
2099 Manager *m = userdata;
2100 const char *path;
2101 Session *session;
2102 User *user;
ebcf1f97 2103 int r;
fb6becb4 2104
cc377381
LP
2105 assert(bus);
2106 assert(message);
2107 assert(m);
fb6becb4 2108
cc377381
LP
2109 path = sd_bus_message_get_path(message);
2110 if (!path)
2111 return 0;
fb6becb4 2112
ebcf1f97
LP
2113 r = unit_name_from_dbus_path(path, &unit);
2114 if (r < 0)
a87105a3
ZJS
2115 /* quietly ignore non-units paths */
2116 return r == -EINVAL ? 0 : r;
fb6becb4 2117
cc377381
LP
2118 session = hashmap_get(m->session_units, unit);
2119 if (session)
2120 session_add_to_gc_queue(session);
fb6becb4 2121
cc377381
LP
2122 user = hashmap_get(m->user_units, unit);
2123 if (user)
2124 user_add_to_gc_queue(user);
fb6becb4 2125
cc377381
LP
2126 return 0;
2127}
6fa48533 2128
ebcf1f97 2129int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
2130 Manager *m = userdata;
2131 Session *session;
2132 Iterator i;
2133 int b, r;
943aca8e 2134
cc377381 2135 assert(bus);
943aca8e 2136
cc377381
LP
2137 r = sd_bus_message_read(message, "b", &b);
2138 if (r < 0) {
ebcf1f97
LP
2139 bus_log_parse_error(r);
2140 return r;
cc377381 2141 }
943aca8e 2142
cc377381
LP
2143 if (b)
2144 return 0;
943aca8e 2145
cc377381
LP
2146 /* systemd finished reloading, let's recheck all our sessions */
2147 log_debug("System manager has been reloaded, rechecking sessions...");
6797c324 2148
cc377381
LP
2149 HASHMAP_FOREACH(session, m->sessions, i)
2150 session_add_to_gc_queue(session);
6797c324 2151
cc377381
LP
2152 return 0;
2153}
943aca8e 2154
ebcf1f97 2155int match_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
2156 const char *name, *old, *new;
2157 Manager *m = userdata;
2158 Session *session;
2159 Iterator i;
2160 int r;
943aca8e 2161
6797c324 2162
cc377381 2163 char *key;
e8b212fe 2164
cc377381
LP
2165 r = sd_bus_message_read(message, "sss", &name, &old, &new);
2166 if (r < 0) {
ebcf1f97
LP
2167 bus_log_parse_error(r);
2168 return r;
cc377381 2169 }
e8b212fe 2170
cc377381
LP
2171 if (isempty(old) || !isempty(new))
2172 return 0;
e8b212fe 2173
cc377381
LP
2174 key = set_remove(m->busnames, (char*) old);
2175 if (!key)
2176 return 0;
ae5e06bd 2177
cc377381 2178 /* Drop all controllers owned by this name */
ae5e06bd 2179
cc377381 2180 free(key);
1713813d 2181
cc377381
LP
2182 HASHMAP_FOREACH(session, m->sessions, i)
2183 if (session_is_controller(session, old))
2184 session_drop_controller(session);
1713813d 2185
cc377381 2186 return 0;
1713813d
LP
2187}
2188
cc377381
LP
2189int manager_send_changed(Manager *manager, const char *property, ...) {
2190 char **l;
9418f147
LP
2191
2192 assert(manager);
2193
cc377381 2194 l = strv_from_stdarg_alloca(property);
9418f147 2195
cc377381
LP
2196 return sd_bus_emit_properties_changed_strv(
2197 manager->bus,
2198 "/org/freedesktop/login1",
2199 "org.freedesktop.login1.Manager",
2200 l);
9418f147 2201}
eecd1362 2202
d889a206 2203int manager_dispatch_delayed(Manager *manager) {
cc377381 2204 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
85a428c6 2205 Inhibitor *offending = NULL;
eecd1362
LP
2206 int r;
2207
2208 assert(manager);
2209
84286536 2210 if (manager->action_what == 0 || manager->action_job)
eecd1362
LP
2211 return 0;
2212
2213 /* Continue delay? */
85a428c6
LP
2214 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) {
2215 _cleanup_free_ char *comm = NULL, *u = NULL;
2216
2217 get_process_comm(offending->pid, &comm);
2218 u = uid_to_name(offending->uid);
eecd1362 2219
314b4b0a
LP
2220 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2221 return 0;
af9792ac 2222
de0671ee
ZJS
2223 log_info("Delay lock is active (UID "UID_FMT"/%s, PID "PID_FMT"/%s) but inhibitor timeout is reached.",
2224 offending->uid, strna(u),
2225 offending->pid, strna(comm));
314b4b0a 2226 }
eecd1362 2227
314b4b0a 2228 /* Actually do the operation */
314b4b0a 2229 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
eecd1362 2230 if (r < 0) {
cc377381 2231 log_warning("Failed to send delayed message: %s", bus_error_message(&error, r));
314b4b0a
LP
2232
2233 manager->action_unit = NULL;
2234 manager->action_what = 0;
eecd1362
LP
2235 return r;
2236 }
2237
eecd1362
LP
2238 return 1;
2239}
fb6becb4
LP
2240
2241int manager_start_scope(
2242 Manager *manager,
2243 const char *scope,
2244 pid_t pid,
2245 const char *slice,
2246 const char *description,
ba4c5d93 2247 const char *after, const char *after2,
cc377381 2248 sd_bus_error *error,
fb6becb4
LP
2249 char **job) {
2250
cc377381
LP
2251 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
2252 int r;
fb6becb4
LP
2253
2254 assert(manager);
2255 assert(scope);
2256 assert(pid > 1);
2257
cc377381
LP
2258 r = sd_bus_message_new_method_call(
2259 manager->bus,
151b9b96 2260 &m,
fb6becb4
LP
2261 "org.freedesktop.systemd1",
2262 "/org/freedesktop/systemd1",
2263 "org.freedesktop.systemd1.Manager",
151b9b96 2264 "StartTransientUnit");
cc377381
LP
2265 if (r < 0)
2266 return r;
fb6becb4 2267
cc377381
LP
2268 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
2269 if (r < 0)
2270 return r;
fb6becb4 2271
cc377381
LP
2272 r = sd_bus_message_open_container(m, 'a', "(sv)");
2273 if (r < 0)
2274 return r;
fb6becb4
LP
2275
2276 if (!isempty(slice)) {
cc377381
LP
2277 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
2278 if (r < 0)
2279 return r;
fb6becb4
LP
2280 }
2281
2282 if (!isempty(description)) {
cc377381
LP
2283 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
2284 if (r < 0)
2285 return r;
fb6becb4
LP
2286 }
2287
ba4c5d93 2288 if (!isempty(after)) {
cc377381
LP
2289 r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after);
2290 if (r < 0)
2291 return r;
7fb3ee51
LP
2292 }
2293
ba4c5d93
LP
2294 if (!isempty(after2)) {
2295 r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after2);
2296 if (r < 0)
2297 return r;
2298 }
2299
fb6becb4
LP
2300 /* cgroup empty notification is not available in containers
2301 * currently. To make this less problematic, let's shorten the
2302 * stop timeout for sessions, so that we don't wait
2303 * forever. */
2304
743e8945
LP
2305 /* Make sure that the session shells are terminated with
2306 * SIGHUP since bash and friends tend to ignore SIGTERM */
cc377381
LP
2307 r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", true);
2308 if (r < 0)
2309 return r;
2310
2311 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
2312 if (r < 0)
2313 return r;
2314
2315 r = sd_bus_message_close_container(m);
2316 if (r < 0)
2317 return r;
86b8d289
LP
2318
2319 r = sd_bus_message_append(m, "a(sa(sv))", 0);
2320 if (r < 0)
2321 return r;
cc377381 2322
c49b30a2 2323 r = sd_bus_call(manager->bus, m, 0, error, &reply);
cc377381
LP
2324 if (r < 0)
2325 return r;
fb6becb4
LP
2326
2327 if (job) {
2328 const char *j;
2329 char *copy;
2330
cc377381
LP
2331 r = sd_bus_message_read(reply, "o", &j);
2332 if (r < 0)
2333 return r;
fb6becb4
LP
2334
2335 copy = strdup(j);
2336 if (!copy)
2337 return -ENOMEM;
2338
2339 *job = copy;
2340 }
2341
cc377381 2342 return 1;
fb6becb4
LP
2343}
2344
cc377381
LP
2345int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
2346 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
fb6becb4
LP
2347 int r;
2348
2349 assert(manager);
2350 assert(unit);
2351
cc377381 2352 r = sd_bus_call_method(
fb6becb4
LP
2353 manager->bus,
2354 "org.freedesktop.systemd1",
2355 "/org/freedesktop/systemd1",
2356 "org.freedesktop.systemd1.Manager",
2357 "StartUnit",
fb6becb4 2358 error,
cc377381
LP
2359 &reply,
2360 "ss", unit, "fail");
2361 if (r < 0)
fb6becb4 2362 return r;
fb6becb4
LP
2363
2364 if (job) {
2365 const char *j;
2366 char *copy;
2367
cc377381
LP
2368 r = sd_bus_message_read(reply, "o", &j);
2369 if (r < 0)
2370 return r;
fb6becb4
LP
2371
2372 copy = strdup(j);
2373 if (!copy)
2374 return -ENOMEM;
2375
2376 *job = copy;
2377 }
2378
cc377381 2379 return 1;
fb6becb4
LP
2380}
2381
cc377381
LP
2382int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
2383 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
fb6becb4
LP
2384 int r;
2385
2386 assert(manager);
2387 assert(unit);
2388
cc377381 2389 r = sd_bus_call_method(
fb6becb4
LP
2390 manager->bus,
2391 "org.freedesktop.systemd1",
2392 "/org/freedesktop/systemd1",
2393 "org.freedesktop.systemd1.Manager",
2394 "StopUnit",
fb6becb4 2395 error,
cc377381
LP
2396 &reply,
2397 "ss", unit, "fail");
fb6becb4 2398 if (r < 0) {
cc377381
LP
2399 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
2400 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
2401
2402 if (job)
2403 *job = NULL;
2404
cc377381 2405 sd_bus_error_free(error);
6797c324
LP
2406 return 0;
2407 }
2408
fb6becb4
LP
2409 return r;
2410 }
2411
2412 if (job) {
2413 const char *j;
2414 char *copy;
2415
cc377381
LP
2416 r = sd_bus_message_read(reply, "o", &j);
2417 if (r < 0)
2418 return r;
fb6becb4
LP
2419
2420 copy = strdup(j);
2421 if (!copy)
2422 return -ENOMEM;
2423
2424 *job = copy;
2425 }
2426
6797c324 2427 return 1;
fb6becb4
LP
2428}
2429
5f41d1f1 2430int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error) {
5f41d1f1
LP
2431 _cleanup_free_ char *path = NULL;
2432 int r;
2433
2434 assert(manager);
2435 assert(scope);
2436
2437 path = unit_dbus_path_from_name(scope);
2438 if (!path)
2439 return -ENOMEM;
2440
2441 r = sd_bus_call_method(
2442 manager->bus,
2443 "org.freedesktop.systemd1",
2444 path,
2445 "org.freedesktop.systemd1.Scope",
2446 "Abandon",
2447 error,
2448 NULL,
2449 NULL);
2450 if (r < 0) {
2451 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
4e2f8d27
LP
2452 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED) ||
2453 sd_bus_error_has_name(error, BUS_ERROR_SCOPE_NOT_RUNNING)) {
5f41d1f1
LP
2454 sd_bus_error_free(error);
2455 return 0;
2456 }
2457
2458 return r;
2459 }
2460
2461 return 1;
2462}
2463
cc377381 2464int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
fb6becb4
LP
2465 assert(manager);
2466 assert(unit);
2467
cc377381 2468 return sd_bus_call_method(
fb6becb4
LP
2469 manager->bus,
2470 "org.freedesktop.systemd1",
2471 "/org/freedesktop/systemd1",
2472 "org.freedesktop.systemd1.Manager",
2473 "KillUnit",
fb6becb4 2474 error,
cc377381
LP
2475 NULL,
2476 "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
fb6becb4
LP
2477}
2478
2479int manager_unit_is_active(Manager *manager, const char *unit) {
cc377381
LP
2480 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2481 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
fb6becb4 2482 _cleanup_free_ char *path = NULL;
fb6becb4 2483 const char *state;
fb6becb4
LP
2484 int r;
2485
2486 assert(manager);
2487 assert(unit);
2488
fb6becb4
LP
2489 path = unit_dbus_path_from_name(unit);
2490 if (!path)
2491 return -ENOMEM;
2492
cc377381 2493 r = sd_bus_get_property(
fb6becb4
LP
2494 manager->bus,
2495 "org.freedesktop.systemd1",
2496 path,
cc377381
LP
2497 "org.freedesktop.systemd1.Unit",
2498 "ActiveState",
fb6becb4 2499 &error,
cc377381
LP
2500 &reply,
2501 "s");
fb6becb4 2502 if (r < 0) {
cc377381
LP
2503 /* systemd might have droppped off momentarily, let's
2504 * not make this an error */
2505 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
2506 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 2507 return true;
6797c324 2508
cc377381
LP
2509 /* If the unit is already unloaded then it's not
2510 * active */
2511 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
2512 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 2513 return false;
6797c324 2514
fb6becb4
LP
2515 return r;
2516 }
2517
cc377381
LP
2518 r = sd_bus_message_read(reply, "s", &state);
2519 if (r < 0)
fb6becb4 2520 return -EINVAL;
fb6becb4 2521
cc377381
LP
2522 return !streq(state, "inactive") && !streq(state, "failed");
2523}
2524
2525int manager_job_is_active(Manager *manager, const char *path) {
2526 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2527 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
2528 int r;
2529
2530 assert(manager);
2531 assert(path);
2532
2533 r = sd_bus_get_property(
2534 manager->bus,
2535 "org.freedesktop.systemd1",
2536 path,
2537 "org.freedesktop.systemd1.Job",
2538 "State",
2539 &error,
2540 &reply,
2541 "s");
2542 if (r < 0) {
2543 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
2544 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
2545 return true;
2546
2547 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
2548 return false;
2549
2550 return r;
fb6becb4
LP
2551 }
2552
cc377381
LP
2553 /* We don't actually care about the state really. The fact
2554 * that we could read the job state is enough for us */
fb6becb4 2555
cc377381 2556 return true;
fb6becb4 2557}