]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-session.c
tree-wide: replace all remaining uses of parse_env_file() for parsing /proc/cmdline
[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);
39
8c29a457
LP
40int session_new(Session **ret, Manager *m, const char *id) {
41 _cleanup_(session_freep) Session *s = NULL;
42 int r;
20263082 43
8c29a457 44 assert(ret);
20263082
LP
45 assert(m);
46 assert(id);
47
8c29a457
LP
48 if (!session_id_valid(id))
49 return -EINVAL;
50
51 s = new(Session, 1);
20263082 52 if (!s)
8c29a457
LP
53 return -ENOMEM;
54
55 *s = (Session) {
56 .manager = m,
57 .fifo_fd = -1,
58 .vtfd = -1,
59 .audit_id = AUDIT_SESSION_INVALID,
3d0ef5c7 60 .tty_validity = _TTY_VALIDITY_INVALID,
8c29a457 61 };
20263082 62
98a28fef 63 s->state_file = strappend("/run/systemd/sessions/", id);
6b430fdb 64 if (!s->state_file)
8c29a457 65 return -ENOMEM;
118ecf32 66
2b6bf07d 67 s->id = basename(s->state_file);
20263082 68
8c29a457
LP
69 s->devices = hashmap_new(&devt_hash_ops);
70 if (!s->devices)
71 return -ENOMEM;
20263082 72
8c29a457
LP
73 r = hashmap_put(m->sessions, s->id, s);
74 if (r < 0)
75 return r;
20263082 76
8c29a457
LP
77 *ret = TAKE_PTR(s);
78 return 0;
20263082
LP
79}
80
8c29a457 81Session* session_free(Session *s) {
118ecf32
DH
82 SessionDevice *sd;
83
8c29a457
LP
84 if (!s)
85 return NULL;
20263082 86
14c3baca 87 if (s->in_gc_queue)
71fda00f 88 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
14c3baca 89
5f41d1f1
LP
90 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
91
cc377381
LP
92 session_remove_fifo(s);
93
ae5e06bd
DH
94 session_drop_controller(s);
95
118ecf32
DH
96 while ((sd = hashmap_first(s->devices)))
97 session_device_free(sd);
98
99 hashmap_free(s->devices);
100
20263082 101 if (s->user) {
71fda00f 102 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
20263082
LP
103
104 if (s->user->display == s)
105 s->user->display = NULL;
9afe9efb
LP
106
107 user_update_last_session_timer(s->user);
20263082
LP
108 }
109
9418f147
LP
110 if (s->seat) {
111 if (s->seat->active == s)
112 s->seat->active = NULL;
d7bd01b5
DH
113 if (s->seat->pending_switch == s)
114 s->seat->pending_switch = NULL;
9418f147 115
49e6fdbf 116 seat_evict_position(s->seat, s);
71fda00f 117 LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
9418f147 118 }
20263082 119
fb6becb4
LP
120 if (s->scope) {
121 hashmap_remove(s->manager->session_units, s->scope);
122 free(s->scope);
123 }
124
238794b1
LP
125 if (pid_is_valid(s->leader))
126 (void) hashmap_remove_value(s->manager->sessions_by_leader, PID_TO_PTR(s->leader), s);
127
fb6becb4 128 free(s->scope_job);
1713813d 129
cc377381 130 sd_bus_message_unref(s->create_message);
20263082
LP
131
132 free(s->tty);
133 free(s->display);
134 free(s->remote_host);
3f49d45a 135 free(s->remote_user);
98a28fef 136 free(s->service);
a4cd87e9 137 free(s->desktop);
20263082
LP
138
139 hashmap_remove(s->manager->sessions, s->id);
98a28fef 140
d2f92cdf 141 free(s->state_file);
8c29a457
LP
142
143 return mfree(s);
20263082
LP
144}
145
9444b1f2
LP
146void session_set_user(Session *s, User *u) {
147 assert(s);
148 assert(!s->user);
149
150 s->user = u;
71fda00f 151 LIST_PREPEND(sessions_by_user, u->sessions, s);
9afe9efb
LP
152
153 user_update_last_session_timer(u);
9444b1f2
LP
154}
155
238794b1
LP
156int session_set_leader(Session *s, pid_t pid) {
157 int r;
158
159 assert(s);
160
161 if (!pid_is_valid(pid))
162 return -EINVAL;
163
164 if (s->leader == pid)
165 return 0;
166
167 r = hashmap_put(s->manager->sessions_by_leader, PID_TO_PTR(pid), s);
168 if (r < 0)
169 return r;
170
171 if (pid_is_valid(s->leader))
172 (void) hashmap_remove_value(s->manager->sessions_by_leader, PID_TO_PTR(s->leader), s);
173
174 s->leader = pid;
175 (void) audit_session_from_pid(pid, &s->audit_id);
176
177 return 1;
178}
179
aed24c4c
FB
180static void session_save_devices(Session *s, FILE *f) {
181 SessionDevice *sd;
182 Iterator i;
183
184 if (!hashmap_isempty(s->devices)) {
185 fprintf(f, "DEVICES=");
186 HASHMAP_FOREACH(sd, s->devices, i)
187 fprintf(f, "%u:%u ", major(sd->dev), minor(sd->dev));
188 fprintf(f, "\n");
189 }
190}
191
20263082 192int session_save(Session *s) {
507f22bd 193 _cleanup_free_ char *temp_path = NULL;
cc377381 194 _cleanup_fclose_ FILE *f = NULL;
20263082
LP
195 int r = 0;
196
197 assert(s);
198
9444b1f2
LP
199 if (!s->user)
200 return -ESTALE;
201
accaeded
LP
202 if (!s->started)
203 return 0;
204
37c1d5e9 205 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0, MKDIR_WARN_MODE);
20263082 206 if (r < 0)
dacd6cee 207 goto fail;
20263082 208
14c3baca
LP
209 r = fopen_temporary(s->state_file, &f, &temp_path);
210 if (r < 0)
dacd6cee 211 goto fail;
20263082 212
44176400
LP
213 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
214 (void) fchmod(fileno(f), 0644);
14c3baca 215
20263082
LP
216 fprintf(f,
217 "# This is private data. Do not parse.\n"
90b2de37 218 "UID="UID_FMT"\n"
20263082
LP
219 "USER=%s\n"
220 "ACTIVE=%i\n"
1c8280fd 221 "IS_DISPLAY=%i\n"
0604381b 222 "STATE=%s\n"
fb6becb4 223 "REMOTE=%i\n",
90b2de37 224 s->user->uid,
20263082
LP
225 s->user->name,
226 session_is_active(s),
1c8280fd 227 s->user->display == s,
0604381b 228 session_state_to_string(session_get_state(s)),
fb6becb4 229 s->remote);
20263082 230
a91e4e53 231 if (s->type >= 0)
507f22bd 232 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
a91e4e53 233
55efac6c 234 if (s->class >= 0)
507f22bd 235 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
55efac6c 236
fb6becb4
LP
237 if (s->scope)
238 fprintf(f, "SCOPE=%s\n", s->scope);
fb6becb4
LP
239 if (s->scope_job)
240 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
20263082 241
932e3ee7 242 if (s->fifo_path)
507f22bd 243 fprintf(f, "FIFO=%s\n", s->fifo_path);
932e3ee7 244
20263082 245 if (s->seat)
507f22bd 246 fprintf(f, "SEAT=%s\n", s->seat->id);
20263082
LP
247
248 if (s->tty)
507f22bd 249 fprintf(f, "TTY=%s\n", s->tty);
20263082 250
3d0ef5c7
LP
251 if (s->tty_validity >= 0)
252 fprintf(f, "TTY_VALIDITY=%s\n", tty_validity_to_string(s->tty_validity));
253
20263082 254 if (s->display)
507f22bd 255 fprintf(f, "DISPLAY=%s\n", s->display);
20263082 256
558c6490
LP
257 if (s->remote_host) {
258 _cleanup_free_ char *escaped;
259
260 escaped = cescape(s->remote_host);
261 if (!escaped) {
262 r = -ENOMEM;
dacd6cee 263 goto fail;
558c6490
LP
264 }
265
266 fprintf(f, "REMOTE_HOST=%s\n", escaped);
267 }
268
269 if (s->remote_user) {
270 _cleanup_free_ char *escaped;
271
272 escaped = cescape(s->remote_user);
273 if (!escaped) {
274 r = -ENOMEM;
dacd6cee 275 goto fail;
558c6490
LP
276 }
277
278 fprintf(f, "REMOTE_USER=%s\n", escaped);
279 }
280
281 if (s->service) {
282 _cleanup_free_ char *escaped;
20263082 283
558c6490
LP
284 escaped = cescape(s->service);
285 if (!escaped) {
286 r = -ENOMEM;
dacd6cee 287 goto fail;
558c6490
LP
288 }
289
290 fprintf(f, "SERVICE=%s\n", escaped);
291 }
3f49d45a 292
558c6490
LP
293 if (s->desktop) {
294 _cleanup_free_ char *escaped;
98a28fef 295
558c6490
LP
296 escaped = cescape(s->desktop);
297 if (!escaped) {
298 r = -ENOMEM;
dacd6cee 299 goto fail;
558c6490
LP
300 }
301
302 fprintf(f, "DESKTOP=%s\n", escaped);
303 }
a4cd87e9 304
bf7825ae 305 if (s->seat && seat_has_vts(s->seat))
92bd5ff3 306 fprintf(f, "VTNR=%u\n", s->vtnr);
20263082 307
49e6fdbf 308 if (!s->vtnr)
e6494a07 309 fprintf(f, "POSITION=%u\n", s->position);
49e6fdbf 310
54191eb3 311 if (pid_is_valid(s->leader))
90b2de37 312 fprintf(f, "LEADER="PID_FMT"\n", s->leader);
20263082 313
3a87a86e 314 if (audit_session_is_valid(s->audit_id))
507f22bd 315 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
20263082 316
9444b1f2
LP
317 if (dual_timestamp_is_set(&s->timestamp))
318 fprintf(f,
90b2de37
ZJS
319 "REALTIME="USEC_FMT"\n"
320 "MONOTONIC="USEC_FMT"\n",
321 s->timestamp.realtime,
322 s->timestamp.monotonic);
9444b1f2 323
aed24c4c 324 if (s->controller) {
6d33772f 325 fprintf(f, "CONTROLLER=%s\n", s->controller);
aed24c4c
FB
326 session_save_devices(s, f);
327 }
6d33772f 328
dacd6cee
LP
329 r = fflush_and_check(f);
330 if (r < 0)
331 goto fail;
14c3baca 332
dacd6cee 333 if (rename(temp_path, s->state_file) < 0) {
20263082 334 r = -errno;
dacd6cee 335 goto fail;
20263082
LP
336 }
337
dacd6cee
LP
338 return 0;
339
340fail:
341 (void) unlink(s->state_file);
14c3baca 342
dacd6cee
LP
343 if (temp_path)
344 (void) unlink(temp_path);
345
346 return log_error_errno(r, "Failed to save session data %s: %m", s->state_file);
20263082
LP
347}
348
aed24c4c
FB
349static int session_load_devices(Session *s, const char *devices) {
350 const char *p;
351 int r = 0;
352
353 assert(s);
354
355 for (p = devices;;) {
356 _cleanup_free_ char *word = NULL;
357 SessionDevice *sd;
358 dev_t dev;
359 int k;
360
361 k = extract_first_word(&p, &word, NULL, 0);
362 if (k == 0)
363 break;
364 if (k < 0) {
365 r = k;
366 break;
367 }
368
369 k = parse_dev(word, &dev);
370 if (k < 0) {
371 r = k;
372 continue;
373 }
374
375 /* The file descriptors for loaded devices will be reattached later. */
376 k = session_device_new(s, dev, false, &sd);
377 if (k < 0)
378 r = k;
379 }
380
381 if (r < 0)
382 log_error_errno(r, "Loading session devices for session %s failed: %m", s->id);
383
384 return r;
385}
dacd6cee 386
20263082 387int session_load(Session *s) {
9444b1f2 388 _cleanup_free_ char *remote = NULL,
a185c5aa 389 *seat = NULL,
3d0ef5c7 390 *tty_validity = NULL,
a185c5aa 391 *vtnr = NULL,
be94d954 392 *state = NULL,
e6494a07 393 *position = NULL,
a185c5aa 394 *leader = NULL,
55efac6c 395 *type = NULL,
9444b1f2
LP
396 *class = NULL,
397 *uid = NULL,
398 *realtime = NULL,
6d33772f 399 *monotonic = NULL,
aed24c4c
FB
400 *controller = NULL,
401 *active = NULL,
1c8280fd
LP
402 *devices = NULL,
403 *is_display = NULL;
a185c5aa
LP
404
405 int k, r;
406
20263082
LP
407 assert(s);
408
1a5a177e 409 r = parse_env_file(NULL, s->state_file, NEWLINE,
a185c5aa 410 "REMOTE", &remote,
fb6becb4
LP
411 "SCOPE", &s->scope,
412 "SCOPE_JOB", &s->scope_job,
932e3ee7 413 "FIFO", &s->fifo_path,
a185c5aa
LP
414 "SEAT", &seat,
415 "TTY", &s->tty,
3d0ef5c7 416 "TTY_VALIDITY", &tty_validity,
a185c5aa
LP
417 "DISPLAY", &s->display,
418 "REMOTE_HOST", &s->remote_host,
419 "REMOTE_USER", &s->remote_user,
98a28fef 420 "SERVICE", &s->service,
a4cd87e9 421 "DESKTOP", &s->desktop,
a185c5aa 422 "VTNR", &vtnr,
be94d954 423 "STATE", &state,
e6494a07 424 "POSITION", &position,
a185c5aa 425 "LEADER", &leader,
a91e4e53 426 "TYPE", &type,
55efac6c 427 "CLASS", &class,
9444b1f2
LP
428 "UID", &uid,
429 "REALTIME", &realtime,
430 "MONOTONIC", &monotonic,
6d33772f 431 "CONTROLLER", &controller,
aed24c4c
FB
432 "ACTIVE", &active,
433 "DEVICES", &devices,
1c8280fd 434 "IS_DISPLAY", &is_display,
a185c5aa
LP
435 NULL);
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
1227void session_restore_vt(Session *s) {
16597ac3
LP
1228
1229 static const struct vt_mode mode = {
1230 .mode = VT_AUTO,
1231 };
1232
c83f349c 1233 int vt, old_fd;
90a18413 1234
128df4cf
OT
1235 /* We need to get a fresh handle to the virtual terminal,
1236 * since the old file-descriptor is potentially in a hung-up
1237 * state after the controlling process exited; we do a
1238 * little dance to avoid having the terminal be available
1239 * for reuse before we've cleaned it up.
1240 */
c10d6bdb 1241 old_fd = TAKE_FD(s->vtfd);
128df4cf 1242
90a18413 1243 vt = session_open_vt(s);
128df4cf
OT
1244 safe_close(old_fd);
1245
90a18413
DH
1246 if (vt < 0)
1247 return;
1248
2bf10523 1249 (void) ioctl(vt, KDSETMODE, KD_TEXT);
90a18413 1250
c83f349c 1251 (void) vt_reset_keyboard(vt);
90a18413 1252
2bf10523 1253 (void) ioctl(vt, VT_SETMODE, &mode);
16597ac3 1254 (void) fchown(vt, 0, (gid_t) -1);
d6176c6c 1255
03e334a1 1256 s->vtfd = safe_close(s->vtfd);
90a18413
DH
1257}
1258
2ec3ff66 1259void session_leave_vt(Session *s) {
ce540a24
DH
1260 int r;
1261
2ec3ff66
DH
1262 assert(s);
1263
1264 /* This is called whenever we get a VT-switch signal from the kernel.
1265 * We acknowledge all of them unconditionally. Note that session are
1266 * free to overwrite those handlers and we only register them for
1267 * sessions with controllers. Legacy sessions are not affected.
1268 * However, if we switch from a non-legacy to a legacy session, we must
1269 * make sure to pause all device before acknowledging the switch. We
1270 * process the real switch only after we are notified via sysfs, so the
1271 * legacy session might have already started using the devices. If we
1272 * don't pause the devices before the switch, we might confuse the
1273 * session we switch to. */
1274
1275 if (s->vtfd < 0)
1276 return;
1277
1278 session_device_pause_all(s);
ce540a24
DH
1279 r = ioctl(s->vtfd, VT_RELDISP, 1);
1280 if (r < 0)
56f64d95 1281 log_debug_errno(errno, "Cannot release VT of session %s: %m", s->id);
2ec3ff66
DH
1282}
1283
cc377381 1284bool session_is_controller(Session *s, const char *sender) {
ae5e06bd
DH
1285 assert(s);
1286
1287 return streq_ptr(s->controller, sender);
1288}
1289
b12e5615
DH
1290static void session_release_controller(Session *s, bool notify) {
1291 _cleanup_free_ char *name = NULL;
6d33772f
DH
1292 SessionDevice *sd;
1293
b12e5615
DH
1294 if (!s->controller)
1295 return;
6d33772f 1296
b12e5615 1297 name = s->controller;
90a18413 1298
b12e5615
DH
1299 /* By resetting the controller before releasing the devices, we won't
1300 * send notification signals. This avoids sending useless notifications
1301 * if the controller is released on disconnects. */
1302 if (!notify)
1303 s->controller = NULL;
6d33772f 1304
b12e5615
DH
1305 while ((sd = hashmap_first(s->devices)))
1306 session_device_free(sd);
1307
1308 s->controller = NULL;
3cde9e8f
DM
1309 s->track = sd_bus_track_unref(s->track);
1310}
1311
1312static int on_bus_track(sd_bus_track *track, void *userdata) {
1313 Session *s = userdata;
1314
1315 assert(track);
1316 assert(s);
1317
1318 session_drop_controller(s);
1319
1320 return 0;
6d33772f
DH
1321}
1322
dc6284e9 1323int session_set_controller(Session *s, const char *sender, bool force, bool prepare) {
b12e5615 1324 _cleanup_free_ char *name = NULL;
ae5e06bd
DH
1325 int r;
1326
1327 assert(s);
1328 assert(sender);
1329
1330 if (session_is_controller(s, sender))
1331 return 0;
1332 if (s->controller && !force)
1333 return -EBUSY;
1334
b12e5615
DH
1335 name = strdup(sender);
1336 if (!name)
ae5e06bd
DH
1337 return -ENOMEM;
1338
3cde9e8f
DM
1339 s->track = sd_bus_track_unref(s->track);
1340 r = sd_bus_track_new(s->manager->bus, &s->track, on_bus_track, s);
1341 if (r < 0)
1342 return r;
1343
1344 r = sd_bus_track_add_name(s->track, name);
1345 if (r < 0)
ae5e06bd 1346 return r;
ae5e06bd 1347
90a18413
DH
1348 /* When setting a session controller, we forcibly mute the VT and set
1349 * it into graphics-mode. Applications can override that by changing
1350 * VT state after calling TakeControl(). However, this serves as a good
1351 * default and well-behaving controllers can now ignore VTs entirely.
1352 * Note that we reset the VT on ReleaseControl() and if the controller
1353 * exits.
1354 * If logind crashes/restarts, we restore the controller during restart
dc6284e9
FB
1355 * (without preparing the VT since the controller has probably overridden
1356 * VT state by now) or reset the VT in case it crashed/exited, too. */
1357 if (prepare) {
1358 r = session_prepare_vt(s);
1359 if (r < 0) {
1360 s->track = sd_bus_track_unref(s->track);
1361 return r;
1362 }
13f493dc 1363 }
baccf3e4 1364
b12e5615 1365 session_release_controller(s, true);
ae2a15bc 1366 s->controller = TAKE_PTR(name);
b12e5615 1367 session_save(s);
90a18413 1368
ae5e06bd
DH
1369 return 0;
1370}
1371
1372void session_drop_controller(Session *s) {
1373 assert(s);
1374
1375 if (!s->controller)
1376 return;
1377
3cde9e8f 1378 s->track = sd_bus_track_unref(s->track);
b12e5615
DH
1379 session_release_controller(s, false);
1380 session_save(s);
1381 session_restore_vt(s);
ae5e06bd
DH
1382}
1383
fb6becb4
LP
1384static const char* const session_state_table[_SESSION_STATE_MAX] = {
1385 [SESSION_OPENING] = "opening",
0604381b
LP
1386 [SESSION_ONLINE] = "online",
1387 [SESSION_ACTIVE] = "active",
1388 [SESSION_CLOSING] = "closing"
1389};
1390
1391DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1392
20263082 1393static const char* const session_type_table[_SESSION_TYPE_MAX] = {
2c5859af 1394 [SESSION_UNSPECIFIED] = "unspecified",
3f49d45a 1395 [SESSION_TTY] = "tty",
98a28fef 1396 [SESSION_X11] = "x11",
d9eb81f9 1397 [SESSION_WAYLAND] = "wayland",
9541666b 1398 [SESSION_MIR] = "mir",
e9e74f28 1399 [SESSION_WEB] = "web",
20263082
LP
1400};
1401
1402DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
de07ab16 1403
55efac6c
LP
1404static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1405 [SESSION_USER] = "user",
1406 [SESSION_GREETER] = "greeter",
e2acb67b
LP
1407 [SESSION_LOCK_SCREEN] = "lock-screen",
1408 [SESSION_BACKGROUND] = "background"
55efac6c
LP
1409};
1410
1411DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1412
de07ab16
LP
1413static const char* const kill_who_table[_KILL_WHO_MAX] = {
1414 [KILL_LEADER] = "leader",
1415 [KILL_ALL] = "all"
1416};
1417
1418DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
3d0ef5c7
LP
1419
1420static const char* const tty_validity_table[_TTY_VALIDITY_MAX] = {
1421 [TTY_FROM_PAM] = "from-pam",
1422 [TTY_FROM_UTMP] = "from-utmp",
1423 [TTY_UTMP_INCONSISTENT] = "utmp-inconsistent",
1424};
1425
1426DEFINE_STRING_TABLE_LOOKUP(tty_validity, TTYValidity);