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