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