]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session.c
Make tables for DEFINE_STRING_TABLE_LOOKUP consistent
[thirdparty/systemd.git] / src / login / logind-session.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <linux/vt.h>
25 #include <linux/kd.h>
26 #include <signal.h>
27 #include <string.h>
28 #include <sys/ioctl.h>
29 #include <unistd.h>
30
31 #include "sd-id128.h"
32 #include "sd-messages.h"
33 #include "strv.h"
34 #include "util.h"
35 #include "mkdir.h"
36 #include "path-util.h"
37 #include "fileio.h"
38 #include "audit.h"
39 #include "bus-util.h"
40 #include "bus-error.h"
41 #include "logind-session.h"
42
43 #define RELEASE_USEC (20*USEC_PER_SEC)
44
45 static void session_remove_fifo(Session *s);
46
47 static unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
48 uint64_t u = *(const dev_t*)p;
49
50 return uint64_hash_func(&u, hash_key);
51 }
52
53 static int devt_compare_func(const void *_a, const void *_b) {
54 dev_t a, b;
55
56 a = *(const dev_t*) _a;
57 b = *(const dev_t*) _b;
58
59 return a < b ? -1 : (a > b ? 1 : 0);
60 }
61
62 Session* session_new(Manager *m, const char *id) {
63 Session *s;
64
65 assert(m);
66 assert(id);
67 assert(session_id_valid(id));
68
69 s = new0(Session, 1);
70 if (!s)
71 return NULL;
72
73 s->state_file = strappend("/run/systemd/sessions/", id);
74 if (!s->state_file) {
75 free(s);
76 return NULL;
77 }
78
79 s->devices = hashmap_new(devt_hash_func, devt_compare_func);
80 if (!s->devices) {
81 free(s->state_file);
82 free(s);
83 return NULL;
84 }
85
86 s->id = basename(s->state_file);
87
88 if (hashmap_put(m->sessions, s->id, s) < 0) {
89 hashmap_free(s->devices);
90 free(s->state_file);
91 free(s);
92 return NULL;
93 }
94
95 s->manager = m;
96 s->fifo_fd = -1;
97 s->vtfd = -1;
98
99 return s;
100 }
101
102 void session_free(Session *s) {
103 SessionDevice *sd;
104
105 assert(s);
106
107 if (s->in_gc_queue)
108 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
109
110 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
111
112 session_remove_fifo(s);
113
114 session_drop_controller(s);
115
116 while ((sd = hashmap_first(s->devices)))
117 session_device_free(sd);
118
119 hashmap_free(s->devices);
120
121 if (s->user) {
122 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
123
124 if (s->user->display == s)
125 s->user->display = NULL;
126 }
127
128 if (s->seat) {
129 if (s->seat->active == s)
130 s->seat->active = NULL;
131 if (s->seat->pending_switch == s)
132 s->seat->pending_switch = NULL;
133
134 seat_evict_position(s->seat, s);
135 LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
136 }
137
138 if (s->scope) {
139 hashmap_remove(s->manager->session_units, s->scope);
140 free(s->scope);
141 }
142
143 free(s->scope_job);
144
145 sd_bus_message_unref(s->create_message);
146
147 free(s->tty);
148 free(s->display);
149 free(s->remote_host);
150 free(s->remote_user);
151 free(s->service);
152 free(s->desktop);
153
154 hashmap_remove(s->manager->sessions, s->id);
155
156 s->vt_source = sd_event_source_unref(s->vt_source);
157
158 free(s->state_file);
159 free(s);
160 }
161
162 void session_set_user(Session *s, User *u) {
163 assert(s);
164 assert(!s->user);
165
166 s->user = u;
167 LIST_PREPEND(sessions_by_user, u->sessions, s);
168 }
169
170 int session_save(Session *s) {
171 _cleanup_free_ char *temp_path = NULL;
172 _cleanup_fclose_ FILE *f = NULL;
173 int r = 0;
174
175 assert(s);
176
177 if (!s->user)
178 return -ESTALE;
179
180 if (!s->started)
181 return 0;
182
183 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
184 if (r < 0)
185 goto finish;
186
187 r = fopen_temporary(s->state_file, &f, &temp_path);
188 if (r < 0)
189 goto finish;
190
191 assert(s->user);
192
193 fchmod(fileno(f), 0644);
194
195 fprintf(f,
196 "# This is private data. Do not parse.\n"
197 "UID="UID_FMT"\n"
198 "USER=%s\n"
199 "ACTIVE=%i\n"
200 "STATE=%s\n"
201 "REMOTE=%i\n",
202 s->user->uid,
203 s->user->name,
204 session_is_active(s),
205 session_state_to_string(session_get_state(s)),
206 s->remote);
207
208 if (s->type >= 0)
209 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
210
211 if (s->class >= 0)
212 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
213
214 if (s->scope)
215 fprintf(f, "SCOPE=%s\n", s->scope);
216
217 if (s->scope_job)
218 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
219
220 if (s->fifo_path)
221 fprintf(f, "FIFO=%s\n", s->fifo_path);
222
223 if (s->seat)
224 fprintf(f, "SEAT=%s\n", s->seat->id);
225
226 if (s->tty)
227 fprintf(f, "TTY=%s\n", s->tty);
228
229 if (s->display)
230 fprintf(f, "DISPLAY=%s\n", s->display);
231
232 if (s->remote_host)
233 fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
234
235 if (s->remote_user)
236 fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
237
238 if (s->service)
239 fprintf(f, "SERVICE=%s\n", s->service);
240
241 if (s->desktop)
242 fprintf(f, "DESKTOP=%s\n", s->desktop);
243
244 if (s->seat && seat_has_vts(s->seat))
245 fprintf(f, "VTNR=%u\n", s->vtnr);
246
247 if (!s->vtnr)
248 fprintf(f, "POS=%u\n", s->pos);
249
250 if (s->leader > 0)
251 fprintf(f, "LEADER="PID_FMT"\n", s->leader);
252
253 if (s->audit_id > 0)
254 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
255
256 if (dual_timestamp_is_set(&s->timestamp))
257 fprintf(f,
258 "REALTIME="USEC_FMT"\n"
259 "MONOTONIC="USEC_FMT"\n",
260 s->timestamp.realtime,
261 s->timestamp.monotonic);
262
263 if (s->controller)
264 fprintf(f, "CONTROLLER=%s\n", s->controller);
265
266 fflush(f);
267
268 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
269 r = -errno;
270 unlink(s->state_file);
271 unlink(temp_path);
272 }
273
274 finish:
275 if (r < 0)
276 log_error("Failed to save session data %s: %s", s->state_file, strerror(-r));
277
278 return r;
279 }
280
281 int session_load(Session *s) {
282 _cleanup_free_ char *remote = NULL,
283 *seat = NULL,
284 *vtnr = NULL,
285 *pos = NULL,
286 *leader = NULL,
287 *type = NULL,
288 *class = NULL,
289 *uid = NULL,
290 *realtime = NULL,
291 *monotonic = NULL,
292 *controller = NULL;
293
294 int k, r;
295
296 assert(s);
297
298 r = parse_env_file(s->state_file, NEWLINE,
299 "REMOTE", &remote,
300 "SCOPE", &s->scope,
301 "SCOPE_JOB", &s->scope_job,
302 "FIFO", &s->fifo_path,
303 "SEAT", &seat,
304 "TTY", &s->tty,
305 "DISPLAY", &s->display,
306 "REMOTE_HOST", &s->remote_host,
307 "REMOTE_USER", &s->remote_user,
308 "SERVICE", &s->service,
309 "DESKTOP", &s->desktop,
310 "VTNR", &vtnr,
311 "POS", &pos,
312 "LEADER", &leader,
313 "TYPE", &type,
314 "CLASS", &class,
315 "UID", &uid,
316 "REALTIME", &realtime,
317 "MONOTONIC", &monotonic,
318 "CONTROLLER", &controller,
319 NULL);
320
321 if (r < 0) {
322 log_error("Failed to read %s: %s", s->state_file, strerror(-r));
323 return r;
324 }
325
326 if (!s->user) {
327 uid_t u;
328 User *user;
329
330 if (!uid) {
331 log_error("UID not specified for session %s", s->id);
332 return -ENOENT;
333 }
334
335 r = parse_uid(uid, &u);
336 if (r < 0) {
337 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
338 return r;
339 }
340
341 user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
342 if (!user) {
343 log_error("User of session %s not known.", s->id);
344 return -ENOENT;
345 }
346
347 session_set_user(s, user);
348 }
349
350 if (remote) {
351 k = parse_boolean(remote);
352 if (k >= 0)
353 s->remote = k;
354 }
355
356 if (vtnr)
357 safe_atou(vtnr, &s->vtnr);
358
359 if (seat && !s->seat) {
360 Seat *o;
361
362 o = hashmap_get(s->manager->seats, seat);
363 if (o)
364 r = seat_attach_session(o, s);
365 if (!o || r < 0)
366 log_error("Cannot attach session %s to seat %s", s->id, seat);
367 }
368
369 if (!s->seat || !seat_has_vts(s->seat))
370 s->vtnr = 0;
371
372 if (pos && s->seat) {
373 unsigned int npos;
374
375 safe_atou(pos, &npos);
376 seat_claim_position(s->seat, s, npos);
377 }
378
379 if (leader) {
380 k = parse_pid(leader, &s->leader);
381 if (k >= 0)
382 audit_session_from_pid(s->leader, &s->audit_id);
383 }
384
385 if (type) {
386 SessionType t;
387
388 t = session_type_from_string(type);
389 if (t >= 0)
390 s->type = t;
391 }
392
393 if (class) {
394 SessionClass c;
395
396 c = session_class_from_string(class);
397 if (c >= 0)
398 s->class = c;
399 }
400
401 if (s->fifo_path) {
402 int fd;
403
404 /* If we open an unopened pipe for reading we will not
405 get an EOF. to trigger an EOF we hence open it for
406 reading, but close it right-away which then will
407 trigger the EOF. */
408
409 fd = session_create_fifo(s);
410 if (fd >= 0)
411 close_nointr_nofail(fd);
412 }
413
414 if (realtime) {
415 unsigned long long l;
416 if (sscanf(realtime, "%llu", &l) > 0)
417 s->timestamp.realtime = l;
418 }
419
420 if (monotonic) {
421 unsigned long long l;
422 if (sscanf(monotonic, "%llu", &l) > 0)
423 s->timestamp.monotonic = l;
424 }
425
426 if (controller) {
427 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
428 session_set_controller(s, controller, false);
429 else
430 session_restore_vt(s);
431 }
432
433 return r;
434 }
435
436 int session_activate(Session *s) {
437 unsigned int num_pending;
438
439 assert(s);
440 assert(s->user);
441
442 if (!s->seat)
443 return -ENOTSUP;
444
445 if (s->seat->active == s)
446 return 0;
447
448 /* on seats with VTs, we let VTs manage session-switching */
449 if (seat_has_vts(s->seat)) {
450 if (!s->vtnr)
451 return -ENOTSUP;
452
453 return chvt(s->vtnr);
454 }
455
456 /* On seats without VTs, we implement session-switching in logind. We
457 * try to pause all session-devices and wait until the session
458 * controller acknowledged them. Once all devices are asleep, we simply
459 * switch the active session and be done.
460 * We save the session we want to switch to in seat->pending_switch and
461 * seat_complete_switch() will perform the final switch. */
462
463 s->seat->pending_switch = s;
464
465 /* if no devices are running, immediately perform the session switch */
466 num_pending = session_device_try_pause_all(s);
467 if (!num_pending)
468 seat_complete_switch(s->seat);
469
470 return 0;
471 }
472
473 static int session_start_scope(Session *s) {
474 int r;
475
476 assert(s);
477 assert(s->user);
478 assert(s->user->slice);
479
480 if (!s->scope) {
481 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
482 _cleanup_free_ char *description = NULL;
483 char *scope, *job = NULL;
484
485 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
486 if (!description)
487 return log_oom();
488
489 scope = strjoin("session-", s->id, ".scope", NULL);
490 if (!scope)
491 return log_oom();
492
493 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job);
494 if (r < 0) {
495 log_error("Failed to start session scope %s: %s %s",
496 scope, bus_error_message(&error, r), error.name);
497 free(scope);
498 return r;
499 } else {
500 s->scope = scope;
501
502 free(s->scope_job);
503 s->scope_job = job;
504 }
505 }
506
507 if (s->scope)
508 hashmap_put(s->manager->session_units, s->scope, s);
509
510 return 0;
511 }
512
513 int session_start(Session *s) {
514 int r;
515
516 assert(s);
517
518 if (!s->user)
519 return -ESTALE;
520
521 if (s->started)
522 return 0;
523
524 r = user_start(s->user);
525 if (r < 0)
526 return r;
527
528 /* Create cgroup */
529 r = session_start_scope(s);
530 if (r < 0)
531 return r;
532
533 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
534 MESSAGE_ID(SD_MESSAGE_SESSION_START),
535 "SESSION_ID=%s", s->id,
536 "USER_ID=%s", s->user->name,
537 "LEADER=%lu", (unsigned long) s->leader,
538 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
539 NULL);
540
541 if (!dual_timestamp_is_set(&s->timestamp))
542 dual_timestamp_get(&s->timestamp);
543
544 if (s->seat)
545 seat_read_active_vt(s->seat);
546
547 s->started = true;
548
549 /* Save data */
550 session_save(s);
551 user_save(s->user);
552 if (s->seat)
553 seat_save(s->seat);
554
555 /* Send signals */
556 session_send_signal(s, true);
557 user_send_changed(s->user, "Sessions", NULL);
558 if (s->seat) {
559 if (s->seat->active == s)
560 seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
561 else
562 seat_send_changed(s->seat, "Sessions", NULL);
563 }
564
565 return 0;
566 }
567
568 static int session_stop_scope(Session *s, bool force) {
569 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
570 char *job = NULL;
571 int r;
572
573 assert(s);
574
575 if (!s->scope)
576 return 0;
577
578 if (force || manager_shall_kill(s->manager, s->user->name)) {
579 r = manager_stop_unit(s->manager, s->scope, &error, &job);
580 if (r < 0) {
581 log_error("Failed to stop session scope: %s", bus_error_message(&error, r));
582 return r;
583 }
584
585 free(s->scope_job);
586 s->scope_job = job;
587 } else {
588 r = manager_abandon_scope(s->manager, s->scope, &error);
589 if (r < 0) {
590 log_error("Failed to abandon session scope: %s", bus_error_message(&error, r));
591 return r;
592 }
593 }
594
595 return 0;
596 }
597
598 int session_stop(Session *s, bool force) {
599 int r;
600
601 assert(s);
602
603 if (!s->user)
604 return -ESTALE;
605
606 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
607
608 /* We are going down, don't care about FIFOs anymore */
609 session_remove_fifo(s);
610
611 /* Kill cgroup */
612 r = session_stop_scope(s, force);
613
614 s->stopping = true;
615
616 session_save(s);
617 user_save(s->user);
618
619 return r;
620 }
621
622 int session_finalize(Session *s) {
623 int r = 0;
624 SessionDevice *sd;
625
626 assert(s);
627
628 if (!s->user)
629 return -ESTALE;
630
631 if (s->started)
632 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
633 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
634 "SESSION_ID=%s", s->id,
635 "USER_ID=%s", s->user->name,
636 "LEADER=%lu", (unsigned long) s->leader,
637 "MESSAGE=Removed session %s.", s->id,
638 NULL);
639
640 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
641
642 /* Kill session devices */
643 while ((sd = hashmap_first(s->devices)))
644 session_device_free(sd);
645
646 unlink(s->state_file);
647 session_add_to_gc_queue(s);
648 user_add_to_gc_queue(s->user);
649
650 if (s->started) {
651 session_send_signal(s, false);
652 s->started = false;
653 }
654
655 if (s->seat) {
656 if (s->seat->active == s)
657 seat_set_active(s->seat, NULL);
658
659 seat_save(s->seat);
660 seat_send_changed(s->seat, "Sessions", NULL);
661 }
662
663 user_save(s->user);
664 user_send_changed(s->user, "Sessions", NULL);
665
666 return r;
667 }
668
669 static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
670 Session *s = userdata;
671
672 assert(es);
673 assert(s);
674
675 session_stop(s, false);
676 return 0;
677 }
678
679 void session_release(Session *s) {
680 assert(s);
681
682 if (!s->started || s->stopping)
683 return;
684
685 if (!s->timer_event_source)
686 sd_event_add_monotonic(s->manager->event, &s->timer_event_source, now(CLOCK_MONOTONIC) + RELEASE_USEC, 0, release_timeout_callback, s);
687 }
688
689 bool session_is_active(Session *s) {
690 assert(s);
691
692 if (!s->seat)
693 return true;
694
695 return s->seat->active == s;
696 }
697
698 static int get_tty_atime(const char *tty, usec_t *atime) {
699 _cleanup_free_ char *p = NULL;
700 struct stat st;
701
702 assert(tty);
703 assert(atime);
704
705 if (!path_is_absolute(tty)) {
706 p = strappend("/dev/", tty);
707 if (!p)
708 return -ENOMEM;
709
710 tty = p;
711 } else if (!path_startswith(tty, "/dev/"))
712 return -ENOENT;
713
714 if (lstat(tty, &st) < 0)
715 return -errno;
716
717 *atime = timespec_load(&st.st_atim);
718 return 0;
719 }
720
721 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
722 _cleanup_free_ char *p = NULL;
723 int r;
724
725 assert(pid > 0);
726 assert(atime);
727
728 r = get_ctty(pid, NULL, &p);
729 if (r < 0)
730 return r;
731
732 return get_tty_atime(p, atime);
733 }
734
735 int session_get_idle_hint(Session *s, dual_timestamp *t) {
736 usec_t atime = 0, n;
737 int r;
738
739 assert(s);
740
741 /* Explicit idle hint is set */
742 if (s->idle_hint) {
743 if (t)
744 *t = s->idle_hint_timestamp;
745
746 return s->idle_hint;
747 }
748
749 /* Graphical sessions should really implement a real
750 * idle hint logic */
751 if (s->display)
752 goto dont_know;
753
754 /* For sessions with an explicitly configured tty, let's check
755 * its atime */
756 if (s->tty) {
757 r = get_tty_atime(s->tty, &atime);
758 if (r >= 0)
759 goto found_atime;
760 }
761
762 /* For sessions with a leader but no explicitly configured
763 * tty, let's check the controlling tty of the leader */
764 if (s->leader > 0) {
765 r = get_process_ctty_atime(s->leader, &atime);
766 if (r >= 0)
767 goto found_atime;
768 }
769
770 dont_know:
771 if (t)
772 *t = s->idle_hint_timestamp;
773
774 return 0;
775
776 found_atime:
777 if (t)
778 dual_timestamp_from_realtime(t, atime);
779
780 n = now(CLOCK_REALTIME);
781
782 if (s->manager->idle_action_usec <= 0)
783 return 0;
784
785 return atime + s->manager->idle_action_usec <= n;
786 }
787
788 void session_set_idle_hint(Session *s, bool b) {
789 assert(s);
790
791 if (s->idle_hint == b)
792 return;
793
794 s->idle_hint = b;
795 dual_timestamp_get(&s->idle_hint_timestamp);
796
797 session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
798
799 if (s->seat)
800 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
801
802 user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
803 manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
804 }
805
806 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
807 Session *s = userdata;
808
809 assert(s);
810 assert(s->fifo_fd == fd);
811
812 /* EOF on the FIFO means the session died abnormally. */
813
814 session_remove_fifo(s);
815 session_stop(s, false);
816
817 return 1;
818 }
819
820 int session_create_fifo(Session *s) {
821 int r;
822
823 assert(s);
824
825 /* Create FIFO */
826 if (!s->fifo_path) {
827 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
828 if (r < 0)
829 return r;
830
831 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
832 return -ENOMEM;
833
834 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
835 return -errno;
836 }
837
838 /* Open reading side */
839 if (s->fifo_fd < 0) {
840 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
841 if (s->fifo_fd < 0)
842 return -errno;
843
844 }
845
846 if (!s->fifo_event_source) {
847 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
848 if (r < 0)
849 return r;
850
851 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
852 if (r < 0)
853 return r;
854 }
855
856 /* Open writing side */
857 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
858 if (r < 0)
859 return -errno;
860
861 return r;
862 }
863
864 static void session_remove_fifo(Session *s) {
865 assert(s);
866
867 if (s->fifo_event_source)
868 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
869
870 if (s->fifo_fd >= 0) {
871 close_nointr_nofail(s->fifo_fd);
872 s->fifo_fd = -1;
873 }
874
875 if (s->fifo_path) {
876 unlink(s->fifo_path);
877 free(s->fifo_path);
878 s->fifo_path = NULL;
879 }
880 }
881
882 bool session_check_gc(Session *s, bool drop_not_started) {
883 assert(s);
884
885 if (drop_not_started && !s->started)
886 return false;
887
888 if (!s->user)
889 return false;
890
891 if (s->fifo_fd >= 0) {
892 if (pipe_eof(s->fifo_fd) <= 0)
893 return true;
894 }
895
896 if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
897 return true;
898
899 if (s->scope && manager_unit_is_active(s->manager, s->scope))
900 return true;
901
902 return false;
903 }
904
905 void session_add_to_gc_queue(Session *s) {
906 assert(s);
907
908 if (s->in_gc_queue)
909 return;
910
911 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
912 s->in_gc_queue = true;
913 }
914
915 SessionState session_get_state(Session *s) {
916 assert(s);
917
918 /* always check closing first */
919 if (s->stopping || s->timer_event_source)
920 return SESSION_CLOSING;
921
922 if (s->scope_job || s->fifo_fd < 0)
923 return SESSION_OPENING;
924
925 if (session_is_active(s))
926 return SESSION_ACTIVE;
927
928 return SESSION_ONLINE;
929 }
930
931 int session_kill(Session *s, KillWho who, int signo) {
932 assert(s);
933
934 if (!s->scope)
935 return -ESRCH;
936
937 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
938 }
939
940 static int session_open_vt(Session *s) {
941 char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
942
943 if (!s->vtnr)
944 return -1;
945
946 if (s->vtfd >= 0)
947 return s->vtfd;
948
949 sprintf(path, "/dev/tty%u", s->vtnr);
950 s->vtfd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
951 if (s->vtfd < 0) {
952 log_error("cannot open VT %s of session %s: %m", path, s->id);
953 return -1;
954 }
955
956 return s->vtfd;
957 }
958
959 static int session_vt_fn(sd_event_source *source, const struct signalfd_siginfo *si, void *data) {
960 Session *s = data;
961
962 if (s->vtfd >= 0)
963 ioctl(s->vtfd, VT_RELDISP, 1);
964
965 return 0;
966 }
967
968 void session_mute_vt(Session *s) {
969 int vt, r;
970 struct vt_mode mode = { 0 };
971 sigset_t mask;
972
973 vt = session_open_vt(s);
974 if (vt < 0)
975 return;
976
977 r = ioctl(vt, KDSKBMODE, K_OFF);
978 if (r < 0)
979 goto error;
980
981 r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
982 if (r < 0)
983 goto error;
984
985 sigemptyset(&mask);
986 sigaddset(&mask, SIGUSR1);
987 sigprocmask(SIG_BLOCK, &mask, NULL);
988
989 r = sd_event_add_signal(s->manager->event, &s->vt_source, SIGUSR1, session_vt_fn, s);
990 if (r < 0)
991 goto error;
992
993 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
994 * So we need a dummy handler here which just acknowledges *all* VT
995 * switch requests. */
996 mode.mode = VT_PROCESS;
997 mode.relsig = SIGUSR1;
998 mode.acqsig = SIGUSR1;
999 r = ioctl(vt, VT_SETMODE, &mode);
1000 if (r < 0)
1001 goto error;
1002
1003 return;
1004
1005 error:
1006 log_error("cannot mute VT %u for session %s (%d/%d)", s->vtnr, s->id, r, errno);
1007 session_restore_vt(s);
1008 }
1009
1010 void session_restore_vt(Session *s) {
1011 _cleanup_free_ char *utf8 = NULL;
1012 int vt, kb = K_XLATE;
1013 struct vt_mode mode = { 0 };
1014
1015 vt = session_open_vt(s);
1016 if (vt < 0)
1017 return;
1018
1019 s->vt_source = sd_event_source_unref(s->vt_source);
1020
1021 ioctl(vt, KDSETMODE, KD_TEXT);
1022
1023 if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
1024 kb = K_UNICODE;
1025 ioctl(vt, KDSKBMODE, kb);
1026
1027 mode.mode = VT_AUTO;
1028 ioctl(vt, VT_SETMODE, &mode);
1029
1030 close_nointr_nofail(vt);
1031 s->vtfd = -1;
1032 }
1033
1034 bool session_is_controller(Session *s, const char *sender) {
1035 assert(s);
1036
1037 return streq_ptr(s->controller, sender);
1038 }
1039
1040 static void session_swap_controller(Session *s, char *name) {
1041 SessionDevice *sd;
1042
1043 if (s->controller) {
1044 manager_drop_busname(s->manager, s->controller);
1045 free(s->controller);
1046 s->controller = NULL;
1047
1048 /* Drop all devices as they're now unused. Do that after the
1049 * controller is released to avoid sending out useles
1050 * dbus signals. */
1051 while ((sd = hashmap_first(s->devices)))
1052 session_device_free(sd);
1053
1054 if (!name)
1055 session_restore_vt(s);
1056 }
1057
1058 s->controller = name;
1059 session_save(s);
1060 }
1061
1062 int session_set_controller(Session *s, const char *sender, bool force) {
1063 char *t;
1064 int r;
1065
1066 assert(s);
1067 assert(sender);
1068
1069 if (session_is_controller(s, sender))
1070 return 0;
1071 if (s->controller && !force)
1072 return -EBUSY;
1073
1074 t = strdup(sender);
1075 if (!t)
1076 return -ENOMEM;
1077
1078 r = manager_watch_busname(s->manager, sender);
1079 if (r) {
1080 free(t);
1081 return r;
1082 }
1083
1084 session_swap_controller(s, t);
1085
1086 /* When setting a session controller, we forcibly mute the VT and set
1087 * it into graphics-mode. Applications can override that by changing
1088 * VT state after calling TakeControl(). However, this serves as a good
1089 * default and well-behaving controllers can now ignore VTs entirely.
1090 * Note that we reset the VT on ReleaseControl() and if the controller
1091 * exits.
1092 * If logind crashes/restarts, we restore the controller during restart
1093 * or reset the VT in case it crashed/exited, too. */
1094 session_mute_vt(s);
1095
1096 return 0;
1097 }
1098
1099 void session_drop_controller(Session *s) {
1100 assert(s);
1101
1102 if (!s->controller)
1103 return;
1104
1105 session_swap_controller(s, NULL);
1106 }
1107
1108 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1109 [SESSION_OPENING] = "opening",
1110 [SESSION_ONLINE] = "online",
1111 [SESSION_ACTIVE] = "active",
1112 [SESSION_CLOSING] = "closing"
1113 };
1114
1115 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1116
1117 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1118 [SESSION_UNSPECIFIED] = "unspecified",
1119 [SESSION_TTY] = "tty",
1120 [SESSION_X11] = "x11",
1121 [SESSION_WAYLAND] = "wayland",
1122 };
1123
1124 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1125
1126 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1127 [SESSION_USER] = "user",
1128 [SESSION_GREETER] = "greeter",
1129 [SESSION_LOCK_SCREEN] = "lock-screen",
1130 [SESSION_BACKGROUND] = "background"
1131 };
1132
1133 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1134
1135 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1136 [KILL_LEADER] = "leader",
1137 [KILL_ALL] = "all"
1138 };
1139
1140 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);