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