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