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