]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session.c
use "Out of memory." consistantly (or with "\n")
[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 "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 log_error("Out of memory.");
379 return -ENOMEM;
380 }
381
382 c = stpcpy(f, "/tmp/.X11-unix/X");
383 memcpy(c, s->display+1, k);
384 c[k] = 0;
385
386 if (access(f, F_OK) < 0) {
387 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
388 free(f);
389 return -ENOENT;
390 }
391
392 /* Note that this cannot be in a subdir to avoid
393 * vulnerabilities since we are privileged but the runtime
394 * path is owned by the user */
395
396 t = strappend(s->user->runtime_path, "/X11-display");
397 if (!t) {
398 log_error("Out of memory.");
399 free(f);
400 return -ENOMEM;
401 }
402
403 if (link(f, t) < 0) {
404 if (errno == EEXIST) {
405 unlink(t);
406
407 if (link(f, t) >= 0)
408 goto done;
409 }
410
411 if (symlink(f, t) < 0) {
412
413 if (errno == EEXIST) {
414 unlink(t);
415
416 if (symlink(f, t) >= 0)
417 goto done;
418 }
419
420 log_error("Failed to link %s to %s: %m", f, t);
421 free(f);
422 free(t);
423 return -errno;
424 }
425 }
426
427 done:
428 log_info("Linked %s to %s.", f, t);
429 free(f);
430 free(t);
431
432 s->user->display = s;
433
434 return 0;
435 }
436
437 static int session_create_one_group(Session *s, const char *controller, const char *path) {
438 int r;
439
440 assert(s);
441 assert(controller);
442 assert(path);
443
444 if (s->leader > 0) {
445 r = cg_create_and_attach(controller, path, s->leader);
446 if (r < 0)
447 r = cg_create(controller, path);
448 } else
449 r = cg_create(controller, path);
450
451 if (r < 0)
452 return r;
453
454 r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid, -1);
455 if (r >= 0)
456 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
457
458 return r;
459 }
460
461 static int session_create_cgroup(Session *s) {
462 char **k;
463 char *p;
464 int r;
465
466 assert(s);
467 assert(s->user);
468 assert(s->user->cgroup_path);
469
470 if (!s->cgroup_path) {
471 if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0) {
472 log_error("Out of memory.");
473 return -ENOMEM;
474 }
475 } else
476 p = s->cgroup_path;
477
478 r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
479 if (r < 0) {
480 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
481 free(p);
482 s->cgroup_path = NULL;
483 return r;
484 }
485
486 s->cgroup_path = p;
487
488 STRV_FOREACH(k, s->controllers) {
489
490 if (strv_contains(s->reset_controllers, *k))
491 continue;
492
493 r = session_create_one_group(s, *k, p);
494 if (r < 0)
495 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
496 }
497
498 STRV_FOREACH(k, s->manager->controllers) {
499
500 if (strv_contains(s->reset_controllers, *k) ||
501 strv_contains(s->manager->reset_controllers, *k) ||
502 strv_contains(s->controllers, *k))
503 continue;
504
505 r = session_create_one_group(s, *k, p);
506 if (r < 0)
507 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
508 }
509
510 if (s->leader > 0) {
511
512 STRV_FOREACH(k, s->reset_controllers) {
513 r = cg_attach(*k, "/", s->leader);
514 if (r < 0)
515 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
516
517 }
518
519 STRV_FOREACH(k, s->manager->reset_controllers) {
520
521 if (strv_contains(s->reset_controllers, *k) ||
522 strv_contains(s->controllers, *k))
523 continue;
524
525 r = cg_attach(*k, "/", s->leader);
526 if (r < 0)
527 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
528
529 }
530 }
531
532 hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
533
534 return 0;
535 }
536
537 int session_start(Session *s) {
538 int r;
539
540 assert(s);
541 assert(s->user);
542
543 if (s->started)
544 return 0;
545
546 r = user_start(s->user);
547 if (r < 0)
548 return r;
549
550 log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
551 "New session %s of user %s.", s->id, s->user->name);
552
553 /* Create cgroup */
554 r = session_create_cgroup(s);
555 if (r < 0)
556 return r;
557
558 /* Create X11 symlink */
559 session_link_x11_socket(s);
560
561 dual_timestamp_get(&s->timestamp);
562
563 if (s->seat)
564 seat_read_active_vt(s->seat);
565
566 s->started = true;
567
568 /* Save session data */
569 session_save(s);
570 user_save(s->user);
571
572 session_send_signal(s, true);
573
574 if (s->seat) {
575 seat_save(s->seat);
576
577 if (s->seat->active == s)
578 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
579 else
580 seat_send_changed(s->seat, "Sessions\0");
581 }
582
583 user_send_changed(s->user, "Sessions\0");
584
585 return 0;
586 }
587
588 static bool session_shall_kill(Session *s) {
589 assert(s);
590
591 if (!s->kill_processes)
592 return false;
593
594 if (strv_contains(s->manager->kill_exclude_users, s->user->name))
595 return false;
596
597 if (strv_isempty(s->manager->kill_only_users))
598 return true;
599
600 return strv_contains(s->manager->kill_only_users, s->user->name);
601 }
602
603 static int session_terminate_cgroup(Session *s) {
604 int r;
605 char **k;
606
607 assert(s);
608
609 if (!s->cgroup_path)
610 return 0;
611
612 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
613
614 if (session_shall_kill(s)) {
615
616 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
617 if (r < 0)
618 log_error("Failed to kill session cgroup: %s", strerror(-r));
619
620 } else {
621 if (s->leader > 0) {
622 Session *t;
623
624 /* We still send a HUP to the leader process,
625 * even if we are not supposed to kill the
626 * whole cgroup. But let's first check the
627 * leader still exists and belongs to our
628 * session... */
629
630 r = manager_get_session_by_pid(s->manager, s->leader, &t);
631 if (r > 0 && t == s) {
632 kill(s->leader, SIGTERM); /* for normal processes */
633 kill(s->leader, SIGHUP); /* for shells */
634 kill(s->leader, SIGCONT); /* in case they are stopped */
635 }
636 }
637
638 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
639 if (r < 0)
640 log_error("Failed to check session cgroup: %s", strerror(-r));
641 else if (r > 0) {
642 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
643 if (r < 0)
644 log_error("Failed to delete session cgroup: %s", strerror(-r));
645 }
646 }
647
648 STRV_FOREACH(k, s->user->manager->controllers)
649 cg_trim(*k, s->cgroup_path, true);
650
651 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
652
653 free(s->cgroup_path);
654 s->cgroup_path = NULL;
655
656 return 0;
657 }
658
659 static int session_unlink_x11_socket(Session *s) {
660 char *t;
661 int r;
662
663 assert(s);
664 assert(s->user);
665
666 if (s->user->display != s)
667 return 0;
668
669 s->user->display = NULL;
670
671 t = strappend(s->user->runtime_path, "/X11-display");
672 if (!t) {
673 log_error("Out of memory.");
674 return -ENOMEM;
675 }
676
677 r = unlink(t);
678 free(t);
679
680 return r < 0 ? -errno : 0;
681 }
682
683 int session_stop(Session *s) {
684 int r = 0, k;
685
686 assert(s);
687
688 if (s->started)
689 log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
690 "Removed session %s.", s->id);
691
692 /* Kill cgroup */
693 k = session_terminate_cgroup(s);
694 if (k < 0)
695 r = k;
696
697 /* Remove X11 symlink */
698 session_unlink_x11_socket(s);
699
700 unlink(s->state_file);
701 session_add_to_gc_queue(s);
702 user_add_to_gc_queue(s->user);
703
704 if (s->started)
705 session_send_signal(s, false);
706
707 if (s->seat) {
708 if (s->seat->active == s)
709 seat_set_active(s->seat, NULL);
710
711 seat_send_changed(s->seat, "Sessions\0");
712 }
713
714 user_send_changed(s->user, "Sessions\0");
715
716 s->started = false;
717
718 return r;
719 }
720
721 bool session_is_active(Session *s) {
722 assert(s);
723
724 if (!s->seat)
725 return true;
726
727 return s->seat->active == s;
728 }
729
730 int session_get_idle_hint(Session *s, dual_timestamp *t) {
731 char *p;
732 struct stat st;
733 usec_t u, n;
734 bool b;
735 int k;
736
737 assert(s);
738
739 if (s->idle_hint) {
740 if (t)
741 *t = s->idle_hint_timestamp;
742
743 return s->idle_hint;
744 }
745
746 if (isempty(s->tty))
747 goto dont_know;
748
749 if (s->tty[0] != '/') {
750 p = strappend("/dev/", s->tty);
751 if (!p)
752 return -ENOMEM;
753 } else
754 p = NULL;
755
756 if (!startswith(p ? p : s->tty, "/dev/")) {
757 free(p);
758 goto dont_know;
759 }
760
761 k = lstat(p ? p : s->tty, &st);
762 free(p);
763
764 if (k < 0)
765 goto dont_know;
766
767 u = timespec_load(&st.st_atim);
768 n = now(CLOCK_REALTIME);
769 b = u + IDLE_THRESHOLD_USEC < n;
770
771 if (t)
772 dual_timestamp_from_realtime(t, u + b*IDLE_THRESHOLD_USEC);
773
774 return b;
775
776 dont_know:
777 if (t)
778 *t = s->idle_hint_timestamp;
779
780 return 0;
781 }
782
783 void session_set_idle_hint(Session *s, bool b) {
784 assert(s);
785
786 if (s->idle_hint == b)
787 return;
788
789 s->idle_hint = b;
790 dual_timestamp_get(&s->idle_hint_timestamp);
791
792 session_send_changed(s,
793 "IdleHint\0"
794 "IdleSinceHint\0"
795 "IdleSinceHintMonotonic\0");
796
797 if (s->seat)
798 seat_send_changed(s->seat,
799 "IdleHint\0"
800 "IdleSinceHint\0"
801 "IdleSinceHintMonotonic\0");
802
803 user_send_changed(s->user,
804 "IdleHint\0"
805 "IdleSinceHint\0"
806 "IdleSinceHintMonotonic\0");
807
808 manager_send_changed(s->manager,
809 "IdleHint\0"
810 "IdleSinceHint\0"
811 "IdleSinceHintMonotonic\0");
812 }
813
814 int session_create_fifo(Session *s) {
815 int r;
816
817 assert(s);
818
819 /* Create FIFO */
820 if (!s->fifo_path) {
821 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
822 if (r < 0)
823 return r;
824
825 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
826 return -ENOMEM;
827
828 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
829 return -errno;
830 }
831
832 /* Open reading side */
833 if (s->fifo_fd < 0) {
834 struct epoll_event ev;
835
836 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
837 if (s->fifo_fd < 0)
838 return -errno;
839
840 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
841 if (r < 0)
842 return r;
843
844 zero(ev);
845 ev.events = 0;
846 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
847
848 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
849 return -errno;
850 }
851
852 /* Open writing side */
853 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
854 if (r < 0)
855 return -errno;
856
857 return r;
858 }
859
860 void session_remove_fifo(Session *s) {
861 assert(s);
862
863 if (s->fifo_fd >= 0) {
864 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
865 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
866 close_nointr_nofail(s->fifo_fd);
867 s->fifo_fd = -1;
868 }
869
870 if (s->fifo_path) {
871 unlink(s->fifo_path);
872 free(s->fifo_path);
873 s->fifo_path = NULL;
874 }
875 }
876
877 int session_check_gc(Session *s, bool drop_not_started) {
878 int r;
879
880 assert(s);
881
882 if (drop_not_started && !s->started)
883 return 0;
884
885 if (s->fifo_fd >= 0) {
886
887 r = pipe_eof(s->fifo_fd);
888 if (r < 0)
889 return r;
890
891 if (r == 0)
892 return 1;
893 }
894
895 if (s->cgroup_path) {
896
897 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
898 if (r < 0)
899 return r;
900
901 if (r <= 0)
902 return 1;
903 }
904
905 return 0;
906 }
907
908 void session_add_to_gc_queue(Session *s) {
909 assert(s);
910
911 if (s->in_gc_queue)
912 return;
913
914 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
915 s->in_gc_queue = true;
916 }
917
918 SessionState session_get_state(Session *s) {
919 assert(s);
920
921 if (s->fifo_fd < 0)
922 return SESSION_CLOSING;
923
924 if (session_is_active(s))
925 return SESSION_ACTIVE;
926
927 return SESSION_ONLINE;
928 }
929
930 int session_kill(Session *s, KillWho who, int signo) {
931 int r = 0;
932 Set *pid_set = NULL;
933
934 assert(s);
935
936 if (!s->cgroup_path)
937 return -ESRCH;
938
939 if (s->leader <= 0 && who == KILL_LEADER)
940 return -ESRCH;
941
942 if (s->leader > 0)
943 if (kill(s->leader, signo) < 0)
944 r = -errno;
945
946 if (who == KILL_ALL) {
947 int q;
948
949 pid_set = set_new(trivial_hash_func, trivial_compare_func);
950 if (!pid_set)
951 return -ENOMEM;
952
953 if (s->leader > 0) {
954 q = set_put(pid_set, LONG_TO_PTR(s->leader));
955 if (q < 0)
956 r = q;
957 }
958
959 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
960 if (q < 0)
961 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
962 r = q;
963 }
964
965 if (pid_set)
966 set_free(pid_set);
967
968 return r;
969 }
970
971 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
972 [SESSION_ONLINE] = "online",
973 [SESSION_ACTIVE] = "active",
974 [SESSION_CLOSING] = "closing"
975 };
976
977 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
978
979 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
980 [SESSION_TTY] = "tty",
981 [SESSION_X11] = "x11",
982 [SESSION_UNSPECIFIED] = "unspecified"
983 };
984
985 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
986
987 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
988 [SESSION_USER] = "user",
989 [SESSION_GREETER] = "greeter",
990 [SESSION_LOCK_SCREEN] = "lock-screen"
991 };
992
993 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
994
995 static const char* const kill_who_table[_KILL_WHO_MAX] = {
996 [KILL_LEADER] = "leader",
997 [KILL_ALL] = "all"
998 };
999
1000 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);