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