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