]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session.c
Use initalization instead of explicit zeroing
[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(controller);
440 assert(path);
441
442 if (s->leader > 0) {
443 r = cg_create_and_attach(controller, path, s->leader);
444 if (r < 0)
445 r = cg_create(controller, path);
446 } else
447 r = cg_create(controller, path);
448
449 if (r < 0)
450 return r;
451
452 r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid, -1);
453 if (r >= 0)
454 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
455
456 return r;
457 }
458
459 static int session_create_cgroup(Session *s) {
460 char **k;
461 char *p;
462 int r;
463
464 assert(s);
465 assert(s->user);
466 assert(s->user->cgroup_path);
467
468 if (!s->cgroup_path) {
469 if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0)
470 return log_oom();
471 } else
472 p = s->cgroup_path;
473
474 r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
475 if (r < 0) {
476 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
477 free(p);
478 s->cgroup_path = NULL;
479 return r;
480 }
481
482 s->cgroup_path = p;
483
484 STRV_FOREACH(k, s->controllers) {
485
486 if (strv_contains(s->reset_controllers, *k))
487 continue;
488
489 r = session_create_one_group(s, *k, p);
490 if (r < 0)
491 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
492 }
493
494 STRV_FOREACH(k, s->manager->controllers) {
495
496 if (strv_contains(s->reset_controllers, *k) ||
497 strv_contains(s->manager->reset_controllers, *k) ||
498 strv_contains(s->controllers, *k))
499 continue;
500
501 r = session_create_one_group(s, *k, p);
502 if (r < 0)
503 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
504 }
505
506 if (s->leader > 0) {
507
508 STRV_FOREACH(k, s->reset_controllers) {
509 r = cg_attach(*k, "/", s->leader);
510 if (r < 0)
511 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
512
513 }
514
515 STRV_FOREACH(k, s->manager->reset_controllers) {
516
517 if (strv_contains(s->reset_controllers, *k) ||
518 strv_contains(s->controllers, *k))
519 continue;
520
521 r = cg_attach(*k, "/", s->leader);
522 if (r < 0)
523 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
524
525 }
526 }
527
528 r = hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
529 if (r < 0)
530 log_warning("Failed to create mapping between cgroup and session");
531
532 return 0;
533 }
534
535 int session_start(Session *s) {
536 int r;
537
538 assert(s);
539 assert(s->user);
540
541 if (s->started)
542 return 0;
543
544 r = user_start(s->user);
545 if (r < 0)
546 return r;
547
548 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
549 MESSAGE_ID(SD_MESSAGE_SESSION_START),
550 "SESSION_ID=%s", s->id,
551 "USER_ID=%s", s->user->name,
552 "LEADER=%lu", (unsigned long) s->leader,
553 "MESSAGE=New session %s of user %s.", s->id, s->user->name,
554 NULL);
555
556 /* Create cgroup */
557 r = session_create_cgroup(s);
558 if (r < 0)
559 return r;
560
561 /* Create X11 symlink */
562 session_link_x11_socket(s);
563
564 dual_timestamp_get(&s->timestamp);
565
566 if (s->seat)
567 seat_read_active_vt(s->seat);
568
569 s->started = true;
570
571 /* Save session data */
572 session_save(s);
573 user_save(s->user);
574
575 session_send_signal(s, true);
576
577 if (s->seat) {
578 seat_save(s->seat);
579
580 if (s->seat->active == s)
581 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
582 else
583 seat_send_changed(s->seat, "Sessions\0");
584 }
585
586 user_send_changed(s->user, "Sessions\0");
587
588 return 0;
589 }
590
591 static bool session_shall_kill(Session *s) {
592 assert(s);
593
594 if (!s->kill_processes)
595 return false;
596
597 if (strv_contains(s->manager->kill_exclude_users, s->user->name))
598 return false;
599
600 if (strv_isempty(s->manager->kill_only_users))
601 return true;
602
603 return strv_contains(s->manager->kill_only_users, s->user->name);
604 }
605
606 static int session_terminate_cgroup(Session *s) {
607 int r;
608 char **k;
609
610 assert(s);
611
612 if (!s->cgroup_path)
613 return 0;
614
615 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
616
617 if (session_shall_kill(s)) {
618
619 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
620 if (r < 0)
621 log_error("Failed to kill session cgroup: %s", strerror(-r));
622
623 } else {
624 if (s->leader > 0) {
625 Session *t;
626
627 /* We still send a HUP to the leader process,
628 * even if we are not supposed to kill the
629 * whole cgroup. But let's first check the
630 * leader still exists and belongs to our
631 * session... */
632
633 r = manager_get_session_by_pid(s->manager, s->leader, &t);
634 if (r > 0 && t == s) {
635 kill(s->leader, SIGTERM); /* for normal processes */
636 kill(s->leader, SIGHUP); /* for shells */
637 kill(s->leader, SIGCONT); /* in case they are stopped */
638 }
639 }
640
641 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
642 if (r < 0)
643 log_error("Failed to check session cgroup: %s", strerror(-r));
644 else if (r > 0) {
645 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
646 if (r < 0)
647 log_error("Failed to delete session cgroup: %s", strerror(-r));
648 }
649 }
650
651 STRV_FOREACH(k, s->user->manager->controllers)
652 cg_trim(*k, s->cgroup_path, true);
653
654 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
655
656 free(s->cgroup_path);
657 s->cgroup_path = NULL;
658
659 return 0;
660 }
661
662 static int session_unlink_x11_socket(Session *s) {
663 char *t;
664 int r;
665
666 assert(s);
667 assert(s->user);
668
669 if (s->user->display != s)
670 return 0;
671
672 s->user->display = NULL;
673
674 t = strappend(s->user->runtime_path, "/X11-display");
675 if (!t)
676 return log_oom();
677
678 r = unlink(t);
679 free(t);
680
681 return r < 0 ? -errno : 0;
682 }
683
684 int session_stop(Session *s) {
685 int r = 0, k;
686
687 assert(s);
688
689 if (s->started)
690 log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
691 MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
692 "SESSION_ID=%s", s->id,
693 "USER_ID=%s", s->user->name,
694 "LEADER=%lu", (unsigned long) s->leader,
695 "MESSAGE=Removed session %s.", s->id,
696 NULL);
697
698 /* Kill cgroup */
699 k = session_terminate_cgroup(s);
700 if (k < 0)
701 r = k;
702
703 /* Remove X11 symlink */
704 session_unlink_x11_socket(s);
705
706 unlink(s->state_file);
707 session_add_to_gc_queue(s);
708 user_add_to_gc_queue(s->user);
709
710 if (s->started)
711 session_send_signal(s, false);
712
713 if (s->seat) {
714 if (s->seat->active == s)
715 seat_set_active(s->seat, NULL);
716
717 seat_send_changed(s->seat, "Sessions\0");
718 seat_save(s->seat);
719 }
720
721 user_send_changed(s->user, "Sessions\0");
722 user_save(s->user);
723
724 s->started = false;
725
726 return r;
727 }
728
729 bool session_is_active(Session *s) {
730 assert(s);
731
732 if (!s->seat)
733 return true;
734
735 return s->seat->active == s;
736 }
737
738 static int get_tty_atime(const char *tty, usec_t *atime) {
739 _cleanup_free_ char *p = NULL;
740 struct stat st;
741
742 assert(tty);
743 assert(atime);
744
745 if (!path_is_absolute(tty)) {
746 p = strappend("/dev/", tty);
747 if (!p)
748 return -ENOMEM;
749
750 tty = p;
751 } else if (!path_startswith(tty, "/dev/"))
752 return -ENOENT;
753
754 if (lstat(tty, &st) < 0)
755 return -errno;
756
757 *atime = timespec_load(&st.st_atim);
758 return 0;
759 }
760
761 static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
762 _cleanup_free_ char *p = NULL;
763 int r;
764
765 assert(pid > 0);
766 assert(atime);
767
768 r = get_ctty(pid, NULL, &p);
769 if (r < 0)
770 return r;
771
772 return get_tty_atime(p, atime);
773 }
774
775 int session_get_idle_hint(Session *s, dual_timestamp *t) {
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 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 ev.events = 0;
912 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
913
914 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
915 return -errno;
916 }
917
918 /* Open writing side */
919 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
920 if (r < 0)
921 return -errno;
922
923 return r;
924 }
925
926 void session_remove_fifo(Session *s) {
927 assert(s);
928
929 if (s->fifo_fd >= 0) {
930 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
931 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
932 close_nointr_nofail(s->fifo_fd);
933 s->fifo_fd = -1;
934
935 session_save(s);
936 user_save(s->user);
937 }
938
939 if (s->fifo_path) {
940 unlink(s->fifo_path);
941 free(s->fifo_path);
942 s->fifo_path = NULL;
943 }
944 }
945
946 int session_check_gc(Session *s, bool drop_not_started) {
947 int r;
948
949 assert(s);
950
951 if (drop_not_started && !s->started)
952 return 0;
953
954 if (s->fifo_fd >= 0) {
955
956 r = pipe_eof(s->fifo_fd);
957 if (r < 0)
958 return r;
959
960 if (r == 0)
961 return 1;
962 }
963
964 if (s->cgroup_path) {
965
966 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
967 if (r < 0)
968 return r;
969
970 if (r <= 0)
971 return 1;
972 }
973
974 return 0;
975 }
976
977 void session_add_to_gc_queue(Session *s) {
978 assert(s);
979
980 if (s->in_gc_queue)
981 return;
982
983 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
984 s->in_gc_queue = true;
985 }
986
987 SessionState session_get_state(Session *s) {
988 assert(s);
989
990 if (s->fifo_fd < 0)
991 return SESSION_CLOSING;
992
993 if (session_is_active(s))
994 return SESSION_ACTIVE;
995
996 return SESSION_ONLINE;
997 }
998
999 int session_kill(Session *s, KillWho who, int signo) {
1000 int r = 0;
1001 Set *pid_set = NULL;
1002
1003 assert(s);
1004
1005 if (!s->cgroup_path)
1006 return -ESRCH;
1007
1008 if (s->leader <= 0 && who == KILL_LEADER)
1009 return -ESRCH;
1010
1011 if (s->leader > 0)
1012 if (kill(s->leader, signo) < 0)
1013 r = -errno;
1014
1015 if (who == KILL_ALL) {
1016 int q;
1017
1018 pid_set = set_new(trivial_hash_func, trivial_compare_func);
1019 if (!pid_set)
1020 return -ENOMEM;
1021
1022 if (s->leader > 0) {
1023 q = set_put(pid_set, LONG_TO_PTR(s->leader));
1024 if (q < 0)
1025 r = q;
1026 }
1027
1028 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
1029 if (q < 0)
1030 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
1031 r = q;
1032 }
1033
1034 if (pid_set)
1035 set_free(pid_set);
1036
1037 return r;
1038 }
1039
1040 static const char* const session_state_table[_SESSION_TYPE_MAX] = {
1041 [SESSION_ONLINE] = "online",
1042 [SESSION_ACTIVE] = "active",
1043 [SESSION_CLOSING] = "closing"
1044 };
1045
1046 DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1047
1048 static const char* const session_type_table[_SESSION_TYPE_MAX] = {
1049 [SESSION_TTY] = "tty",
1050 [SESSION_X11] = "x11",
1051 [SESSION_UNSPECIFIED] = "unspecified"
1052 };
1053
1054 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
1055
1056 static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1057 [SESSION_USER] = "user",
1058 [SESSION_GREETER] = "greeter",
1059 [SESSION_LOCK_SCREEN] = "lock-screen"
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);