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