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