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