chiark / gitweb /
Use initalization instead of explicit zeroing
[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(controller);
440         assert(path);
441
442         if (s->leader > 0) {
443                 r = cg_create_and_attach(controller, path, s->leader);
444                 if (r < 0)
445                         r = cg_create(controller, path);
446         } else
447                 r = cg_create(controller, path);
448
449         if (r < 0)
450                 return r;
451
452         r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid, -1);
453         if (r >= 0)
454                 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
455
456         return r;
457 }
458
459 static int session_create_cgroup(Session *s) {
460         char **k;
461         char *p;
462         int r;
463
464         assert(s);
465         assert(s->user);
466         assert(s->user->cgroup_path);
467
468         if (!s->cgroup_path) {
469                 if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0)
470                         return log_oom();
471         } else
472                 p = s->cgroup_path;
473
474         r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
475         if (r < 0) {
476                 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
477                 free(p);
478                 s->cgroup_path = NULL;
479                 return r;
480         }
481
482         s->cgroup_path = p;
483
484         STRV_FOREACH(k, s->controllers) {
485
486                 if (strv_contains(s->reset_controllers, *k))
487                         continue;
488
489                 r = session_create_one_group(s, *k, p);
490                 if (r < 0)
491                         log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
492         }
493
494         STRV_FOREACH(k, s->manager->controllers) {
495
496                 if (strv_contains(s->reset_controllers, *k) ||
497                     strv_contains(s->manager->reset_controllers, *k) ||
498                     strv_contains(s->controllers, *k))
499                         continue;
500
501                 r = session_create_one_group(s, *k, p);
502                 if (r < 0)
503                         log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
504         }
505
506         if (s->leader > 0) {
507
508                 STRV_FOREACH(k, s->reset_controllers) {
509                         r = cg_attach(*k, "/", s->leader);
510                         if (r < 0)
511                                 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
512
513                 }
514
515                 STRV_FOREACH(k, s->manager->reset_controllers) {
516
517                         if (strv_contains(s->reset_controllers, *k) ||
518                             strv_contains(s->controllers, *k))
519                                 continue;
520
521                         r = cg_attach(*k, "/", s->leader);
522                         if (r < 0)
523                                 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
524
525                 }
526         }
527
528         r = hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
529         if (r < 0)
530                 log_warning("Failed to create mapping between cgroup and session");
531
532         return 0;
533 }
534
535 int session_start(Session *s) {
536         int r;
537
538         assert(s);
539         assert(s->user);
540
541         if (s->started)
542                 return 0;
543
544         r = user_start(s->user);
545         if (r < 0)
546                 return r;
547
548         log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
549                    MESSAGE_ID(SD_MESSAGE_SESSION_START),
550                    "SESSION_ID=%s", s->id,
551                    "USER_ID=%s", s->user->name,
552                    "LEADER=%lu", (unsigned long) s->leader,
553                    "MESSAGE=New session %s of user %s.", s->id, s->user->name,
554                    NULL);
555
556         /* Create cgroup */
557         r = session_create_cgroup(s);
558         if (r < 0)
559                 return r;
560
561         /* Create X11 symlink */
562         session_link_x11_socket(s);
563
564         dual_timestamp_get(&s->timestamp);
565
566         if (s->seat)
567                 seat_read_active_vt(s->seat);
568
569         s->started = true;
570
571         /* Save session data */
572         session_save(s);
573         user_save(s->user);
574
575         session_send_signal(s, true);
576
577         if (s->seat) {
578                 seat_save(s->seat);
579
580                 if (s->seat->active == s)
581                         seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
582                 else
583                         seat_send_changed(s->seat, "Sessions\0");
584         }
585
586         user_send_changed(s->user, "Sessions\0");
587
588         return 0;
589 }
590
591 static bool session_shall_kill(Session *s) {
592         assert(s);
593
594         if (!s->kill_processes)
595                 return false;
596
597         if (strv_contains(s->manager->kill_exclude_users, s->user->name))
598                 return false;
599
600         if (strv_isempty(s->manager->kill_only_users))
601                 return true;
602
603         return strv_contains(s->manager->kill_only_users, s->user->name);
604 }
605
606 static int session_terminate_cgroup(Session *s) {
607         int r;
608         char **k;
609
610         assert(s);
611
612         if (!s->cgroup_path)
613                 return 0;
614
615         cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
616
617         if (session_shall_kill(s)) {
618
619                 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
620                 if (r < 0)
621                         log_error("Failed to kill session cgroup: %s", strerror(-r));
622
623         } else {
624                 if (s->leader > 0) {
625                         Session *t;
626
627                         /* We still send a HUP to the leader process,
628                          * even if we are not supposed to kill the
629                          * whole cgroup. But let's first check the
630                          * leader still exists and belongs to our
631                          * session... */
632
633                         r = manager_get_session_by_pid(s->manager, s->leader, &t);
634                         if (r > 0 && t == s) {
635                                 kill(s->leader, SIGTERM); /* for normal processes */
636                                 kill(s->leader, SIGHUP);  /* for shells */
637                                 kill(s->leader, SIGCONT); /* in case they are stopped */
638                         }
639                 }
640
641                 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
642                 if (r < 0)
643                         log_error("Failed to check session cgroup: %s", strerror(-r));
644                 else if (r > 0) {
645                         r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
646                         if (r < 0)
647                                 log_error("Failed to delete session cgroup: %s", strerror(-r));
648                 }
649         }
650
651         STRV_FOREACH(k, s->user->manager->controllers)
652                 cg_trim(*k, s->cgroup_path, true);
653
654         hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
655
656         free(s->cgroup_path);
657         s->cgroup_path = NULL;
658
659         return 0;
660 }
661
662 static int session_unlink_x11_socket(Session *s) {
663         char *t;
664         int r;
665
666         assert(s);
667         assert(s->user);
668
669         if (s->user->display != s)
670                 return 0;
671
672         s->user->display = NULL;
673
674         t = strappend(s->user->runtime_path, "/X11-display");
675         if (!t)
676                 return log_oom();
677
678         r = unlink(t);
679         free(t);
680
681         return r < 0 ? -errno : 0;
682 }
683
684 int session_stop(Session *s) {
685         int r = 0, k;
686
687         assert(s);
688
689         if (s->started)
690                 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
691                            MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
692                            "SESSION_ID=%s", s->id,
693                            "USER_ID=%s", s->user->name,
694                            "LEADER=%lu", (unsigned long) s->leader,
695                            "MESSAGE=Removed session %s.", s->id,
696                            NULL);
697
698         /* Kill cgroup */
699         k = session_terminate_cgroup(s);
700         if (k < 0)
701                 r = k;
702
703         /* Remove X11 symlink */
704         session_unlink_x11_socket(s);
705
706         unlink(s->state_file);
707         session_add_to_gc_queue(s);
708         user_add_to_gc_queue(s->user);
709
710         if (s->started)
711                 session_send_signal(s, false);
712
713         if (s->seat) {
714                 if (s->seat->active == s)
715                         seat_set_active(s->seat, NULL);
716
717                 seat_send_changed(s->seat, "Sessions\0");
718                 seat_save(s->seat);
719         }
720
721         user_send_changed(s->user, "Sessions\0");
722         user_save(s->user);
723
724         s->started = false;
725
726         return r;
727 }
728
729 bool session_is_active(Session *s) {
730         assert(s);
731
732         if (!s->seat)
733                 return true;
734
735         return s->seat->active == s;
736 }
737
738 static int get_tty_atime(const char *tty, usec_t *atime) {
739         _cleanup_free_ char *p = NULL;
740         struct stat st;
741
742         assert(tty);
743         assert(atime);
744
745         if (!path_is_absolute(tty)) {
746                 p = strappend("/dev/", tty);
747                 if (!p)
748                         return -ENOMEM;
749
750                 tty = p;
751         } else if (!path_startswith(tty, "/dev/"))
752                 return -ENOENT;
753
754         if (lstat(tty, &st) < 0)
755                 return -errno;
756
757         *atime = timespec_load(&st.st_atim);
758         return 0;
759 }
760
761 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
762         _cleanup_free_ char *p = NULL;
763         int r;
764
765         assert(pid > 0);
766         assert(atime);
767
768         r = get_ctty(pid, NULL, &p);
769         if (r < 0)
770                 return r;
771
772         return get_tty_atime(p, atime);
773 }
774
775 int session_get_idle_hint(Session *s, dual_timestamp *t) {
776         usec_t atime = 0, n;
777         int r;
778
779         assert(s);
780
781         /* Explicit idle hint is set */
782         if (s->idle_hint) {
783                 if (t)
784                         *t = s->idle_hint_timestamp;
785
786                 return s->idle_hint;
787         }
788
789         /* Graphical sessions should really implement a real
790          * idle hint logic */
791         if (s->display)
792                 goto dont_know;
793
794         /* For sessions with an explicitly configured tty, let's check
795          * its atime */
796         if (s->tty) {
797                 r = get_tty_atime(s->tty, &atime);
798                 if (r >= 0)
799                         goto found_atime;
800         }
801
802         /* For sessions with a leader but no explicitly configured
803          * tty, let's check the controlling tty of the leader */
804         if (s->leader > 0) {
805                 r = get_process_ctty_atime(s->leader, &atime);
806                 if (r >= 0)
807                         goto found_atime;
808         }
809
810         /* For other TTY sessions, let's find the most recent atime of
811          * the ttys of any of the processes of the session */
812         if (s->cgroup_path) {
813                 _cleanup_fclose_ FILE *f = NULL;
814
815                 if (cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &f) >= 0) {
816                         pid_t pid;
817
818                         atime = 0;
819                         while (cg_read_pid(f, &pid) > 0) {
820                                 usec_t a;
821
822                                 if (get_process_ctty_atime(pid, &a) >= 0)
823                                         if (atime == 0 || atime < a)
824                                                 atime = a;
825                         }
826
827                         if (atime != 0)
828                                 goto found_atime;
829                 }
830         }
831
832 dont_know:
833         if (t)
834                 *t = s->idle_hint_timestamp;
835
836         return 0;
837
838 found_atime:
839         if (t)
840                 dual_timestamp_from_realtime(t, atime);
841
842         n = now(CLOCK_REALTIME);
843
844         if (s->manager->idle_action_usec <= 0)
845                 return 0;
846
847         return atime + s->manager->idle_action_usec <= n;
848 }
849
850 void session_set_idle_hint(Session *s, bool b) {
851         assert(s);
852
853         if (s->idle_hint == b)
854                 return;
855
856         s->idle_hint = b;
857         dual_timestamp_get(&s->idle_hint_timestamp);
858
859         session_send_changed(s,
860                              "IdleHint\0"
861                              "IdleSinceHint\0"
862                              "IdleSinceHintMonotonic\0");
863
864         if (s->seat)
865                 seat_send_changed(s->seat,
866                                   "IdleHint\0"
867                                   "IdleSinceHint\0"
868                                   "IdleSinceHintMonotonic\0");
869
870         user_send_changed(s->user,
871                           "IdleHint\0"
872                           "IdleSinceHint\0"
873                           "IdleSinceHintMonotonic\0");
874
875         manager_send_changed(s->manager,
876                              "IdleHint\0"
877                              "IdleSinceHint\0"
878                              "IdleSinceHintMonotonic\0");
879 }
880
881 int session_create_fifo(Session *s) {
882         int r;
883
884         assert(s);
885
886         /* Create FIFO */
887         if (!s->fifo_path) {
888                 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
889                 if (r < 0)
890                         return r;
891
892                 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
893                         return -ENOMEM;
894
895                 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
896                         return -errno;
897         }
898
899         /* Open reading side */
900         if (s->fifo_fd < 0) {
901                 struct epoll_event ev = {};
902
903                 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
904                 if (s->fifo_fd < 0)
905                         return -errno;
906
907                 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
908                 if (r < 0)
909                         return r;
910
911                 ev.events = 0;
912                 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
913
914                 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
915                         return -errno;
916         }
917
918         /* Open writing side */
919         r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
920         if (r < 0)
921                 return -errno;
922
923         return r;
924 }
925
926 void session_remove_fifo(Session *s) {
927         assert(s);
928
929         if (s->fifo_fd >= 0) {
930                 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
931                 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
932                 close_nointr_nofail(s->fifo_fd);
933                 s->fifo_fd = -1;
934
935                 session_save(s);
936                 user_save(s->user);
937         }
938
939         if (s->fifo_path) {
940                 unlink(s->fifo_path);
941                 free(s->fifo_path);
942                 s->fifo_path = NULL;
943         }
944 }
945
946 int session_check_gc(Session *s, bool drop_not_started) {
947         int r;
948
949         assert(s);
950
951         if (drop_not_started && !s->started)
952                 return 0;
953
954         if (s->fifo_fd >= 0) {
955
956                 r = pipe_eof(s->fifo_fd);
957                 if (r < 0)
958                         return r;
959
960                 if (r == 0)
961                         return 1;
962         }
963
964         if (s->cgroup_path) {
965
966                 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
967                 if (r < 0)
968                         return r;
969
970                 if (r <= 0)
971                         return 1;
972         }
973
974         return 0;
975 }
976
977 void session_add_to_gc_queue(Session *s) {
978         assert(s);
979
980         if (s->in_gc_queue)
981                 return;
982
983         LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
984         s->in_gc_queue = true;
985 }
986
987 SessionState session_get_state(Session *s) {
988         assert(s);
989
990         if (s->fifo_fd < 0)
991                 return SESSION_CLOSING;
992
993         if (session_is_active(s))
994                 return SESSION_ACTIVE;
995
996         return SESSION_ONLINE;
997 }
998
999 int session_kill(Session *s, KillWho who, int signo) {
1000         int r = 0;
1001         Set *pid_set = NULL;
1002
1003         assert(s);
1004
1005         if (!s->cgroup_path)
1006                 return -ESRCH;
1007
1008         if (s->leader <= 0 && who == KILL_LEADER)
1009                 return -ESRCH;
1010
1011         if (s->leader > 0)
1012                 if (kill(s->leader, signo) < 0)
1013                         r = -errno;
1014
1015         if (who == KILL_ALL) {
1016                 int q;
1017
1018                 pid_set = set_new(trivial_hash_func, trivial_compare_func);
1019                 if (!pid_set)
1020                         return -ENOMEM;
1021
1022                 if (s->leader > 0) {
1023                         q = set_put(pid_set, LONG_TO_PTR(s->leader));
1024                         if (q < 0)
1025                                 r = q;
1026                 }
1027
1028                 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
1029                 if (q < 0)
1030                         if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
1031                                 r = q;
1032         }
1033
1034         if (pid_set)
1035                 set_free(pid_set);
1036
1037         return r;
1038 }
1039
1040 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
1041         [SESSION_ONLINE] = "online",
1042         [SESSION_ACTIVE] = "active",
1043         [SESSION_CLOSING] = "closing"
1044 };
1045
1046 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1047
1048 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1049         [SESSION_TTY] = "tty",
1050         [SESSION_X11] = "x11",
1051         [SESSION_UNSPECIFIED] = "unspecified"
1052 };
1053
1054 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1055
1056 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1057         [SESSION_USER] = "user",
1058         [SESSION_GREETER] = "greeter",
1059         [SESSION_LOCK_SCREEN] = "lock-screen"
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);