chiark / gitweb /
logind: split up HandleSleepKey= into HandleSuspendKey= and HandleHibernateKey=
[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         int k;
742
743         assert(s);
744
745         if (s->idle_hint) {
746                 if (t)
747                         *t = s->idle_hint_timestamp;
748
749                 return s->idle_hint;
750         }
751
752         if (isempty(s->tty))
753                 goto dont_know;
754
755         if (s->tty[0] != '/') {
756                 p = strappend("/dev/", s->tty);
757                 if (!p)
758                         return -ENOMEM;
759         } else
760                 p = NULL;
761
762         if (!startswith(p ? p : s->tty, "/dev/")) {
763                 free(p);
764                 goto dont_know;
765         }
766
767         k = lstat(p ? p : s->tty, &st);
768         free(p);
769
770         if (k < 0)
771                 goto dont_know;
772
773         u = timespec_load(&st.st_atim);
774         n = now(CLOCK_REALTIME);
775
776         if (t)
777                 dual_timestamp_from_realtime(t, u);
778
779         return u + IDLE_THRESHOLD_USEC < n;
780
781 dont_know:
782         if (t)
783                 *t = s->idle_hint_timestamp;
784
785         return 0;
786 }
787
788 void session_set_idle_hint(Session *s, bool b) {
789         assert(s);
790
791         if (s->idle_hint == b)
792                 return;
793
794         s->idle_hint = b;
795         dual_timestamp_get(&s->idle_hint_timestamp);
796
797         session_send_changed(s,
798                              "IdleHint\0"
799                              "IdleSinceHint\0"
800                              "IdleSinceHintMonotonic\0");
801
802         if (s->seat)
803                 seat_send_changed(s->seat,
804                                   "IdleHint\0"
805                                   "IdleSinceHint\0"
806                                   "IdleSinceHintMonotonic\0");
807
808         user_send_changed(s->user,
809                           "IdleHint\0"
810                           "IdleSinceHint\0"
811                           "IdleSinceHintMonotonic\0");
812
813         manager_send_changed(s->manager,
814                              "IdleHint\0"
815                              "IdleSinceHint\0"
816                              "IdleSinceHintMonotonic\0");
817 }
818
819 int session_create_fifo(Session *s) {
820         int r;
821
822         assert(s);
823
824         /* Create FIFO */
825         if (!s->fifo_path) {
826                 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
827                 if (r < 0)
828                         return r;
829
830                 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
831                         return -ENOMEM;
832
833                 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
834                         return -errno;
835         }
836
837         /* Open reading side */
838         if (s->fifo_fd < 0) {
839                 struct epoll_event ev;
840
841                 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
842                 if (s->fifo_fd < 0)
843                         return -errno;
844
845                 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
846                 if (r < 0)
847                         return r;
848
849                 zero(ev);
850                 ev.events = 0;
851                 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
852
853                 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
854                         return -errno;
855         }
856
857         /* Open writing side */
858         r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
859         if (r < 0)
860                 return -errno;
861
862         return r;
863 }
864
865 void session_remove_fifo(Session *s) {
866         assert(s);
867
868         if (s->fifo_fd >= 0) {
869                 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
870                 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
871                 close_nointr_nofail(s->fifo_fd);
872                 s->fifo_fd = -1;
873
874                 session_save(s);
875                 user_save(s->user);
876         }
877
878         if (s->fifo_path) {
879                 unlink(s->fifo_path);
880                 free(s->fifo_path);
881                 s->fifo_path = NULL;
882         }
883 }
884
885 int session_check_gc(Session *s, bool drop_not_started) {
886         int r;
887
888         assert(s);
889
890         if (drop_not_started && !s->started)
891                 return 0;
892
893         if (s->fifo_fd >= 0) {
894
895                 r = pipe_eof(s->fifo_fd);
896                 if (r < 0)
897                         return r;
898
899                 if (r == 0)
900                         return 1;
901         }
902
903         if (s->cgroup_path) {
904
905                 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
906                 if (r < 0)
907                         return r;
908
909                 if (r <= 0)
910                         return 1;
911         }
912
913         return 0;
914 }
915
916 void session_add_to_gc_queue(Session *s) {
917         assert(s);
918
919         if (s->in_gc_queue)
920                 return;
921
922         LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
923         s->in_gc_queue = true;
924 }
925
926 SessionState session_get_state(Session *s) {
927         assert(s);
928
929         if (s->fifo_fd < 0)
930                 return SESSION_CLOSING;
931
932         if (session_is_active(s))
933                 return SESSION_ACTIVE;
934
935         return SESSION_ONLINE;
936 }
937
938 int session_kill(Session *s, KillWho who, int signo) {
939         int r = 0;
940         Set *pid_set = NULL;
941
942         assert(s);
943
944         if (!s->cgroup_path)
945                 return -ESRCH;
946
947         if (s->leader <= 0 && who == KILL_LEADER)
948                 return -ESRCH;
949
950         if (s->leader > 0)
951                 if (kill(s->leader, signo) < 0)
952                         r = -errno;
953
954         if (who == KILL_ALL) {
955                 int q;
956
957                 pid_set = set_new(trivial_hash_func, trivial_compare_func);
958                 if (!pid_set)
959                         return -ENOMEM;
960
961                 if (s->leader > 0) {
962                         q = set_put(pid_set, LONG_TO_PTR(s->leader));
963                         if (q < 0)
964                                 r = q;
965                 }
966
967                 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
968                 if (q < 0)
969                         if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
970                                 r = q;
971         }
972
973         if (pid_set)
974                 set_free(pid_set);
975
976         return r;
977 }
978
979 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
980         [SESSION_ONLINE] = "online",
981         [SESSION_ACTIVE] = "active",
982         [SESSION_CLOSING] = "closing"
983 };
984
985 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
986
987 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
988         [SESSION_TTY] = "tty",
989         [SESSION_X11] = "x11",
990         [SESSION_UNSPECIFIED] = "unspecified"
991 };
992
993 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
994
995 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
996         [SESSION_USER] = "user",
997         [SESSION_GREETER] = "greeter",
998         [SESSION_LOCK_SCREEN] = "lock-screen"
999 };
1000
1001 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1002
1003 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1004         [KILL_LEADER] = "leader",
1005         [KILL_ALL] = "all"
1006 };
1007
1008 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);