]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-session.c
logind: add hashtable for finding session by leader PID
[thirdparty/systemd.git] / src / login / logind-session.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
20263082
LP
2
3#include <errno.h>
90a18413 4#include <fcntl.h>
90a18413 5#include <linux/kd.h>
4f5dd394 6#include <linux/vt.h>
90a18413 7#include <signal.h>
44176400 8#include <stdio_ext.h>
20263082 9#include <string.h>
90a18413 10#include <sys/ioctl.h>
20263082
LP
11#include <unistd.h>
12
cc377381 13#include "sd-messages.h"
4f5dd394 14
b5efdb8a 15#include "alloc-util.h"
430f0182 16#include "audit-util.h"
cc377381 17#include "bus-error.h"
4f5dd394
LP
18#include "bus-util.h"
19#include "escape.h"
3ffd4af2 20#include "fd-util.h"
4f5dd394 21#include "fileio.h"
f97b34a6 22#include "format-util.h"
c004493c 23#include "io-util.h"
3ffd4af2 24#include "logind-session.h"
4f5dd394 25#include "mkdir.h"
6bedfcbb 26#include "parse-util.h"
4f5dd394 27#include "path-util.h"
8c29a457 28#include "process-util.h"
8b43440b 29#include "string-table.h"
25a1ab4e 30#include "strv.h"
288a74cc 31#include "terminal-util.h"
b1d4f8e1 32#include "user-util.h"
4f5dd394 33#include "util.h"
20263082 34
5f41d1f1
LP
35#define RELEASE_USEC (20*USEC_PER_SEC)
36
37static void session_remove_fifo(Session *s);
38
8c29a457
LP
39int session_new(Session **ret, Manager *m, const char *id) {
40 _cleanup_(session_freep) Session *s = NULL;
41 int r;
20263082 42
8c29a457 43 assert(ret);
20263082
LP
44 assert(m);
45 assert(id);
46
8c29a457
LP
47 if (!session_id_valid(id))
48 return -EINVAL;
49
50 s = new(Session, 1);
20263082 51 if (!s)
8c29a457
LP
52 return -ENOMEM;
53
54 *s = (Session) {
55 .manager = m,
56 .fifo_fd = -1,
57 .vtfd = -1,
58 .audit_id = AUDIT_SESSION_INVALID,
59 };
20263082 60
98a28fef 61 s->state_file = strappend("/run/systemd/sessions/", id);
6b430fdb 62 if (!s->state_file)
8c29a457 63 return -ENOMEM;
118ecf32 64
2b6bf07d 65 s->id = basename(s->state_file);
20263082 66
8c29a457
LP
67 s->devices = hashmap_new(&devt_hash_ops);
68 if (!s->devices)
69 return -ENOMEM;
20263082 70
8c29a457
LP
71 r = hashmap_put(m->sessions, s->id, s);
72 if (r < 0)
73 return r;
20263082 74
8c29a457
LP
75 *ret = TAKE_PTR(s);
76 return 0;
20263082
LP
77}
78
8c29a457 79Session* session_free(Session *s) {
118ecf32
DH
80 SessionDevice *sd;
81
8c29a457
LP
82 if (!s)
83 return NULL;
20263082 84
14c3baca 85 if (s->in_gc_queue)
71fda00f 86 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
14c3baca 87
5f41d1f1
LP
88 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
89
cc377381
LP
90 session_remove_fifo(s);
91
ae5e06bd
DH
92 session_drop_controller(s);
93
118ecf32
DH
94 while ((sd = hashmap_first(s->devices)))
95 session_device_free(sd);
96
97 hashmap_free(s->devices);
98
20263082 99 if (s->user) {
71fda00f 100 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
20263082
LP
101
102 if (s->user->display == s)
103 s->user->display = NULL;
9afe9efb
LP
104
105 user_update_last_session_timer(s->user);
20263082
LP
106 }
107
9418f147
LP
108 if (s->seat) {
109 if (s->seat->active == s)
110 s->seat->active = NULL;
d7bd01b5
DH
111 if (s->seat->pending_switch == s)
112 s->seat->pending_switch = NULL;
9418f147 113
49e6fdbf 114 seat_evict_position(s->seat, s);
71fda00f 115 LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
9418f147 116 }
20263082 117
fb6becb4
LP
118 if (s->scope) {
119 hashmap_remove(s->manager->session_units, s->scope);
120 free(s->scope);
121 }
122
238794b1
LP
123 if (pid_is_valid(s->leader))
124 (void) hashmap_remove_value(s->manager->sessions_by_leader, PID_TO_PTR(s->leader), s);
125
fb6becb4 126 free(s->scope_job);
1713813d 127
cc377381 128 sd_bus_message_unref(s->create_message);
20263082
LP
129
130 free(s->tty);
131 free(s->display);
132 free(s->remote_host);
3f49d45a 133 free(s->remote_user);
98a28fef 134 free(s->service);
a4cd87e9 135 free(s->desktop);
20263082
LP
136
137 hashmap_remove(s->manager->sessions, s->id);
98a28fef 138
d2f92cdf 139 free(s->state_file);
8c29a457
LP
140
141 return mfree(s);
20263082
LP
142}
143
9444b1f2
LP
144void session_set_user(Session *s, User *u) {
145 assert(s);
146 assert(!s->user);
147
148 s->user = u;
71fda00f 149 LIST_PREPEND(sessions_by_user, u->sessions, s);
9afe9efb
LP
150
151 user_update_last_session_timer(u);
9444b1f2
LP
152}
153
238794b1
LP
154int session_set_leader(Session *s, pid_t pid) {
155 int r;
156
157 assert(s);
158
159 if (!pid_is_valid(pid))
160 return -EINVAL;
161
162 if (s->leader == pid)
163 return 0;
164
165 r = hashmap_put(s->manager->sessions_by_leader, PID_TO_PTR(pid), s);
166 if (r < 0)
167 return r;
168
169 if (pid_is_valid(s->leader))
170 (void) hashmap_remove_value(s->manager->sessions_by_leader, PID_TO_PTR(s->leader), s);
171
172 s->leader = pid;
173 (void) audit_session_from_pid(pid, &s->audit_id);
174
175 return 1;
176}
177
aed24c4c
FB
178static void session_save_devices(Session *s, FILE *f) {
179 SessionDevice *sd;
180 Iterator i;
181
182 if (!hashmap_isempty(s->devices)) {
183 fprintf(f, "DEVICES=");
184 HASHMAP_FOREACH(sd, s->devices, i)
185 fprintf(f, "%u:%u ", major(sd->dev), minor(sd->dev));
186 fprintf(f, "\n");
187 }
188}
189
20263082 190int session_save(Session *s) {
507f22bd 191 _cleanup_free_ char *temp_path = NULL;
cc377381 192 _cleanup_fclose_ FILE *f = NULL;
20263082
LP
193 int r = 0;
194
195 assert(s);
196
9444b1f2
LP
197 if (!s->user)
198 return -ESTALE;
199
accaeded
LP
200 if (!s->started)
201 return 0;
202
37c1d5e9 203 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0, MKDIR_WARN_MODE);
20263082 204 if (r < 0)
dacd6cee 205 goto fail;
20263082 206
14c3baca
LP
207 r = fopen_temporary(s->state_file, &f, &temp_path);
208 if (r < 0)
dacd6cee 209 goto fail;
20263082 210
44176400
LP
211 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
212 (void) fchmod(fileno(f), 0644);
14c3baca 213
20263082
LP
214 fprintf(f,
215 "# This is private data. Do not parse.\n"
90b2de37 216 "UID="UID_FMT"\n"
20263082
LP
217 "USER=%s\n"
218 "ACTIVE=%i\n"
1c8280fd 219 "IS_DISPLAY=%i\n"
0604381b 220 "STATE=%s\n"
fb6becb4 221 "REMOTE=%i\n",
90b2de37 222 s->user->uid,
20263082
LP
223 s->user->name,
224 session_is_active(s),
1c8280fd 225 s->user->display == s,
0604381b 226 session_state_to_string(session_get_state(s)),
fb6becb4 227 s->remote);
20263082 228
a91e4e53 229 if (s->type >= 0)
507f22bd 230 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
a91e4e53 231
55efac6c 232 if (s->class >= 0)
507f22bd 233 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
55efac6c 234
fb6becb4
LP
235 if (s->scope)
236 fprintf(f, "SCOPE=%s\n", s->scope);
fb6becb4
LP
237 if (s->scope_job)
238 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
20263082 239
932e3ee7 240 if (s->fifo_path)
507f22bd 241 fprintf(f, "FIFO=%s\n", s->fifo_path);
932e3ee7 242
20263082 243 if (s->seat)
507f22bd 244 fprintf(f, "SEAT=%s\n", s->seat->id);
20263082
LP
245
246 if (s->tty)
507f22bd 247 fprintf(f, "TTY=%s\n", s->tty);
20263082
LP
248
249 if (s->display)
507f22bd 250 fprintf(f, "DISPLAY=%s\n", s->display);
20263082 251
558c6490
LP
252 if (s->remote_host) {
253 _cleanup_free_ char *escaped;
254
255 escaped = cescape(s->remote_host);
256 if (!escaped) {
257 r = -ENOMEM;
dacd6cee 258 goto fail;
558c6490
LP
259 }
260
261 fprintf(f, "REMOTE_HOST=%s\n", escaped);
262 }
263
264 if (s->remote_user) {
265 _cleanup_free_ char *escaped;
266
267 escaped = cescape(s->remote_user);
268 if (!escaped) {
269 r = -ENOMEM;
dacd6cee 270 goto fail;
558c6490
LP
271 }
272
273 fprintf(f, "REMOTE_USER=%s\n", escaped);
274 }
275
276 if (s->service) {
277 _cleanup_free_ char *escaped;
20263082 278
558c6490
LP
279 escaped = cescape(s->service);
280 if (!escaped) {
281 r = -ENOMEM;
dacd6cee 282 goto fail;
558c6490
LP
283 }
284
285 fprintf(f, "SERVICE=%s\n", escaped);
286 }
3f49d45a 287
558c6490
LP
288 if (s->desktop) {
289 _cleanup_free_ char *escaped;
98a28fef 290
558c6490
LP
291 escaped = cescape(s->desktop);
292 if (!escaped) {
293 r = -ENOMEM;
dacd6cee 294 goto fail;
558c6490
LP
295 }
296
297 fprintf(f, "DESKTOP=%s\n", escaped);
298 }
a4cd87e9 299
bf7825ae 300 if (s->seat && seat_has_vts(s->seat))
92bd5ff3 301 fprintf(f, "VTNR=%u\n", s->vtnr);
20263082 302
49e6fdbf 303 if (!s->vtnr)
e6494a07 304 fprintf(f, "POSITION=%u\n", s->position);
49e6fdbf 305
54191eb3 306 if (pid_is_valid(s->leader))
90b2de37 307 fprintf(f, "LEADER="PID_FMT"\n", s->leader);
20263082 308
3a87a86e 309 if (audit_session_is_valid(s->audit_id))
507f22bd 310 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
20263082 311
9444b1f2
LP
312 if (dual_timestamp_is_set(&s->timestamp))
313 fprintf(f,
90b2de37
ZJS
314 "REALTIME="USEC_FMT"\n"
315 "MONOTONIC="USEC_FMT"\n",
316 s->timestamp.realtime,
317 s->timestamp.monotonic);
9444b1f2 318
aed24c4c 319 if (s->controller) {
6d33772f 320 fprintf(f, "CONTROLLER=%s\n", s->controller);
aed24c4c
FB
321 session_save_devices(s, f);
322 }
6d33772f 323
dacd6cee
LP
324 r = fflush_and_check(f);
325 if (r < 0)
326 goto fail;
14c3baca 327
dacd6cee 328 if (rename(temp_path, s->state_file) < 0) {
20263082 329 r = -errno;
dacd6cee 330 goto fail;
20263082
LP
331 }
332
dacd6cee
LP
333 return 0;
334
335fail:
336 (void) unlink(s->state_file);
14c3baca 337
dacd6cee
LP
338 if (temp_path)
339 (void) unlink(temp_path);
340
341 return log_error_errno(r, "Failed to save session data %s: %m", s->state_file);
20263082
LP
342}
343
aed24c4c
FB
344static int session_load_devices(Session *s, const char *devices) {
345 const char *p;
346 int r = 0;
347
348 assert(s);
349
350 for (p = devices;;) {
351 _cleanup_free_ char *word = NULL;
352 SessionDevice *sd;
353 dev_t dev;
354 int k;
355
356 k = extract_first_word(&p, &word, NULL, 0);
357 if (k == 0)
358 break;
359 if (k < 0) {
360 r = k;
361 break;
362 }
363
364 k = parse_dev(word, &dev);
365 if (k < 0) {
366 r = k;
367 continue;
368 }
369
370 /* The file descriptors for loaded devices will be reattached later. */
371 k = session_device_new(s, dev, false, &sd);
372 if (k < 0)
373 r = k;
374 }
375
376 if (r < 0)
377 log_error_errno(r, "Loading session devices for session %s failed: %m", s->id);
378
379 return r;
380}
dacd6cee 381
20263082 382int session_load(Session *s) {
9444b1f2 383 _cleanup_free_ char *remote = NULL,
a185c5aa
LP
384 *seat = NULL,
385 *vtnr = NULL,
be94d954 386 *state = NULL,
e6494a07 387 *position = NULL,
a185c5aa 388 *leader = NULL,
55efac6c 389 *type = NULL,
9444b1f2
LP
390 *class = NULL,
391 *uid = NULL,
392 *realtime = NULL,
6d33772f 393 *monotonic = NULL,
aed24c4c
FB
394 *controller = NULL,
395 *active = NULL,
1c8280fd
LP
396 *devices = NULL,
397 *is_display = NULL;
a185c5aa
LP
398
399 int k, r;
400
20263082
LP
401 assert(s);
402
1a5a177e 403 r = parse_env_file(NULL, s->state_file, NEWLINE,
a185c5aa 404 "REMOTE", &remote,
fb6becb4
LP
405 "SCOPE", &s->scope,
406 "SCOPE_JOB", &s->scope_job,
932e3ee7 407 "FIFO", &s->fifo_path,
a185c5aa
LP
408 "SEAT", &seat,
409 "TTY", &s->tty,
410 "DISPLAY", &s->display,
411 "REMOTE_HOST", &s->remote_host,
412 "REMOTE_USER", &s->remote_user,
98a28fef 413 "SERVICE", &s->service,
a4cd87e9 414 "DESKTOP", &s->desktop,
a185c5aa 415 "VTNR", &vtnr,
be94d954 416 "STATE", &state,
e6494a07 417 "POSITION", &position,
a185c5aa 418 "LEADER", &leader,
a91e4e53 419 "TYPE", &type,
55efac6c 420 "CLASS", &class,
9444b1f2
LP
421 "UID", &uid,
422 "REALTIME", &realtime,
423 "MONOTONIC", &monotonic,
6d33772f 424 "CONTROLLER", &controller,
aed24c4c
FB
425 "ACTIVE", &active,
426 "DEVICES", &devices,
1c8280fd 427 "IS_DISPLAY", &is_display,
a185c5aa
LP
428 NULL);
429
f647962d
MS
430 if (r < 0)
431 return log_error_errno(r, "Failed to read %s: %m", s->state_file);
9444b1f2
LP
432
433 if (!s->user) {
434 uid_t u;
435 User *user;
436
437 if (!uid) {
438 log_error("UID not specified for session %s", s->id);
439 return -ENOENT;
440 }
441
442 r = parse_uid(uid, &u);
443 if (r < 0) {
444 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
445 return r;
446 }
447
8cb4ab00 448 user = hashmap_get(s->manager->users, UID_TO_PTR(u));
9444b1f2
LP
449 if (!user) {
450 log_error("User of session %s not known.", s->id);
451 return -ENOENT;
452 }
453
454 session_set_user(s, user);
455 }
a185c5aa
LP
456
457 if (remote) {
458 k = parse_boolean(remote);
459 if (k >= 0)
460 s->remote = k;
461 }
462
c506027a
DH
463 if (vtnr)
464 safe_atou(vtnr, &s->vtnr);
465
9418f147 466 if (seat && !s->seat) {
a185c5aa
LP
467 Seat *o;
468
469 o = hashmap_get(s->manager->seats, seat);
470 if (o)
c506027a
DH
471 r = seat_attach_session(o, s);
472 if (!o || r < 0)
473 log_error("Cannot attach session %s to seat %s", s->id, seat);
a185c5aa
LP
474 }
475
c506027a
DH
476 if (!s->seat || !seat_has_vts(s->seat))
477 s->vtnr = 0;
a185c5aa 478
e6494a07 479 if (position && s->seat) {
49e6fdbf
DH
480 unsigned int npos;
481
e6494a07 482 safe_atou(position, &npos);
49e6fdbf
DH
483 seat_claim_position(s->seat, s, npos);
484 }
485
a185c5aa 486 if (leader) {
238794b1
LP
487 pid_t pid;
488
489 r = parse_pid(leader, &pid);
490 if (r < 0)
491 log_debug_errno(r, "Failed to parse leader PID of session: %s", leader);
492 else {
493 r = session_set_leader(s, pid);
494 if (r < 0)
495 log_warning_errno(r, "Failed to set session leader PID, ignoring: %m");
496 }
a185c5aa
LP
497 }
498
a91e4e53
LP
499 if (type) {
500 SessionType t;
501
502 t = session_type_from_string(type);
503 if (t >= 0)
504 s->type = t;
505 }
506
55efac6c
LP
507 if (class) {
508 SessionClass c;
509
510 c = session_class_from_string(class);
511 if (c >= 0)
512 s->class = c;
513 }
514
be94d954
MP
515 if (state && streq(state, "closing"))
516 s->stopping = true;
517
b4f78aea
LP
518 if (s->fifo_path) {
519 int fd;
520
521 /* If we open an unopened pipe for reading we will not
522 get an EOF. to trigger an EOF we hence open it for
be94d954
MP
523 writing, but close it right away which then will
524 trigger the EOF. This will happen immediately if no
525 other process has the FIFO open for writing, i. e.
526 when the session died before logind (re)started. */
b4f78aea
LP
527
528 fd = session_create_fifo(s);
03e334a1 529 safe_close(fd);
b4f78aea
LP
530 }
531
b895a735
BR
532 if (realtime)
533 timestamp_deserialize(realtime, &s->timestamp.realtime);
534 if (monotonic)
535 timestamp_deserialize(monotonic, &s->timestamp.monotonic);
a185c5aa 536
aed24c4c
FB
537 if (active) {
538 k = parse_boolean(active);
539 if (k >= 0)
540 s->was_active = k;
541 }
542
1c8280fd
LP
543 if (is_display) {
544 /* Note that when enumerating users are loaded before sessions, hence the display session to use is
545 * something we have to store along with the session and not the user, as in that case we couldn't
546 * apply it at the time we load the user. */
547
548 k = parse_boolean(is_display);
549 if (k < 0)
550 log_warning_errno(k, "Failed to parse IS_DISPLAY session property: %m");
551 else if (k > 0)
552 s->user->display = s;
553 }
554
6d33772f 555 if (controller) {
aed24c4c 556 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0) {
dc6284e9 557 session_set_controller(s, controller, false, false);
aed24c4c
FB
558 session_load_devices(s, devices);
559 } else
90a18413 560 session_restore_vt(s);
6d33772f
DH
561 }
562
a185c5aa 563 return r;
20263082
LP
564}
565
566int session_activate(Session *s) {
d7bd01b5
DH
567 unsigned int num_pending;
568
20263082 569 assert(s);
9444b1f2 570 assert(s->user);
20263082 571
20263082 572 if (!s->seat)
15411c0c 573 return -EOPNOTSUPP;
20263082
LP
574
575 if (s->seat->active == s)
576 return 0;
577
d7bd01b5
DH
578 /* on seats with VTs, we let VTs manage session-switching */
579 if (seat_has_vts(s->seat)) {
709d0587 580 if (s->vtnr == 0)
15411c0c 581 return -EOPNOTSUPP;
d7bd01b5
DH
582
583 return chvt(s->vtnr);
584 }
585
586 /* On seats without VTs, we implement session-switching in logind. We
587 * try to pause all session-devices and wait until the session
588 * controller acknowledged them. Once all devices are asleep, we simply
589 * switch the active session and be done.
590 * We save the session we want to switch to in seat->pending_switch and
591 * seat_complete_switch() will perform the final switch. */
592
593 s->seat->pending_switch = s;
594
595 /* if no devices are running, immediately perform the session switch */
596 num_pending = session_device_try_pause_all(s);
597 if (!num_pending)
598 seat_complete_switch(s->seat);
20263082 599
d7bd01b5 600 return 0;
20263082
LP
601}
602
25a1ab4e 603static int session_start_scope(Session *s, sd_bus_message *properties, sd_bus_error *error) {
98a28fef
LP
604 int r;
605
606 assert(s);
9444b1f2 607 assert(s->user);
98a28fef 608
fb6becb4 609 if (!s->scope) {
fb2367ed 610 _cleanup_free_ char *scope = NULL;
90558f31 611 const char *description;
405e0255 612
25a1ab4e
LP
613 s->scope_job = mfree(s->scope_job);
614
605405c6 615 scope = strjoin("session-", s->id, ".scope");
d0af76e6 616 if (!scope)
ae018d9b
LP
617 return log_oom();
618
81d62103 619 description = strjoina("Session ", s->id, " of user ", s->user->name);
90558f31
LP
620
621 r = manager_start_scope(
622 s->manager,
623 scope,
624 s->leader,
625 s->user->slice,
626 description,
25a1ab4e
LP
627 STRV_MAKE(s->user->runtime_dir_service, s->user->service), /* These two have StopWhenUnneeded= set, hence add a dep towards them */
628 STRV_MAKE("systemd-logind.service", "systemd-user-sessions.service", s->user->runtime_dir_service, s->user->service), /* And order us after some more */
22f93314 629 properties,
25a1ab4e
LP
630 error,
631 &s->scope_job);
fb2367ed 632 if (r < 0)
25a1ab4e 633 return log_error_errno(r, "Failed to start session scope %s: %s", scope, bus_error_message(error, r));
fb2367ed
YW
634
635 s->scope = TAKE_PTR(scope);
20263082
LP
636 }
637
d0af76e6 638 if (s->scope)
90558f31 639 (void) hashmap_put(s->manager->session_units, s->scope, s);
d0af76e6 640
20263082
LP
641 return 0;
642}
643
25a1ab4e 644int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error) {
20263082
LP
645 int r;
646
647 assert(s);
9444b1f2
LP
648
649 if (!s->user)
650 return -ESTALE;
20263082 651
25a1ab4e
LP
652 if (s->stopping)
653 return -EINVAL;
654
9418f147
LP
655 if (s->started)
656 return 0;
657
ed18b08b
LP
658 r = user_start(s->user);
659 if (r < 0)
660 return r;
661
25a1ab4e 662 r = session_start_scope(s, properties, error);
fb6becb4
LP
663 if (r < 0)
664 return r;
665
d9eb81f9 666 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
2b044526 667 "MESSAGE_ID=" SD_MESSAGE_SESSION_START_STR,
877d54e9
LP
668 "SESSION_ID=%s", s->id,
669 "USER_ID=%s", s->user->name,
de0671ee 670 "LEADER="PID_FMT, s->leader,
a1230ff9 671 LOG_MESSAGE("New session %s of user %s.", s->id, s->user->name));
98a28fef 672
9444b1f2
LP
673 if (!dual_timestamp_is_set(&s->timestamp))
674 dual_timestamp_get(&s->timestamp);
14c3baca 675
e9816c48
LP
676 if (s->seat)
677 seat_read_active_vt(s->seat);
678
9418f147
LP
679 s->started = true;
680
952d3260
LP
681 user_elect_display(s->user);
682
5f41d1f1 683 /* Save data */
e9816c48 684 session_save(s);
7f7bb946 685 user_save(s->user);
5f41d1f1
LP
686 if (s->seat)
687 seat_save(s->seat);
e9816c48 688
5f41d1f1 689 /* Send signals */
da119395 690 session_send_signal(s, true);
7d049e30 691 user_send_changed(s->user, "Display", NULL);
9418f147
LP
692 if (s->seat) {
693 if (s->seat->active == s)
7d049e30 694 seat_send_changed(s->seat, "ActiveSession", NULL);
9418f147
LP
695 }
696
20263082
LP
697 return 0;
698}
699
9bb69af4 700static int session_stop_scope(Session *s, bool force) {
4afd3348 701 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
20263082 702 int r;
20263082
LP
703
704 assert(s);
705
fb6becb4
LP
706 if (!s->scope)
707 return 0;
9b221b63 708
756ed0e2 709 /* Let's always abandon the scope first. This tells systemd that we are not interested anymore, and everything
629ff674 710 * that is left in the scope is "left-over". Informing systemd about this has the benefit that it will log
756ed0e2
LP
711 * when killing any processes left after this point. */
712 r = manager_abandon_scope(s->manager, s->scope, &error);
25a1ab4e 713 if (r < 0) {
756ed0e2 714 log_warning_errno(r, "Failed to abandon session scope, ignoring: %s", bus_error_message(&error, r));
25a1ab4e
LP
715 sd_bus_error_free(&error);
716 }
717
718 s->scope_job = mfree(s->scope_job);
756ed0e2
LP
719
720 /* Optionally, let's kill everything that's left now. */
9bb69af4 721 if (force || manager_shall_kill(s->manager, s->user->name)) {
801a884d 722
25a1ab4e
LP
723 r = manager_stop_unit(s->manager, s->scope, &error, &s->scope_job);
724 if (r < 0) {
725 if (force)
726 return log_error_errno(r, "Failed to stop session scope: %s", bus_error_message(&error, r));
20263082 727
25a1ab4e
LP
728 log_warning_errno(r, "Failed to stop session scope, ignoring: %s", bus_error_message(&error, r));
729 }
8150acb1 730 } else {
20263082 731
8150acb1
AJ
732 /* With no killing, this session is allowed to persist in "closing" state indefinitely.
733 * Therefore session stop and session removal may be two distinct events.
734 * Session stop is quite significant on its own, let's log it. */
735 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
736 "SESSION_ID=%s", s->id,
737 "USER_ID=%s", s->user->name,
738 "LEADER="PID_FMT, s->leader,
f4cf1d66 739 LOG_MESSAGE("Session %s logged out. Waiting for processes to exit.", s->id));
8150acb1
AJ
740 }
741
9b221b63 742 return 0;
20263082
LP
743}
744
9bb69af4 745int session_stop(Session *s, bool force) {
405e0255
LP
746 int r;
747
748 assert(s);
749
25a1ab4e
LP
750 /* This is called whenever we begin with tearing down a session record. It's called in four cases: explicit API
751 * request via the bus (either directly for the session object or for the seat or user object this session
752 * belongs to; 'force' is true), or due to automatic GC (i.e. scope vanished; 'force' is false), or because the
753 * session FIFO saw an EOF ('force' is false), or because the release timer hit ('force' is false). */
754
405e0255
LP
755 if (!s->user)
756 return -ESTALE;
25a1ab4e
LP
757 if (!s->started)
758 return 0;
759 if (s->stopping)
760 return 0;
405e0255 761
5f41d1f1
LP
762 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
763
10189fd6
DH
764 if (s->seat)
765 seat_evict_position(s->seat, s);
766
5f41d1f1
LP
767 /* We are going down, don't care about FIFOs anymore */
768 session_remove_fifo(s);
769
405e0255 770 /* Kill cgroup */
9bb69af4 771 r = session_stop_scope(s, force);
405e0255 772
5f41d1f1
LP
773 s->stopping = true;
774
952d3260
LP
775 user_elect_display(s->user);
776
405e0255 777 session_save(s);
cc377381 778 user_save(s->user);
405e0255
LP
779
780 return r;
781}
782
783int session_finalize(Session *s) {
118ecf32 784 SessionDevice *sd;
20263082
LP
785
786 assert(s);
787
9444b1f2
LP
788 if (!s->user)
789 return -ESTALE;
790
ed18b08b 791 if (s->started)
d9eb81f9 792 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
2b044526 793 "MESSAGE_ID=" SD_MESSAGE_SESSION_STOP_STR,
877d54e9
LP
794 "SESSION_ID=%s", s->id,
795 "USER_ID=%s", s->user->name,
de0671ee 796 "LEADER="PID_FMT, s->leader,
a1230ff9 797 LOG_MESSAGE("Removed session %s.", s->id));
98a28fef 798
5f41d1f1
LP
799 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
800
10189fd6
DH
801 if (s->seat)
802 seat_evict_position(s->seat, s);
803
118ecf32
DH
804 /* Kill session devices */
805 while ((sd = hashmap_first(s->devices)))
806 session_device_free(sd);
807
491ac9f2 808 (void) unlink(s->state_file);
d2f92cdf 809 session_add_to_gc_queue(s);
ed18b08b 810 user_add_to_gc_queue(s->user);
14c3baca 811
405e0255 812 if (s->started) {
ed18b08b 813 session_send_signal(s, false);
405e0255
LP
814 s->started = false;
815 }
50fb9793 816
9418f147
LP
817 if (s->seat) {
818 if (s->seat->active == s)
819 seat_set_active(s->seat, NULL);
820
23bd3b62 821 seat_save(s->seat);
9418f147
LP
822 }
823
23bd3b62 824 user_save(s->user);
7d049e30 825 user_send_changed(s->user, "Display", NULL);
9418f147 826
491ac9f2 827 return 0;
20263082
LP
828}
829
5f41d1f1
LP
830static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
831 Session *s = userdata;
832
833 assert(es);
834 assert(s);
835
9bb69af4 836 session_stop(s, false);
5f41d1f1
LP
837 return 0;
838}
839
ad8780c9 840int session_release(Session *s) {
5f41d1f1
LP
841 assert(s);
842
843 if (!s->started || s->stopping)
ad8780c9
ZJS
844 return 0;
845
846 if (s->timer_event_source)
847 return 0;
848
849 return sd_event_add_time(s->manager->event,
850 &s->timer_event_source,
851 CLOCK_MONOTONIC,
061c6607 852 usec_add(now(CLOCK_MONOTONIC), RELEASE_USEC), 0,
ad8780c9 853 release_timeout_callback, s);
5f41d1f1
LP
854}
855
20263082
LP
856bool session_is_active(Session *s) {
857 assert(s);
858
859 if (!s->seat)
860 return true;
861
862 return s->seat->active == s;
863}
864
23406ce5
LP
865static int get_tty_atime(const char *tty, usec_t *atime) {
866 _cleanup_free_ char *p = NULL;
a185c5aa 867 struct stat st;
23406ce5
LP
868
869 assert(tty);
870 assert(atime);
871
872 if (!path_is_absolute(tty)) {
873 p = strappend("/dev/", tty);
874 if (!p)
875 return -ENOMEM;
876
877 tty = p;
878 } else if (!path_startswith(tty, "/dev/"))
879 return -ENOENT;
880
881 if (lstat(tty, &st) < 0)
882 return -errno;
883
884 *atime = timespec_load(&st.st_atim);
885 return 0;
886}
887
888static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
889 _cleanup_free_ char *p = NULL;
890 int r;
891
892 assert(pid > 0);
893 assert(atime);
894
895 r = get_ctty(pid, NULL, &p);
896 if (r < 0)
897 return r;
898
899 return get_tty_atime(p, atime);
900}
901
902int session_get_idle_hint(Session *s, dual_timestamp *t) {
23406ce5
LP
903 usec_t atime = 0, n;
904 int r;
a185c5aa
LP
905
906 assert(s);
907
23406ce5 908 /* Explicit idle hint is set */
a185c5aa
LP
909 if (s->idle_hint) {
910 if (t)
911 *t = s->idle_hint_timestamp;
912
913 return s->idle_hint;
914 }
915
0762eaa3 916 /* Graphical sessions should really implement a real
23406ce5 917 * idle hint logic */
129baf1b 918 if (SESSION_TYPE_IS_GRAPHICAL(s->type))
a185c5aa
LP
919 goto dont_know;
920
23406ce5
LP
921 /* For sessions with an explicitly configured tty, let's check
922 * its atime */
923 if (s->tty) {
924 r = get_tty_atime(s->tty, &atime);
925 if (r >= 0)
926 goto found_atime;
927 }
a185c5aa 928
23406ce5
LP
929 /* For sessions with a leader but no explicitly configured
930 * tty, let's check the controlling tty of the leader */
238794b1 931 if (pid_is_valid(s->leader)) {
23406ce5
LP
932 r = get_process_ctty_atime(s->leader, &atime);
933 if (r >= 0)
934 goto found_atime;
a185c5aa
LP
935 }
936
a185c5aa
LP
937dont_know:
938 if (t)
939 *t = s->idle_hint_timestamp;
940
941 return 0;
23406ce5
LP
942
943found_atime:
944 if (t)
945 dual_timestamp_from_realtime(t, atime);
946
947 n = now(CLOCK_REALTIME);
948
949 if (s->manager->idle_action_usec <= 0)
950 return 0;
951
952 return atime + s->manager->idle_action_usec <= n;
a185c5aa
LP
953}
954
bef422ae
LP
955void session_set_idle_hint(Session *s, bool b) {
956 assert(s);
957
958 if (s->idle_hint == b)
959 return;
960
961 s->idle_hint = b;
962 dual_timestamp_get(&s->idle_hint_timestamp);
9418f147 963
cc377381 964 session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
9418f147
LP
965
966 if (s->seat)
cc377381
LP
967 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
968
969 user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
970 manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
971}
972
42d35e13
VT
973int session_get_locked_hint(Session *s) {
974 assert(s);
975
976 return s->locked_hint;
977}
978
979void session_set_locked_hint(Session *s, bool b) {
980 assert(s);
981
982 if (s->locked_hint == b)
983 return;
984
985 s->locked_hint = b;
986
987 session_send_changed(s, "LockedHint", NULL);
988}
989
cc377381
LP
990static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
991 Session *s = userdata;
992
993 assert(s);
994 assert(s->fifo_fd == fd);
995
996 /* EOF on the FIFO means the session died abnormally. */
997
998 session_remove_fifo(s);
9bb69af4 999 session_stop(s, false);
cc377381
LP
1000
1001 return 1;
bef422ae
LP
1002}
1003
932e3ee7
LP
1004int session_create_fifo(Session *s) {
1005 int r;
1006
31b79c2b
LP
1007 assert(s);
1008
b4f78aea 1009 /* Create FIFO */
932e3ee7 1010 if (!s->fifo_path) {
37c1d5e9 1011 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0, MKDIR_WARN_MODE);
e6061ab2
LP
1012 if (r < 0)
1013 return r;
1014
d5ddc930
LP
1015 s->fifo_path = strjoin("/run/systemd/sessions/", s->id, ".ref");
1016 if (!s->fifo_path)
932e3ee7 1017 return -ENOMEM;
31b79c2b 1018
932e3ee7
LP
1019 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
1020 return -errno;
1021 }
31b79c2b 1022
932e3ee7 1023 /* Open reading side */
b4f78aea 1024 if (s->fifo_fd < 0) {
db4a47e9 1025 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
b4f78aea
LP
1026 if (s->fifo_fd < 0)
1027 return -errno;
cc377381
LP
1028 }
1029
1030 if (!s->fifo_event_source) {
151b9b96 1031 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
b4f78aea
LP
1032 if (r < 0)
1033 return r;
1034
e11544a8
LP
1035 /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new
1036 * sessions). */
1037 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10);
cc377381
LP
1038 if (r < 0)
1039 return r;
b4f78aea 1040 }
932e3ee7
LP
1041
1042 /* Open writing side */
db4a47e9 1043 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NONBLOCK);
932e3ee7
LP
1044 if (r < 0)
1045 return -errno;
31b79c2b 1046
932e3ee7
LP
1047 return r;
1048}
1049
5f41d1f1 1050static void session_remove_fifo(Session *s) {
932e3ee7
LP
1051 assert(s);
1052
03e334a1
LP
1053 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
1054 s->fifo_fd = safe_close(s->fifo_fd);
932e3ee7
LP
1055
1056 if (s->fifo_path) {
75bbdf47 1057 (void) unlink(s->fifo_path);
a1e58e8e 1058 s->fifo_path = mfree(s->fifo_path);
932e3ee7 1059 }
31b79c2b
LP
1060}
1061
5c093a23 1062bool session_may_gc(Session *s, bool drop_not_started) {
bd26aee1
LP
1063 int r;
1064
20263082
LP
1065 assert(s);
1066
4a4b033f 1067 if (drop_not_started && !s->started)
5c093a23 1068 return true;
932e3ee7 1069
9444b1f2 1070 if (!s->user)
5c093a23 1071 return true;
9444b1f2 1072
932e3ee7 1073 if (s->fifo_fd >= 0) {
5f41d1f1 1074 if (pipe_eof(s->fifo_fd) <= 0)
5c093a23 1075 return false;
20263082
LP
1076 }
1077
bd26aee1
LP
1078 if (s->scope_job) {
1079 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1080
1081 r = manager_job_is_active(s->manager, s->scope_job, &error);
1082 if (r < 0)
1083 log_debug_errno(r, "Failed to determine whether job '%s' is pending, ignoring: %s", s->scope_job, bus_error_message(&error, r));
1084 if (r != 0)
1085 return false;
1086 }
20263082 1087
bd26aee1
LP
1088 if (s->scope) {
1089 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1090
1091 r = manager_unit_is_active(s->manager, s->scope, &error);
1092 if (r < 0)
1093 log_debug_errno(r, "Failed to determine whether unit '%s' is active, ignoring: %s", s->scope, bus_error_message(&error, r));
1094 if (r != 0)
1095 return false;
1096 }
20263082 1097
5c093a23 1098 return true;
20263082
LP
1099}
1100
14c3baca
LP
1101void session_add_to_gc_queue(Session *s) {
1102 assert(s);
1103
1104 if (s->in_gc_queue)
1105 return;
1106
71fda00f 1107 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
14c3baca
LP
1108 s->in_gc_queue = true;
1109}
1110
0604381b
LP
1111SessionState session_get_state(Session *s) {
1112 assert(s);
1113
8fe63cd4 1114 /* always check closing first */
5f41d1f1
LP
1115 if (s->stopping || s->timer_event_source)
1116 return SESSION_CLOSING;
1117
8fe63cd4 1118 if (s->scope_job || s->fifo_fd < 0)
405e0255 1119 return SESSION_OPENING;
fb6becb4 1120
0604381b
LP
1121 if (session_is_active(s))
1122 return SESSION_ACTIVE;
1123
1124 return SESSION_ONLINE;
1125}
1126
de07ab16 1127int session_kill(Session *s, KillWho who, int signo) {
de07ab16
LP
1128 assert(s);
1129
fb6becb4 1130 if (!s->scope)
de07ab16
LP
1131 return -ESRCH;
1132
fb6becb4 1133 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
de07ab16
LP
1134}
1135
90a18413 1136static int session_open_vt(Session *s) {
5f41d1f1 1137 char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
90a18413 1138
baccf3e4
OB
1139 if (s->vtnr < 1)
1140 return -ENODEV;
90a18413
DH
1141
1142 if (s->vtfd >= 0)
1143 return s->vtfd;
1144
92bd5ff3 1145 sprintf(path, "/dev/tty%u", s->vtnr);
22356953 1146 s->vtfd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
4a62c710 1147 if (s->vtfd < 0)
709f6e46 1148 return log_error_errno(s->vtfd, "cannot open VT %s of session %s: %m", path, s->id);
90a18413
DH
1149
1150 return s->vtfd;
1151}
1152
baccf3e4 1153int session_prepare_vt(Session *s) {
90a18413
DH
1154 int vt, r;
1155 struct vt_mode mode = { 0 };
90a18413 1156
baccf3e4
OB
1157 if (s->vtnr < 1)
1158 return 0;
1159
90a18413
DH
1160 vt = session_open_vt(s);
1161 if (vt < 0)
baccf3e4 1162 return vt;
90a18413 1163
d6176c6c 1164 r = fchown(vt, s->user->uid, -1);
baccf3e4 1165 if (r < 0) {
94c156cd
LP
1166 r = log_error_errno(errno,
1167 "Cannot change owner of /dev/tty%u: %m",
1168 s->vtnr);
d6176c6c 1169 goto error;
baccf3e4 1170 }
d6176c6c 1171
90a18413 1172 r = ioctl(vt, KDSKBMODE, K_OFF);
baccf3e4 1173 if (r < 0) {
94c156cd
LP
1174 r = log_error_errno(errno,
1175 "Cannot set K_OFF on /dev/tty%u: %m",
1176 s->vtnr);
90a18413 1177 goto error;
baccf3e4 1178 }
90a18413
DH
1179
1180 r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
baccf3e4 1181 if (r < 0) {
94c156cd
LP
1182 r = log_error_errno(errno,
1183 "Cannot set KD_GRAPHICS on /dev/tty%u: %m",
1184 s->vtnr);
90a18413 1185 goto error;
baccf3e4 1186 }
90a18413 1187
90a18413
DH
1188 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1189 * So we need a dummy handler here which just acknowledges *all* VT
1190 * switch requests. */
1191 mode.mode = VT_PROCESS;
92683ad2
DH
1192 mode.relsig = SIGRTMIN;
1193 mode.acqsig = SIGRTMIN + 1;
90a18413 1194 r = ioctl(vt, VT_SETMODE, &mode);
baccf3e4 1195 if (r < 0) {
94c156cd
LP
1196 r = log_error_errno(errno,
1197 "Cannot set VT_PROCESS on /dev/tty%u: %m",
1198 s->vtnr);
90a18413 1199 goto error;
baccf3e4 1200 }
90a18413 1201
baccf3e4 1202 return 0;
90a18413
DH
1203
1204error:
90a18413 1205 session_restore_vt(s);
baccf3e4 1206 return r;
90a18413
DH
1207}
1208
1209void session_restore_vt(Session *s) {
16597ac3
LP
1210
1211 static const struct vt_mode mode = {
1212 .mode = VT_AUTO,
1213 };
1214
c83f349c 1215 int vt, old_fd;
90a18413 1216
128df4cf
OT
1217 /* We need to get a fresh handle to the virtual terminal,
1218 * since the old file-descriptor is potentially in a hung-up
1219 * state after the controlling process exited; we do a
1220 * little dance to avoid having the terminal be available
1221 * for reuse before we've cleaned it up.
1222 */
c10d6bdb 1223 old_fd = TAKE_FD(s->vtfd);
128df4cf 1224
90a18413 1225 vt = session_open_vt(s);
128df4cf
OT
1226 safe_close(old_fd);
1227
90a18413
DH
1228 if (vt < 0)
1229 return;
1230
2bf10523 1231 (void) ioctl(vt, KDSETMODE, KD_TEXT);
90a18413 1232
c83f349c 1233 (void) vt_reset_keyboard(vt);
90a18413 1234
2bf10523 1235 (void) ioctl(vt, VT_SETMODE, &mode);
16597ac3 1236 (void) fchown(vt, 0, (gid_t) -1);
d6176c6c 1237
03e334a1 1238 s->vtfd = safe_close(s->vtfd);
90a18413
DH
1239}
1240
2ec3ff66 1241void session_leave_vt(Session *s) {
ce540a24
DH
1242 int r;
1243
2ec3ff66
DH
1244 assert(s);
1245
1246 /* This is called whenever we get a VT-switch signal from the kernel.
1247 * We acknowledge all of them unconditionally. Note that session are
1248 * free to overwrite those handlers and we only register them for
1249 * sessions with controllers. Legacy sessions are not affected.
1250 * However, if we switch from a non-legacy to a legacy session, we must
1251 * make sure to pause all device before acknowledging the switch. We
1252 * process the real switch only after we are notified via sysfs, so the
1253 * legacy session might have already started using the devices. If we
1254 * don't pause the devices before the switch, we might confuse the
1255 * session we switch to. */
1256
1257 if (s->vtfd < 0)
1258 return;
1259
1260 session_device_pause_all(s);
ce540a24
DH
1261 r = ioctl(s->vtfd, VT_RELDISP, 1);
1262 if (r < 0)
56f64d95 1263 log_debug_errno(errno, "Cannot release VT of session %s: %m", s->id);
2ec3ff66
DH
1264}
1265
cc377381 1266bool session_is_controller(Session *s, const char *sender) {
ae5e06bd
DH
1267 assert(s);
1268
1269 return streq_ptr(s->controller, sender);
1270}
1271
b12e5615
DH
1272static void session_release_controller(Session *s, bool notify) {
1273 _cleanup_free_ char *name = NULL;
6d33772f
DH
1274 SessionDevice *sd;
1275
b12e5615
DH
1276 if (!s->controller)
1277 return;
6d33772f 1278
b12e5615 1279 name = s->controller;
90a18413 1280
b12e5615
DH
1281 /* By resetting the controller before releasing the devices, we won't
1282 * send notification signals. This avoids sending useless notifications
1283 * if the controller is released on disconnects. */
1284 if (!notify)
1285 s->controller = NULL;
6d33772f 1286
b12e5615
DH
1287 while ((sd = hashmap_first(s->devices)))
1288 session_device_free(sd);
1289
1290 s->controller = NULL;
3cde9e8f
DM
1291 s->track = sd_bus_track_unref(s->track);
1292}
1293
1294static int on_bus_track(sd_bus_track *track, void *userdata) {
1295 Session *s = userdata;
1296
1297 assert(track);
1298 assert(s);
1299
1300 session_drop_controller(s);
1301
1302 return 0;
6d33772f
DH
1303}
1304
dc6284e9 1305int session_set_controller(Session *s, const char *sender, bool force, bool prepare) {
b12e5615 1306 _cleanup_free_ char *name = NULL;
ae5e06bd
DH
1307 int r;
1308
1309 assert(s);
1310 assert(sender);
1311
1312 if (session_is_controller(s, sender))
1313 return 0;
1314 if (s->controller && !force)
1315 return -EBUSY;
1316
b12e5615
DH
1317 name = strdup(sender);
1318 if (!name)
ae5e06bd
DH
1319 return -ENOMEM;
1320
3cde9e8f
DM
1321 s->track = sd_bus_track_unref(s->track);
1322 r = sd_bus_track_new(s->manager->bus, &s->track, on_bus_track, s);
1323 if (r < 0)
1324 return r;
1325
1326 r = sd_bus_track_add_name(s->track, name);
1327 if (r < 0)
ae5e06bd 1328 return r;
ae5e06bd 1329
90a18413
DH
1330 /* When setting a session controller, we forcibly mute the VT and set
1331 * it into graphics-mode. Applications can override that by changing
1332 * VT state after calling TakeControl(). However, this serves as a good
1333 * default and well-behaving controllers can now ignore VTs entirely.
1334 * Note that we reset the VT on ReleaseControl() and if the controller
1335 * exits.
1336 * If logind crashes/restarts, we restore the controller during restart
dc6284e9
FB
1337 * (without preparing the VT since the controller has probably overridden
1338 * VT state by now) or reset the VT in case it crashed/exited, too. */
1339 if (prepare) {
1340 r = session_prepare_vt(s);
1341 if (r < 0) {
1342 s->track = sd_bus_track_unref(s->track);
1343 return r;
1344 }
13f493dc 1345 }
baccf3e4 1346
b12e5615 1347 session_release_controller(s, true);
ae2a15bc 1348 s->controller = TAKE_PTR(name);
b12e5615 1349 session_save(s);
90a18413 1350
ae5e06bd
DH
1351 return 0;
1352}
1353
1354void session_drop_controller(Session *s) {
1355 assert(s);
1356
1357 if (!s->controller)
1358 return;
1359
3cde9e8f 1360 s->track = sd_bus_track_unref(s->track);
b12e5615
DH
1361 session_release_controller(s, false);
1362 session_save(s);
1363 session_restore_vt(s);
ae5e06bd
DH
1364}
1365
fb6becb4
LP
1366static const char* const session_state_table[_SESSION_STATE_MAX] = {
1367 [SESSION_OPENING] = "opening",
0604381b
LP
1368 [SESSION_ONLINE] = "online",
1369 [SESSION_ACTIVE] = "active",
1370 [SESSION_CLOSING] = "closing"
1371};
1372
1373DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1374
20263082 1375static const char* const session_type_table[_SESSION_TYPE_MAX] = {
2c5859af 1376 [SESSION_UNSPECIFIED] = "unspecified",
3f49d45a 1377 [SESSION_TTY] = "tty",
98a28fef 1378 [SESSION_X11] = "x11",
d9eb81f9 1379 [SESSION_WAYLAND] = "wayland",
9541666b 1380 [SESSION_MIR] = "mir",
e9e74f28 1381 [SESSION_WEB] = "web",
20263082
LP
1382};
1383
1384DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
de07ab16 1385
55efac6c
LP
1386static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1387 [SESSION_USER] = "user",
1388 [SESSION_GREETER] = "greeter",
e2acb67b
LP
1389 [SESSION_LOCK_SCREEN] = "lock-screen",
1390 [SESSION_BACKGROUND] = "background"
55efac6c
LP
1391};
1392
1393DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1394
de07ab16
LP
1395static const char* const kill_who_table[_KILL_WHO_MAX] = {
1396 [KILL_LEADER] = "leader",
1397 [KILL_ALL] = "all"
1398};
1399
1400DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);