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