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