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