chiark / gitweb /
[4/5] Apply missing fixes from upstream
[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, "systemd-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
542                         free(s->scope_job);
543                         s->scope_job = job;
544                 }
545         }
546
547         if (s->scope)
548                 hashmap_put(s->manager->session_units, s->scope, s);
549
550         return 0;
551 }
552 #endif // 0
553
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
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 /// elogind does its own session management without systemd units,
591 /// slices and scopes
592 #if 0
593         r = session_start_scope(s);
594 #else
595         r = session_start_cgroup(s);
596 #endif // 0
597         if (r < 0)
598                 return r;
599
600         log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
601                    LOG_MESSAGE_ID(SD_MESSAGE_SESSION_START),
602                    "SESSION_ID=%s", s->id,
603                    "USER_ID=%s", s->user->name,
604                    "LEADER="PID_FMT, s->leader,
605                    LOG_MESSAGE("New session %s of user %s.", s->id, s->user->name),
606                    NULL);
607
608         if (!dual_timestamp_is_set(&s->timestamp))
609                 dual_timestamp_get(&s->timestamp);
610
611         if (s->seat)
612                 seat_read_active_vt(s->seat);
613
614         s->started = true;
615
616         user_elect_display(s->user);
617
618         /* Save data */
619         session_save(s);
620         user_save(s->user);
621         if (s->seat)
622                 seat_save(s->seat);
623
624         /* Send signals */
625         session_send_signal(s, true);
626         user_send_changed(s->user, "Sessions", "Display", NULL);
627         if (s->seat) {
628                 if (s->seat->active == s)
629                         seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
630                 else
631                         seat_send_changed(s->seat, "Sessions", NULL);
632         }
633
634         return 0;
635 }
636
637 /// UNNEEDED by elogind
638 #if 0
639 static int session_stop_scope(Session *s, bool force) {
640         _cleanup_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_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 /// elogind does not start scopes, but sessions
703 #if 0
704         r = session_stop_scope(s, force);
705 #else
706         r = session_stop_cgroup(s, force);
707 #endif // 0
708
709         s->stopping = true;
710
711         user_elect_display(s->user);
712
713         session_save(s);
714         user_save(s->user);
715
716         return r;
717 }
718
719 int session_finalize(Session *s) {
720         SessionDevice *sd;
721
722         assert(s);
723
724         if (!s->user)
725                 return -ESTALE;
726
727         if (s->started)
728                 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
729                            LOG_MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
730                            "SESSION_ID=%s", s->id,
731                            "USER_ID=%s", s->user->name,
732                            "LEADER="PID_FMT, s->leader,
733                            LOG_MESSAGE("Removed session %s.", s->id),
734                            NULL);
735
736         s->timer_event_source = sd_event_source_unref(s->timer_event_source);
737
738         if (s->seat)
739                 seat_evict_position(s->seat, s);
740
741         /* Kill session devices */
742         while ((sd = hashmap_first(s->devices)))
743                 session_device_free(sd);
744
745         (void) unlink(s->state_file);
746         session_add_to_gc_queue(s);
747         user_add_to_gc_queue(s->user);
748
749         if (s->started) {
750                 session_send_signal(s, false);
751                 s->started = false;
752         }
753
754         if (s->seat) {
755                 if (s->seat->active == s)
756                         seat_set_active(s->seat, NULL);
757
758                 seat_save(s->seat);
759                 seat_send_changed(s->seat, "Sessions", NULL);
760         }
761
762         user_save(s->user);
763         user_send_changed(s->user, "Sessions", "Display", NULL);
764
765         return 0;
766 }
767
768 /// UNNEEDED by elogind
769 #if 0
770 static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
771         Session *s = userdata;
772
773         assert(es);
774         assert(s);
775
776         session_stop(s, false);
777         return 0;
778 }
779 #endif // 0
780
781 int session_release(Session *s) {
782         assert(s);
783
784         if (!s->started || s->stopping)
785                 return 0;
786
787         if (s->timer_event_source)
788                 return 0;
789
790         /* In systemd, session release is triggered by user jobs
791            dying.  In elogind we don't have that so go ahead and stop
792            now.  */
793 #if 0
794         return sd_event_add_time(s->manager->event,
795                                  &s->timer_event_source,
796                                  CLOCK_MONOTONIC,
797                                  now(CLOCK_MONOTONIC) + RELEASE_USEC, 0,
798                                  release_timeout_callback, s);
799
800 #else
801         return session_stop(s, false);
802 #endif // 0
803 }
804
805 bool session_is_active(Session *s) {
806         assert(s);
807
808         if (!s->seat)
809                 return true;
810
811         return s->seat->active == s;
812 }
813
814 static int get_tty_atime(const char *tty, usec_t *atime) {
815         _cleanup_free_ char *p = NULL;
816         struct stat st;
817
818         assert(tty);
819         assert(atime);
820
821         if (!path_is_absolute(tty)) {
822                 p = strappend("/dev/", tty);
823                 if (!p)
824                         return -ENOMEM;
825
826                 tty = p;
827         } else if (!path_startswith(tty, "/dev/"))
828                 return -ENOENT;
829
830         if (lstat(tty, &st) < 0)
831                 return -errno;
832
833         *atime = timespec_load(&st.st_atim);
834         return 0;
835 }
836
837 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
838         _cleanup_free_ char *p = NULL;
839         int r;
840
841         assert(pid > 0);
842         assert(atime);
843
844         r = get_ctty(pid, NULL, &p);
845         if (r < 0)
846                 return r;
847
848         return get_tty_atime(p, atime);
849 }
850
851 int session_get_idle_hint(Session *s, dual_timestamp *t) {
852         usec_t atime = 0, n;
853         int r;
854
855         assert(s);
856
857         /* Explicit idle hint is set */
858         if (s->idle_hint) {
859                 if (t)
860                         *t = s->idle_hint_timestamp;
861
862                 return s->idle_hint;
863         }
864
865         /* Graphical sessions should really implement a real
866          * idle hint logic */
867         if (s->display)
868                 goto dont_know;
869
870         /* For sessions with an explicitly configured tty, let's check
871          * its atime */
872         if (s->tty) {
873                 r = get_tty_atime(s->tty, &atime);
874                 if (r >= 0)
875                         goto found_atime;
876         }
877
878         /* For sessions with a leader but no explicitly configured
879          * tty, let's check the controlling tty of the leader */
880         if (s->leader > 0) {
881                 r = get_process_ctty_atime(s->leader, &atime);
882                 if (r >= 0)
883                         goto found_atime;
884         }
885
886 dont_know:
887         if (t)
888                 *t = s->idle_hint_timestamp;
889
890         return 0;
891
892 found_atime:
893         if (t)
894                 dual_timestamp_from_realtime(t, atime);
895
896         n = now(CLOCK_REALTIME);
897
898         if (s->manager->idle_action_usec <= 0)
899                 return 0;
900
901         return atime + s->manager->idle_action_usec <= n;
902 }
903
904 void session_set_idle_hint(Session *s, bool b) {
905         assert(s);
906
907         if (s->idle_hint == b)
908                 return;
909
910         s->idle_hint = b;
911         dual_timestamp_get(&s->idle_hint_timestamp);
912
913         session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
914
915         if (s->seat)
916                 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
917
918         user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
919         manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
920 }
921
922 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
923         Session *s = userdata;
924
925         assert(s);
926         assert(s->fifo_fd == fd);
927
928         /* EOF on the FIFO means the session died abnormally. */
929
930         session_remove_fifo(s);
931         session_stop(s, false);
932
933         return 1;
934 }
935
936 int session_create_fifo(Session *s) {
937         int r;
938
939         assert(s);
940
941         /* Create FIFO */
942         if (!s->fifo_path) {
943                 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
944                 if (r < 0)
945                         return r;
946
947                 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
948                         return -ENOMEM;
949
950                 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
951                         return -errno;
952         }
953
954         /* Open reading side */
955         if (s->fifo_fd < 0) {
956                 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
957                 if (s->fifo_fd < 0)
958                         return -errno;
959
960         }
961
962         if (!s->fifo_event_source) {
963                 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
964                 if (r < 0)
965                         return r;
966
967                 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
968                 if (r < 0)
969                         return r;
970         }
971
972         /* Open writing side */
973         r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
974         if (r < 0)
975                 return -errno;
976
977         return r;
978 }
979
980 static void session_remove_fifo(Session *s) {
981         assert(s);
982
983         s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
984         s->fifo_fd = safe_close(s->fifo_fd);
985
986         if (s->fifo_path) {
987                 unlink(s->fifo_path);
988                 s->fifo_path = mfree(s->fifo_path);
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 (SYSTEMD_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 (SYSTEMD_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 = log_error_errno(errno,
1114                                     "Cannot change owner of /dev/tty%u: %m",
1115                                     s->vtnr);
1116                 goto error;
1117         }
1118
1119         r = ioctl(vt, KDSKBMODE, K_OFF);
1120         if (r < 0) {
1121                 r = log_error_errno(errno,
1122                                     "Cannot set K_OFF on /dev/tty%u: %m",
1123                                     s->vtnr);
1124                 goto error;
1125         }
1126
1127         r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
1128         if (r < 0) {
1129                 r = log_error_errno(errno,
1130                                     "Cannot set KD_GRAPHICS on /dev/tty%u: %m",
1131                                     s->vtnr);
1132                 goto error;
1133         }
1134
1135         /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1136          * So we need a dummy handler here which just acknowledges *all* VT
1137          * switch requests. */
1138         mode.mode = VT_PROCESS;
1139         mode.relsig = SIGRTMIN;
1140         mode.acqsig = SIGRTMIN + 1;
1141         r = ioctl(vt, VT_SETMODE, &mode);
1142         if (r < 0) {
1143                 r = log_error_errno(errno,
1144                                     "Cannot set VT_PROCESS on /dev/tty%u: %m",
1145                                     s->vtnr);
1146                 goto error;
1147         }
1148
1149         return 0;
1150
1151 error:
1152         session_restore_vt(s);
1153         return r;
1154 }
1155
1156 void session_restore_vt(Session *s) {
1157         _cleanup_free_ char *utf8 = NULL;
1158         int vt, kb = K_XLATE;
1159         struct vt_mode mode = { 0 };
1160
1161         /* We need to get a fresh handle to the virtual terminal,
1162          * since the old file-descriptor is potentially in a hung-up
1163          * state after the controlling process exited; we do a
1164          * little dance to avoid having the terminal be available
1165          * for reuse before we've cleaned it up.
1166          */
1167         int old_fd = s->vtfd;
1168         s->vtfd = -1;
1169
1170         vt = session_open_vt(s);
1171         safe_close(old_fd);
1172
1173         if (vt < 0)
1174                 return;
1175
1176         (void) ioctl(vt, KDSETMODE, KD_TEXT);
1177
1178         if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
1179                 kb = K_UNICODE;
1180
1181         (void) ioctl(vt, KDSKBMODE, kb);
1182
1183         mode.mode = VT_AUTO;
1184         (void) ioctl(vt, VT_SETMODE, &mode);
1185
1186         fchown(vt, 0, -1);
1187
1188         s->vtfd = safe_close(s->vtfd);
1189 }
1190
1191 void session_leave_vt(Session *s) {
1192         int r;
1193
1194         assert(s);
1195
1196         /* This is called whenever we get a VT-switch signal from the kernel.
1197          * We acknowledge all of them unconditionally. Note that session are
1198          * free to overwrite those handlers and we only register them for
1199          * sessions with controllers. Legacy sessions are not affected.
1200          * However, if we switch from a non-legacy to a legacy session, we must
1201          * make sure to pause all device before acknowledging the switch. We
1202          * process the real switch only after we are notified via sysfs, so the
1203          * legacy session might have already started using the devices. If we
1204          * don't pause the devices before the switch, we might confuse the
1205          * session we switch to. */
1206
1207         if (s->vtfd < 0)
1208                 return;
1209
1210         session_device_pause_all(s);
1211         r = ioctl(s->vtfd, VT_RELDISP, 1);
1212         if (r < 0)
1213                 log_debug_errno(errno, "Cannot release VT of session %s: %m", s->id);
1214 }
1215
1216 bool session_is_controller(Session *s, const char *sender) {
1217         assert(s);
1218
1219         return streq_ptr(s->controller, sender);
1220 }
1221
1222 static void session_release_controller(Session *s, bool notify) {
1223         _cleanup_free_ char *name = NULL;
1224         SessionDevice *sd;
1225
1226         if (!s->controller)
1227                 return;
1228
1229         name = s->controller;
1230
1231         /* By resetting the controller before releasing the devices, we won't
1232          * send notification signals. This avoids sending useless notifications
1233          * if the controller is released on disconnects. */
1234         if (!notify)
1235                 s->controller = NULL;
1236
1237         while ((sd = hashmap_first(s->devices)))
1238                 session_device_free(sd);
1239
1240         s->controller = NULL;
1241         s->track = sd_bus_track_unref(s->track);
1242 }
1243
1244 static int on_bus_track(sd_bus_track *track, void *userdata) {
1245         Session *s = userdata;
1246
1247         assert(track);
1248         assert(s);
1249
1250         session_drop_controller(s);
1251
1252         return 0;
1253 }
1254
1255 int session_set_controller(Session *s, const char *sender, bool force) {
1256         _cleanup_free_ char *name = NULL;
1257         int r;
1258
1259         assert(s);
1260         assert(sender);
1261
1262         if (session_is_controller(s, sender))
1263                 return 0;
1264         if (s->controller && !force)
1265                 return -EBUSY;
1266
1267         name = strdup(sender);
1268         if (!name)
1269                 return -ENOMEM;
1270
1271         s->track = sd_bus_track_unref(s->track);
1272         r = sd_bus_track_new(s->manager->bus, &s->track, on_bus_track, s);
1273         if (r < 0)
1274                 return r;
1275
1276         r = sd_bus_track_add_name(s->track, name);
1277         if (r < 0)
1278                 return r;
1279
1280         /* When setting a session controller, we forcibly mute the VT and set
1281          * it into graphics-mode. Applications can override that by changing
1282          * VT state after calling TakeControl(). However, this serves as a good
1283          * default and well-behaving controllers can now ignore VTs entirely.
1284          * Note that we reset the VT on ReleaseControl() and if the controller
1285          * exits.
1286          * If logind crashes/restarts, we restore the controller during restart
1287          * or reset the VT in case it crashed/exited, too. */
1288         r = session_prepare_vt(s);
1289         if (r < 0) {
1290                 s->track = sd_bus_track_unref(s->track);
1291                 return r;
1292         }
1293
1294         session_release_controller(s, true);
1295         s->controller = name;
1296         name = NULL;
1297         session_save(s);
1298
1299         return 0;
1300 }
1301
1302 void session_drop_controller(Session *s) {
1303         assert(s);
1304
1305         if (!s->controller)
1306                 return;
1307
1308         s->track = sd_bus_track_unref(s->track);
1309         session_release_controller(s, false);
1310         session_save(s);
1311         session_restore_vt(s);
1312 }
1313
1314 static const char* const session_state_table[_SESSION_STATE_MAX] = {
1315         [SESSION_OPENING] = "opening",
1316         [SESSION_ONLINE] = "online",
1317         [SESSION_ACTIVE] = "active",
1318         [SESSION_CLOSING] = "closing"
1319 };
1320
1321 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1322
1323 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1324         [SESSION_UNSPECIFIED] = "unspecified",
1325         [SESSION_TTY] = "tty",
1326         [SESSION_X11] = "x11",
1327         [SESSION_WAYLAND] = "wayland",
1328         [SESSION_MIR] = "mir",
1329         [SESSION_WEB] = "web",
1330 };
1331
1332 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1333
1334 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1335         [SESSION_USER] = "user",
1336         [SESSION_GREETER] = "greeter",
1337         [SESSION_LOCK_SCREEN] = "lock-screen",
1338         [SESSION_BACKGROUND] = "background"
1339 };
1340
1341 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1342
1343 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1344         [KILL_LEADER] = "leader",
1345         [KILL_ALL] = "all"
1346 };
1347
1348 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);