]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session.c
relicense to LGPLv2.1 (with exceptions)
[thirdparty/systemd.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 "logind-session.h"
29 #include "strv.h"
30 #include "util.h"
31 #include "mkdir.h"
32 #include "cgroup-util.h"
33
34 #define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE)
35
36 Session* session_new(Manager *m, User *u, const char *id) {
37 Session *s;
38
39 assert(m);
40 assert(id);
41
42 s = new0(Session, 1);
43 if (!s)
44 return NULL;
45
46 s->state_file = strappend("/run/systemd/sessions/", id);
47 if (!s->state_file) {
48 free(s);
49 return NULL;
50 }
51
52 s->id = file_name_from_path(s->state_file);
53
54 if (hashmap_put(m->sessions, s->id, s) < 0) {
55 free(s->id);
56 free(s);
57 return NULL;
58 }
59
60 s->manager = m;
61 s->fifo_fd = -1;
62 s->user = u;
63
64 LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
65
66 return s;
67 }
68
69 void session_free(Session *s) {
70 assert(s);
71
72 if (s->in_gc_queue)
73 LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
74
75 if (s->user) {
76 LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
77
78 if (s->user->display == s)
79 s->user->display = NULL;
80 }
81
82 if (s->seat) {
83 if (s->seat->active == s)
84 s->seat->active = NULL;
85
86 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
87 }
88
89 if (s->cgroup_path)
90 hashmap_remove(s->manager->cgroups, s->cgroup_path);
91
92 free(s->cgroup_path);
93 strv_free(s->controllers);
94
95 free(s->tty);
96 free(s->display);
97 free(s->remote_host);
98 free(s->remote_user);
99 free(s->service);
100
101 hashmap_remove(s->manager->sessions, s->id);
102
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 = safe_mkdir("/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 "REMOTE=%i\n"
137 "KILL_PROCESSES=%i\n",
138 (unsigned long) s->user->uid,
139 s->user->name,
140 session_is_active(s),
141 s->remote,
142 s->kill_processes);
143
144 if (s->type >= 0)
145 fprintf(f,
146 "TYPE=%s\n",
147 session_type_to_string(s->type));
148
149 if (s->class >= 0)
150 fprintf(f,
151 "CLASS=%s\n",
152 session_class_to_string(s->class));
153
154 if (s->cgroup_path)
155 fprintf(f,
156 "CGROUP=%s\n",
157 s->cgroup_path);
158
159 if (s->fifo_path)
160 fprintf(f,
161 "FIFO=%s\n",
162 s->fifo_path);
163
164 if (s->seat)
165 fprintf(f,
166 "SEAT=%s\n",
167 s->seat->id);
168
169 if (s->tty)
170 fprintf(f,
171 "TTY=%s\n",
172 s->tty);
173
174 if (s->display)
175 fprintf(f,
176 "DISPLAY=%s\n",
177 s->display);
178
179 if (s->remote_host)
180 fprintf(f,
181 "REMOTE_HOST=%s\n",
182 s->remote_host);
183
184 if (s->remote_user)
185 fprintf(f,
186 "REMOTE_USER=%s\n",
187 s->remote_user);
188
189 if (s->service)
190 fprintf(f,
191 "SERVICE=%s\n",
192 s->service);
193
194 if (s->seat && seat_can_multi_session(s->seat))
195 fprintf(f,
196 "VTNR=%i\n",
197 s->vtnr);
198
199 if (s->leader > 0)
200 fprintf(f,
201 "LEADER=%lu\n",
202 (unsigned long) s->leader);
203
204 if (s->audit_id > 0)
205 fprintf(f,
206 "AUDIT=%llu\n",
207 (unsigned long long) s->audit_id);
208
209 fflush(f);
210
211 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
212 r = -errno;
213 unlink(s->state_file);
214 unlink(temp_path);
215 }
216
217 fclose(f);
218 free(temp_path);
219
220 finish:
221 if (r < 0)
222 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
223
224 return r;
225 }
226
227 int session_load(Session *s) {
228 char *remote = NULL,
229 *kill_processes = NULL,
230 *seat = NULL,
231 *vtnr = NULL,
232 *leader = NULL,
233 *audit_id = NULL,
234 *type = NULL,
235 *class = NULL;
236
237 int k, r;
238
239 assert(s);
240
241 r = parse_env_file(s->state_file, NEWLINE,
242 "REMOTE", &remote,
243 "KILL_PROCESSES", &kill_processes,
244 "CGROUP", &s->cgroup_path,
245 "FIFO", &s->fifo_path,
246 "SEAT", &seat,
247 "TTY", &s->tty,
248 "DISPLAY", &s->display,
249 "REMOTE_HOST", &s->remote_host,
250 "REMOTE_USER", &s->remote_user,
251 "SERVICE", &s->service,
252 "VTNR", &vtnr,
253 "LEADER", &leader,
254 "TYPE", &type,
255 "CLASS", &class,
256 NULL);
257
258 if (r < 0)
259 goto finish;
260
261 if (remote) {
262 k = parse_boolean(remote);
263 if (k >= 0)
264 s->remote = k;
265 }
266
267 if (kill_processes) {
268 k = parse_boolean(kill_processes);
269 if (k >= 0)
270 s->kill_processes = k;
271 }
272
273 if (seat && !s->seat) {
274 Seat *o;
275
276 o = hashmap_get(s->manager->seats, seat);
277 if (o)
278 seat_attach_session(o, s);
279 }
280
281 if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
282 int v;
283
284 k = safe_atoi(vtnr, &v);
285 if (k >= 0 && v >= 1)
286 s->vtnr = v;
287 }
288
289 if (leader) {
290 pid_t pid;
291
292 k = parse_pid(leader, &pid);
293 if (k >= 0 && pid >= 1) {
294 s->leader = pid;
295
296 audit_session_from_pid(pid, &s->audit_id);
297 }
298 }
299
300 if (type) {
301 SessionType t;
302
303 t = session_type_from_string(type);
304 if (t >= 0)
305 s->type = t;
306 }
307
308 if (class) {
309 SessionClass c;
310
311 c = session_class_from_string(class);
312 if (c >= 0)
313 s->class = c;
314 }
315
316 if (s->fifo_path) {
317 int fd;
318
319 /* If we open an unopened pipe for reading we will not
320 get an EOF. to trigger an EOF we hence open it for
321 reading, but close it right-away which then will
322 trigger the EOF. */
323
324 fd = session_create_fifo(s);
325 if (fd >= 0)
326 close_nointr_nofail(fd);
327 }
328
329
330 finish:
331 free(remote);
332 free(kill_processes);
333 free(seat);
334 free(vtnr);
335 free(leader);
336 free(audit_id);
337
338 return r;
339 }
340
341 int session_activate(Session *s) {
342 int r;
343
344 assert(s);
345
346 if (s->vtnr < 0)
347 return -ENOTSUP;
348
349 if (!s->seat)
350 return -ENOTSUP;
351
352 if (s->seat->active == s)
353 return 0;
354
355 assert(seat_is_vtconsole(s->seat));
356
357 r = chvt(s->vtnr);
358 if (r < 0)
359 return r;
360
361 return seat_set_active(s->seat, s);
362 }
363
364 static int session_link_x11_socket(Session *s) {
365 char *t, *f, *c;
366 size_t k;
367
368 assert(s);
369 assert(s->user);
370 assert(s->user->runtime_path);
371
372 if (s->user->display)
373 return 0;
374
375 if (!s->display || !display_is_local(s->display))
376 return 0;
377
378 k = strspn(s->display+1, "0123456789");
379 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
380 if (!f) {
381 log_error("Out of memory");
382 return -ENOMEM;
383 }
384
385 c = stpcpy(f, "/tmp/.X11-unix/X");
386 memcpy(c, s->display+1, k);
387 c[k] = 0;
388
389 if (access(f, F_OK) < 0) {
390 log_warning("Session %s has display %s with nonexisting socket %s.", s->id, s->display, f);
391 free(f);
392 return -ENOENT;
393 }
394
395 /* Note that this cannot be in a subdir to avoid
396 * vulnerabilities since we are privileged but the runtime
397 * path is owned by the user */
398
399 t = strappend(s->user->runtime_path, "/X11-display");
400 if (!t) {
401 log_error("Out of memory");
402 free(f);
403 return -ENOMEM;
404 }
405
406 if (link(f, t) < 0) {
407 if (errno == EEXIST) {
408 unlink(t);
409
410 if (link(f, t) >= 0)
411 goto done;
412 }
413
414 if (symlink(f, t) < 0) {
415
416 if (errno == EEXIST) {
417 unlink(t);
418
419 if (symlink(f, t) >= 0)
420 goto done;
421 }
422
423 log_error("Failed to link %s to %s: %m", f, t);
424 free(f);
425 free(t);
426 return -errno;
427 }
428 }
429
430 done:
431 log_info("Linked %s to %s.", f, t);
432 free(f);
433 free(t);
434
435 s->user->display = s;
436
437 return 0;
438 }
439
440 static int session_create_one_group(Session *s, const char *controller, const char *path) {
441 int r;
442
443 assert(s);
444 assert(controller);
445 assert(path);
446
447 if (s->leader > 0) {
448 r = cg_create_and_attach(controller, path, s->leader);
449 if (r < 0)
450 r = cg_create(controller, path);
451 } else
452 r = cg_create(controller, path);
453
454 if (r < 0)
455 return r;
456
457 r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid, -1);
458 if (r >= 0)
459 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
460
461 return r;
462 }
463
464 static int session_create_cgroup(Session *s) {
465 char **k;
466 char *p;
467 int r;
468
469 assert(s);
470 assert(s->user);
471 assert(s->user->cgroup_path);
472
473 if (!s->cgroup_path) {
474 if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0) {
475 log_error("Out of memory");
476 return -ENOMEM;
477 }
478 } else
479 p = s->cgroup_path;
480
481 r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
482 if (r < 0) {
483 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
484 free(p);
485 s->cgroup_path = NULL;
486 return r;
487 }
488
489 s->cgroup_path = p;
490
491 STRV_FOREACH(k, s->controllers) {
492
493 if (strv_contains(s->reset_controllers, *k))
494 continue;
495
496 r = session_create_one_group(s, *k, p);
497 if (r < 0)
498 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
499 }
500
501 STRV_FOREACH(k, s->manager->controllers) {
502
503 if (strv_contains(s->reset_controllers, *k) ||
504 strv_contains(s->manager->reset_controllers, *k) ||
505 strv_contains(s->controllers, *k))
506 continue;
507
508 r = session_create_one_group(s, *k, p);
509 if (r < 0)
510 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
511 }
512
513 if (s->leader > 0) {
514
515 STRV_FOREACH(k, s->reset_controllers) {
516 r = cg_attach(*k, "/", s->leader);
517 if (r < 0)
518 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
519
520 }
521
522 STRV_FOREACH(k, s->manager->reset_controllers) {
523
524 if (strv_contains(s->reset_controllers, *k) ||
525 strv_contains(s->controllers, *k))
526 continue;
527
528 r = cg_attach(*k, "/", s->leader);
529 if (r < 0)
530 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
531
532 }
533 }
534
535 hashmap_put(s->manager->cgroups, s->cgroup_path, s);
536
537 return 0;
538 }
539
540 int session_start(Session *s) {
541 int r;
542
543 assert(s);
544 assert(s->user);
545
546 if (s->started)
547 return 0;
548
549 r = user_start(s->user);
550 if (r < 0)
551 return r;
552
553 log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
554 "New session %s of user %s.", s->id, s->user->name);
555
556 /* Create cgroup */
557 r = session_create_cgroup(s);
558 if (r < 0)
559 return r;
560
561 /* Create X11 symlink */
562 session_link_x11_socket(s);
563
564 dual_timestamp_get(&s->timestamp);
565
566 if (s->seat)
567 seat_read_active_vt(s->seat);
568
569 s->started = true;
570
571 /* Save session data */
572 session_save(s);
573 user_save(s->user);
574
575 session_send_signal(s, true);
576
577 if (s->seat) {
578 seat_save(s->seat);
579
580 if (s->seat->active == s)
581 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
582 else
583 seat_send_changed(s->seat, "Sessions\0");
584 }
585
586 user_send_changed(s->user, "Sessions\0");
587
588 return 0;
589 }
590
591 static bool session_shall_kill(Session *s) {
592 assert(s);
593
594 if (!s->kill_processes)
595 return false;
596
597 if (strv_contains(s->manager->kill_exclude_users, s->user->name))
598 return false;
599
600 if (strv_isempty(s->manager->kill_only_users))
601 return true;
602
603 return strv_contains(s->manager->kill_only_users, s->user->name);
604 }
605
606 static int session_terminate_cgroup(Session *s) {
607 int r;
608 char **k;
609
610 assert(s);
611
612 if (!s->cgroup_path)
613 return 0;
614
615 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
616
617 if (session_shall_kill(s)) {
618
619 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
620 if (r < 0)
621 log_error("Failed to kill session cgroup: %s", strerror(-r));
622
623 } else {
624 if (s->leader > 0) {
625 Session *t;
626
627 /* We still send a HUP to the leader process,
628 * even if we are not supposed to kill the
629 * whole cgroup. But let's first check the
630 * leader still exists and belongs to our
631 * session... */
632
633 r = manager_get_session_by_pid(s->manager, s->leader, &t);
634 if (r > 0 && t == s) {
635 kill(s->leader, SIGTERM); /* for normal processes */
636 kill(s->leader, SIGHUP); /* for shells */
637 kill(s->leader, SIGCONT); /* in case they are stopped */
638 }
639 }
640
641 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
642 if (r < 0)
643 log_error("Failed to check session cgroup: %s", strerror(-r));
644 else if (r > 0) {
645 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
646 if (r < 0)
647 log_error("Failed to delete session cgroup: %s", strerror(-r));
648 }
649 }
650
651 STRV_FOREACH(k, s->user->manager->controllers)
652 cg_trim(*k, s->cgroup_path, true);
653
654 hashmap_remove(s->manager->cgroups, s->cgroup_path);
655
656 free(s->cgroup_path);
657 s->cgroup_path = NULL;
658
659 return 0;
660 }
661
662 static int session_unlink_x11_socket(Session *s) {
663 char *t;
664 int r;
665
666 assert(s);
667 assert(s->user);
668
669 if (s->user->display != s)
670 return 0;
671
672 s->user->display = NULL;
673
674 t = strappend(s->user->runtime_path, "/X11-display");
675 if (!t) {
676 log_error("Out of memory");
677 return -ENOMEM;
678 }
679
680 r = unlink(t);
681 free(t);
682
683 return r < 0 ? -errno : 0;
684 }
685
686 int session_stop(Session *s) {
687 int r = 0, k;
688
689 assert(s);
690
691 if (s->started)
692 log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
693 "Removed session %s.", s->id);
694
695 /* Kill cgroup */
696 k = session_terminate_cgroup(s);
697 if (k < 0)
698 r = k;
699
700 /* Remove X11 symlink */
701 session_unlink_x11_socket(s);
702
703 unlink(s->state_file);
704 session_add_to_gc_queue(s);
705 user_add_to_gc_queue(s->user);
706
707 if (s->started)
708 session_send_signal(s, false);
709
710 if (s->seat) {
711 if (s->seat->active == s)
712 seat_set_active(s->seat, NULL);
713
714 seat_send_changed(s->seat, "Sessions\0");
715 }
716
717 user_send_changed(s->user, "Sessions\0");
718
719 s->started = false;
720
721 return r;
722 }
723
724 bool session_is_active(Session *s) {
725 assert(s);
726
727 if (!s->seat)
728 return true;
729
730 return s->seat->active == s;
731 }
732
733 int session_get_idle_hint(Session *s, dual_timestamp *t) {
734 char *p;
735 struct stat st;
736 usec_t u, n;
737 bool b;
738 int k;
739
740 assert(s);
741
742 if (s->idle_hint) {
743 if (t)
744 *t = s->idle_hint_timestamp;
745
746 return s->idle_hint;
747 }
748
749 if (isempty(s->tty))
750 goto dont_know;
751
752 if (s->tty[0] != '/') {
753 p = strappend("/dev/", s->tty);
754 if (!p)
755 return -ENOMEM;
756 } else
757 p = NULL;
758
759 if (!startswith(p ? p : s->tty, "/dev/")) {
760 free(p);
761 goto dont_know;
762 }
763
764 k = lstat(p ? p : s->tty, &st);
765 free(p);
766
767 if (k < 0)
768 goto dont_know;
769
770 u = timespec_load(&st.st_atim);
771 n = now(CLOCK_REALTIME);
772 b = u + IDLE_THRESHOLD_USEC < n;
773
774 if (t)
775 dual_timestamp_from_realtime(t, u + b ? IDLE_THRESHOLD_USEC : 0);
776
777 return b;
778
779 dont_know:
780 if (t)
781 *t = s->idle_hint_timestamp;
782
783 return 0;
784 }
785
786 void session_set_idle_hint(Session *s, bool b) {
787 assert(s);
788
789 if (s->idle_hint == b)
790 return;
791
792 s->idle_hint = b;
793 dual_timestamp_get(&s->idle_hint_timestamp);
794
795 session_send_changed(s,
796 "IdleHint\0"
797 "IdleSinceHint\0"
798 "IdleSinceHintMonotonic\0");
799
800 if (s->seat)
801 seat_send_changed(s->seat,
802 "IdleHint\0"
803 "IdleSinceHint\0"
804 "IdleSinceHintMonotonic\0");
805
806 user_send_changed(s->user,
807 "IdleHint\0"
808 "IdleSinceHint\0"
809 "IdleSinceHintMonotonic\0");
810
811 manager_send_changed(s->manager,
812 "IdleHint\0"
813 "IdleSinceHint\0"
814 "IdleSinceHintMonotonic\0");
815 }
816
817 int session_create_fifo(Session *s) {
818 int r;
819
820 assert(s);
821
822 /* Create FIFO */
823 if (!s->fifo_path) {
824 r = safe_mkdir("/run/systemd/sessions", 0755, 0, 0);
825 if (r < 0)
826 return r;
827
828 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
829 return -ENOMEM;
830
831 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
832 return -errno;
833 }
834
835 /* Open reading side */
836 if (s->fifo_fd < 0) {
837 struct epoll_event ev;
838
839 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
840 if (s->fifo_fd < 0)
841 return -errno;
842
843 r = hashmap_put(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1), s);
844 if (r < 0)
845 return r;
846
847 zero(ev);
848 ev.events = 0;
849 ev.data.u32 = FD_FIFO_BASE + s->fifo_fd;
850
851 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
852 return -errno;
853 }
854
855 /* Open writing side */
856 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
857 if (r < 0)
858 return -errno;
859
860 return r;
861 }
862
863 void session_remove_fifo(Session *s) {
864 assert(s);
865
866 if (s->fifo_fd >= 0) {
867 assert_se(hashmap_remove(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
868 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
869 close_nointr_nofail(s->fifo_fd);
870 s->fifo_fd = -1;
871 }
872
873 if (s->fifo_path) {
874 unlink(s->fifo_path);
875 free(s->fifo_path);
876 s->fifo_path = NULL;
877 }
878 }
879
880 int session_check_gc(Session *s, bool drop_not_started) {
881 int r;
882
883 assert(s);
884
885 if (drop_not_started && !s->started)
886 return 0;
887
888 if (s->fifo_fd >= 0) {
889
890 r = pipe_eof(s->fifo_fd);
891 if (r < 0)
892 return r;
893
894 if (r == 0)
895 return 1;
896 }
897
898 if (s->cgroup_path) {
899
900 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
901 if (r < 0)
902 return r;
903
904 if (r <= 0)
905 return 1;
906 }
907
908 return 0;
909 }
910
911 void session_add_to_gc_queue(Session *s) {
912 assert(s);
913
914 if (s->in_gc_queue)
915 return;
916
917 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
918 s->in_gc_queue = true;
919 }
920
921 int session_kill(Session *s, KillWho who, int signo) {
922 int r = 0;
923 Set *pid_set = NULL;
924
925 assert(s);
926
927 if (!s->cgroup_path)
928 return -ESRCH;
929
930 if (s->leader <= 0 && who == KILL_LEADER)
931 return -ESRCH;
932
933 if (s->leader > 0)
934 if (kill(s->leader, signo) < 0)
935 r = -errno;
936
937 if (who == KILL_ALL) {
938 int q;
939
940 pid_set = set_new(trivial_hash_func, trivial_compare_func);
941 if (!pid_set)
942 return -ENOMEM;
943
944 if (s->leader > 0) {
945 q = set_put(pid_set, LONG_TO_PTR(s->leader));
946 if (q < 0)
947 r = q;
948 }
949
950 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
951 if (q < 0)
952 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
953 r = q;
954 }
955
956 if (pid_set)
957 set_free(pid_set);
958
959 return r;
960 }
961
962 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
963 [SESSION_TTY] = "tty",
964 [SESSION_X11] = "x11",
965 [SESSION_UNSPECIFIED] = "unspecified"
966 };
967
968 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
969
970 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
971 [SESSION_USER] = "user",
972 [SESSION_GREETER] = "greeter",
973 [SESSION_LOCK_SCREEN] = "lock-screen"
974 };
975
976 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
977
978 static const char* const kill_who_table[_KILL_WHO_MAX] = {
979 [KILL_LEADER] = "leader",
980 [KILL_ALL] = "all"
981 };
982
983 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);