chiark / gitweb /
logind: minor cleanup and use IN_SET() in manager_handle_action()
[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 #else
554 static int session_start_cgroup(Session *s) {
555         int r;
556
557         assert(s);
558         assert(s->user);
559         assert(s->leader > 0);
560
561         /* First, create our own group */
562         r = cg_create(SYSTEMD_CGROUP_CONTROLLER, s->id);
563         if (r < 0)
564                 return log_error_errno(r, "Failed to create cgroup %s: %m", s->id);
565
566         r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, s->id, s->leader);
567         if (r < 0)
568                 log_warning_errno(r, "Failed to attach PID %d to cgroup %s: %m", s->leader, s->id);
569
570         return 0;
571 }
572 #endif // 0
573
574 int session_start(Session *s) {
575         int r;
576
577         assert(s);
578
579         if (!s->user)
580                 return -ESTALE;
581
582         if (s->started)
583                 return 0;
584
585         r = user_start(s->user);
586         if (r < 0)
587                 return r;
588
589         /* Create cgroup */
590 #if 0 /// elogind does its own session management
591         r = session_start_scope(s);
592 #else
593         r = session_start_cgroup(s);
594 #endif // 0
595         if (r < 0)
596                 return r;
597
598         log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
599                    LOG_MESSAGE_ID(SD_MESSAGE_SESSION_START),
600                    "SESSION_ID=%s", s->id,
601                    "USER_ID=%s", s->user->name,
602                    "LEADER="PID_FMT, s->leader,
603                    LOG_MESSAGE("New session %s of user %s.", s->id, s->user->name),
604                    NULL);
605
606         if (!dual_timestamp_is_set(&s->timestamp))
607                 dual_timestamp_get(&s->timestamp);
608
609         if (s->seat)
610                 seat_read_active_vt(s->seat);
611
612         s->started = true;
613
614         user_elect_display(s->user);
615
616         /* Save data */
617         session_save(s);
618         user_save(s->user);
619         if (s->seat)
620                 seat_save(s->seat);
621
622         /* Send signals */
623         session_send_signal(s, true);
624         user_send_changed(s->user, "Sessions", "Display", NULL);
625         if (s->seat) {
626                 if (s->seat->active == s)
627                         seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
628                 else
629                         seat_send_changed(s->seat, "Sessions", NULL);
630         }
631
632         return 0;
633 }
634
635 #if 0 /// UNNEEDED by elogind
636 static int session_stop_scope(Session *s, bool force) {
637         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
638         char *job = NULL;
639         int r;
640
641         assert(s);
642
643         if (!s->scope)
644                 return 0;
645
646         if (force || manager_shall_kill(s->manager, s->user->name)) {
647                 r = manager_stop_unit(s->manager, s->scope, &error, &job);
648                 if (r < 0) {
649                         log_error("Failed to stop session scope: %s", bus_error_message(&error, r));
650                         return r;
651                 }
652
653                 free(s->scope_job);
654                 s->scope_job = job;
655         } else {
656                 r = manager_abandon_scope(s->manager, s->scope, &error);
657                 if (r < 0) {
658                         log_error("Failed to abandon session scope: %s", bus_error_message(&error, r));
659                         return r;
660                 }
661         }
662
663         return 0;
664 }
665 #else
666 static int session_stop_cgroup(Session *s, bool force) {
667         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
668         int r;
669
670         assert(s);
671
672         if (force || manager_shall_kill(s->manager, s->user->name)) {
673                 r = session_kill(s, KILL_ALL, SIGTERM);
674                 if (r < 0)
675                         return r;
676         }
677
678         return 0;
679 }
680 #endif // 0
681
682 int session_stop(Session *s, bool force) {
683         int r;
684
685         assert(s);
686
687         if (!s->user)
688                 return -ESTALE;
689
690         s->timer_event_source = sd_event_source_unref(s->timer_event_source);
691
692         if (s->seat)
693                 seat_evict_position(s->seat, s);
694
695         /* We are going down, don't care about FIFOs anymore */
696         session_remove_fifo(s);
697
698         /* Kill cgroup */
699 #if 0 /// elogind does not start scopes, but sessions
700         r = session_stop_scope(s, force);
701 #else
702         r = session_stop_cgroup(s, force);
703 #endif // 0
704
705         s->stopping = true;
706
707         user_elect_display(s->user);
708
709         session_save(s);
710         user_save(s->user);
711
712         return r;
713 }
714
715 int session_finalize(Session *s) {
716         SessionDevice *sd;
717
718         assert(s);
719
720         if (!s->user)
721                 return -ESTALE;
722
723         if (s->started)
724                 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
725                            LOG_MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
726                            "SESSION_ID=%s", s->id,
727                            "USER_ID=%s", s->user->name,
728                            "LEADER="PID_FMT, s->leader,
729                            LOG_MESSAGE("Removed session %s.", s->id),
730                            NULL);
731
732         s->timer_event_source = sd_event_source_unref(s->timer_event_source);
733
734         if (s->seat)
735                 seat_evict_position(s->seat, s);
736
737         /* Kill session devices */
738         while ((sd = hashmap_first(s->devices)))
739                 session_device_free(sd);
740
741         (void) unlink(s->state_file);
742         session_add_to_gc_queue(s);
743         user_add_to_gc_queue(s->user);
744
745         if (s->started) {
746                 session_send_signal(s, false);
747                 s->started = false;
748         }
749
750         if (s->seat) {
751                 if (s->seat->active == s)
752                         seat_set_active(s->seat, NULL);
753
754                 seat_save(s->seat);
755                 seat_send_changed(s->seat, "Sessions", NULL);
756         }
757
758         user_save(s->user);
759         user_send_changed(s->user, "Sessions", "Display", NULL);
760
761         return 0;
762 }
763
764 #if 0 /// UNNEEDED by elogind
765 static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
766         Session *s = userdata;
767
768         assert(es);
769         assert(s);
770
771         session_stop(s, false);
772         return 0;
773 }
774 #endif // 0
775
776 int session_release(Session *s) {
777         assert(s);
778
779         if (!s->started || s->stopping)
780                 return 0;
781
782         if (s->timer_event_source)
783                 return 0;
784
785 #if 0 /// UNNEEDED by elogind
786         return sd_event_add_time(s->manager->event,
787                                  &s->timer_event_source,
788                                  CLOCK_MONOTONIC,
789                                  now(CLOCK_MONOTONIC) + RELEASE_USEC, 0,
790                                  release_timeout_callback, s);
791 #else
792         /* In systemd, session release is triggered by user jobs
793            dying.  In elogind we don't have that so go ahead and stop
794            now.  */
795         return session_stop(s, false);
796 #endif // 0
797 }
798
799 bool session_is_active(Session *s) {
800         assert(s);
801
802         if (!s->seat)
803                 return true;
804
805         return s->seat->active == s;
806 }
807
808 static int get_tty_atime(const char *tty, usec_t *atime) {
809         _cleanup_free_ char *p = NULL;
810         struct stat st;
811
812         assert(tty);
813         assert(atime);
814
815         if (!path_is_absolute(tty)) {
816                 p = strappend("/dev/", tty);
817                 if (!p)
818                         return -ENOMEM;
819
820                 tty = p;
821         } else if (!path_startswith(tty, "/dev/"))
822                 return -ENOENT;
823
824         if (lstat(tty, &st) < 0)
825                 return -errno;
826
827         *atime = timespec_load(&st.st_atim);
828         return 0;
829 }
830
831 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
832         _cleanup_free_ char *p = NULL;
833         int r;
834
835         assert(pid > 0);
836         assert(atime);
837
838         r = get_ctty(pid, NULL, &p);
839         if (r < 0)
840                 return r;
841
842         return get_tty_atime(p, atime);
843 }
844
845 int session_get_idle_hint(Session *s, dual_timestamp *t) {
846         usec_t atime = 0, n;
847         int r;
848
849         assert(s);
850
851         /* Explicit idle hint is set */
852         if (s->idle_hint) {
853                 if (t)
854                         *t = s->idle_hint_timestamp;
855
856                 return s->idle_hint;
857         }
858
859         /* Graphical sessions should really implement a real
860          * idle hint logic */
861         if (SESSION_TYPE_IS_GRAPHICAL(s->type))
862                 goto dont_know;
863
864         /* For sessions with an explicitly configured tty, let's check
865          * its atime */
866         if (s->tty) {
867                 r = get_tty_atime(s->tty, &atime);
868                 if (r >= 0)
869                         goto found_atime;
870         }
871
872         /* For sessions with a leader but no explicitly configured
873          * tty, let's check the controlling tty of the leader */
874         if (s->leader > 0) {
875                 r = get_process_ctty_atime(s->leader, &atime);
876                 if (r >= 0)
877                         goto found_atime;
878         }
879
880 dont_know:
881         if (t)
882                 *t = s->idle_hint_timestamp;
883
884         return 0;
885
886 found_atime:
887         if (t)
888                 dual_timestamp_from_realtime(t, atime);
889
890         n = now(CLOCK_REALTIME);
891
892         if (s->manager->idle_action_usec <= 0)
893                 return 0;
894
895         return atime + s->manager->idle_action_usec <= n;
896 }
897
898 void session_set_idle_hint(Session *s, bool b) {
899         assert(s);
900
901         if (s->idle_hint == b)
902                 return;
903
904         s->idle_hint = b;
905         dual_timestamp_get(&s->idle_hint_timestamp);
906
907         session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
908
909         if (s->seat)
910                 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
911
912         user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
913         manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
914 }
915
916 int session_get_locked_hint(Session *s) {
917         assert(s);
918
919         return s->locked_hint;
920 }
921
922 void session_set_locked_hint(Session *s, bool b) {
923         assert(s);
924
925         if (s->locked_hint == b)
926                 return;
927
928         s->locked_hint = b;
929
930         session_send_changed(s, "LockedHint", NULL);
931 }
932
933 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
934         Session *s = userdata;
935
936         assert(s);
937         assert(s->fifo_fd == fd);
938
939         /* EOF on the FIFO means the session died abnormally. */
940
941         session_remove_fifo(s);
942         session_stop(s, false);
943
944         return 1;
945 }
946
947 int session_create_fifo(Session *s) {
948         int r;
949
950         assert(s);
951
952         /* Create FIFO */
953         if (!s->fifo_path) {
954                 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
955                 if (r < 0)
956                         return r;
957
958                 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
959                         return -ENOMEM;
960
961                 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
962                         return -errno;
963         }
964
965         /* Open reading side */
966         if (s->fifo_fd < 0) {
967                 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
968                 if (s->fifo_fd < 0)
969                         return -errno;
970
971         }
972
973         if (!s->fifo_event_source) {
974                 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
975                 if (r < 0)
976                         return r;
977
978                 /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new
979                  * sessions). */
980                 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10);
981                 if (r < 0)
982                         return r;
983         }
984
985         /* Open writing side */
986         r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
987         if (r < 0)
988                 return -errno;
989
990         return r;
991 }
992
993 static void session_remove_fifo(Session *s) {
994         assert(s);
995
996         s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
997         s->fifo_fd = safe_close(s->fifo_fd);
998
999         if (s->fifo_path) {
1000                 unlink(s->fifo_path);
1001                 s->fifo_path = mfree(s->fifo_path);
1002         }
1003 }
1004
1005 bool session_check_gc(Session *s, bool drop_not_started) {
1006         assert(s);
1007
1008         if (drop_not_started && !s->started)
1009                 return false;
1010
1011         if (!s->user)
1012                 return false;
1013
1014         if (s->fifo_fd >= 0) {
1015                 if (pipe_eof(s->fifo_fd) <= 0)
1016                         return true;
1017         }
1018
1019 #if 0 /// elogind supports neither scopes nor jobs
1020         if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
1021                 return true;
1022
1023         if (s->scope && manager_unit_is_active(s->manager, s->scope))
1024                 return true;
1025 #endif // 0
1026
1027         return false;
1028 }
1029
1030 void session_add_to_gc_queue(Session *s) {
1031         assert(s);
1032
1033         if (s->in_gc_queue)
1034                 return;
1035
1036         LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
1037         s->in_gc_queue = true;
1038 }
1039
1040 SessionState session_get_state(Session *s) {
1041         assert(s);
1042
1043         /* always check closing first */
1044         if (s->stopping || s->timer_event_source)
1045                 return SESSION_CLOSING;
1046
1047 #if 0 /// elogind does not support systemd scope_jobs
1048         if (s->scope_job || s->fifo_fd < 0)
1049 #else
1050         if (s->fifo_fd < 0)
1051 #endif // 0
1052                 return SESSION_OPENING;
1053
1054         if (session_is_active(s))
1055                 return SESSION_ACTIVE;
1056
1057         return SESSION_ONLINE;
1058 }
1059
1060 int session_kill(Session *s, KillWho who, int signo) {
1061         assert(s);
1062
1063 #if 0 /// Without direct cgroup support, elogind can not kill sessions
1064         if (!s->scope)
1065                 return -ESRCH;
1066
1067         return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
1068 #else
1069         if (who == KILL_LEADER) {
1070                 if (s->leader <= 0)
1071                         return -ESRCH;
1072
1073                 /* FIXME: verify that leader is in cgroup?  */
1074
1075                 if (kill(s->leader, signo) < 0) {
1076                         return log_error_errno(errno, "Failed to kill process leader %d for session %s: %m", s->leader, s->id);
1077                 }
1078                 return 0;
1079         } else {
1080                 bool sigcont = false;
1081                 bool ignore_self = true;
1082                 bool rem = true;
1083                 return cg_kill_recursive (SYSTEMD_CGROUP_CONTROLLER, s->id, signo,
1084                                           sigcont, ignore_self, rem, NULL);
1085         }
1086 #endif // 0
1087 }
1088
1089 static int session_open_vt(Session *s) {
1090         char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
1091
1092         if (s->vtnr < 1)
1093                 return -ENODEV;
1094
1095         if (s->vtfd >= 0)
1096                 return s->vtfd;
1097
1098         sprintf(path, "/dev/tty%u", s->vtnr);
1099         s->vtfd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
1100         if (s->vtfd < 0)
1101                 return log_error_errno(s->vtfd, "cannot open VT %s of session %s: %m", path, s->id);
1102
1103         return s->vtfd;
1104 }
1105
1106 int session_prepare_vt(Session *s) {
1107         int vt, r;
1108         struct vt_mode mode = { 0 };
1109
1110         if (s->vtnr < 1)
1111                 return 0;
1112
1113         vt = session_open_vt(s);
1114         if (vt < 0)
1115                 return vt;
1116
1117         r = fchown(vt, s->user->uid, -1);
1118         if (r < 0) {
1119                 r = log_error_errno(errno,
1120                                     "Cannot change owner of /dev/tty%u: %m",
1121                                     s->vtnr);
1122                 goto error;
1123         }
1124
1125         r = ioctl(vt, KDSKBMODE, K_OFF);
1126         if (r < 0) {
1127                 r = log_error_errno(errno,
1128                                     "Cannot set K_OFF on /dev/tty%u: %m",
1129                                     s->vtnr);
1130                 goto error;
1131         }
1132
1133         r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
1134         if (r < 0) {
1135                 r = log_error_errno(errno,
1136                                     "Cannot set KD_GRAPHICS on /dev/tty%u: %m",
1137                                     s->vtnr);
1138                 goto error;
1139         }
1140
1141         /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1142          * So we need a dummy handler here which just acknowledges *all* VT
1143          * switch requests. */
1144         mode.mode = VT_PROCESS;
1145         mode.relsig = SIGRTMIN;
1146         mode.acqsig = SIGRTMIN + 1;
1147         r = ioctl(vt, VT_SETMODE, &mode);
1148         if (r < 0) {
1149                 r = log_error_errno(errno,
1150                                     "Cannot set VT_PROCESS on /dev/tty%u: %m",
1151                                     s->vtnr);
1152                 goto error;
1153         }
1154
1155         return 0;
1156
1157 error:
1158         session_restore_vt(s);
1159         return r;
1160 }
1161
1162 void session_restore_vt(Session *s) {
1163
1164         static const struct vt_mode mode = {
1165                 .mode = VT_AUTO,
1166         };
1167
1168         _cleanup_free_ char *utf8 = NULL;
1169         int vt, kb, old_fd;
1170
1171         /* We need to get a fresh handle to the virtual terminal,
1172          * since the old file-descriptor is potentially in a hung-up
1173          * state after the controlling process exited; we do a
1174          * little dance to avoid having the terminal be available
1175          * for reuse before we've cleaned it up.
1176          */
1177         old_fd = s->vtfd;
1178         s->vtfd = -1;
1179
1180         vt = session_open_vt(s);
1181         safe_close(old_fd);
1182
1183         if (vt < 0)
1184                 return;
1185
1186         (void) ioctl(vt, KDSETMODE, KD_TEXT);
1187
1188         if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
1189                 kb = K_UNICODE;
1190         else
1191                 kb = K_XLATE;
1192
1193         (void) ioctl(vt, KDSKBMODE, kb);
1194
1195         (void) ioctl(vt, VT_SETMODE, &mode);
1196         (void) fchown(vt, 0, (gid_t) -1);
1197
1198         s->vtfd = safe_close(s->vtfd);
1199 }
1200
1201 void session_leave_vt(Session *s) {
1202         int r;
1203
1204         assert(s);
1205
1206         /* This is called whenever we get a VT-switch signal from the kernel.
1207          * We acknowledge all of them unconditionally. Note that session are
1208          * free to overwrite those handlers and we only register them for
1209          * sessions with controllers. Legacy sessions are not affected.
1210          * However, if we switch from a non-legacy to a legacy session, we must
1211          * make sure to pause all device before acknowledging the switch. We
1212          * process the real switch only after we are notified via sysfs, so the
1213          * legacy session might have already started using the devices. If we
1214          * don't pause the devices before the switch, we might confuse the
1215          * session we switch to. */
1216
1217         if (s->vtfd < 0)
1218                 return;
1219
1220         session_device_pause_all(s);
1221         r = ioctl(s->vtfd, VT_RELDISP, 1);
1222         if (r < 0)
1223                 log_debug_errno(errno, "Cannot release VT of session %s: %m", s->id);
1224 }
1225
1226 bool session_is_controller(Session *s, const char *sender) {
1227         assert(s);
1228
1229         return streq_ptr(s->controller, sender);
1230 }
1231
1232 static void session_release_controller(Session *s, bool notify) {
1233         _cleanup_free_ char *name = NULL;
1234         SessionDevice *sd;
1235
1236         if (!s->controller)
1237                 return;
1238
1239         name = s->controller;
1240
1241         /* By resetting the controller before releasing the devices, we won't
1242          * send notification signals. This avoids sending useless notifications
1243          * if the controller is released on disconnects. */
1244         if (!notify)
1245                 s->controller = NULL;
1246
1247         while ((sd = hashmap_first(s->devices)))
1248                 session_device_free(sd);
1249
1250         s->controller = NULL;
1251         s->track = sd_bus_track_unref(s->track);
1252 }
1253
1254 static int on_bus_track(sd_bus_track *track, void *userdata) {
1255         Session *s = userdata;
1256
1257         assert(track);
1258         assert(s);
1259
1260         session_drop_controller(s);
1261
1262         return 0;
1263 }
1264
1265 int session_set_controller(Session *s, const char *sender, bool force) {
1266         _cleanup_free_ char *name = NULL;
1267         int r;
1268
1269         assert(s);
1270         assert(sender);
1271
1272         if (session_is_controller(s, sender))
1273                 return 0;
1274         if (s->controller && !force)
1275                 return -EBUSY;
1276
1277         name = strdup(sender);
1278         if (!name)
1279                 return -ENOMEM;
1280
1281         s->track = sd_bus_track_unref(s->track);
1282         r = sd_bus_track_new(s->manager->bus, &s->track, on_bus_track, s);
1283         if (r < 0)
1284                 return r;
1285
1286         r = sd_bus_track_add_name(s->track, name);
1287         if (r < 0)
1288                 return r;
1289
1290         /* When setting a session controller, we forcibly mute the VT and set
1291          * it into graphics-mode. Applications can override that by changing
1292          * VT state after calling TakeControl(). However, this serves as a good
1293          * default and well-behaving controllers can now ignore VTs entirely.
1294          * Note that we reset the VT on ReleaseControl() and if the controller
1295          * exits.
1296          * If logind crashes/restarts, we restore the controller during restart
1297          * or reset the VT in case it crashed/exited, too. */
1298         r = session_prepare_vt(s);
1299         if (r < 0) {
1300                 s->track = sd_bus_track_unref(s->track);
1301                 return r;
1302         }
1303
1304         session_release_controller(s, true);
1305         s->controller = name;
1306         name = NULL;
1307         session_save(s);
1308
1309         return 0;
1310 }
1311
1312 void session_drop_controller(Session *s) {
1313         assert(s);
1314
1315         if (!s->controller)
1316                 return;
1317
1318         s->track = sd_bus_track_unref(s->track);
1319         session_release_controller(s, false);
1320         session_save(s);
1321         session_restore_vt(s);
1322 }
1323
1324 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1325         [SESSION_OPENING] = "opening",
1326         [SESSION_ONLINE] = "online",
1327         [SESSION_ACTIVE] = "active",
1328         [SESSION_CLOSING] = "closing"
1329 };
1330
1331 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1332
1333 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1334         [SESSION_UNSPECIFIED] = "unspecified",
1335         [SESSION_TTY] = "tty",
1336         [SESSION_X11] = "x11",
1337         [SESSION_WAYLAND] = "wayland",
1338         [SESSION_MIR] = "mir",
1339         [SESSION_WEB] = "web",
1340 };
1341
1342 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1343
1344 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1345         [SESSION_USER] = "user",
1346         [SESSION_GREETER] = "greeter",
1347         [SESSION_LOCK_SCREEN] = "lock-screen",
1348         [SESSION_BACKGROUND] = "background"
1349 };
1350
1351 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1352
1353 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1354         [KILL_LEADER] = "leader",
1355         [KILL_ALL] = "all"
1356 };
1357
1358 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);