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