]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-session.c
macro: add new helper RET_NERRNO()
[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"
4f5dd394 29#include "mkdir.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);
a185c5aa 448
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 */
db4a47e9 1100 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NONBLOCK);
932e3ee7
LP
1101 if (r < 0)
1102 return -errno;
31b79c2b 1103
932e3ee7
LP
1104 return r;
1105}
1106
5f41d1f1 1107static void session_remove_fifo(Session *s) {
932e3ee7
LP
1108 assert(s);
1109
03e334a1
LP
1110 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
1111 s->fifo_fd = safe_close(s->fifo_fd);
932e3ee7
LP
1112
1113 if (s->fifo_path) {
75bbdf47 1114 (void) unlink(s->fifo_path);
a1e58e8e 1115 s->fifo_path = mfree(s->fifo_path);
932e3ee7 1116 }
31b79c2b
LP
1117}
1118
5c093a23 1119bool session_may_gc(Session *s, bool drop_not_started) {
bd26aee1
LP
1120 int r;
1121
20263082
LP
1122 assert(s);
1123
4a4b033f 1124 if (drop_not_started && !s->started)
5c093a23 1125 return true;
932e3ee7 1126
9444b1f2 1127 if (!s->user)
5c093a23 1128 return true;
9444b1f2 1129
932e3ee7 1130 if (s->fifo_fd >= 0) {
5f41d1f1 1131 if (pipe_eof(s->fifo_fd) <= 0)
5c093a23 1132 return false;
20263082
LP
1133 }
1134
bd26aee1
LP
1135 if (s->scope_job) {
1136 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1137
1138 r = manager_job_is_active(s->manager, s->scope_job, &error);
1139 if (r < 0)
1140 log_debug_errno(r, "Failed to determine whether job '%s' is pending, ignoring: %s", s->scope_job, bus_error_message(&error, r));
1141 if (r != 0)
1142 return false;
1143 }
20263082 1144
bd26aee1
LP
1145 if (s->scope) {
1146 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1147
1148 r = manager_unit_is_active(s->manager, s->scope, &error);
1149 if (r < 0)
1150 log_debug_errno(r, "Failed to determine whether unit '%s' is active, ignoring: %s", s->scope, bus_error_message(&error, r));
1151 if (r != 0)
1152 return false;
1153 }
20263082 1154
5c093a23 1155 return true;
20263082
LP
1156}
1157
14c3baca
LP
1158void session_add_to_gc_queue(Session *s) {
1159 assert(s);
1160
1161 if (s->in_gc_queue)
1162 return;
1163
71fda00f 1164 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
14c3baca
LP
1165 s->in_gc_queue = true;
1166}
1167
0604381b
LP
1168SessionState session_get_state(Session *s) {
1169 assert(s);
1170
8fe63cd4 1171 /* always check closing first */
5f41d1f1
LP
1172 if (s->stopping || s->timer_event_source)
1173 return SESSION_CLOSING;
1174
8fe63cd4 1175 if (s->scope_job || s->fifo_fd < 0)
405e0255 1176 return SESSION_OPENING;
fb6becb4 1177
0604381b
LP
1178 if (session_is_active(s))
1179 return SESSION_ACTIVE;
1180
1181 return SESSION_ONLINE;
1182}
1183
de07ab16 1184int session_kill(Session *s, KillWho who, int signo) {
de07ab16
LP
1185 assert(s);
1186
fb6becb4 1187 if (!s->scope)
de07ab16
LP
1188 return -ESRCH;
1189
fb6becb4 1190 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
de07ab16
LP
1191}
1192
90a18413 1193static int session_open_vt(Session *s) {
5f41d1f1 1194 char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
90a18413 1195
baccf3e4
OB
1196 if (s->vtnr < 1)
1197 return -ENODEV;
90a18413
DH
1198
1199 if (s->vtfd >= 0)
1200 return s->vtfd;
1201
92bd5ff3 1202 sprintf(path, "/dev/tty%u", s->vtnr);
22356953 1203 s->vtfd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
4a62c710 1204 if (s->vtfd < 0)
709f6e46 1205 return log_error_errno(s->vtfd, "cannot open VT %s of session %s: %m", path, s->id);
90a18413
DH
1206
1207 return s->vtfd;
1208}
1209
a03cdb17 1210static int session_prepare_vt(Session *s) {
90a18413 1211 int vt, r;
9fb2c8b8 1212 struct vt_mode mode = {};
90a18413 1213
baccf3e4
OB
1214 if (s->vtnr < 1)
1215 return 0;
1216
90a18413
DH
1217 vt = session_open_vt(s);
1218 if (vt < 0)
baccf3e4 1219 return vt;
90a18413 1220
22c902fa 1221 r = fchown(vt, s->user->user_record->uid, -1);
baccf3e4 1222 if (r < 0) {
94c156cd
LP
1223 r = log_error_errno(errno,
1224 "Cannot change owner of /dev/tty%u: %m",
1225 s->vtnr);
d6176c6c 1226 goto error;
baccf3e4 1227 }
d6176c6c 1228
90a18413 1229 r = ioctl(vt, KDSKBMODE, K_OFF);
baccf3e4 1230 if (r < 0) {
94c156cd
LP
1231 r = log_error_errno(errno,
1232 "Cannot set K_OFF on /dev/tty%u: %m",
1233 s->vtnr);
90a18413 1234 goto error;
baccf3e4 1235 }
90a18413
DH
1236
1237 r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
baccf3e4 1238 if (r < 0) {
94c156cd
LP
1239 r = log_error_errno(errno,
1240 "Cannot set KD_GRAPHICS on /dev/tty%u: %m",
1241 s->vtnr);
90a18413 1242 goto error;
baccf3e4 1243 }
90a18413 1244
90a18413
DH
1245 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1246 * So we need a dummy handler here which just acknowledges *all* VT
1247 * switch requests. */
1248 mode.mode = VT_PROCESS;
92683ad2
DH
1249 mode.relsig = SIGRTMIN;
1250 mode.acqsig = SIGRTMIN + 1;
90a18413 1251 r = ioctl(vt, VT_SETMODE, &mode);
baccf3e4 1252 if (r < 0) {
94c156cd
LP
1253 r = log_error_errno(errno,
1254 "Cannot set VT_PROCESS on /dev/tty%u: %m",
1255 s->vtnr);
90a18413 1256 goto error;
baccf3e4 1257 }
90a18413 1258
baccf3e4 1259 return 0;
90a18413
DH
1260
1261error:
90a18413 1262 session_restore_vt(s);
baccf3e4 1263 return r;
90a18413
DH
1264}
1265
0212126c 1266static void session_restore_vt(Session *s) {
8246905a 1267 int r;
128df4cf 1268
8246905a
FB
1269 r = vt_restore(s->vtfd);
1270 if (r == -EIO) {
1271 int vt, old_fd;
ad96887a 1272
8246905a
FB
1273 /* It might happen if the controlling process exited before or while we were
1274 * restoring the VT as it would leave the old file-descriptor in a hung-up
1275 * state. In this case let's retry with a fresh handle to the virtual terminal. */
ad96887a 1276
8246905a
FB
1277 /* We do a little dance to avoid having the terminal be available
1278 * for reuse before we've cleaned it up. */
1279 old_fd = TAKE_FD(s->vtfd);
1280
1281 vt = session_open_vt(s);
1282 safe_close(old_fd);
1283
1284 if (vt >= 0)
1285 r = vt_restore(vt);
1286 }
ad96887a 1287
c0f34168
FB
1288 if (r < 0)
1289 log_warning_errno(r, "Failed to restore VT, ignoring: %m");
d6176c6c 1290
03e334a1 1291 s->vtfd = safe_close(s->vtfd);
90a18413
DH
1292}
1293
2ec3ff66 1294void session_leave_vt(Session *s) {
ce540a24
DH
1295 int r;
1296
2ec3ff66
DH
1297 assert(s);
1298
1299 /* This is called whenever we get a VT-switch signal from the kernel.
1300 * We acknowledge all of them unconditionally. Note that session are
1301 * free to overwrite those handlers and we only register them for
1302 * sessions with controllers. Legacy sessions are not affected.
1303 * However, if we switch from a non-legacy to a legacy session, we must
1304 * make sure to pause all device before acknowledging the switch. We
1305 * process the real switch only after we are notified via sysfs, so the
1306 * legacy session might have already started using the devices. If we
1307 * don't pause the devices before the switch, we might confuse the
1308 * session we switch to. */
1309
1310 if (s->vtfd < 0)
1311 return;
1312
1313 session_device_pause_all(s);
27dafac9 1314 r = vt_release(s->vtfd, false);
ce540a24 1315 if (r < 0)
27dafac9 1316 log_debug_errno(r, "Cannot release VT of session %s: %m", s->id);
2ec3ff66
DH
1317}
1318
cc377381 1319bool session_is_controller(Session *s, const char *sender) {
ae5e06bd
DH
1320 assert(s);
1321
1322 return streq_ptr(s->controller, sender);
1323}
1324
b12e5615 1325static void session_release_controller(Session *s, bool notify) {
d7ac0952 1326 _unused_ _cleanup_free_ char *name = NULL;
6d33772f
DH
1327 SessionDevice *sd;
1328
b12e5615
DH
1329 if (!s->controller)
1330 return;
6d33772f 1331
b12e5615 1332 name = s->controller;
90a18413 1333
6c75e317
ZJS
1334 /* By resetting the controller before releasing the devices, we won't send notification signals.
1335 * This avoids sending useless notifications if the controller is released on disconnects. */
b12e5615
DH
1336 if (!notify)
1337 s->controller = NULL;
6d33772f 1338
b12e5615
DH
1339 while ((sd = hashmap_first(s->devices)))
1340 session_device_free(sd);
1341
1342 s->controller = NULL;
3cde9e8f
DM
1343 s->track = sd_bus_track_unref(s->track);
1344}
1345
1346static int on_bus_track(sd_bus_track *track, void *userdata) {
1347 Session *s = userdata;
1348
1349 assert(track);
1350 assert(s);
1351
1352 session_drop_controller(s);
1353
1354 return 0;
6d33772f
DH
1355}
1356
dc6284e9 1357int session_set_controller(Session *s, const char *sender, bool force, bool prepare) {
b12e5615 1358 _cleanup_free_ char *name = NULL;
ae5e06bd
DH
1359 int r;
1360
1361 assert(s);
1362 assert(sender);
1363
1364 if (session_is_controller(s, sender))
1365 return 0;
1366 if (s->controller && !force)
1367 return -EBUSY;
1368
b12e5615
DH
1369 name = strdup(sender);
1370 if (!name)
ae5e06bd
DH
1371 return -ENOMEM;
1372
3cde9e8f
DM
1373 s->track = sd_bus_track_unref(s->track);
1374 r = sd_bus_track_new(s->manager->bus, &s->track, on_bus_track, s);
1375 if (r < 0)
1376 return r;
1377
1378 r = sd_bus_track_add_name(s->track, name);
1379 if (r < 0)
ae5e06bd 1380 return r;
ae5e06bd 1381
90a18413
DH
1382 /* When setting a session controller, we forcibly mute the VT and set
1383 * it into graphics-mode. Applications can override that by changing
1384 * VT state after calling TakeControl(). However, this serves as a good
1385 * default and well-behaving controllers can now ignore VTs entirely.
1386 * Note that we reset the VT on ReleaseControl() and if the controller
1387 * exits.
1388 * If logind crashes/restarts, we restore the controller during restart
dc6284e9
FB
1389 * (without preparing the VT since the controller has probably overridden
1390 * VT state by now) or reset the VT in case it crashed/exited, too. */
1391 if (prepare) {
1392 r = session_prepare_vt(s);
1393 if (r < 0) {
1394 s->track = sd_bus_track_unref(s->track);
1395 return r;
1396 }
13f493dc 1397 }
baccf3e4 1398
b12e5615 1399 session_release_controller(s, true);
ae2a15bc 1400 s->controller = TAKE_PTR(name);
b12e5615 1401 session_save(s);
90a18413 1402
ae5e06bd
DH
1403 return 0;
1404}
1405
1406void session_drop_controller(Session *s) {
1407 assert(s);
1408
1409 if (!s->controller)
1410 return;
1411
3cde9e8f 1412 s->track = sd_bus_track_unref(s->track);
db72aea4 1413 session_set_type(s, s->original_type);
b12e5615
DH
1414 session_release_controller(s, false);
1415 session_save(s);
1416 session_restore_vt(s);
ae5e06bd
DH
1417}
1418
fb6becb4
LP
1419static const char* const session_state_table[_SESSION_STATE_MAX] = {
1420 [SESSION_OPENING] = "opening",
6c75e317
ZJS
1421 [SESSION_ONLINE] = "online",
1422 [SESSION_ACTIVE] = "active",
1423 [SESSION_CLOSING] = "closing",
0604381b
LP
1424};
1425
1426DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1427
20263082 1428static const char* const session_type_table[_SESSION_TYPE_MAX] = {
2c5859af 1429 [SESSION_UNSPECIFIED] = "unspecified",
6c75e317
ZJS
1430 [SESSION_TTY] = "tty",
1431 [SESSION_X11] = "x11",
1432 [SESSION_WAYLAND] = "wayland",
1433 [SESSION_MIR] = "mir",
1434 [SESSION_WEB] = "web",
20263082
LP
1435};
1436
1437DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
de07ab16 1438
55efac6c 1439static const char* const session_class_table[_SESSION_CLASS_MAX] = {
6c75e317
ZJS
1440 [SESSION_USER] = "user",
1441 [SESSION_GREETER] = "greeter",
e2acb67b 1442 [SESSION_LOCK_SCREEN] = "lock-screen",
6c75e317 1443 [SESSION_BACKGROUND] = "background",
55efac6c
LP
1444};
1445
1446DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1447
de07ab16
LP
1448static const char* const kill_who_table[_KILL_WHO_MAX] = {
1449 [KILL_LEADER] = "leader",
6c75e317 1450 [KILL_ALL] = "all",
de07ab16
LP
1451};
1452
1453DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
3d0ef5c7
LP
1454
1455static const char* const tty_validity_table[_TTY_VALIDITY_MAX] = {
6c75e317
ZJS
1456 [TTY_FROM_PAM] = "from-pam",
1457 [TTY_FROM_UTMP] = "from-utmp",
3d0ef5c7
LP
1458 [TTY_UTMP_INCONSISTENT] = "utmp-inconsistent",
1459};
1460
1461DEFINE_STRING_TABLE_LOOKUP(tty_validity, TTYValidity);