chiark / gitweb /
logind: remove unused variable
[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
37 Session* session_new(Manager *m, User *u, const char *id) {
38         Session *s;
39
40         assert(m);
41         assert(id);
42
43         s = new0(Session, 1);
44         if (!s)
45                 return NULL;
46
47         s->state_file = strappend("/run/systemd/sessions/", id);
48         if (!s->state_file) {
49                 free(s);
50                 return NULL;
51         }
52
53         s->id = path_get_file_name(s->state_file);
54
55         if (hashmap_put(m->sessions, s->id, s) < 0) {
56                 free(s->state_file);
57                 free(s);
58                 return NULL;
59         }
60
61         s->manager = m;
62         s->fifo_fd = -1;
63         s->user = u;
64
65         LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
66
67         return s;
68 }
69
70 void session_free(Session *s) {
71         assert(s);
72
73         if (s->in_gc_queue)
74                 LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
75
76         if (s->user) {
77                 LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
78
79                 if (s->user->display == s)
80                         s->user->display = NULL;
81         }
82
83         if (s->seat) {
84                 if (s->seat->active == s)
85                         s->seat->active = NULL;
86
87                 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
88         }
89
90         if (s->cgroup_path)
91                 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
92
93         free(s->cgroup_path);
94         strv_free(s->controllers);
95
96         free(s->tty);
97         free(s->display);
98         free(s->remote_host);
99         free(s->remote_user);
100         free(s->service);
101
102         hashmap_remove(s->manager->sessions, s->id);
103         session_remove_fifo(s);
104
105         free(s->state_file);
106         free(s);
107 }
108
109 int session_save(Session *s) {
110         FILE *f;
111         int r = 0;
112         char *temp_path;
113
114         assert(s);
115
116         if (!s->started)
117                 return 0;
118
119         r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
120         if (r < 0)
121                 goto finish;
122
123         r = fopen_temporary(s->state_file, &f, &temp_path);
124         if (r < 0)
125                 goto finish;
126
127         assert(s->user);
128
129         fchmod(fileno(f), 0644);
130
131         fprintf(f,
132                 "# This is private data. Do not parse.\n"
133                 "UID=%lu\n"
134                 "USER=%s\n"
135                 "ACTIVE=%i\n"
136                 "STATE=%s\n"
137                 "REMOTE=%i\n"
138                 "KILL_PROCESSES=%i\n",
139                 (unsigned long) s->user->uid,
140                 s->user->name,
141                 session_is_active(s),
142                 session_state_to_string(session_get_state(s)),
143                 s->remote,
144                 s->kill_processes);
145
146         if (s->type >= 0)
147                 fprintf(f,
148                         "TYPE=%s\n",
149                         session_type_to_string(s->type));
150
151         if (s->class >= 0)
152                 fprintf(f,
153                         "CLASS=%s\n",
154                         session_class_to_string(s->class));
155
156         if (s->cgroup_path)
157                 fprintf(f,
158                         "CGROUP=%s\n",
159                         s->cgroup_path);
160
161         if (s->fifo_path)
162                 fprintf(f,
163                         "FIFO=%s\n",
164                         s->fifo_path);
165
166         if (s->seat)
167                 fprintf(f,
168                         "SEAT=%s\n",
169                         s->seat->id);
170
171         if (s->tty)
172                 fprintf(f,
173                         "TTY=%s\n",
174                         s->tty);
175
176         if (s->display)
177                 fprintf(f,
178                         "DISPLAY=%s\n",
179                         s->display);
180
181         if (s->remote_host)
182                 fprintf(f,
183                         "REMOTE_HOST=%s\n",
184                         s->remote_host);
185
186         if (s->remote_user)
187                 fprintf(f,
188                         "REMOTE_USER=%s\n",
189                         s->remote_user);
190
191         if (s->service)
192                 fprintf(f,
193                         "SERVICE=%s\n",
194                         s->service);
195
196         if (s->seat && seat_can_multi_session(s->seat))
197                 fprintf(f,
198                         "VTNR=%i\n",
199                         s->vtnr);
200
201         if (s->leader > 0)
202                 fprintf(f,
203                         "LEADER=%lu\n",
204                         (unsigned long) s->leader);
205
206         if (s->audit_id > 0)
207                 fprintf(f,
208                         "AUDIT=%llu\n",
209                         (unsigned long long) s->audit_id);
210
211         fflush(f);
212
213         if (ferror(f) || rename(temp_path, s->state_file) < 0) {
214                 r = -errno;
215                 unlink(s->state_file);
216                 unlink(temp_path);
217         }
218
219         fclose(f);
220         free(temp_path);
221
222 finish:
223         if (r < 0)
224                 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
225
226         return r;
227 }
228
229 int session_load(Session *s) {
230         char *remote = NULL,
231                 *kill_processes = NULL,
232                 *seat = NULL,
233                 *vtnr = NULL,
234                 *leader = NULL,
235                 *audit_id = NULL,
236                 *type = NULL,
237                 *class = NULL;
238
239         int k, r;
240
241         assert(s);
242
243         r = parse_env_file(s->state_file, NEWLINE,
244                            "REMOTE",         &remote,
245                            "KILL_PROCESSES", &kill_processes,
246                            "CGROUP",         &s->cgroup_path,
247                            "FIFO",           &s->fifo_path,
248                            "SEAT",           &seat,
249                            "TTY",            &s->tty,
250                            "DISPLAY",        &s->display,
251                            "REMOTE_HOST",    &s->remote_host,
252                            "REMOTE_USER",    &s->remote_user,
253                            "SERVICE",        &s->service,
254                            "VTNR",           &vtnr,
255                            "LEADER",         &leader,
256                            "TYPE",           &type,
257                            "CLASS",          &class,
258                            NULL);
259
260         if (r < 0)
261                 goto finish;
262
263         if (remote) {
264                 k = parse_boolean(remote);
265                 if (k >= 0)
266                         s->remote = k;
267         }
268
269         if (kill_processes) {
270                 k = parse_boolean(kill_processes);
271                 if (k >= 0)
272                         s->kill_processes = k;
273         }
274
275         if (seat && !s->seat) {
276                 Seat *o;
277
278                 o = hashmap_get(s->manager->seats, seat);
279                 if (o)
280                         seat_attach_session(o, s);
281         }
282
283         if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
284                 int v;
285
286                 k = safe_atoi(vtnr, &v);
287                 if (k >= 0 && v >= 1)
288                         s->vtnr = v;
289         }
290
291         if (leader) {
292                 k = parse_pid(leader, &s->leader);
293                 if (k >= 0)
294                         audit_session_from_pid(s->leader, &s->audit_id);
295         }
296
297         if (type) {
298                 SessionType t;
299
300                 t = session_type_from_string(type);
301                 if (t >= 0)
302                         s->type = t;
303         }
304
305         if (class) {
306                 SessionClass c;
307
308                 c = session_class_from_string(class);
309                 if (c >= 0)
310                         s->class = c;
311         }
312
313         if (s->fifo_path) {
314                 int fd;
315
316                 /* If we open an unopened pipe for reading we will not
317                    get an EOF. to trigger an EOF we hence open it for
318                    reading, but close it right-away which then will
319                    trigger the EOF. */
320
321                 fd = session_create_fifo(s);
322                 if (fd >= 0)
323                         close_nointr_nofail(fd);
324         }
325
326 finish:
327         free(remote);
328         free(kill_processes);
329         free(seat);
330         free(vtnr);
331         free(leader);
332         free(audit_id);
333         free(class);
334
335         return r;
336 }
337
338 int session_activate(Session *s) {
339         int r;
340
341         assert(s);
342
343         if (s->vtnr < 0)
344                 return -ENOTSUP;
345
346         if (!s->seat)
347                 return -ENOTSUP;
348
349         if (s->seat->active == s)
350                 return 0;
351
352         assert(seat_is_vtconsole(s->seat));
353
354         r = chvt(s->vtnr);
355         if (r < 0)
356                 return r;
357
358         return seat_set_active(s->seat, s);
359 }
360
361 static int session_link_x11_socket(Session *s) {
362         char *t, *f, *c;
363         size_t k;
364
365         assert(s);
366         assert(s->user);
367         assert(s->user->runtime_path);
368
369         if (s->user->display)
370                 return 0;
371
372         if (!s->display || !display_is_local(s->display))
373                 return 0;
374
375         k = strspn(s->display+1, "0123456789");
376         f = new(char, sizeof("/tmp/.X11-unix/X") + k);
377         if (!f)
378                 return log_oom();
379
380         c = stpcpy(f, "/tmp/.X11-unix/X");
381         memcpy(c, s->display+1, k);
382         c[k] = 0;
383
384         if (access(f, F_OK) < 0) {
385                 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
386                 free(f);
387                 return -ENOENT;
388         }
389
390         /* Note that this cannot be in a subdir to avoid
391          * vulnerabilities since we are privileged but the runtime
392          * path is owned by the user */
393
394         t = strappend(s->user->runtime_path, "/X11-display");
395         if (!t) {
396                 free(f);
397                 return log_oom();
398         }
399
400         if (link(f, t) < 0) {
401                 if (errno == EEXIST) {
402                         unlink(t);
403
404                         if (link(f, t) >= 0)
405                                 goto done;
406                 }
407
408                 if (symlink(f, t) < 0) {
409
410                         if (errno == EEXIST) {
411                                 unlink(t);
412
413                                 if (symlink(f, t) >= 0)
414                                         goto done;
415                         }
416
417                         log_error("Failed to link %s to %s: %m", f, t);
418                         free(f);
419                         free(t);
420                         return -errno;
421                 }
422         }
423
424 done:
425         log_info("Linked %s to %s.", f, t);
426         free(f);
427         free(t);
428
429         s->user->display = s;
430
431         return 0;
432 }
433
434 static int session_create_one_group(Session *s, const char *controller, const char *path) {
435         int r;
436
437         assert(s);
438         assert(controller);
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);
445         } else
446                 r = cg_create(controller, path);
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         if (s->seat) {
713                 if (s->seat->active == s)
714                         seat_set_active(s->seat, NULL);
715
716                 seat_send_changed(s->seat, "Sessions\0");
717                 seat_save(s->seat);
718         }
719
720         user_send_changed(s->user, "Sessions\0");
721         user_save(s->user);
722
723         s->started = false;
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                 zero(ev);
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);