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