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