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