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