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