chiark / gitweb /
logind: fix printf format
[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                 if (fd >= 0)
411                         close_nointr_nofail(fd);
412         }
413
414         if (realtime) {
415                 unsigned long long l;
416                 if (sscanf(realtime, "%llu", &l) > 0)
417                         s->timestamp.realtime = l;
418         }
419
420         if (monotonic) {
421                 unsigned long long l;
422                 if (sscanf(monotonic, "%llu", &l) > 0)
423                         s->timestamp.monotonic = l;
424         }
425
426         if (controller) {
427                 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
428                         session_set_controller(s, controller, false);
429                 else
430                         session_restore_vt(s);
431         }
432
433         return r;
434 }
435
436 int session_activate(Session *s) {
437         unsigned int num_pending;
438
439         assert(s);
440         assert(s->user);
441
442         if (!s->seat)
443                 return -ENOTSUP;
444
445         if (s->seat->active == s)
446                 return 0;
447
448         /* on seats with VTs, we let VTs manage session-switching */
449         if (seat_has_vts(s->seat)) {
450                 if (!s->vtnr)
451                         return -ENOTSUP;
452
453                 return chvt(s->vtnr);
454         }
455
456         /* On seats without VTs, we implement session-switching in logind. We
457          * try to pause all session-devices and wait until the session
458          * controller acknowledged them. Once all devices are asleep, we simply
459          * switch the active session and be done.
460          * We save the session we want to switch to in seat->pending_switch and
461          * seat_complete_switch() will perform the final switch. */
462
463         s->seat->pending_switch = s;
464
465         /* if no devices are running, immediately perform the session switch */
466         num_pending = session_device_try_pause_all(s);
467         if (!num_pending)
468                 seat_complete_switch(s->seat);
469
470         return 0;
471 }
472
473 static int session_start_scope(Session *s) {
474         int r;
475
476         assert(s);
477         assert(s->user);
478         assert(s->user->slice);
479
480         if (!s->scope) {
481                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
482                 _cleanup_free_ char *description = NULL;
483                 char *scope, *job = NULL;
484
485                 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
486                 if (!description)
487                         return log_oom();
488
489                 scope = strjoin("session-", s->id, ".scope", NULL);
490                 if (!scope)
491                         return log_oom();
492
493                 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-session.service", &error, &job);
494                 if (r < 0) {
495                         log_error("Failed to start session scope %s: %s %s",
496                                   scope, bus_error_message(&error, r), error.name);
497                         free(scope);
498                         return r;
499                 } else {
500                         s->scope = scope;
501
502                         free(s->scope_job);
503                         s->scope_job = job;
504                 }
505         }
506
507         if (s->scope)
508                 hashmap_put(s->manager->session_units, s->scope, s);
509
510         return 0;
511 }
512
513 int session_start(Session *s) {
514         int r;
515
516         assert(s);
517
518         if (!s->user)
519                 return -ESTALE;
520
521         if (s->started)
522                 return 0;
523
524         r = user_start(s->user);
525         if (r < 0)
526                 return r;
527
528         /* Create cgroup */
529         r = session_start_scope(s);
530         if (r < 0)
531                 return r;
532
533         log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
534                    MESSAGE_ID(SD_MESSAGE_SESSION_START),
535                    "SESSION_ID=%s", s->id,
536                    "USER_ID=%s", s->user->name,
537                    "LEADER=%lu", (unsigned long) s->leader,
538                    "MESSAGE=New session %s of user %s.", s->id, s->user->name,
539                    NULL);
540
541         if (!dual_timestamp_is_set(&s->timestamp))
542                 dual_timestamp_get(&s->timestamp);
543
544         if (s->seat)
545                 seat_read_active_vt(s->seat);
546
547         s->started = true;
548
549         /* Save data */
550         session_save(s);
551         user_save(s->user);
552         if (s->seat)
553                 seat_save(s->seat);
554
555         /* Send signals */
556         session_send_signal(s, true);
557         user_send_changed(s->user, "Sessions", NULL);
558         if (s->seat) {
559                 if (s->seat->active == s)
560                         seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
561                 else
562                         seat_send_changed(s->seat, "Sessions", NULL);
563         }
564
565         return 0;
566 }
567
568 static int session_stop_scope(Session *s, bool force) {
569         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
570         char *job = NULL;
571         int r;
572
573         assert(s);
574
575         if (!s->scope)
576                 return 0;
577
578         if (force || manager_shall_kill(s->manager, s->user->name)) {
579                 r = manager_stop_unit(s->manager, s->scope, &error, &job);
580                 if (r < 0) {
581                         log_error("Failed to stop session scope: %s", bus_error_message(&error, r));
582                         return r;
583                 }
584
585                 free(s->scope_job);
586                 s->scope_job = job;
587         } else {
588                 r = manager_abandon_scope(s->manager, s->scope, &error);
589                 if (r < 0) {
590                         log_error("Failed to abandon session scope: %s", bus_error_message(&error, r));
591                         return r;
592                 }
593         }
594
595         return 0;
596 }
597
598 int session_stop(Session *s, bool force) {
599         int r;
600
601         assert(s);
602
603         if (!s->user)
604                 return -ESTALE;
605
606         s->timer_event_source = sd_event_source_unref(s->timer_event_source);
607
608         /* We are going down, don't care about FIFOs anymore */
609         session_remove_fifo(s);
610
611         /* Kill cgroup */
612         r = session_stop_scope(s, force);
613
614         s->stopping = true;
615
616         session_save(s);
617         user_save(s->user);
618
619         return r;
620 }
621
622 int session_finalize(Session *s) {
623         int r = 0;
624         SessionDevice *sd;
625
626         assert(s);
627
628         if (!s->user)
629                 return -ESTALE;
630
631         if (s->started)
632                 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
633                            MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
634                            "SESSION_ID=%s", s->id,
635                            "USER_ID=%s", s->user->name,
636                            "LEADER=%lu", (unsigned long) s->leader,
637                            "MESSAGE=Removed session %s.", s->id,
638                            NULL);
639
640         s->timer_event_source = sd_event_source_unref(s->timer_event_source);
641
642         /* Kill session devices */
643         while ((sd = hashmap_first(s->devices)))
644                 session_device_free(sd);
645
646         unlink(s->state_file);
647         session_add_to_gc_queue(s);
648         user_add_to_gc_queue(s->user);
649
650         if (s->started) {
651                 session_send_signal(s, false);
652                 s->started = false;
653         }
654
655         if (s->seat) {
656                 if (s->seat->active == s)
657                         seat_set_active(s->seat, NULL);
658
659                 seat_save(s->seat);
660                 seat_send_changed(s->seat, "Sessions", NULL);
661         }
662
663         user_save(s->user);
664         user_send_changed(s->user, "Sessions", NULL);
665
666         return r;
667 }
668
669 static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
670         Session *s = userdata;
671
672         assert(es);
673         assert(s);
674
675         session_stop(s, false);
676         return 0;
677 }
678
679 void session_release(Session *s) {
680         assert(s);
681
682         if (!s->started || s->stopping)
683                 return;
684
685         if (!s->timer_event_source)
686                 sd_event_add_monotonic(s->manager->event, &s->timer_event_source, now(CLOCK_MONOTONIC) + RELEASE_USEC, 0, release_timeout_callback, s);
687 }
688
689 bool session_is_active(Session *s) {
690         assert(s);
691
692         if (!s->seat)
693                 return true;
694
695         return s->seat->active == s;
696 }
697
698 static int get_tty_atime(const char *tty, usec_t *atime) {
699         _cleanup_free_ char *p = NULL;
700         struct stat st;
701
702         assert(tty);
703         assert(atime);
704
705         if (!path_is_absolute(tty)) {
706                 p = strappend("/dev/", tty);
707                 if (!p)
708                         return -ENOMEM;
709
710                 tty = p;
711         } else if (!path_startswith(tty, "/dev/"))
712                 return -ENOENT;
713
714         if (lstat(tty, &st) < 0)
715                 return -errno;
716
717         *atime = timespec_load(&st.st_atim);
718         return 0;
719 }
720
721 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
722         _cleanup_free_ char *p = NULL;
723         int r;
724
725         assert(pid > 0);
726         assert(atime);
727
728         r = get_ctty(pid, NULL, &p);
729         if (r < 0)
730                 return r;
731
732         return get_tty_atime(p, atime);
733 }
734
735 int session_get_idle_hint(Session *s, dual_timestamp *t) {
736         usec_t atime = 0, n;
737         int r;
738
739         assert(s);
740
741         /* Explicit idle hint is set */
742         if (s->idle_hint) {
743                 if (t)
744                         *t = s->idle_hint_timestamp;
745
746                 return s->idle_hint;
747         }
748
749         /* Graphical sessions should really implement a real
750          * idle hint logic */
751         if (s->display)
752                 goto dont_know;
753
754         /* For sessions with an explicitly configured tty, let's check
755          * its atime */
756         if (s->tty) {
757                 r = get_tty_atime(s->tty, &atime);
758                 if (r >= 0)
759                         goto found_atime;
760         }
761
762         /* For sessions with a leader but no explicitly configured
763          * tty, let's check the controlling tty of the leader */
764         if (s->leader > 0) {
765                 r = get_process_ctty_atime(s->leader, &atime);
766                 if (r >= 0)
767                         goto found_atime;
768         }
769
770 dont_know:
771         if (t)
772                 *t = s->idle_hint_timestamp;
773
774         return 0;
775
776 found_atime:
777         if (t)
778                 dual_timestamp_from_realtime(t, atime);
779
780         n = now(CLOCK_REALTIME);
781
782         if (s->manager->idle_action_usec <= 0)
783                 return 0;
784
785         return atime + s->manager->idle_action_usec <= n;
786 }
787
788 void session_set_idle_hint(Session *s, bool b) {
789         assert(s);
790
791         if (s->idle_hint == b)
792                 return;
793
794         s->idle_hint = b;
795         dual_timestamp_get(&s->idle_hint_timestamp);
796
797         session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
798
799         if (s->seat)
800                 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
801
802         user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
803         manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
804 }
805
806 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
807         Session *s = userdata;
808
809         assert(s);
810         assert(s->fifo_fd == fd);
811
812         /* EOF on the FIFO means the session died abnormally. */
813
814         session_remove_fifo(s);
815         session_stop(s, false);
816
817         return 1;
818 }
819
820 int session_create_fifo(Session *s) {
821         int r;
822
823         assert(s);
824
825         /* Create FIFO */
826         if (!s->fifo_path) {
827                 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
828                 if (r < 0)
829                         return r;
830
831                 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
832                         return -ENOMEM;
833
834                 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
835                         return -errno;
836         }
837
838         /* Open reading side */
839         if (s->fifo_fd < 0) {
840                 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
841                 if (s->fifo_fd < 0)
842                         return -errno;
843
844         }
845
846         if (!s->fifo_event_source) {
847                 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
848                 if (r < 0)
849                         return r;
850
851                 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
852                 if (r < 0)
853                         return r;
854         }
855
856         /* Open writing side */
857         r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
858         if (r < 0)
859                 return -errno;
860
861         return r;
862 }
863
864 static void session_remove_fifo(Session *s) {
865         assert(s);
866
867         if (s->fifo_event_source)
868                 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
869
870         if (s->fifo_fd >= 0) {
871                 close_nointr_nofail(s->fifo_fd);
872                 s->fifo_fd = -1;
873         }
874
875         if (s->fifo_path) {
876                 unlink(s->fifo_path);
877                 free(s->fifo_path);
878                 s->fifo_path = NULL;
879         }
880 }
881
882 bool session_check_gc(Session *s, bool drop_not_started) {
883         assert(s);
884
885         if (drop_not_started && !s->started)
886                 return false;
887
888         if (!s->user)
889                 return false;
890
891         if (s->fifo_fd >= 0) {
892                 if (pipe_eof(s->fifo_fd) <= 0)
893                         return true;
894         }
895
896         if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
897                 return true;
898
899         if (s->scope && manager_unit_is_active(s->manager, s->scope))
900                 return true;
901
902         return false;
903 }
904
905 void session_add_to_gc_queue(Session *s) {
906         assert(s);
907
908         if (s->in_gc_queue)
909                 return;
910
911         LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
912         s->in_gc_queue = true;
913 }
914
915 SessionState session_get_state(Session *s) {
916         assert(s);
917
918         /* always check closing first */
919         if (s->stopping || s->timer_event_source)
920                 return SESSION_CLOSING;
921
922         if (s->scope_job || s->fifo_fd < 0)
923                 return SESSION_OPENING;
924
925         if (session_is_active(s))
926                 return SESSION_ACTIVE;
927
928         return SESSION_ONLINE;
929 }
930
931 int session_kill(Session *s, KillWho who, int signo) {
932         assert(s);
933
934         if (!s->scope)
935                 return -ESRCH;
936
937         return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
938 }
939
940 static int session_open_vt(Session *s) {
941         char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
942
943         if (!s->vtnr)
944                 return -1;
945
946         if (s->vtfd >= 0)
947                 return s->vtfd;
948
949         sprintf(path, "/dev/tty%u", s->vtnr);
950         s->vtfd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
951         if (s->vtfd < 0) {
952                 log_error("cannot open VT %s of session %s: %m", path, s->id);
953                 return -1;
954         }
955
956         return s->vtfd;
957 }
958
959 static int session_vt_fn(sd_event_source *source, const struct signalfd_siginfo *si, void *data) {
960         Session *s = data;
961
962         if (s->vtfd >= 0)
963                 ioctl(s->vtfd, VT_RELDISP, 1);
964
965         return 0;
966 }
967
968 void session_mute_vt(Session *s) {
969         int vt, r;
970         struct vt_mode mode = { 0 };
971         sigset_t mask;
972
973         vt = session_open_vt(s);
974         if (vt < 0)
975                 return;
976
977         r = ioctl(vt, KDSKBMODE, K_OFF);
978         if (r < 0)
979                 goto error;
980
981         r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
982         if (r < 0)
983                 goto error;
984
985         sigemptyset(&mask);
986         sigaddset(&mask, SIGUSR1);
987         sigprocmask(SIG_BLOCK, &mask, NULL);
988
989         r = sd_event_add_signal(s->manager->event, &s->vt_source, SIGUSR1, session_vt_fn, s);
990         if (r < 0)
991                 goto error;
992
993         /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
994          * So we need a dummy handler here which just acknowledges *all* VT
995          * switch requests. */
996         mode.mode = VT_PROCESS;
997         mode.relsig = SIGUSR1;
998         mode.acqsig = SIGUSR1;
999         r = ioctl(vt, VT_SETMODE, &mode);
1000         if (r < 0)
1001                 goto error;
1002
1003         return;
1004
1005 error:
1006         log_error("cannot mute VT %u for session %s (%d/%d)", s->vtnr, s->id, r, errno);
1007         session_restore_vt(s);
1008 }
1009
1010 void session_restore_vt(Session *s) {
1011         _cleanup_free_ char *utf8 = NULL;
1012         int vt, kb = K_XLATE;
1013         struct vt_mode mode = { 0 };
1014
1015         vt = session_open_vt(s);
1016         if (vt < 0)
1017                 return;
1018
1019         s->vt_source = sd_event_source_unref(s->vt_source);
1020
1021         ioctl(vt, KDSETMODE, KD_TEXT);
1022
1023         if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
1024                 kb = K_UNICODE;
1025         ioctl(vt, KDSKBMODE, kb);
1026
1027         mode.mode = VT_AUTO;
1028         ioctl(vt, VT_SETMODE, &mode);
1029
1030         close_nointr_nofail(vt);
1031         s->vtfd = -1;
1032 }
1033
1034 bool session_is_controller(Session *s, const char *sender) {
1035         assert(s);
1036
1037         return streq_ptr(s->controller, sender);
1038 }
1039
1040 static void session_swap_controller(Session *s, char *name) {
1041         SessionDevice *sd;
1042
1043         if (s->controller) {
1044                 manager_drop_busname(s->manager, s->controller);
1045                 free(s->controller);
1046                 s->controller = NULL;
1047
1048                 /* Drop all devices as they're now unused. Do that after the
1049                  * controller is released to avoid sending out useles
1050                  * dbus signals. */
1051                 while ((sd = hashmap_first(s->devices)))
1052                         session_device_free(sd);
1053
1054                 if (!name)
1055                         session_restore_vt(s);
1056         }
1057
1058         s->controller = name;
1059         session_save(s);
1060 }
1061
1062 int session_set_controller(Session *s, const char *sender, bool force) {
1063         char *t;
1064         int r;
1065
1066         assert(s);
1067         assert(sender);
1068
1069         if (session_is_controller(s, sender))
1070                 return 0;
1071         if (s->controller && !force)
1072                 return -EBUSY;
1073
1074         t = strdup(sender);
1075         if (!t)
1076                 return -ENOMEM;
1077
1078         r = manager_watch_busname(s->manager, sender);
1079         if (r) {
1080                 free(t);
1081                 return r;
1082         }
1083
1084         session_swap_controller(s, t);
1085
1086         /* When setting a session controller, we forcibly mute the VT and set
1087          * it into graphics-mode. Applications can override that by changing
1088          * VT state after calling TakeControl(). However, this serves as a good
1089          * default and well-behaving controllers can now ignore VTs entirely.
1090          * Note that we reset the VT on ReleaseControl() and if the controller
1091          * exits.
1092          * If logind crashes/restarts, we restore the controller during restart
1093          * or reset the VT in case it crashed/exited, too. */
1094         session_mute_vt(s);
1095
1096         return 0;
1097 }
1098
1099 void session_drop_controller(Session *s) {
1100         assert(s);
1101
1102         if (!s->controller)
1103                 return;
1104
1105         session_swap_controller(s, NULL);
1106 }
1107
1108 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1109         [SESSION_OPENING] = "opening",
1110         [SESSION_ONLINE] = "online",
1111         [SESSION_ACTIVE] = "active",
1112         [SESSION_CLOSING] = "closing"
1113 };
1114
1115 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1116
1117 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1118         [SESSION_TTY] = "tty",
1119         [SESSION_X11] = "x11",
1120         [SESSION_WAYLAND] = "wayland",
1121         [SESSION_UNSPECIFIED] = "unspecified",
1122 };
1123
1124 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1125
1126 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1127         [SESSION_USER] = "user",
1128         [SESSION_GREETER] = "greeter",
1129         [SESSION_LOCK_SCREEN] = "lock-screen",
1130         [SESSION_BACKGROUND] = "background"
1131 };
1132
1133 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1134
1135 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1136         [KILL_LEADER] = "leader",
1137         [KILL_ALL] = "all"
1138 };
1139
1140 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);