]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-dbus.c
util: fix handling of trailing whitespace in split_quoted()
[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 498
92bd5ff3 499 if (!vtnr)
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)) {
c506027a 517 if (!vtnr || 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 &&
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 &&
85a428c6 1401 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0, NULL);
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;
85a428c6 1467 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
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 1611 multiple_sessions = r > 0;
85a428c6 1612 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
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),
baae0358 1858 SD_BUS_METHOD("CreateSession", "uussssussbssa(sv)", "soshusub", method_create_session, 0),
cc377381
LP
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;
85a428c6 2107 Inhibitor *offending = 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? */
85a428c6
LP
2116 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) {
2117 _cleanup_free_ char *comm = NULL, *u = NULL;
2118
2119 get_process_comm(offending->pid, &comm);
2120 u = uid_to_name(offending->uid);
eecd1362 2121
314b4b0a
LP
2122 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2123 return 0;
af9792ac 2124
85a428c6
LP
2125 log_info("Delay lock is active (UID %lu/%s, PID %lu/%s) but inhibitor timeout is reached.",
2126 (unsigned long) offending->uid, strna(u),
2127 (unsigned long) offending->pid, strna(comm));
314b4b0a 2128 }
eecd1362 2129
314b4b0a 2130 /* Actually do the operation */
314b4b0a 2131 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
eecd1362 2132 if (r < 0) {
cc377381 2133 log_warning("Failed to send delayed message: %s", bus_error_message(&error, r));
314b4b0a
LP
2134
2135 manager->action_unit = NULL;
2136 manager->action_what = 0;
eecd1362
LP
2137 return r;
2138 }
2139
eecd1362
LP
2140 return 1;
2141}
fb6becb4
LP
2142
2143int manager_start_scope(
2144 Manager *manager,
2145 const char *scope,
2146 pid_t pid,
2147 const char *slice,
2148 const char *description,
7fb3ee51 2149 const char *after,
405e0255 2150 const char *kill_mode,
cc377381 2151 sd_bus_error *error,
fb6becb4
LP
2152 char **job) {
2153
cc377381
LP
2154 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
2155 int r;
fb6becb4
LP
2156
2157 assert(manager);
2158 assert(scope);
2159 assert(pid > 1);
2160
cc377381
LP
2161 r = sd_bus_message_new_method_call(
2162 manager->bus,
fb6becb4
LP
2163 "org.freedesktop.systemd1",
2164 "/org/freedesktop/systemd1",
2165 "org.freedesktop.systemd1.Manager",
cc377381
LP
2166 "StartTransientUnit",
2167 &m);
2168 if (r < 0)
2169 return r;
fb6becb4 2170
cc377381
LP
2171 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
2172 if (r < 0)
2173 return r;
fb6becb4 2174
cc377381
LP
2175 r = sd_bus_message_open_container(m, 'a', "(sv)");
2176 if (r < 0)
2177 return r;
fb6becb4
LP
2178
2179 if (!isempty(slice)) {
cc377381
LP
2180 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
2181 if (r < 0)
2182 return r;
fb6becb4
LP
2183 }
2184
2185 if (!isempty(description)) {
cc377381
LP
2186 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
2187 if (r < 0)
2188 return r;
fb6becb4
LP
2189 }
2190
cc377381
LP
2191 if (!isempty(description)) {
2192 r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after);
2193 if (r < 0)
2194 return r;
7fb3ee51
LP
2195 }
2196
405e0255 2197 if (!isempty(kill_mode)) {
cc377381
LP
2198 r = sd_bus_message_append(m, "(sv)", "KillMode", "s", kill_mode);
2199 if (r < 0)
2200 return r;
405e0255
LP
2201 }
2202
fb6becb4
LP
2203 /* cgroup empty notification is not available in containers
2204 * currently. To make this less problematic, let's shorten the
2205 * stop timeout for sessions, so that we don't wait
2206 * forever. */
2207
cc377381
LP
2208 r = sd_bus_message_append(m, "(sv)", "TimeoutStopUSec", "t", 500 * USEC_PER_MSEC);
2209 if (r < 0)
2210 return r;
fb6becb4 2211
743e8945
LP
2212 /* Make sure that the session shells are terminated with
2213 * SIGHUP since bash and friends tend to ignore SIGTERM */
cc377381
LP
2214 r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", true);
2215 if (r < 0)
2216 return r;
2217
2218 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
2219 if (r < 0)
2220 return r;
2221
2222 r = sd_bus_message_close_container(m);
2223 if (r < 0)
2224 return r;
86b8d289
LP
2225
2226 r = sd_bus_message_append(m, "a(sa(sv))", 0);
2227 if (r < 0)
2228 return r;
cc377381 2229
c49b30a2 2230 r = sd_bus_call(manager->bus, m, 0, error, &reply);
cc377381
LP
2231 if (r < 0)
2232 return r;
fb6becb4
LP
2233
2234 if (job) {
2235 const char *j;
2236 char *copy;
2237
cc377381
LP
2238 r = sd_bus_message_read(reply, "o", &j);
2239 if (r < 0)
2240 return r;
fb6becb4
LP
2241
2242 copy = strdup(j);
2243 if (!copy)
2244 return -ENOMEM;
2245
2246 *job = copy;
2247 }
2248
cc377381 2249 return 1;
fb6becb4
LP
2250}
2251
cc377381
LP
2252int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
2253 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
fb6becb4
LP
2254 int r;
2255
2256 assert(manager);
2257 assert(unit);
2258
cc377381 2259 r = sd_bus_call_method(
fb6becb4
LP
2260 manager->bus,
2261 "org.freedesktop.systemd1",
2262 "/org/freedesktop/systemd1",
2263 "org.freedesktop.systemd1.Manager",
2264 "StartUnit",
fb6becb4 2265 error,
cc377381
LP
2266 &reply,
2267 "ss", unit, "fail");
2268 if (r < 0)
fb6becb4 2269 return r;
fb6becb4
LP
2270
2271 if (job) {
2272 const char *j;
2273 char *copy;
2274
cc377381
LP
2275 r = sd_bus_message_read(reply, "o", &j);
2276 if (r < 0)
2277 return r;
fb6becb4
LP
2278
2279 copy = strdup(j);
2280 if (!copy)
2281 return -ENOMEM;
2282
2283 *job = copy;
2284 }
2285
cc377381 2286 return 1;
fb6becb4
LP
2287}
2288
cc377381
LP
2289int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
2290 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
fb6becb4
LP
2291 int r;
2292
2293 assert(manager);
2294 assert(unit);
2295
cc377381 2296 r = sd_bus_call_method(
fb6becb4
LP
2297 manager->bus,
2298 "org.freedesktop.systemd1",
2299 "/org/freedesktop/systemd1",
2300 "org.freedesktop.systemd1.Manager",
2301 "StopUnit",
fb6becb4 2302 error,
cc377381
LP
2303 &reply,
2304 "ss", unit, "fail");
fb6becb4 2305 if (r < 0) {
cc377381
LP
2306 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
2307 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
2308
2309 if (job)
2310 *job = NULL;
2311
cc377381 2312 sd_bus_error_free(error);
6797c324
LP
2313 return 0;
2314 }
2315
fb6becb4
LP
2316 return r;
2317 }
2318
2319 if (job) {
2320 const char *j;
2321 char *copy;
2322
cc377381
LP
2323 r = sd_bus_message_read(reply, "o", &j);
2324 if (r < 0)
2325 return r;
fb6becb4
LP
2326
2327 copy = strdup(j);
2328 if (!copy)
2329 return -ENOMEM;
2330
2331 *job = copy;
2332 }
2333
6797c324 2334 return 1;
fb6becb4
LP
2335}
2336
cc377381 2337int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
fb6becb4
LP
2338 assert(manager);
2339 assert(unit);
2340
cc377381 2341 return sd_bus_call_method(
fb6becb4
LP
2342 manager->bus,
2343 "org.freedesktop.systemd1",
2344 "/org/freedesktop/systemd1",
2345 "org.freedesktop.systemd1.Manager",
2346 "KillUnit",
fb6becb4 2347 error,
cc377381
LP
2348 NULL,
2349 "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
fb6becb4
LP
2350}
2351
2352int manager_unit_is_active(Manager *manager, const char *unit) {
cc377381
LP
2353 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2354 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
fb6becb4 2355 _cleanup_free_ char *path = NULL;
fb6becb4 2356 const char *state;
fb6becb4
LP
2357 int r;
2358
2359 assert(manager);
2360 assert(unit);
2361
fb6becb4
LP
2362 path = unit_dbus_path_from_name(unit);
2363 if (!path)
2364 return -ENOMEM;
2365
cc377381 2366 r = sd_bus_get_property(
fb6becb4
LP
2367 manager->bus,
2368 "org.freedesktop.systemd1",
2369 path,
cc377381
LP
2370 "org.freedesktop.systemd1.Unit",
2371 "ActiveState",
fb6becb4 2372 &error,
cc377381
LP
2373 &reply,
2374 "s");
fb6becb4 2375 if (r < 0) {
cc377381
LP
2376 /* systemd might have droppped off momentarily, let's
2377 * not make this an error */
2378 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
2379 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 2380 return true;
6797c324 2381
cc377381
LP
2382 /* If the unit is already unloaded then it's not
2383 * active */
2384 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
2385 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 2386 return false;
6797c324 2387
fb6becb4
LP
2388 return r;
2389 }
2390
cc377381
LP
2391 r = sd_bus_message_read(reply, "s", &state);
2392 if (r < 0)
fb6becb4 2393 return -EINVAL;
fb6becb4 2394
cc377381
LP
2395 return !streq(state, "inactive") && !streq(state, "failed");
2396}
2397
2398int manager_job_is_active(Manager *manager, const char *path) {
2399 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2400 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
2401 int r;
2402
2403 assert(manager);
2404 assert(path);
2405
2406 r = sd_bus_get_property(
2407 manager->bus,
2408 "org.freedesktop.systemd1",
2409 path,
2410 "org.freedesktop.systemd1.Job",
2411 "State",
2412 &error,
2413 &reply,
2414 "s");
2415 if (r < 0) {
2416 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
2417 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
2418 return true;
2419
2420 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
2421 return false;
2422
2423 return r;
fb6becb4
LP
2424 }
2425
cc377381
LP
2426 /* We don't actually care about the state really. The fact
2427 * that we could read the job state is enough for us */
fb6becb4 2428
cc377381 2429 return true;
fb6becb4 2430}