]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session.c
e297d3feeba689880c2b01e51ffd8c0e31df79b2
[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 free(class);
331
332 return r;
333 }
334
335 int session_activate(Session *s) {
336 int r;
337
338 assert(s);
339
340 if (s->vtnr < 0)
341 return -ENOTSUP;
342
343 if (!s->seat)
344 return -ENOTSUP;
345
346 if (s->seat->active == s)
347 return 0;
348
349 assert(seat_is_vtconsole(s->seat));
350
351 r = chvt(s->vtnr);
352 if (r < 0)
353 return r;
354
355 return seat_set_active(s->seat, s);
356 }
357
358 static int session_link_x11_socket(Session *s) {
359 char *t, *f, *c;
360 size_t k;
361
362 assert(s);
363 assert(s->user);
364 assert(s->user->runtime_path);
365
366 if (s->user->display)
367 return 0;
368
369 if (!s->display || !display_is_local(s->display))
370 return 0;
371
372 k = strspn(s->display+1, "0123456789");
373 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
374 if (!f) {
375 log_error("Out of memory");
376 return -ENOMEM;
377 }
378
379 c = stpcpy(f, "/tmp/.X11-unix/X");
380 memcpy(c, s->display+1, k);
381 c[k] = 0;
382
383 if (access(f, F_OK) < 0) {
384 log_warning("Session %s has display %s with nonexisting socket %s.", s->id, s->display, f);
385 free(f);
386 return -ENOENT;
387 }
388
389 /* Note that this cannot be in a subdir to avoid
390 * vulnerabilities since we are privileged but the runtime
391 * path is owned by the user */
392
393 t = strappend(s->user->runtime_path, "/X11-display");
394 if (!t) {
395 log_error("Out of memory");
396 free(f);
397 return -ENOMEM;
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 log_error("Out of memory");
470 return -ENOMEM;
471 }
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->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_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
548 "New session %s of user %s.", s->id, s->user->name);
549
550 /* Create cgroup */
551 r = session_create_cgroup(s);
552 if (r < 0)
553 return r;
554
555 /* Create X11 symlink */
556 session_link_x11_socket(s);
557
558 dual_timestamp_get(&s->timestamp);
559
560 if (s->seat)
561 seat_read_active_vt(s->seat);
562
563 s->started = true;
564
565 /* Save session data */
566 session_save(s);
567 user_save(s->user);
568
569 session_send_signal(s, true);
570
571 if (s->seat) {
572 seat_save(s->seat);
573
574 if (s->seat->active == s)
575 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
576 else
577 seat_send_changed(s->seat, "Sessions\0");
578 }
579
580 user_send_changed(s->user, "Sessions\0");
581
582 return 0;
583 }
584
585 static bool session_shall_kill(Session *s) {
586 assert(s);
587
588 if (!s->kill_processes)
589 return false;
590
591 if (strv_contains(s->manager->kill_exclude_users, s->user->name))
592 return false;
593
594 if (strv_isempty(s->manager->kill_only_users))
595 return true;
596
597 return strv_contains(s->manager->kill_only_users, s->user->name);
598 }
599
600 static int session_terminate_cgroup(Session *s) {
601 int r;
602 char **k;
603
604 assert(s);
605
606 if (!s->cgroup_path)
607 return 0;
608
609 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
610
611 if (session_shall_kill(s)) {
612
613 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
614 if (r < 0)
615 log_error("Failed to kill session cgroup: %s", strerror(-r));
616
617 } else {
618 if (s->leader > 0) {
619 Session *t;
620
621 /* We still send a HUP to the leader process,
622 * even if we are not supposed to kill the
623 * whole cgroup. But let's first check the
624 * leader still exists and belongs to our
625 * session... */
626
627 r = manager_get_session_by_pid(s->manager, s->leader, &t);
628 if (r > 0 && t == s) {
629 kill(s->leader, SIGTERM); /* for normal processes */
630 kill(s->leader, SIGHUP); /* for shells */
631 kill(s->leader, SIGCONT); /* in case they are stopped */
632 }
633 }
634
635 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
636 if (r < 0)
637 log_error("Failed to check session cgroup: %s", strerror(-r));
638 else if (r > 0) {
639 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
640 if (r < 0)
641 log_error("Failed to delete session cgroup: %s", strerror(-r));
642 }
643 }
644
645 STRV_FOREACH(k, s->user->manager->controllers)
646 cg_trim(*k, s->cgroup_path, true);
647
648 hashmap_remove(s->manager->cgroups, s->cgroup_path);
649
650 free(s->cgroup_path);
651 s->cgroup_path = NULL;
652
653 return 0;
654 }
655
656 static int session_unlink_x11_socket(Session *s) {
657 char *t;
658 int r;
659
660 assert(s);
661 assert(s->user);
662
663 if (s->user->display != s)
664 return 0;
665
666 s->user->display = NULL;
667
668 t = strappend(s->user->runtime_path, "/X11-display");
669 if (!t) {
670 log_error("Out of memory");
671 return -ENOMEM;
672 }
673
674 r = unlink(t);
675 free(t);
676
677 return r < 0 ? -errno : 0;
678 }
679
680 int session_stop(Session *s) {
681 int r = 0, k;
682
683 assert(s);
684
685 if (s->started)
686 log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
687 "Removed session %s.", s->id);
688
689 /* Kill cgroup */
690 k = session_terminate_cgroup(s);
691 if (k < 0)
692 r = k;
693
694 /* Remove X11 symlink */
695 session_unlink_x11_socket(s);
696
697 unlink(s->state_file);
698 session_add_to_gc_queue(s);
699 user_add_to_gc_queue(s->user);
700
701 if (s->started)
702 session_send_signal(s, false);
703
704 if (s->seat) {
705 if (s->seat->active == s)
706 seat_set_active(s->seat, NULL);
707
708 seat_send_changed(s->seat, "Sessions\0");
709 }
710
711 user_send_changed(s->user, "Sessions\0");
712
713 s->started = false;
714
715 return r;
716 }
717
718 bool session_is_active(Session *s) {
719 assert(s);
720
721 if (!s->seat)
722 return true;
723
724 return s->seat->active == s;
725 }
726
727 int session_get_idle_hint(Session *s, dual_timestamp *t) {
728 char *p;
729 struct stat st;
730 usec_t u, n;
731 bool b;
732 int k;
733
734 assert(s);
735
736 if (s->idle_hint) {
737 if (t)
738 *t = s->idle_hint_timestamp;
739
740 return s->idle_hint;
741 }
742
743 if (isempty(s->tty))
744 goto dont_know;
745
746 if (s->tty[0] != '/') {
747 p = strappend("/dev/", s->tty);
748 if (!p)
749 return -ENOMEM;
750 } else
751 p = NULL;
752
753 if (!startswith(p ? p : s->tty, "/dev/")) {
754 free(p);
755 goto dont_know;
756 }
757
758 k = lstat(p ? p : s->tty, &st);
759 free(p);
760
761 if (k < 0)
762 goto dont_know;
763
764 u = timespec_load(&st.st_atim);
765 n = now(CLOCK_REALTIME);
766 b = u + IDLE_THRESHOLD_USEC < n;
767
768 if (t)
769 dual_timestamp_from_realtime(t, u + b ? IDLE_THRESHOLD_USEC : 0);
770
771 return b;
772
773 dont_know:
774 if (t)
775 *t = s->idle_hint_timestamp;
776
777 return 0;
778 }
779
780 void session_set_idle_hint(Session *s, bool b) {
781 assert(s);
782
783 if (s->idle_hint == b)
784 return;
785
786 s->idle_hint = b;
787 dual_timestamp_get(&s->idle_hint_timestamp);
788
789 session_send_changed(s,
790 "IdleHint\0"
791 "IdleSinceHint\0"
792 "IdleSinceHintMonotonic\0");
793
794 if (s->seat)
795 seat_send_changed(s->seat,
796 "IdleHint\0"
797 "IdleSinceHint\0"
798 "IdleSinceHintMonotonic\0");
799
800 user_send_changed(s->user,
801 "IdleHint\0"
802 "IdleSinceHint\0"
803 "IdleSinceHintMonotonic\0");
804
805 manager_send_changed(s->manager,
806 "IdleHint\0"
807 "IdleSinceHint\0"
808 "IdleSinceHintMonotonic\0");
809 }
810
811 int session_create_fifo(Session *s) {
812 int r;
813
814 assert(s);
815
816 /* Create FIFO */
817 if (!s->fifo_path) {
818 r = safe_mkdir("/run/systemd/sessions", 0755, 0, 0);
819 if (r < 0)
820 return r;
821
822 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
823 return -ENOMEM;
824
825 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
826 return -errno;
827 }
828
829 /* Open reading side */
830 if (s->fifo_fd < 0) {
831 struct epoll_event ev;
832
833 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
834 if (s->fifo_fd < 0)
835 return -errno;
836
837 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
838 if (r < 0)
839 return r;
840
841 zero(ev);
842 ev.events = 0;
843 ev.data.u32 = FD_FIFO_BASE + s->fifo_fd;
844
845 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
846 return -errno;
847 }
848
849 /* Open writing side */
850 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
851 if (r < 0)
852 return -errno;
853
854 return r;
855 }
856
857 void session_remove_fifo(Session *s) {
858 assert(s);
859
860 if (s->fifo_fd >= 0) {
861 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
862 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
863 close_nointr_nofail(s->fifo_fd);
864 s->fifo_fd = -1;
865 }
866
867 if (s->fifo_path) {
868 unlink(s->fifo_path);
869 free(s->fifo_path);
870 s->fifo_path = NULL;
871 }
872 }
873
874 int session_check_gc(Session *s, bool drop_not_started) {
875 int r;
876
877 assert(s);
878
879 if (drop_not_started && !s->started)
880 return 0;
881
882 if (s->fifo_fd >= 0) {
883
884 r = pipe_eof(s->fifo_fd);
885 if (r < 0)
886 return r;
887
888 if (r == 0)
889 return 1;
890 }
891
892 if (s->cgroup_path) {
893
894 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
895 if (r < 0)
896 return r;
897
898 if (r <= 0)
899 return 1;
900 }
901
902 return 0;
903 }
904
905 void session_add_to_gc_queue(Session *s) {
906 assert(s);
907
908 if (s->in_gc_queue)
909 return;
910
911 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
912 s->in_gc_queue = true;
913 }
914
915 int session_kill(Session *s, KillWho who, int signo) {
916 int r = 0;
917 Set *pid_set = NULL;
918
919 assert(s);
920
921 if (!s->cgroup_path)
922 return -ESRCH;
923
924 if (s->leader <= 0 && who == KILL_LEADER)
925 return -ESRCH;
926
927 if (s->leader > 0)
928 if (kill(s->leader, signo) < 0)
929 r = -errno;
930
931 if (who == KILL_ALL) {
932 int q;
933
934 pid_set = set_new(trivial_hash_func, trivial_compare_func);
935 if (!pid_set)
936 return -ENOMEM;
937
938 if (s->leader > 0) {
939 q = set_put(pid_set, LONG_TO_PTR(s->leader));
940 if (q < 0)
941 r = q;
942 }
943
944 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
945 if (q < 0)
946 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
947 r = q;
948 }
949
950 if (pid_set)
951 set_free(pid_set);
952
953 return r;
954 }
955
956 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
957 [SESSION_TTY] = "tty",
958 [SESSION_X11] = "x11",
959 [SESSION_UNSPECIFIED] = "unspecified"
960 };
961
962 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
963
964 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
965 [SESSION_USER] = "user",
966 [SESSION_GREETER] = "greeter",
967 [SESSION_LOCK_SCREEN] = "lock-screen"
968 };
969
970 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
971
972 static const char* const kill_who_table[_KILL_WHO_MAX] = {
973 [KILL_LEADER] = "leader",
974 [KILL_ALL] = "all"
975 };
976
977 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);