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