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