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