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