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