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