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