chiark / gitweb /
Incorporate sleep.conf into logind.conf
[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
41 #define RELEASE_USEC (20*USEC_PER_SEC)
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, "POS=%u\n", s->pos);
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                 *pos = 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                            "POS",            &pos,
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 (pos && s->seat) {
376                 unsigned int npos;
377
378                 safe_atou(pos, &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         /* We are going down, don't care about FIFOs anymore */
543         session_remove_fifo(s);
544
545         s->stopping = true;
546
547         user_elect_display(s->user);
548
549         session_save(s);
550         user_save(s->user);
551
552         return r;
553 }
554
555 int session_finalize(Session *s) {
556         int r = 0;
557         SessionDevice *sd;
558
559         assert(s);
560
561         if (!s->user)
562                 return -ESTALE;
563
564         if (s->started)
565                 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
566                            LOG_MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
567                            "SESSION_ID=%s", s->id,
568                            "USER_ID=%s", s->user->name,
569                            "LEADER="PID_FMT, s->leader,
570                            LOG_MESSAGE("Removed session %s.", s->id),
571                            NULL);
572
573         s->timer_event_source = sd_event_source_unref(s->timer_event_source);
574
575         /* Kill session devices */
576         while ((sd = hashmap_first(s->devices)))
577                 session_device_free(sd);
578
579         unlink(s->state_file);
580         session_add_to_gc_queue(s);
581         user_add_to_gc_queue(s->user);
582
583         if (s->started) {
584                 session_send_signal(s, false);
585                 s->started = false;
586         }
587
588         if (s->seat) {
589                 if (s->seat->active == s)
590                         seat_set_active(s->seat, NULL);
591
592                 seat_save(s->seat);
593                 seat_send_changed(s->seat, "Sessions", NULL);
594         }
595
596         user_save(s->user);
597         user_send_changed(s->user, "Sessions", "Display", NULL);
598
599         return r;
600 }
601
602 static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
603         Session *s = userdata;
604
605         assert(es);
606         assert(s);
607
608         session_stop(s, false);
609         return 0;
610 }
611
612 int session_release(Session *s) {
613         assert(s);
614
615         if (!s->started || s->stopping)
616                 return 0;
617
618         if (s->timer_event_source)
619                 return 0;
620
621         return sd_event_add_time(s->manager->event,
622                                  &s->timer_event_source,
623                                  CLOCK_MONOTONIC,
624                                  now(CLOCK_MONOTONIC) + RELEASE_USEC, 0,
625                                  release_timeout_callback, s);
626 }
627
628 bool session_is_active(Session *s) {
629         assert(s);
630
631         if (!s->seat)
632                 return true;
633
634         return s->seat->active == s;
635 }
636
637 static int get_tty_atime(const char *tty, usec_t *atime) {
638         _cleanup_free_ char *p = NULL;
639         struct stat st;
640
641         assert(tty);
642         assert(atime);
643
644         if (!path_is_absolute(tty)) {
645                 p = strappend("/dev/", tty);
646                 if (!p)
647                         return -ENOMEM;
648
649                 tty = p;
650         } else if (!path_startswith(tty, "/dev/"))
651                 return -ENOENT;
652
653         if (lstat(tty, &st) < 0)
654                 return -errno;
655
656         *atime = timespec_load(&st.st_atim);
657         return 0;
658 }
659
660 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
661         _cleanup_free_ char *p = NULL;
662         int r;
663
664         assert(pid > 0);
665         assert(atime);
666
667         r = get_ctty(pid, NULL, &p);
668         if (r < 0)
669                 return r;
670
671         return get_tty_atime(p, atime);
672 }
673
674 int session_get_idle_hint(Session *s, dual_timestamp *t) {
675         usec_t atime = 0, n;
676         int r;
677
678         assert(s);
679
680         /* Explicit idle hint is set */
681         if (s->idle_hint) {
682                 if (t)
683                         *t = s->idle_hint_timestamp;
684
685                 return s->idle_hint;
686         }
687
688         /* Graphical sessions should really implement a real
689          * idle hint logic */
690         if (s->display)
691                 goto dont_know;
692
693         /* For sessions with an explicitly configured tty, let's check
694          * its atime */
695         if (s->tty) {
696                 r = get_tty_atime(s->tty, &atime);
697                 if (r >= 0)
698                         goto found_atime;
699         }
700
701         /* For sessions with a leader but no explicitly configured
702          * tty, let's check the controlling tty of the leader */
703         if (s->leader > 0) {
704                 r = get_process_ctty_atime(s->leader, &atime);
705                 if (r >= 0)
706                         goto found_atime;
707         }
708
709 dont_know:
710         if (t)
711                 *t = s->idle_hint_timestamp;
712
713         return 0;
714
715 found_atime:
716         if (t)
717                 dual_timestamp_from_realtime(t, atime);
718
719         n = now(CLOCK_REALTIME);
720
721         if (s->manager->idle_action_usec <= 0)
722                 return 0;
723
724         return atime + s->manager->idle_action_usec <= n;
725 }
726
727 void session_set_idle_hint(Session *s, bool b) {
728         assert(s);
729
730         if (s->idle_hint == b)
731                 return;
732
733         s->idle_hint = b;
734         dual_timestamp_get(&s->idle_hint_timestamp);
735
736         session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
737
738         if (s->seat)
739                 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
740
741         user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
742         manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
743 }
744
745 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
746         Session *s = userdata;
747
748         assert(s);
749         assert(s->fifo_fd == fd);
750
751         /* EOF on the FIFO means the session died abnormally. */
752
753         session_remove_fifo(s);
754         session_stop(s, false);
755
756         return 1;
757 }
758
759 int session_create_fifo(Session *s) {
760         int r;
761
762         assert(s);
763
764         /* Create FIFO */
765         if (!s->fifo_path) {
766                 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
767                 if (r < 0)
768                         return r;
769
770                 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
771                         return -ENOMEM;
772
773                 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
774                         return -errno;
775         }
776
777         /* Open reading side */
778         if (s->fifo_fd < 0) {
779                 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
780                 if (s->fifo_fd < 0)
781                         return -errno;
782
783         }
784
785         if (!s->fifo_event_source) {
786                 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
787                 if (r < 0)
788                         return r;
789
790                 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
791                 if (r < 0)
792                         return r;
793         }
794
795         /* Open writing side */
796         r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
797         if (r < 0)
798                 return -errno;
799
800         return r;
801 }
802
803 static void session_remove_fifo(Session *s) {
804         assert(s);
805
806         s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
807         s->fifo_fd = safe_close(s->fifo_fd);
808
809         if (s->fifo_path) {
810                 unlink(s->fifo_path);
811                 free(s->fifo_path);
812                 s->fifo_path = NULL;
813         }
814 }
815
816 bool session_check_gc(Session *s, bool drop_not_started) {
817         assert(s);
818
819         if (drop_not_started && !s->started)
820                 return false;
821
822         if (!s->user)
823                 return false;
824
825         if (s->fifo_fd >= 0) {
826                 if (pipe_eof(s->fifo_fd) <= 0)
827                         return true;
828         }
829
830         return false;
831 }
832
833 void session_add_to_gc_queue(Session *s) {
834         assert(s);
835
836         if (s->in_gc_queue)
837                 return;
838
839         LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
840         s->in_gc_queue = true;
841 }
842
843 SessionState session_get_state(Session *s) {
844         assert(s);
845
846         /* always check closing first */
847         if (s->stopping || s->timer_event_source)
848                 return SESSION_CLOSING;
849
850         if (s->fifo_fd < 0)
851                 return SESSION_OPENING;
852
853         if (session_is_active(s))
854                 return SESSION_ACTIVE;
855
856         return SESSION_ONLINE;
857 }
858
859 int session_kill(Session *s, KillWho who, int signo) {
860         assert(s);
861
862         /* No way to kill the session without cgroups.  */
863         return -ESRCH;
864 }
865
866 static int session_open_vt(Session *s) {
867         char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
868
869         if (s->vtnr < 1)
870                 return -ENODEV;
871
872         if (s->vtfd >= 0)
873                 return s->vtfd;
874
875         sprintf(path, "/dev/tty%u", s->vtnr);
876         s->vtfd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
877         if (s->vtfd < 0)
878                 return log_error_errno(errno, "cannot open VT %s of session %s: %m", path, s->id);
879
880         return s->vtfd;
881 }
882
883 int session_prepare_vt(Session *s) {
884         int vt, r;
885         struct vt_mode mode = { 0 };
886
887         if (s->vtnr < 1)
888                 return 0;
889
890         vt = session_open_vt(s);
891         if (vt < 0)
892                 return vt;
893
894         r = fchown(vt, s->user->uid, -1);
895         if (r < 0) {
896                 r = -errno;
897                 log_error_errno(errno, "Cannot change owner of /dev/tty%u: %m", s->vtnr);
898                 goto error;
899         }
900
901         r = ioctl(vt, KDSKBMODE, K_OFF);
902         if (r < 0) {
903                 r = -errno;
904                 log_error_errno(errno, "Cannot set K_OFF on /dev/tty%u: %m", s->vtnr);
905                 goto error;
906         }
907
908         r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
909         if (r < 0) {
910                 r = -errno;
911                 log_error_errno(errno, "Cannot set KD_GRAPHICS on /dev/tty%u: %m", s->vtnr);
912                 goto error;
913         }
914
915         /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
916          * So we need a dummy handler here which just acknowledges *all* VT
917          * switch requests. */
918         mode.mode = VT_PROCESS;
919         mode.relsig = SIGRTMIN;
920         mode.acqsig = SIGRTMIN + 1;
921         r = ioctl(vt, VT_SETMODE, &mode);
922         if (r < 0) {
923                 r = -errno;
924                 log_error_errno(errno, "Cannot set VT_PROCESS on /dev/tty%u: %m", s->vtnr);
925                 goto error;
926         }
927
928         return 0;
929
930 error:
931         session_restore_vt(s);
932         return r;
933 }
934
935 void session_restore_vt(Session *s) {
936         _cleanup_free_ char *utf8 = NULL;
937         int vt, kb = K_XLATE;
938         struct vt_mode mode = { 0 };
939
940         vt = session_open_vt(s);
941         if (vt < 0)
942                 return;
943
944         (void) ioctl(vt, KDSETMODE, KD_TEXT);
945
946         if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
947                 kb = K_UNICODE;
948
949         (void) ioctl(vt, KDSKBMODE, kb);
950
951         mode.mode = VT_AUTO;
952         (void) ioctl(vt, VT_SETMODE, &mode);
953
954         fchown(vt, 0, -1);
955
956         s->vtfd = safe_close(s->vtfd);
957 }
958
959 void session_leave_vt(Session *s) {
960         int r;
961
962         assert(s);
963
964         /* This is called whenever we get a VT-switch signal from the kernel.
965          * We acknowledge all of them unconditionally. Note that session are
966          * free to overwrite those handlers and we only register them for
967          * sessions with controllers. Legacy sessions are not affected.
968          * However, if we switch from a non-legacy to a legacy session, we must
969          * make sure to pause all device before acknowledging the switch. We
970          * process the real switch only after we are notified via sysfs, so the
971          * legacy session might have already started using the devices. If we
972          * don't pause the devices before the switch, we might confuse the
973          * session we switch to. */
974
975         if (s->vtfd < 0)
976                 return;
977
978         session_device_pause_all(s);
979         r = ioctl(s->vtfd, VT_RELDISP, 1);
980         if (r < 0)
981                 log_debug_errno(errno, "Cannot release VT of session %s: %m", s->id);
982 }
983
984 bool session_is_controller(Session *s, const char *sender) {
985         assert(s);
986
987         return streq_ptr(s->controller, sender);
988 }
989
990 static void session_release_controller(Session *s, bool notify) {
991         _cleanup_free_ char *name = NULL;
992         SessionDevice *sd;
993
994         if (!s->controller)
995                 return;
996
997         name = s->controller;
998
999         /* By resetting the controller before releasing the devices, we won't
1000          * send notification signals. This avoids sending useless notifications
1001          * if the controller is released on disconnects. */
1002         if (!notify)
1003                 s->controller = NULL;
1004
1005         while ((sd = hashmap_first(s->devices)))
1006                 session_device_free(sd);
1007
1008         s->controller = NULL;
1009         manager_drop_busname(s->manager, name);
1010 }
1011
1012 int session_set_controller(Session *s, const char *sender, bool force) {
1013         _cleanup_free_ char *name = NULL;
1014         int r;
1015
1016         assert(s);
1017         assert(sender);
1018
1019         if (session_is_controller(s, sender))
1020                 return 0;
1021         if (s->controller && !force)
1022                 return -EBUSY;
1023
1024         name = strdup(sender);
1025         if (!name)
1026                 return -ENOMEM;
1027
1028         r = manager_watch_busname(s->manager, name);
1029         if (r)
1030                 return r;
1031
1032         /* When setting a session controller, we forcibly mute the VT and set
1033          * it into graphics-mode. Applications can override that by changing
1034          * VT state after calling TakeControl(). However, this serves as a good
1035          * default and well-behaving controllers can now ignore VTs entirely.
1036          * Note that we reset the VT on ReleaseControl() and if the controller
1037          * exits.
1038          * If logind crashes/restarts, we restore the controller during restart
1039          * or reset the VT in case it crashed/exited, too. */
1040         r = session_prepare_vt(s);
1041         if (r < 0) {
1042                 manager_drop_busname(s->manager, name);
1043                 return r;
1044         }
1045
1046         session_release_controller(s, true);
1047         s->controller = name;
1048         name = NULL;
1049         session_save(s);
1050
1051         return 0;
1052 }
1053
1054 void session_drop_controller(Session *s) {
1055         assert(s);
1056
1057         if (!s->controller)
1058                 return;
1059
1060         session_release_controller(s, false);
1061         session_save(s);
1062         session_restore_vt(s);
1063 }
1064
1065 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1066         [SESSION_OPENING] = "opening",
1067         [SESSION_ONLINE] = "online",
1068         [SESSION_ACTIVE] = "active",
1069         [SESSION_CLOSING] = "closing"
1070 };
1071
1072 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1073
1074 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1075         [SESSION_UNSPECIFIED] = "unspecified",
1076         [SESSION_TTY] = "tty",
1077         [SESSION_X11] = "x11",
1078         [SESSION_WAYLAND] = "wayland",
1079         [SESSION_MIR] = "mir",
1080         [SESSION_WEB] = "web",
1081 };
1082
1083 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1084
1085 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1086         [SESSION_USER] = "user",
1087         [SESSION_GREETER] = "greeter",
1088         [SESSION_LOCK_SCREEN] = "lock-screen",
1089         [SESSION_BACKGROUND] = "background"
1090 };
1091
1092 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1093
1094 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1095         [KILL_LEADER] = "leader",
1096         [KILL_ALL] = "all"
1097 };
1098
1099 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);