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