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