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