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