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