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