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