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