chiark / gitweb /
16d4955d5d94bc1f69151140ad689026149ec12b
[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 "strv.h"
29 #include "util.h"
30 #include "mkdir.h"
31 #include "path-util.h"
32 #include "cgroup-util.h"
33 #include "logind-session.h"
34
35 #define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE)
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         hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
528
529         return 0;
530 }
531
532 int session_start(Session *s) {
533         int r;
534
535         assert(s);
536         assert(s->user);
537
538         if (s->started)
539                 return 0;
540
541         r = user_start(s->user);
542         if (r < 0)
543                 return r;
544
545         log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
546                  "New session %s of user %s.", s->id, s->user->name);
547
548         /* Create cgroup */
549         r = session_create_cgroup(s);
550         if (r < 0)
551                 return r;
552
553         /* Create X11 symlink */
554         session_link_x11_socket(s);
555
556         dual_timestamp_get(&s->timestamp);
557
558         if (s->seat)
559                 seat_read_active_vt(s->seat);
560
561         s->started = true;
562
563         /* Save session data */
564         session_save(s);
565         user_save(s->user);
566
567         session_send_signal(s, true);
568
569         if (s->seat) {
570                 seat_save(s->seat);
571
572                 if (s->seat->active == s)
573                         seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
574                 else
575                         seat_send_changed(s->seat, "Sessions\0");
576         }
577
578         user_send_changed(s->user, "Sessions\0");
579
580         return 0;
581 }
582
583 static bool session_shall_kill(Session *s) {
584         assert(s);
585
586         if (!s->kill_processes)
587                 return false;
588
589         if (strv_contains(s->manager->kill_exclude_users, s->user->name))
590                 return false;
591
592         if (strv_isempty(s->manager->kill_only_users))
593                 return true;
594
595         return strv_contains(s->manager->kill_only_users, s->user->name);
596 }
597
598 static int session_terminate_cgroup(Session *s) {
599         int r;
600         char **k;
601
602         assert(s);
603
604         if (!s->cgroup_path)
605                 return 0;
606
607         cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
608
609         if (session_shall_kill(s)) {
610
611                 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
612                 if (r < 0)
613                         log_error("Failed to kill session cgroup: %s", strerror(-r));
614
615         } else {
616                 if (s->leader > 0) {
617                         Session *t;
618
619                         /* We still send a HUP to the leader process,
620                          * even if we are not supposed to kill the
621                          * whole cgroup. But let's first check the
622                          * leader still exists and belongs to our
623                          * session... */
624
625                         r = manager_get_session_by_pid(s->manager, s->leader, &t);
626                         if (r > 0 && t == s) {
627                                 kill(s->leader, SIGTERM); /* for normal processes */
628                                 kill(s->leader, SIGHUP);  /* for shells */
629                                 kill(s->leader, SIGCONT); /* in case they are stopped */
630                         }
631                 }
632
633                 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
634                 if (r < 0)
635                         log_error("Failed to check session cgroup: %s", strerror(-r));
636                 else if (r > 0) {
637                         r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
638                         if (r < 0)
639                                 log_error("Failed to delete session cgroup: %s", strerror(-r));
640                 }
641         }
642
643         STRV_FOREACH(k, s->user->manager->controllers)
644                 cg_trim(*k, s->cgroup_path, true);
645
646         hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
647
648         free(s->cgroup_path);
649         s->cgroup_path = NULL;
650
651         return 0;
652 }
653
654 static int session_unlink_x11_socket(Session *s) {
655         char *t;
656         int r;
657
658         assert(s);
659         assert(s->user);
660
661         if (s->user->display != s)
662                 return 0;
663
664         s->user->display = NULL;
665
666         t = strappend(s->user->runtime_path, "/X11-display");
667         if (!t)
668                 return log_oom();
669
670         r = unlink(t);
671         free(t);
672
673         return r < 0 ? -errno : 0;
674 }
675
676 int session_stop(Session *s) {
677         int r = 0, k;
678
679         assert(s);
680
681         if (s->started)
682                 log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
683                          "Removed session %s.", s->id);
684
685         /* Kill cgroup */
686         k = session_terminate_cgroup(s);
687         if (k < 0)
688                 r = k;
689
690         /* Remove X11 symlink */
691         session_unlink_x11_socket(s);
692
693         unlink(s->state_file);
694         session_add_to_gc_queue(s);
695         user_add_to_gc_queue(s->user);
696
697         if (s->started)
698                 session_send_signal(s, false);
699
700         if (s->seat) {
701                 if (s->seat->active == s)
702                         seat_set_active(s->seat, NULL);
703
704                 seat_send_changed(s->seat, "Sessions\0");
705         }
706
707         user_send_changed(s->user, "Sessions\0");
708
709         s->started = false;
710
711         return r;
712 }
713
714 bool session_is_active(Session *s) {
715         assert(s);
716
717         if (!s->seat)
718                 return true;
719
720         return s->seat->active == s;
721 }
722
723 int session_get_idle_hint(Session *s, dual_timestamp *t) {
724         char *p;
725         struct stat st;
726         usec_t u, n;
727         bool b;
728         int k;
729
730         assert(s);
731
732         if (s->idle_hint) {
733                 if (t)
734                         *t = s->idle_hint_timestamp;
735
736                 return s->idle_hint;
737         }
738
739         if (isempty(s->tty))
740                 goto dont_know;
741
742         if (s->tty[0] != '/') {
743                 p = strappend("/dev/", s->tty);
744                 if (!p)
745                         return -ENOMEM;
746         } else
747                 p = NULL;
748
749         if (!startswith(p ? p : s->tty, "/dev/")) {
750                 free(p);
751                 goto dont_know;
752         }
753
754         k = lstat(p ? p : s->tty, &st);
755         free(p);
756
757         if (k < 0)
758                 goto dont_know;
759
760         u = timespec_load(&st.st_atim);
761         n = now(CLOCK_REALTIME);
762         b = u + IDLE_THRESHOLD_USEC < n;
763
764         if (t)
765                 dual_timestamp_from_realtime(t, u + b*IDLE_THRESHOLD_USEC);
766
767         return b;
768
769 dont_know:
770         if (t)
771                 *t = s->idle_hint_timestamp;
772
773         return 0;
774 }
775
776 void session_set_idle_hint(Session *s, bool b) {
777         assert(s);
778
779         if (s->idle_hint == b)
780                 return;
781
782         s->idle_hint = b;
783         dual_timestamp_get(&s->idle_hint_timestamp);
784
785         session_send_changed(s,
786                              "IdleHint\0"
787                              "IdleSinceHint\0"
788                              "IdleSinceHintMonotonic\0");
789
790         if (s->seat)
791                 seat_send_changed(s->seat,
792                                   "IdleHint\0"
793                                   "IdleSinceHint\0"
794                                   "IdleSinceHintMonotonic\0");
795
796         user_send_changed(s->user,
797                           "IdleHint\0"
798                           "IdleSinceHint\0"
799                           "IdleSinceHintMonotonic\0");
800
801         manager_send_changed(s->manager,
802                              "IdleHint\0"
803                              "IdleSinceHint\0"
804                              "IdleSinceHintMonotonic\0");
805 }
806
807 int session_create_fifo(Session *s) {
808         int r;
809
810         assert(s);
811
812         /* Create FIFO */
813         if (!s->fifo_path) {
814                 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
815                 if (r < 0)
816                         return r;
817
818                 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
819                         return -ENOMEM;
820
821                 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
822                         return -errno;
823         }
824
825         /* Open reading side */
826         if (s->fifo_fd < 0) {
827                 struct epoll_event ev;
828
829                 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
830                 if (s->fifo_fd < 0)
831                         return -errno;
832
833                 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
834                 if (r < 0)
835                         return r;
836
837                 zero(ev);
838                 ev.events = 0;
839                 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
840
841                 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
842                         return -errno;
843         }
844
845         /* Open writing side */
846         r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
847         if (r < 0)
848                 return -errno;
849
850         return r;
851 }
852
853 void session_remove_fifo(Session *s) {
854         assert(s);
855
856         if (s->fifo_fd >= 0) {
857                 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
858                 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
859                 close_nointr_nofail(s->fifo_fd);
860                 s->fifo_fd = -1;
861         }
862
863         if (s->fifo_path) {
864                 unlink(s->fifo_path);
865                 free(s->fifo_path);
866                 s->fifo_path = NULL;
867         }
868 }
869
870 int session_check_gc(Session *s, bool drop_not_started) {
871         int r;
872
873         assert(s);
874
875         if (drop_not_started && !s->started)
876                 return 0;
877
878         if (s->fifo_fd >= 0) {
879
880                 r = pipe_eof(s->fifo_fd);
881                 if (r < 0)
882                         return r;
883
884                 if (r == 0)
885                         return 1;
886         }
887
888         if (s->cgroup_path) {
889
890                 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
891                 if (r < 0)
892                         return r;
893
894                 if (r <= 0)
895                         return 1;
896         }
897
898         return 0;
899 }
900
901 void session_add_to_gc_queue(Session *s) {
902         assert(s);
903
904         if (s->in_gc_queue)
905                 return;
906
907         LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
908         s->in_gc_queue = true;
909 }
910
911 SessionState session_get_state(Session *s) {
912         assert(s);
913
914         if (s->fifo_fd < 0)
915                 return SESSION_CLOSING;
916
917         if (session_is_active(s))
918                 return SESSION_ACTIVE;
919
920         return SESSION_ONLINE;
921 }
922
923 int session_kill(Session *s, KillWho who, int signo) {
924         int r = 0;
925         Set *pid_set = NULL;
926
927         assert(s);
928
929         if (!s->cgroup_path)
930                 return -ESRCH;
931
932         if (s->leader <= 0 && who == KILL_LEADER)
933                 return -ESRCH;
934
935         if (s->leader > 0)
936                 if (kill(s->leader, signo) < 0)
937                         r = -errno;
938
939         if (who == KILL_ALL) {
940                 int q;
941
942                 pid_set = set_new(trivial_hash_func, trivial_compare_func);
943                 if (!pid_set)
944                         return -ENOMEM;
945
946                 if (s->leader > 0) {
947                         q = set_put(pid_set, LONG_TO_PTR(s->leader));
948                         if (q < 0)
949                                 r = q;
950                 }
951
952                 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
953                 if (q < 0)
954                         if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
955                                 r = q;
956         }
957
958         if (pid_set)
959                 set_free(pid_set);
960
961         return r;
962 }
963
964 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
965         [SESSION_ONLINE] = "online",
966         [SESSION_ACTIVE] = "active",
967         [SESSION_CLOSING] = "closing"
968 };
969
970 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
971
972 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
973         [SESSION_TTY] = "tty",
974         [SESSION_X11] = "x11",
975         [SESSION_UNSPECIFIED] = "unspecified"
976 };
977
978 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
979
980 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
981         [SESSION_USER] = "user",
982         [SESSION_GREETER] = "greeter",
983         [SESSION_LOCK_SCREEN] = "lock-screen"
984 };
985
986 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
987
988 static const char* const kill_who_table[_KILL_WHO_MAX] = {
989         [KILL_LEADER] = "leader",
990         [KILL_ALL] = "all"
991 };
992
993 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);