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