]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session.c
nspawn: introduce the new /machine/ tree in the cgroup tree and move containers there
[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 if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0)
469 return log_oom();
470 } else
471 p = s->cgroup_path;
472
473 r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
474 if (r < 0) {
475 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
476 free(p);
477 s->cgroup_path = NULL;
478 return r;
479 }
480
481 s->cgroup_path = p;
482
483 STRV_FOREACH(k, s->controllers) {
484
485 if (strv_contains(s->reset_controllers, *k))
486 continue;
487
488 r = session_create_one_group(s, *k, p);
489 if (r < 0)
490 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
491 }
492
493 STRV_FOREACH(k, s->manager->controllers) {
494
495 if (strv_contains(s->reset_controllers, *k) ||
496 strv_contains(s->manager->reset_controllers, *k) ||
497 strv_contains(s->controllers, *k))
498 continue;
499
500 r = session_create_one_group(s, *k, p);
501 if (r < 0)
502 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
503 }
504
505 if (s->leader > 0) {
506
507 STRV_FOREACH(k, s->reset_controllers) {
508 r = cg_attach(*k, "/", s->leader);
509 if (r < 0)
510 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
511
512 }
513
514 STRV_FOREACH(k, s->manager->reset_controllers) {
515
516 if (strv_contains(s->reset_controllers, *k) ||
517 strv_contains(s->controllers, *k))
518 continue;
519
520 r = cg_attach(*k, "/", s->leader);
521 if (r < 0)
522 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
523
524 }
525 }
526
527 r = hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
528 if (r < 0)
529 log_warning("Failed to create mapping between cgroup and session");
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_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
548 MESSAGE_ID(SD_MESSAGE_SESSION_START),
549 "SESSION_ID=%s", s->id,
550 "USER_ID=%s", s->user->name,
551 "LEADER=%lu", (unsigned long) s->leader,
552 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
553 NULL);
554
555 /* Create cgroup */
556 r = session_create_cgroup(s);
557 if (r < 0)
558 return r;
559
560 /* Create X11 symlink */
561 session_link_x11_socket(s);
562
563 dual_timestamp_get(&s->timestamp);
564
565 if (s->seat)
566 seat_read_active_vt(s->seat);
567
568 s->started = true;
569
570 /* Save session data */
571 session_save(s);
572 user_save(s->user);
573
574 session_send_signal(s, true);
575
576 if (s->seat) {
577 seat_save(s->seat);
578
579 if (s->seat->active == s)
580 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
581 else
582 seat_send_changed(s->seat, "Sessions\0");
583 }
584
585 user_send_changed(s->user, "Sessions\0");
586
587 return 0;
588 }
589
590 static bool session_shall_kill(Session *s) {
591 assert(s);
592
593 if (!s->kill_processes)
594 return false;
595
596 if (strv_contains(s->manager->kill_exclude_users, s->user->name))
597 return false;
598
599 if (strv_isempty(s->manager->kill_only_users))
600 return true;
601
602 return strv_contains(s->manager->kill_only_users, s->user->name);
603 }
604
605 static int session_terminate_cgroup(Session *s) {
606 int r;
607 char **k;
608
609 assert(s);
610
611 if (!s->cgroup_path)
612 return 0;
613
614 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
615
616 if (session_shall_kill(s)) {
617
618 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
619 if (r < 0)
620 log_error("Failed to kill session cgroup: %s", strerror(-r));
621
622 } else {
623 if (s->leader > 0) {
624 Session *t;
625
626 /* We still send a HUP to the leader process,
627 * even if we are not supposed to kill the
628 * whole cgroup. But let's first check the
629 * leader still exists and belongs to our
630 * session... */
631
632 r = manager_get_session_by_pid(s->manager, s->leader, &t);
633 if (r > 0 && t == s) {
634 kill(s->leader, SIGTERM); /* for normal processes */
635 kill(s->leader, SIGHUP); /* for shells */
636 kill(s->leader, SIGCONT); /* in case they are stopped */
637 }
638 }
639
640 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
641 if (r < 0)
642 log_error("Failed to check session cgroup: %s", strerror(-r));
643 else if (r > 0) {
644 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
645 if (r < 0)
646 log_error("Failed to delete session cgroup: %s", strerror(-r));
647 }
648 }
649
650 STRV_FOREACH(k, s->user->manager->controllers)
651 cg_trim(*k, s->cgroup_path, true);
652
653 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
654
655 free(s->cgroup_path);
656 s->cgroup_path = NULL;
657
658 return 0;
659 }
660
661 static int session_unlink_x11_socket(Session *s) {
662 char *t;
663 int r;
664
665 assert(s);
666 assert(s->user);
667
668 if (s->user->display != s)
669 return 0;
670
671 s->user->display = NULL;
672
673 t = strappend(s->user->runtime_path, "/X11-display");
674 if (!t)
675 return log_oom();
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_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
690 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
691 "SESSION_ID=%s", s->id,
692 "USER_ID=%s", s->user->name,
693 "LEADER=%lu", (unsigned long) s->leader,
694 "MESSAGE=Removed session %s.", s->id,
695 NULL);
696
697 /* Kill cgroup */
698 k = session_terminate_cgroup(s);
699 if (k < 0)
700 r = k;
701
702 /* Remove X11 symlink */
703 session_unlink_x11_socket(s);
704
705 unlink(s->state_file);
706 session_add_to_gc_queue(s);
707 user_add_to_gc_queue(s->user);
708
709 if (s->started)
710 session_send_signal(s, false);
711
712 s->started = false;
713
714 if (s->seat) {
715 if (s->seat->active == s)
716 seat_set_active(s->seat, NULL);
717
718 seat_send_changed(s->seat, "Sessions\0");
719 seat_save(s->seat);
720 }
721
722 user_send_changed(s->user, "Sessions\0");
723 user_save(s->user);
724
725 return r;
726 }
727
728 bool session_is_active(Session *s) {
729 assert(s);
730
731 if (!s->seat)
732 return true;
733
734 return s->seat->active == s;
735 }
736
737 static int get_tty_atime(const char *tty, usec_t *atime) {
738 _cleanup_free_ char *p = NULL;
739 struct stat st;
740
741 assert(tty);
742 assert(atime);
743
744 if (!path_is_absolute(tty)) {
745 p = strappend("/dev/", tty);
746 if (!p)
747 return -ENOMEM;
748
749 tty = p;
750 } else if (!path_startswith(tty, "/dev/"))
751 return -ENOENT;
752
753 if (lstat(tty, &st) < 0)
754 return -errno;
755
756 *atime = timespec_load(&st.st_atim);
757 return 0;
758 }
759
760 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
761 _cleanup_free_ char *p = NULL;
762 int r;
763
764 assert(pid > 0);
765 assert(atime);
766
767 r = get_ctty(pid, NULL, &p);
768 if (r < 0)
769 return r;
770
771 return get_tty_atime(p, atime);
772 }
773
774 int session_get_idle_hint(Session *s, dual_timestamp *t) {
775 usec_t atime = 0, n;
776 int r;
777
778 assert(s);
779
780 /* Explicit idle hint is set */
781 if (s->idle_hint) {
782 if (t)
783 *t = s->idle_hint_timestamp;
784
785 return s->idle_hint;
786 }
787
788 /* Graphical sessions should really implement a real
789 * idle hint logic */
790 if (s->display)
791 goto dont_know;
792
793 /* For sessions with an explicitly configured tty, let's check
794 * its atime */
795 if (s->tty) {
796 r = get_tty_atime(s->tty, &atime);
797 if (r >= 0)
798 goto found_atime;
799 }
800
801 /* For sessions with a leader but no explicitly configured
802 * tty, let's check the controlling tty of the leader */
803 if (s->leader > 0) {
804 r = get_process_ctty_atime(s->leader, &atime);
805 if (r >= 0)
806 goto found_atime;
807 }
808
809 /* For other TTY sessions, let's find the most recent atime of
810 * the ttys of any of the processes of the session */
811 if (s->cgroup_path) {
812 _cleanup_fclose_ FILE *f = NULL;
813
814 if (cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &f) >= 0) {
815 pid_t pid;
816
817 atime = 0;
818 while (cg_read_pid(f, &pid) > 0) {
819 usec_t a;
820
821 if (get_process_ctty_atime(pid, &a) >= 0)
822 if (atime == 0 || atime < a)
823 atime = a;
824 }
825
826 if (atime != 0)
827 goto found_atime;
828 }
829 }
830
831 dont_know:
832 if (t)
833 *t = s->idle_hint_timestamp;
834
835 return 0;
836
837 found_atime:
838 if (t)
839 dual_timestamp_from_realtime(t, atime);
840
841 n = now(CLOCK_REALTIME);
842
843 if (s->manager->idle_action_usec <= 0)
844 return 0;
845
846 return atime + s->manager->idle_action_usec <= n;
847 }
848
849 void session_set_idle_hint(Session *s, bool b) {
850 assert(s);
851
852 if (s->idle_hint == b)
853 return;
854
855 s->idle_hint = b;
856 dual_timestamp_get(&s->idle_hint_timestamp);
857
858 session_send_changed(s,
859 "IdleHint\0"
860 "IdleSinceHint\0"
861 "IdleSinceHintMonotonic\0");
862
863 if (s->seat)
864 seat_send_changed(s->seat,
865 "IdleHint\0"
866 "IdleSinceHint\0"
867 "IdleSinceHintMonotonic\0");
868
869 user_send_changed(s->user,
870 "IdleHint\0"
871 "IdleSinceHint\0"
872 "IdleSinceHintMonotonic\0");
873
874 manager_send_changed(s->manager,
875 "IdleHint\0"
876 "IdleSinceHint\0"
877 "IdleSinceHintMonotonic\0");
878 }
879
880 int session_create_fifo(Session *s) {
881 int r;
882
883 assert(s);
884
885 /* Create FIFO */
886 if (!s->fifo_path) {
887 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
888 if (r < 0)
889 return r;
890
891 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
892 return -ENOMEM;
893
894 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
895 return -errno;
896 }
897
898 /* Open reading side */
899 if (s->fifo_fd < 0) {
900 struct epoll_event ev = {};
901
902 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
903 if (s->fifo_fd < 0)
904 return -errno;
905
906 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
907 if (r < 0)
908 return r;
909
910 ev.events = 0;
911 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
912
913 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
914 return -errno;
915 }
916
917 /* Open writing side */
918 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
919 if (r < 0)
920 return -errno;
921
922 return r;
923 }
924
925 void session_remove_fifo(Session *s) {
926 assert(s);
927
928 if (s->fifo_fd >= 0) {
929 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
930 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
931 close_nointr_nofail(s->fifo_fd);
932 s->fifo_fd = -1;
933
934 session_save(s);
935 user_save(s->user);
936 }
937
938 if (s->fifo_path) {
939 unlink(s->fifo_path);
940 free(s->fifo_path);
941 s->fifo_path = NULL;
942 }
943 }
944
945 int session_check_gc(Session *s, bool drop_not_started) {
946 int r;
947
948 assert(s);
949
950 if (drop_not_started && !s->started)
951 return 0;
952
953 if (s->fifo_fd >= 0) {
954
955 r = pipe_eof(s->fifo_fd);
956 if (r < 0)
957 return r;
958
959 if (r == 0)
960 return 1;
961 }
962
963 if (s->cgroup_path) {
964
965 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
966 if (r < 0)
967 return r;
968
969 if (r <= 0)
970 return 1;
971 }
972
973 return 0;
974 }
975
976 void session_add_to_gc_queue(Session *s) {
977 assert(s);
978
979 if (s->in_gc_queue)
980 return;
981
982 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
983 s->in_gc_queue = true;
984 }
985
986 SessionState session_get_state(Session *s) {
987 assert(s);
988
989 if (s->fifo_fd < 0)
990 return SESSION_CLOSING;
991
992 if (session_is_active(s))
993 return SESSION_ACTIVE;
994
995 return SESSION_ONLINE;
996 }
997
998 int session_kill(Session *s, KillWho who, int signo) {
999 int r = 0;
1000 Set *pid_set = NULL;
1001
1002 assert(s);
1003
1004 if (!s->cgroup_path)
1005 return -ESRCH;
1006
1007 if (s->leader <= 0 && who == KILL_LEADER)
1008 return -ESRCH;
1009
1010 if (s->leader > 0)
1011 if (kill(s->leader, signo) < 0)
1012 r = -errno;
1013
1014 if (who == KILL_ALL) {
1015 int q;
1016
1017 pid_set = set_new(trivial_hash_func, trivial_compare_func);
1018 if (!pid_set)
1019 return -ENOMEM;
1020
1021 if (s->leader > 0) {
1022 q = set_put(pid_set, LONG_TO_PTR(s->leader));
1023 if (q < 0)
1024 r = q;
1025 }
1026
1027 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
1028 if (q < 0)
1029 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
1030 r = q;
1031 }
1032
1033 if (pid_set)
1034 set_free(pid_set);
1035
1036 return r;
1037 }
1038
1039 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
1040 [SESSION_ONLINE] = "online",
1041 [SESSION_ACTIVE] = "active",
1042 [SESSION_CLOSING] = "closing"
1043 };
1044
1045 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1046
1047 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1048 [SESSION_TTY] = "tty",
1049 [SESSION_X11] = "x11",
1050 [SESSION_UNSPECIFIED] = "unspecified"
1051 };
1052
1053 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1054
1055 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1056 [SESSION_USER] = "user",
1057 [SESSION_GREETER] = "greeter",
1058 [SESSION_LOCK_SCREEN] = "lock-screen",
1059 [SESSION_BACKGROUND] = "background"
1060 };
1061
1062 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1063
1064 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1065 [KILL_LEADER] = "leader",
1066 [KILL_ALL] = "all"
1067 };
1068
1069 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);