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