]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session.c
logind: add support for automatic suspend/hibernate/shutdown on idle
[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
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 return log_oom();
379
380 c = stpcpy(f, "/tmp/.X11-unix/X");
381 memcpy(c, s->display+1, k);
382 c[k] = 0;
383
384 if (access(f, F_OK) < 0) {
385 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
386 free(f);
387 return -ENOENT;
388 }
389
390 /* Note that this cannot be in a subdir to avoid
391 * vulnerabilities since we are privileged but the runtime
392 * path is owned by the user */
393
394 t = strappend(s->user->runtime_path, "/X11-display");
395 if (!t) {
396 free(f);
397 return log_oom();
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 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 if (s->seat) {
713 if (s->seat->active == s)
714 seat_set_active(s->seat, NULL);
715
716 seat_send_changed(s->seat, "Sessions\0");
717 seat_save(s->seat);
718 }
719
720 user_send_changed(s->user, "Sessions\0");
721 user_save(s->user);
722
723 s->started = false;
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 _cleanup_free_ char *p = NULL;
776 usec_t atime = 0, n;
777 int r;
778
779 assert(s);
780
781 /* Explicit idle hint is set */
782 if (s->idle_hint) {
783 if (t)
784 *t = s->idle_hint_timestamp;
785
786 return s->idle_hint;
787 }
788
789 /* Graphical sessions really should really implement a real
790 * idle hint logic */
791 if (s->display)
792 goto dont_know;
793
794 /* For sessions with an explicitly configured tty, let's check
795 * its atime */
796 if (s->tty) {
797 r = get_tty_atime(s->tty, &atime);
798 if (r >= 0)
799 goto found_atime;
800 }
801
802 /* For sessions with a leader but no explicitly configured
803 * tty, let's check the controlling tty of the leader */
804 if (s->leader > 0) {
805 r = get_process_ctty_atime(s->leader, &atime);
806 if (r >= 0)
807 goto found_atime;
808 }
809
810 /* For other TTY sessions, let's find the most recent atime of
811 * the ttys of any of the processes of the session */
812 if (s->cgroup_path) {
813 _cleanup_fclose_ FILE *f = NULL;
814
815 if (cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &f) >= 0) {
816 pid_t pid;
817
818 atime = 0;
819 while (cg_read_pid(f, &pid) > 0) {
820 usec_t a;
821
822 if (get_process_ctty_atime(pid, &a) >= 0)
823 if (atime == 0 || atime < a)
824 atime = a;
825 }
826
827 if (atime != 0)
828 goto found_atime;
829 }
830 }
831
832 dont_know:
833 if (t)
834 *t = s->idle_hint_timestamp;
835
836 return 0;
837
838 found_atime:
839 if (t)
840 dual_timestamp_from_realtime(t, atime);
841
842 n = now(CLOCK_REALTIME);
843
844 if (s->manager->idle_action_usec <= 0)
845 return 0;
846
847 return atime + s->manager->idle_action_usec <= n;
848 }
849
850 void session_set_idle_hint(Session *s, bool b) {
851 assert(s);
852
853 if (s->idle_hint == b)
854 return;
855
856 s->idle_hint = b;
857 dual_timestamp_get(&s->idle_hint_timestamp);
858
859 session_send_changed(s,
860 "IdleHint\0"
861 "IdleSinceHint\0"
862 "IdleSinceHintMonotonic\0");
863
864 if (s->seat)
865 seat_send_changed(s->seat,
866 "IdleHint\0"
867 "IdleSinceHint\0"
868 "IdleSinceHintMonotonic\0");
869
870 user_send_changed(s->user,
871 "IdleHint\0"
872 "IdleSinceHint\0"
873 "IdleSinceHintMonotonic\0");
874
875 manager_send_changed(s->manager,
876 "IdleHint\0"
877 "IdleSinceHint\0"
878 "IdleSinceHintMonotonic\0");
879 }
880
881 int session_create_fifo(Session *s) {
882 int r;
883
884 assert(s);
885
886 /* Create FIFO */
887 if (!s->fifo_path) {
888 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
889 if (r < 0)
890 return r;
891
892 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
893 return -ENOMEM;
894
895 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
896 return -errno;
897 }
898
899 /* Open reading side */
900 if (s->fifo_fd < 0) {
901 struct epoll_event ev;
902
903 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
904 if (s->fifo_fd < 0)
905 return -errno;
906
907 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
908 if (r < 0)
909 return r;
910
911 zero(ev);
912 ev.events = 0;
913 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
914
915 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
916 return -errno;
917 }
918
919 /* Open writing side */
920 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
921 if (r < 0)
922 return -errno;
923
924 return r;
925 }
926
927 void session_remove_fifo(Session *s) {
928 assert(s);
929
930 if (s->fifo_fd >= 0) {
931 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
932 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
933 close_nointr_nofail(s->fifo_fd);
934 s->fifo_fd = -1;
935
936 session_save(s);
937 user_save(s->user);
938 }
939
940 if (s->fifo_path) {
941 unlink(s->fifo_path);
942 free(s->fifo_path);
943 s->fifo_path = NULL;
944 }
945 }
946
947 int session_check_gc(Session *s, bool drop_not_started) {
948 int r;
949
950 assert(s);
951
952 if (drop_not_started && !s->started)
953 return 0;
954
955 if (s->fifo_fd >= 0) {
956
957 r = pipe_eof(s->fifo_fd);
958 if (r < 0)
959 return r;
960
961 if (r == 0)
962 return 1;
963 }
964
965 if (s->cgroup_path) {
966
967 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
968 if (r < 0)
969 return r;
970
971 if (r <= 0)
972 return 1;
973 }
974
975 return 0;
976 }
977
978 void session_add_to_gc_queue(Session *s) {
979 assert(s);
980
981 if (s->in_gc_queue)
982 return;
983
984 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
985 s->in_gc_queue = true;
986 }
987
988 SessionState session_get_state(Session *s) {
989 assert(s);
990
991 if (s->fifo_fd < 0)
992 return SESSION_CLOSING;
993
994 if (session_is_active(s))
995 return SESSION_ACTIVE;
996
997 return SESSION_ONLINE;
998 }
999
1000 int session_kill(Session *s, KillWho who, int signo) {
1001 int r = 0;
1002 Set *pid_set = NULL;
1003
1004 assert(s);
1005
1006 if (!s->cgroup_path)
1007 return -ESRCH;
1008
1009 if (s->leader <= 0 && who == KILL_LEADER)
1010 return -ESRCH;
1011
1012 if (s->leader > 0)
1013 if (kill(s->leader, signo) < 0)
1014 r = -errno;
1015
1016 if (who == KILL_ALL) {
1017 int q;
1018
1019 pid_set = set_new(trivial_hash_func, trivial_compare_func);
1020 if (!pid_set)
1021 return -ENOMEM;
1022
1023 if (s->leader > 0) {
1024 q = set_put(pid_set, LONG_TO_PTR(s->leader));
1025 if (q < 0)
1026 r = q;
1027 }
1028
1029 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
1030 if (q < 0)
1031 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
1032 r = q;
1033 }
1034
1035 if (pid_set)
1036 set_free(pid_set);
1037
1038 return r;
1039 }
1040
1041 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
1042 [SESSION_ONLINE] = "online",
1043 [SESSION_ACTIVE] = "active",
1044 [SESSION_CLOSING] = "closing"
1045 };
1046
1047 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1048
1049 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1050 [SESSION_TTY] = "tty",
1051 [SESSION_X11] = "x11",
1052 [SESSION_UNSPECIFIED] = "unspecified"
1053 };
1054
1055 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1056
1057 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1058 [SESSION_USER] = "user",
1059 [SESSION_GREETER] = "greeter",
1060 [SESSION_LOCK_SCREEN] = "lock-screen"
1061 };
1062
1063 DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1064
1065 static const char* const kill_who_table[_KILL_WHO_MAX] = {
1066 [KILL_LEADER] = "leader",
1067 [KILL_ALL] = "all"
1068 };
1069
1070 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);