chiark / gitweb /
logind: add infrastructure to keep track of machines, and move to slices
[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 <string.h>
24 #include <unistd.h>
25 #include <sys/epoll.h>
26 #include <fcntl.h>
27
28 #include "systemd/sd-id128.h"
29 #include "systemd/sd-messages.h"
30 #include "strv.h"
31 #include "util.h"
32 #include "mkdir.h"
33 #include "path-util.h"
34 #include "cgroup-util.h"
35 #include "logind-session.h"
36 #include "fileio.h"
37
38 Session* session_new(Manager *m, const char *id) {
39         Session *s;
40
41         assert(m);
42         assert(id);
43
44         s = new0(Session, 1);
45         if (!s)
46                 return NULL;
47
48         s->state_file = strappend("/run/systemd/sessions/", id);
49         if (!s->state_file) {
50                 free(s);
51                 return NULL;
52         }
53
54         s->id = path_get_file_name(s->state_file);
55
56         if (hashmap_put(m->sessions, s->id, s) < 0) {
57                 free(s->state_file);
58                 free(s);
59                 return NULL;
60         }
61
62         s->manager = m;
63         s->fifo_fd = -1;
64
65         return s;
66 }
67
68 void session_free(Session *s) {
69         assert(s);
70
71         if (s->in_gc_queue)
72                 LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
73
74         if (s->user) {
75                 LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
76
77                 if (s->user->display == s)
78                         s->user->display = NULL;
79         }
80
81         if (s->seat) {
82                 if (s->seat->active == s)
83                         s->seat->active = NULL;
84
85                 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
86         }
87
88         if (s->cgroup_path)
89                 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
90
91         free(s->cgroup_path);
92         strv_free(s->controllers);
93
94         free(s->tty);
95         free(s->display);
96         free(s->remote_host);
97         free(s->remote_user);
98         free(s->service);
99         free(s->slice);
100
101         hashmap_remove(s->manager->sessions, s->id);
102         session_remove_fifo(s);
103
104         free(s->state_file);
105         free(s);
106 }
107
108 void session_set_user(Session *s, User *u) {
109         assert(s);
110         assert(!s->user);
111
112         s->user = u;
113         LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
114 }
115
116 int session_save(Session *s) {
117         _cleanup_fclose_ FILE *f = NULL;
118         _cleanup_free_ char *temp_path = NULL;
119         int r = 0;
120
121         assert(s);
122
123         if (!s->user)
124                 return -ESTALE;
125
126         if (!s->started)
127                 return 0;
128
129         r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
130         if (r < 0)
131                 goto finish;
132
133         r = fopen_temporary(s->state_file, &f, &temp_path);
134         if (r < 0)
135                 goto finish;
136
137         assert(s->user);
138
139         fchmod(fileno(f), 0644);
140
141         fprintf(f,
142                 "# This is private data. Do not parse.\n"
143                 "UID=%lu\n"
144                 "USER=%s\n"
145                 "ACTIVE=%i\n"
146                 "STATE=%s\n"
147                 "REMOTE=%i\n"
148                 "KILL_PROCESSES=%i\n",
149                 (unsigned long) s->user->uid,
150                 s->user->name,
151                 session_is_active(s),
152                 session_state_to_string(session_get_state(s)),
153                 s->remote,
154                 s->kill_processes);
155
156         if (s->type >= 0)
157                 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
158
159         if (s->class >= 0)
160                 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
161
162         if (s->cgroup_path)
163                 fprintf(f, "CGROUP=%s\n", s->cgroup_path);
164
165         if (s->fifo_path)
166                 fprintf(f, "FIFO=%s\n", s->fifo_path);
167
168         if (s->seat)
169                 fprintf(f, "SEAT=%s\n", s->seat->id);
170
171         if (s->tty)
172                 fprintf(f, "TTY=%s\n", s->tty);
173
174         if (s->display)
175                 fprintf(f, "DISPLAY=%s\n", s->display);
176
177         if (s->remote_host)
178                 fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
179
180         if (s->remote_user)
181                 fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
182
183         if (s->service)
184                 fprintf(f, "SERVICE=%s\n", s->service);
185
186         if (s->seat)
187                 fprintf(f, "SLICE=%s\n", s->slice);
188
189         if (s->seat && seat_can_multi_session(s->seat))
190                 fprintf(f, "VTNR=%i\n", s->vtnr);
191
192         if (s->leader > 0)
193                 fprintf(f, "LEADER=%lu\n", (unsigned long) s->leader);
194
195         if (s->audit_id > 0)
196                 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
197
198         if (dual_timestamp_is_set(&s->timestamp))
199                 fprintf(f,
200                         "REALTIME=%llu\n"
201                         "MONOTONIC=%llu\n",
202                         (unsigned long long) s->timestamp.realtime,
203                         (unsigned long long) s->timestamp.monotonic);
204
205         fflush(f);
206
207         if (ferror(f) || rename(temp_path, s->state_file) < 0) {
208                 r = -errno;
209                 unlink(s->state_file);
210                 unlink(temp_path);
211         }
212
213 finish:
214         if (r < 0)
215                 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
216
217         return r;
218 }
219
220 int session_load(Session *s) {
221         _cleanup_free_ char *remote = NULL,
222                 *kill_processes = NULL,
223                 *seat = NULL,
224                 *vtnr = NULL,
225                 *leader = NULL,
226                 *audit_id = NULL,
227                 *type = NULL,
228                 *class = NULL,
229                 *uid = NULL,
230                 *realtime = NULL,
231                 *monotonic = NULL;
232
233         int k, r;
234
235         assert(s);
236
237         r = parse_env_file(s->state_file, NEWLINE,
238                            "REMOTE",         &remote,
239                            "KILL_PROCESSES", &kill_processes,
240                            "CGROUP",         &s->cgroup_path,
241                            "FIFO",           &s->fifo_path,
242                            "SEAT",           &seat,
243                            "TTY",            &s->tty,
244                            "DISPLAY",        &s->display,
245                            "REMOTE_HOST",    &s->remote_host,
246                            "REMOTE_USER",    &s->remote_user,
247                            "SERVICE",        &s->service,
248                            "SLICE",          &s->slice,
249                            "VTNR",           &vtnr,
250                            "LEADER",         &leader,
251                            "TYPE",           &type,
252                            "CLASS",          &class,
253                            "UID",            &uid,
254                            "REALTIME",       &realtime,
255                            "MONOTONIC",      &monotonic,
256                            NULL);
257
258         if (r < 0) {
259                 log_error("Failed to read %s: %s", s->state_file, strerror(-r));
260                 return r;
261         }
262
263         if (!s->user) {
264                 uid_t u;
265                 User *user;
266
267                 if (!uid) {
268                         log_error("UID not specified for session %s", s->id);
269                         return -ENOENT;
270                 }
271
272                 r = parse_uid(uid, &u);
273                 if (r < 0)  {
274                         log_error("Failed to parse UID value %s for session %s.", uid, s->id);
275                         return r;
276                 }
277
278                 user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
279                 if (!user) {
280                         log_error("User of session %s not known.", s->id);
281                         return -ENOENT;
282                 }
283
284                 session_set_user(s, user);
285         }
286
287         if (remote) {
288                 k = parse_boolean(remote);
289                 if (k >= 0)
290                         s->remote = k;
291         }
292
293         if (kill_processes) {
294                 k = parse_boolean(kill_processes);
295                 if (k >= 0)
296                         s->kill_processes = k;
297         }
298
299         if (seat && !s->seat) {
300                 Seat *o;
301
302                 o = hashmap_get(s->manager->seats, seat);
303                 if (o)
304                         seat_attach_session(o, s);
305         }
306
307         if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
308                 int v;
309
310                 k = safe_atoi(vtnr, &v);
311                 if (k >= 0 && v >= 1)
312                         s->vtnr = v;
313         }
314
315         if (leader) {
316                 k = parse_pid(leader, &s->leader);
317                 if (k >= 0)
318                         audit_session_from_pid(s->leader, &s->audit_id);
319         }
320
321         if (type) {
322                 SessionType t;
323
324                 t = session_type_from_string(type);
325                 if (t >= 0)
326                         s->type = t;
327         }
328
329         if (class) {
330                 SessionClass c;
331
332                 c = session_class_from_string(class);
333                 if (c >= 0)
334                         s->class = c;
335         }
336
337         if (s->fifo_path) {
338                 int fd;
339
340                 /* If we open an unopened pipe for reading we will not
341                    get an EOF. to trigger an EOF we hence open it for
342                    reading, but close it right-away which then will
343                    trigger the EOF. */
344
345                 fd = session_create_fifo(s);
346                 if (fd >= 0)
347                         close_nointr_nofail(fd);
348         }
349
350         if (realtime) {
351                 unsigned long long l;
352                 if (sscanf(realtime, "%llu", &l) > 0)
353                         s->timestamp.realtime = l;
354         }
355
356         if (monotonic) {
357                 unsigned long long l;
358                 if (sscanf(monotonic, "%llu", &l) > 0)
359                         s->timestamp.monotonic = l;
360         }
361
362         return r;
363 }
364
365 int session_activate(Session *s) {
366         int r;
367
368         assert(s);
369         assert(s->user);
370
371         if (s->vtnr < 0)
372                 return -ENOTSUP;
373
374         if (!s->seat)
375                 return -ENOTSUP;
376
377         if (s->seat->active == s)
378                 return 0;
379
380         assert(seat_is_vtconsole(s->seat));
381
382         r = chvt(s->vtnr);
383         if (r < 0)
384                 return r;
385
386         return seat_set_active(s->seat, s);
387 }
388
389 static int session_link_x11_socket(Session *s) {
390         char *t, *f, *c;
391         size_t k;
392
393         assert(s);
394         assert(s->user);
395         assert(s->user->runtime_path);
396
397         if (s->user->display)
398                 return 0;
399
400         if (!s->display || !display_is_local(s->display))
401                 return 0;
402
403         k = strspn(s->display+1, "0123456789");
404         f = new(char, sizeof("/tmp/.X11-unix/X") + k);
405         if (!f)
406                 return log_oom();
407
408         c = stpcpy(f, "/tmp/.X11-unix/X");
409         memcpy(c, s->display+1, k);
410         c[k] = 0;
411
412         if (access(f, F_OK) < 0) {
413                 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
414                 free(f);
415                 return -ENOENT;
416         }
417
418         /* Note that this cannot be in a subdir to avoid
419          * vulnerabilities since we are privileged but the runtime
420          * path is owned by the user */
421
422         t = strappend(s->user->runtime_path, "/X11-display");
423         if (!t) {
424                 free(f);
425                 return log_oom();
426         }
427
428         if (link(f, t) < 0) {
429                 if (errno == EEXIST) {
430                         unlink(t);
431
432                         if (link(f, t) >= 0)
433                                 goto done;
434                 }
435
436                 if (symlink(f, t) < 0) {
437
438                         if (errno == EEXIST) {
439                                 unlink(t);
440
441                                 if (symlink(f, t) >= 0)
442                                         goto done;
443                         }
444
445                         log_error("Failed to link %s to %s: %m", f, t);
446                         free(f);
447                         free(t);
448                         return -errno;
449                 }
450         }
451
452 done:
453         log_info("Linked %s to %s.", f, t);
454         free(f);
455         free(t);
456
457         s->user->display = s;
458
459         return 0;
460 }
461
462 static int session_create_one_group(Session *s, const char *controller, const char *path) {
463         int r;
464
465         assert(s);
466         assert(s->user);
467         assert(path);
468
469         if (s->leader > 0)
470                 r = cg_create_and_attach(controller, path, s->leader);
471         else
472                 r = -EINVAL;
473
474         if (r < 0) {
475                 r = cg_create(controller, path, NULL);
476                 if (r < 0)
477                         return r;
478         }
479
480         r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid, -1);
481         if (r >= 0)
482                 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
483
484         return r;
485 }
486
487 static int session_create_cgroup(Session *s) {
488         char **k;
489         int r;
490
491         assert(s);
492         assert(s->user);
493         assert(s->user->cgroup_path);
494
495         if (!s->cgroup_path) {
496                 _cleanup_free_ char *name = NULL, *escaped = NULL;
497
498                 name = strappend(s->id, ".session");
499                 if (!name)
500                         return log_oom();
501
502                 escaped = cg_escape(name);
503                 if (!escaped)
504                         return log_oom();
505
506                 if (s->slice) {
507                         _cleanup_free_ char *slice = NULL;
508
509                         r = cg_slice_to_path(s->slice, &slice);
510                         if (r < 0)
511                                 return r;
512
513                         s->cgroup_path = strjoin(s->manager->cgroup_root, "/", slice, "/", escaped, NULL);
514                 } else
515                         s->cgroup_path = strjoin(s->user->cgroup_path, "/", escaped, NULL);
516
517                 if (!s->cgroup_path)
518                         return log_oom();
519         }
520
521         if (!s->slice) {
522                 s->slice = strdup(s->user->slice);
523                 if (!s->slice)
524                         return log_oom();
525         }
526
527         r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
528         if (r < 0) {
529                 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", s->cgroup_path, strerror(-r));
530                 return r;
531         }
532
533         STRV_FOREACH(k, s->controllers) {
534
535                 if (strv_contains(s->reset_controllers, *k))
536                         continue;
537
538                 r = session_create_one_group(s, *k, s->cgroup_path);
539                 if (r < 0)
540                         log_warning("Failed to create %s:%s: %s", *k, s->cgroup_path, strerror(-r));
541         }
542
543         STRV_FOREACH(k, s->manager->controllers) {
544
545                 if (strv_contains(s->reset_controllers, *k) ||
546                     strv_contains(s->manager->reset_controllers, *k) ||
547                     strv_contains(s->controllers, *k))
548                         continue;
549
550                 r = session_create_one_group(s, *k, s->cgroup_path);
551                 if (r < 0)
552                         log_warning("Failed to create %s:%s: %s", *k, s->cgroup_path, strerror(-r));
553         }
554
555         if (s->leader > 0) {
556
557                 STRV_FOREACH(k, s->reset_controllers) {
558                         r = cg_attach(*k, "/", s->leader);
559                         if (r < 0)
560                                 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
561
562                 }
563
564                 STRV_FOREACH(k, s->manager->reset_controllers) {
565
566                         if (strv_contains(s->reset_controllers, *k) ||
567                             strv_contains(s->controllers, *k))
568                                 continue;
569
570                         r = cg_attach(*k, "/", s->leader);
571                         if (r < 0)
572                                 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
573                 }
574         }
575
576         r = hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
577         if (r < 0)
578                 log_warning("Failed to create mapping between cgroup and session");
579
580         return 0;
581 }
582
583 int session_start(Session *s) {
584         int r;
585
586         assert(s);
587
588         if (!s->user)
589                 return -ESTALE;
590
591         if (s->started)
592                 return 0;
593
594         r = user_start(s->user);
595         if (r < 0)
596                 return r;
597
598         log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
599                    MESSAGE_ID(SD_MESSAGE_SESSION_START),
600                    "SESSION_ID=%s", s->id,
601                    "USER_ID=%s", s->user->name,
602                    "LEADER=%lu", (unsigned long) s->leader,
603                    "MESSAGE=New session %s of user %s.", s->id, s->user->name,
604                    NULL);
605
606         /* Create cgroup */
607         r = session_create_cgroup(s);
608         if (r < 0)
609                 return r;
610
611         /* Create X11 symlink */
612         session_link_x11_socket(s);
613
614         if (!dual_timestamp_is_set(&s->timestamp))
615                 dual_timestamp_get(&s->timestamp);
616
617         if (s->seat)
618                 seat_read_active_vt(s->seat);
619
620         s->started = true;
621
622         /* Save session data */
623         session_save(s);
624         user_save(s->user);
625
626         session_send_signal(s, true);
627
628         if (s->seat) {
629                 seat_save(s->seat);
630
631                 if (s->seat->active == s)
632                         seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
633                 else
634                         seat_send_changed(s->seat, "Sessions\0");
635         }
636
637         user_send_changed(s->user, "Sessions\0");
638
639         return 0;
640 }
641
642 static bool session_shall_kill(Session *s) {
643         assert(s);
644
645         if (!s->kill_processes)
646                 return false;
647
648         if (strv_contains(s->manager->kill_exclude_users, s->user->name))
649                 return false;
650
651         if (strv_isempty(s->manager->kill_only_users))
652                 return true;
653
654         return strv_contains(s->manager->kill_only_users, s->user->name);
655 }
656
657 static int session_terminate_cgroup(Session *s) {
658         int r;
659         char **k;
660
661         assert(s);
662
663         if (!s->cgroup_path)
664                 return 0;
665
666         cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
667
668         if (session_shall_kill(s)) {
669
670                 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
671                 if (r < 0)
672                         log_error("Failed to kill session cgroup: %s", strerror(-r));
673
674         } else {
675                 if (s->leader > 0) {
676                         Session *t;
677
678                         /* We still send a HUP to the leader process,
679                          * even if we are not supposed to kill the
680                          * whole cgroup. But let's first check the
681                          * leader still exists and belongs to our
682                          * session... */
683
684                         r = manager_get_session_by_pid(s->manager, s->leader, &t);
685                         if (r > 0 && t == s) {
686                                 kill(s->leader, SIGTERM); /* for normal processes */
687                                 kill(s->leader, SIGHUP);  /* for shells */
688                                 kill(s->leader, SIGCONT); /* in case they are stopped */
689                         }
690                 }
691
692                 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
693                 if (r < 0)
694                         log_error("Failed to check session cgroup: %s", strerror(-r));
695                 else if (r > 0) {
696                         r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
697                         if (r < 0)
698                                 log_error("Failed to delete session cgroup: %s", strerror(-r));
699                 }
700         }
701
702         STRV_FOREACH(k, s->user->manager->controllers)
703                 cg_trim(*k, s->cgroup_path, true);
704
705         hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
706
707         free(s->cgroup_path);
708         s->cgroup_path = NULL;
709
710         return 0;
711 }
712
713 static int session_unlink_x11_socket(Session *s) {
714         char *t;
715         int r;
716
717         assert(s);
718         assert(s->user);
719
720         if (s->user->display != s)
721                 return 0;
722
723         s->user->display = NULL;
724
725         t = strappend(s->user->runtime_path, "/X11-display");
726         if (!t)
727                 return log_oom();
728
729         r = unlink(t);
730         free(t);
731
732         return r < 0 ? -errno : 0;
733 }
734
735 int session_stop(Session *s) {
736         int r = 0, k;
737
738         assert(s);
739
740         if (!s->user)
741                 return -ESTALE;
742
743         if (s->started)
744                 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
745                            MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
746                            "SESSION_ID=%s", s->id,
747                            "USER_ID=%s", s->user->name,
748                            "LEADER=%lu", (unsigned long) s->leader,
749                            "MESSAGE=Removed session %s.", s->id,
750                            NULL);
751
752         /* Kill cgroup */
753         k = session_terminate_cgroup(s);
754         if (k < 0)
755                 r = k;
756
757         /* Remove X11 symlink */
758         session_unlink_x11_socket(s);
759
760         unlink(s->state_file);
761         session_add_to_gc_queue(s);
762         user_add_to_gc_queue(s->user);
763
764         if (s->started)
765                 session_send_signal(s, false);
766
767         s->started = false;
768
769         if (s->seat) {
770                 if (s->seat->active == s)
771                         seat_set_active(s->seat, NULL);
772
773                 seat_send_changed(s->seat, "Sessions\0");
774                 seat_save(s->seat);
775         }
776
777         user_send_changed(s->user, "Sessions\0");
778         user_save(s->user);
779
780         return r;
781 }
782
783 bool session_is_active(Session *s) {
784         assert(s);
785
786         if (!s->seat)
787                 return true;
788
789         return s->seat->active == s;
790 }
791
792 static int get_tty_atime(const char *tty, usec_t *atime) {
793         _cleanup_free_ char *p = NULL;
794         struct stat st;
795
796         assert(tty);
797         assert(atime);
798
799         if (!path_is_absolute(tty)) {
800                 p = strappend("/dev/", tty);
801                 if (!p)
802                         return -ENOMEM;
803
804                 tty = p;
805         } else if (!path_startswith(tty, "/dev/"))
806                 return -ENOENT;
807
808         if (lstat(tty, &st) < 0)
809                 return -errno;
810
811         *atime = timespec_load(&st.st_atim);
812         return 0;
813 }
814
815 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
816         _cleanup_free_ char *p = NULL;
817         int r;
818
819         assert(pid > 0);
820         assert(atime);
821
822         r = get_ctty(pid, NULL, &p);
823         if (r < 0)
824                 return r;
825
826         return get_tty_atime(p, atime);
827 }
828
829 int session_get_idle_hint(Session *s, dual_timestamp *t) {
830         usec_t atime = 0, n;
831         int r;
832
833         assert(s);
834
835         /* Explicit idle hint is set */
836         if (s->idle_hint) {
837                 if (t)
838                         *t = s->idle_hint_timestamp;
839
840                 return s->idle_hint;
841         }
842
843         /* Graphical sessions should really implement a real
844          * idle hint logic */
845         if (s->display)
846                 goto dont_know;
847
848         /* For sessions with an explicitly configured tty, let's check
849          * its atime */
850         if (s->tty) {
851                 r = get_tty_atime(s->tty, &atime);
852                 if (r >= 0)
853                         goto found_atime;
854         }
855
856         /* For sessions with a leader but no explicitly configured
857          * tty, let's check the controlling tty of the leader */
858         if (s->leader > 0) {
859                 r = get_process_ctty_atime(s->leader, &atime);
860                 if (r >= 0)
861                         goto found_atime;
862         }
863
864         /* For other TTY sessions, let's find the most recent atime of
865          * the ttys of any of the processes of the session */
866         if (s->cgroup_path) {
867                 _cleanup_fclose_ FILE *f = NULL;
868
869                 if (cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &f) >= 0) {
870                         pid_t pid;
871
872                         atime = 0;
873                         while (cg_read_pid(f, &pid) > 0) {
874                                 usec_t a;
875
876                                 if (get_process_ctty_atime(pid, &a) >= 0)
877                                         if (atime == 0 || atime < a)
878                                                 atime = a;
879                         }
880
881                         if (atime != 0)
882                                 goto found_atime;
883                 }
884         }
885
886 dont_know:
887         if (t)
888                 *t = s->idle_hint_timestamp;
889
890         return 0;
891
892 found_atime:
893         if (t)
894                 dual_timestamp_from_realtime(t, atime);
895
896         n = now(CLOCK_REALTIME);
897
898         if (s->manager->idle_action_usec <= 0)
899                 return 0;
900
901         return atime + s->manager->idle_action_usec <= n;
902 }
903
904 void session_set_idle_hint(Session *s, bool b) {
905         assert(s);
906
907         if (s->idle_hint == b)
908                 return;
909
910         s->idle_hint = b;
911         dual_timestamp_get(&s->idle_hint_timestamp);
912
913         session_send_changed(s,
914                              "IdleHint\0"
915                              "IdleSinceHint\0"
916                              "IdleSinceHintMonotonic\0");
917
918         if (s->seat)
919                 seat_send_changed(s->seat,
920                                   "IdleHint\0"
921                                   "IdleSinceHint\0"
922                                   "IdleSinceHintMonotonic\0");
923
924         user_send_changed(s->user,
925                           "IdleHint\0"
926                           "IdleSinceHint\0"
927                           "IdleSinceHintMonotonic\0");
928
929         manager_send_changed(s->manager,
930                              "IdleHint\0"
931                              "IdleSinceHint\0"
932                              "IdleSinceHintMonotonic\0");
933 }
934
935 int session_create_fifo(Session *s) {
936         int r;
937
938         assert(s);
939
940         /* Create FIFO */
941         if (!s->fifo_path) {
942                 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
943                 if (r < 0)
944                         return r;
945
946                 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
947                         return -ENOMEM;
948
949                 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
950                         return -errno;
951         }
952
953         /* Open reading side */
954         if (s->fifo_fd < 0) {
955                 struct epoll_event ev = {};
956
957                 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
958                 if (s->fifo_fd < 0)
959                         return -errno;
960
961                 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
962                 if (r < 0)
963                         return r;
964
965                 ev.events = 0;
966                 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
967
968                 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
969                         return -errno;
970         }
971
972         /* Open writing side */
973         r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
974         if (r < 0)
975                 return -errno;
976
977         return r;
978 }
979
980 void session_remove_fifo(Session *s) {
981         assert(s);
982
983         if (s->fifo_fd >= 0) {
984                 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
985                 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
986                 close_nointr_nofail(s->fifo_fd);
987                 s->fifo_fd = -1;
988
989                 session_save(s);
990                 user_save(s->user);
991         }
992
993         if (s->fifo_path) {
994                 unlink(s->fifo_path);
995                 free(s->fifo_path);
996                 s->fifo_path = NULL;
997         }
998 }
999
1000 int session_check_gc(Session *s, bool drop_not_started) {
1001         int r;
1002
1003         assert(s);
1004
1005         if (drop_not_started && !s->started)
1006                 return 0;
1007
1008         if (!s->user)
1009                 return 0;
1010
1011         if (s->fifo_fd >= 0) {
1012
1013                 r = pipe_eof(s->fifo_fd);
1014                 if (r < 0)
1015                         return r;
1016
1017                 if (r == 0)
1018                         return 1;
1019         }
1020
1021         if (s->cgroup_path) {
1022
1023                 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
1024                 if (r < 0)
1025                         return r;
1026
1027                 if (r <= 0)
1028                         return 1;
1029         }
1030
1031         return 0;
1032 }
1033
1034 void session_add_to_gc_queue(Session *s) {
1035         assert(s);
1036
1037         if (s->in_gc_queue)
1038                 return;
1039
1040         LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
1041         s->in_gc_queue = true;
1042 }
1043
1044 SessionState session_get_state(Session *s) {
1045         assert(s);
1046
1047         if (s->fifo_fd < 0)
1048                 return SESSION_CLOSING;
1049
1050         if (session_is_active(s))
1051                 return SESSION_ACTIVE;
1052
1053         return SESSION_ONLINE;
1054 }
1055
1056 int session_kill(Session *s, KillWho who, int signo) {
1057         _cleanup_set_free_ Set *pid_set = NULL;
1058         int r = 0;
1059
1060         assert(s);
1061
1062         if (!s->cgroup_path)
1063                 return -ESRCH;
1064
1065         if (s->leader <= 0 && who == KILL_LEADER)
1066                 return -ESRCH;
1067
1068         if (s->leader > 0)
1069                 if (kill(s->leader, signo) < 0)
1070                         r = -errno;
1071
1072         if (who == KILL_ALL) {
1073                 int q;
1074
1075                 pid_set = set_new(trivial_hash_func, trivial_compare_func);
1076                 if (!pid_set)
1077                         return log_oom();
1078
1079                 if (s->leader > 0) {
1080                         q = set_put(pid_set, LONG_TO_PTR(s->leader));
1081                         if (q < 0)
1082                                 r = q;
1083                 }
1084
1085                 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
1086                 if (q < 0)
1087                         if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
1088                                 r = q;
1089         }
1090
1091         return r;
1092 }
1093
1094 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
1095         [SESSION_ONLINE] = "online",
1096         [SESSION_ACTIVE] = "active",
1097         [SESSION_CLOSING] = "closing"
1098 };
1099
1100 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1101
1102 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1103         [SESSION_TTY] = "tty",
1104         [SESSION_X11] = "x11",
1105         [SESSION_UNSPECIFIED] = "unspecified"
1106 };
1107
1108 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1109
1110 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1111         [SESSION_USER] = "user",
1112         [SESSION_GREETER] = "greeter",
1113         [SESSION_LOCK_SCREEN] = "lock-screen",
1114         [SESSION_BACKGROUND] = "background"
1115 };
1116
1117 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1118
1119 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1120         [KILL_LEADER] = "leader",
1121         [KILL_ALL] = "all"
1122 };
1123
1124 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);