chiark / gitweb /
logind: Ensure the user, seat and session files are updated when the session is closing.
[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 #define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE)
38
39 Session* session_new(Manager *m, User *u, const char *id) {
40         Session *s;
41
42         assert(m);
43         assert(id);
44
45         s = new0(Session, 1);
46         if (!s)
47                 return NULL;
48
49         s->state_file = strappend("/run/systemd/sessions/", id);
50         if (!s->state_file) {
51                 free(s);
52                 return NULL;
53         }
54
55         s->id = path_get_file_name(s->state_file);
56
57         if (hashmap_put(m->sessions, s->id, s) < 0) {
58                 free(s->state_file);
59                 free(s);
60                 return NULL;
61         }
62
63         s->manager = m;
64         s->fifo_fd = -1;
65         s->user = u;
66
67         LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
68
69         return s;
70 }
71
72 void session_free(Session *s) {
73         assert(s);
74
75         if (s->in_gc_queue)
76                 LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
77
78         if (s->user) {
79                 LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
80
81                 if (s->user->display == s)
82                         s->user->display = NULL;
83         }
84
85         if (s->seat) {
86                 if (s->seat->active == s)
87                         s->seat->active = NULL;
88
89                 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
90         }
91
92         if (s->cgroup_path)
93                 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
94
95         free(s->cgroup_path);
96         strv_free(s->controllers);
97
98         free(s->tty);
99         free(s->display);
100         free(s->remote_host);
101         free(s->remote_user);
102         free(s->service);
103
104         hashmap_remove(s->manager->sessions, s->id);
105         session_remove_fifo(s);
106
107         free(s->state_file);
108         free(s);
109 }
110
111 int session_save(Session *s) {
112         FILE *f;
113         int r = 0;
114         char *temp_path;
115
116         assert(s);
117
118         if (!s->started)
119                 return 0;
120
121         r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
122         if (r < 0)
123                 goto finish;
124
125         r = fopen_temporary(s->state_file, &f, &temp_path);
126         if (r < 0)
127                 goto finish;
128
129         assert(s->user);
130
131         fchmod(fileno(f), 0644);
132
133         fprintf(f,
134                 "# This is private data. Do not parse.\n"
135                 "UID=%lu\n"
136                 "USER=%s\n"
137                 "ACTIVE=%i\n"
138                 "STATE=%s\n"
139                 "REMOTE=%i\n"
140                 "KILL_PROCESSES=%i\n",
141                 (unsigned long) s->user->uid,
142                 s->user->name,
143                 session_is_active(s),
144                 session_state_to_string(session_get_state(s)),
145                 s->remote,
146                 s->kill_processes);
147
148         if (s->type >= 0)
149                 fprintf(f,
150                         "TYPE=%s\n",
151                         session_type_to_string(s->type));
152
153         if (s->class >= 0)
154                 fprintf(f,
155                         "CLASS=%s\n",
156                         session_class_to_string(s->class));
157
158         if (s->cgroup_path)
159                 fprintf(f,
160                         "CGROUP=%s\n",
161                         s->cgroup_path);
162
163         if (s->fifo_path)
164                 fprintf(f,
165                         "FIFO=%s\n",
166                         s->fifo_path);
167
168         if (s->seat)
169                 fprintf(f,
170                         "SEAT=%s\n",
171                         s->seat->id);
172
173         if (s->tty)
174                 fprintf(f,
175                         "TTY=%s\n",
176                         s->tty);
177
178         if (s->display)
179                 fprintf(f,
180                         "DISPLAY=%s\n",
181                         s->display);
182
183         if (s->remote_host)
184                 fprintf(f,
185                         "REMOTE_HOST=%s\n",
186                         s->remote_host);
187
188         if (s->remote_user)
189                 fprintf(f,
190                         "REMOTE_USER=%s\n",
191                         s->remote_user);
192
193         if (s->service)
194                 fprintf(f,
195                         "SERVICE=%s\n",
196                         s->service);
197
198         if (s->seat && seat_can_multi_session(s->seat))
199                 fprintf(f,
200                         "VTNR=%i\n",
201                         s->vtnr);
202
203         if (s->leader > 0)
204                 fprintf(f,
205                         "LEADER=%lu\n",
206                         (unsigned long) s->leader);
207
208         if (s->audit_id > 0)
209                 fprintf(f,
210                         "AUDIT=%llu\n",
211                         (unsigned long long) s->audit_id);
212
213         fflush(f);
214
215         if (ferror(f) || rename(temp_path, s->state_file) < 0) {
216                 r = -errno;
217                 unlink(s->state_file);
218                 unlink(temp_path);
219         }
220
221         fclose(f);
222         free(temp_path);
223
224 finish:
225         if (r < 0)
226                 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
227
228         return r;
229 }
230
231 int session_load(Session *s) {
232         char *remote = NULL,
233                 *kill_processes = NULL,
234                 *seat = NULL,
235                 *vtnr = NULL,
236                 *leader = NULL,
237                 *audit_id = NULL,
238                 *type = NULL,
239                 *class = NULL;
240
241         int k, r;
242
243         assert(s);
244
245         r = parse_env_file(s->state_file, NEWLINE,
246                            "REMOTE",         &remote,
247                            "KILL_PROCESSES", &kill_processes,
248                            "CGROUP",         &s->cgroup_path,
249                            "FIFO",           &s->fifo_path,
250                            "SEAT",           &seat,
251                            "TTY",            &s->tty,
252                            "DISPLAY",        &s->display,
253                            "REMOTE_HOST",    &s->remote_host,
254                            "REMOTE_USER",    &s->remote_user,
255                            "SERVICE",        &s->service,
256                            "VTNR",           &vtnr,
257                            "LEADER",         &leader,
258                            "TYPE",           &type,
259                            "CLASS",          &class,
260                            NULL);
261
262         if (r < 0)
263                 goto finish;
264
265         if (remote) {
266                 k = parse_boolean(remote);
267                 if (k >= 0)
268                         s->remote = k;
269         }
270
271         if (kill_processes) {
272                 k = parse_boolean(kill_processes);
273                 if (k >= 0)
274                         s->kill_processes = k;
275         }
276
277         if (seat && !s->seat) {
278                 Seat *o;
279
280                 o = hashmap_get(s->manager->seats, seat);
281                 if (o)
282                         seat_attach_session(o, s);
283         }
284
285         if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
286                 int v;
287
288                 k = safe_atoi(vtnr, &v);
289                 if (k >= 0 && v >= 1)
290                         s->vtnr = v;
291         }
292
293         if (leader) {
294                 k = parse_pid(leader, &s->leader);
295                 if (k >= 0)
296                         audit_session_from_pid(s->leader, &s->audit_id);
297         }
298
299         if (type) {
300                 SessionType t;
301
302                 t = session_type_from_string(type);
303                 if (t >= 0)
304                         s->type = t;
305         }
306
307         if (class) {
308                 SessionClass c;
309
310                 c = session_class_from_string(class);
311                 if (c >= 0)
312                         s->class = c;
313         }
314
315         if (s->fifo_path) {
316                 int fd;
317
318                 /* If we open an unopened pipe for reading we will not
319                    get an EOF. to trigger an EOF we hence open it for
320                    reading, but close it right-away which then will
321                    trigger the EOF. */
322
323                 fd = session_create_fifo(s);
324                 if (fd >= 0)
325                         close_nointr_nofail(fd);
326         }
327
328 finish:
329         free(remote);
330         free(kill_processes);
331         free(seat);
332         free(vtnr);
333         free(leader);
334         free(audit_id);
335         free(class);
336
337         return r;
338 }
339
340 int session_activate(Session *s) {
341         int r;
342
343         assert(s);
344
345         if (s->vtnr < 0)
346                 return -ENOTSUP;
347
348         if (!s->seat)
349                 return -ENOTSUP;
350
351         if (s->seat->active == s)
352                 return 0;
353
354         assert(seat_is_vtconsole(s->seat));
355
356         r = chvt(s->vtnr);
357         if (r < 0)
358                 return r;
359
360         return seat_set_active(s->seat, s);
361 }
362
363 static int session_link_x11_socket(Session *s) {
364         char *t, *f, *c;
365         size_t k;
366
367         assert(s);
368         assert(s->user);
369         assert(s->user->runtime_path);
370
371         if (s->user->display)
372                 return 0;
373
374         if (!s->display || !display_is_local(s->display))
375                 return 0;
376
377         k = strspn(s->display+1, "0123456789");
378         f = new(char, sizeof("/tmp/.X11-unix/X") + k);
379         if (!f)
380                 return log_oom();
381
382         c = stpcpy(f, "/tmp/.X11-unix/X");
383         memcpy(c, s->display+1, k);
384         c[k] = 0;
385
386         if (access(f, F_OK) < 0) {
387                 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
388                 free(f);
389                 return -ENOENT;
390         }
391
392         /* Note that this cannot be in a subdir to avoid
393          * vulnerabilities since we are privileged but the runtime
394          * path is owned by the user */
395
396         t = strappend(s->user->runtime_path, "/X11-display");
397         if (!t) {
398                 free(f);
399                 return log_oom();
400         }
401
402         if (link(f, t) < 0) {
403                 if (errno == EEXIST) {
404                         unlink(t);
405
406                         if (link(f, t) >= 0)
407                                 goto done;
408                 }
409
410                 if (symlink(f, t) < 0) {
411
412                         if (errno == EEXIST) {
413                                 unlink(t);
414
415                                 if (symlink(f, t) >= 0)
416                                         goto done;
417                         }
418
419                         log_error("Failed to link %s to %s: %m", f, t);
420                         free(f);
421                         free(t);
422                         return -errno;
423                 }
424         }
425
426 done:
427         log_info("Linked %s to %s.", f, t);
428         free(f);
429         free(t);
430
431         s->user->display = s;
432
433         return 0;
434 }
435
436 static int session_create_one_group(Session *s, const char *controller, const char *path) {
437         int r;
438
439         assert(s);
440         assert(controller);
441         assert(path);
442
443         if (s->leader > 0) {
444                 r = cg_create_and_attach(controller, path, s->leader);
445                 if (r < 0)
446                         r = cg_create(controller, path);
447         } else
448                 r = cg_create(controller, path);
449
450         if (r < 0)
451                 return r;
452
453         r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid, -1);
454         if (r >= 0)
455                 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
456
457         return r;
458 }
459
460 static int session_create_cgroup(Session *s) {
461         char **k;
462         char *p;
463         int r;
464
465         assert(s);
466         assert(s->user);
467         assert(s->user->cgroup_path);
468
469         if (!s->cgroup_path) {
470                 if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0)
471                         return log_oom();
472         } else
473                 p = s->cgroup_path;
474
475         r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
476         if (r < 0) {
477                 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
478                 free(p);
479                 s->cgroup_path = NULL;
480                 return r;
481         }
482
483         s->cgroup_path = p;
484
485         STRV_FOREACH(k, s->controllers) {
486
487                 if (strv_contains(s->reset_controllers, *k))
488                         continue;
489
490                 r = session_create_one_group(s, *k, p);
491                 if (r < 0)
492                         log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
493         }
494
495         STRV_FOREACH(k, s->manager->controllers) {
496
497                 if (strv_contains(s->reset_controllers, *k) ||
498                     strv_contains(s->manager->reset_controllers, *k) ||
499                     strv_contains(s->controllers, *k))
500                         continue;
501
502                 r = session_create_one_group(s, *k, p);
503                 if (r < 0)
504                         log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
505         }
506
507         if (s->leader > 0) {
508
509                 STRV_FOREACH(k, s->reset_controllers) {
510                         r = cg_attach(*k, "/", s->leader);
511                         if (r < 0)
512                                 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
513
514                 }
515
516                 STRV_FOREACH(k, s->manager->reset_controllers) {
517
518                         if (strv_contains(s->reset_controllers, *k) ||
519                             strv_contains(s->controllers, *k))
520                                 continue;
521
522                         r = cg_attach(*k, "/", s->leader);
523                         if (r < 0)
524                                 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
525
526                 }
527         }
528
529         hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
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_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(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_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(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 int session_get_idle_hint(Session *s, dual_timestamp *t) {
738         char *p;
739         struct stat st;
740         usec_t u, n;
741         bool b;
742         int k;
743
744         assert(s);
745
746         if (s->idle_hint) {
747                 if (t)
748                         *t = s->idle_hint_timestamp;
749
750                 return s->idle_hint;
751         }
752
753         if (isempty(s->tty))
754                 goto dont_know;
755
756         if (s->tty[0] != '/') {
757                 p = strappend("/dev/", s->tty);
758                 if (!p)
759                         return -ENOMEM;
760         } else
761                 p = NULL;
762
763         if (!startswith(p ? p : s->tty, "/dev/")) {
764                 free(p);
765                 goto dont_know;
766         }
767
768         k = lstat(p ? p : s->tty, &st);
769         free(p);
770
771         if (k < 0)
772                 goto dont_know;
773
774         u = timespec_load(&st.st_atim);
775         n = now(CLOCK_REALTIME);
776         b = u + IDLE_THRESHOLD_USEC < n;
777
778         if (t)
779                 dual_timestamp_from_realtime(t, u + b*IDLE_THRESHOLD_USEC);
780
781         return b;
782
783 dont_know:
784         if (t)
785                 *t = s->idle_hint_timestamp;
786
787         return 0;
788 }
789
790 void session_set_idle_hint(Session *s, bool b) {
791         assert(s);
792
793         if (s->idle_hint == b)
794                 return;
795
796         s->idle_hint = b;
797         dual_timestamp_get(&s->idle_hint_timestamp);
798
799         session_send_changed(s,
800                              "IdleHint\0"
801                              "IdleSinceHint\0"
802                              "IdleSinceHintMonotonic\0");
803
804         if (s->seat)
805                 seat_send_changed(s->seat,
806                                   "IdleHint\0"
807                                   "IdleSinceHint\0"
808                                   "IdleSinceHintMonotonic\0");
809
810         user_send_changed(s->user,
811                           "IdleHint\0"
812                           "IdleSinceHint\0"
813                           "IdleSinceHintMonotonic\0");
814
815         manager_send_changed(s->manager,
816                              "IdleHint\0"
817                              "IdleSinceHint\0"
818                              "IdleSinceHintMonotonic\0");
819 }
820
821 int session_create_fifo(Session *s) {
822         int r;
823
824         assert(s);
825
826         /* Create FIFO */
827         if (!s->fifo_path) {
828                 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
829                 if (r < 0)
830                         return r;
831
832                 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
833                         return -ENOMEM;
834
835                 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
836                         return -errno;
837         }
838
839         /* Open reading side */
840         if (s->fifo_fd < 0) {
841                 struct epoll_event ev;
842
843                 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
844                 if (s->fifo_fd < 0)
845                         return -errno;
846
847                 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
848                 if (r < 0)
849                         return r;
850
851                 zero(ev);
852                 ev.events = 0;
853                 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
854
855                 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
856                         return -errno;
857         }
858
859         /* Open writing side */
860         r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
861         if (r < 0)
862                 return -errno;
863
864         return r;
865 }
866
867 void session_remove_fifo(Session *s) {
868         assert(s);
869
870         if (s->fifo_fd >= 0) {
871                 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
872                 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
873                 close_nointr_nofail(s->fifo_fd);
874                 s->fifo_fd = -1;
875
876                 session_save(s);
877                 user_save(s->user);
878         }
879
880         if (s->fifo_path) {
881                 unlink(s->fifo_path);
882                 free(s->fifo_path);
883                 s->fifo_path = NULL;
884         }
885 }
886
887 int session_check_gc(Session *s, bool drop_not_started) {
888         int r;
889
890         assert(s);
891
892         if (drop_not_started && !s->started)
893                 return 0;
894
895         if (s->fifo_fd >= 0) {
896
897                 r = pipe_eof(s->fifo_fd);
898                 if (r < 0)
899                         return r;
900
901                 if (r == 0)
902                         return 1;
903         }
904
905         if (s->cgroup_path) {
906
907                 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
908                 if (r < 0)
909                         return r;
910
911                 if (r <= 0)
912                         return 1;
913         }
914
915         return 0;
916 }
917
918 void session_add_to_gc_queue(Session *s) {
919         assert(s);
920
921         if (s->in_gc_queue)
922                 return;
923
924         LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
925         s->in_gc_queue = true;
926 }
927
928 SessionState session_get_state(Session *s) {
929         assert(s);
930
931         if (s->fifo_fd < 0)
932                 return SESSION_CLOSING;
933
934         if (session_is_active(s))
935                 return SESSION_ACTIVE;
936
937         return SESSION_ONLINE;
938 }
939
940 int session_kill(Session *s, KillWho who, int signo) {
941         int r = 0;
942         Set *pid_set = NULL;
943
944         assert(s);
945
946         if (!s->cgroup_path)
947                 return -ESRCH;
948
949         if (s->leader <= 0 && who == KILL_LEADER)
950                 return -ESRCH;
951
952         if (s->leader > 0)
953                 if (kill(s->leader, signo) < 0)
954                         r = -errno;
955
956         if (who == KILL_ALL) {
957                 int q;
958
959                 pid_set = set_new(trivial_hash_func, trivial_compare_func);
960                 if (!pid_set)
961                         return -ENOMEM;
962
963                 if (s->leader > 0) {
964                         q = set_put(pid_set, LONG_TO_PTR(s->leader));
965                         if (q < 0)
966                                 r = q;
967                 }
968
969                 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
970                 if (q < 0)
971                         if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
972                                 r = q;
973         }
974
975         if (pid_set)
976                 set_free(pid_set);
977
978         return r;
979 }
980
981 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
982         [SESSION_ONLINE] = "online",
983         [SESSION_ACTIVE] = "active",
984         [SESSION_CLOSING] = "closing"
985 };
986
987 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
988
989 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
990         [SESSION_TTY] = "tty",
991         [SESSION_X11] = "x11",
992         [SESSION_UNSPECIFIED] = "unspecified"
993 };
994
995 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
996
997 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
998         [SESSION_USER] = "user",
999         [SESSION_GREETER] = "greeter",
1000         [SESSION_LOCK_SCREEN] = "lock-screen"
1001 };
1002
1003 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1004
1005 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1006         [KILL_LEADER] = "leader",
1007         [KILL_ALL] = "all"
1008 };
1009
1010 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);