]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/logind-session.c
logind: when initializing drop sessions that are unreferenced
[thirdparty/systemd.git] / src / logind-session.c
CommitLineData
20263082
LP
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 General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
17
18 You should have received a copy of the GNU 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>
31b79c2b 25#include <sys/epoll.h>
932e3ee7 26#include <fcntl.h>
20263082 27
90821c93 28#include "logind-session.h"
20263082
LP
29#include "strv.h"
30#include "util.h"
31#include "cgroup-util.h"
32
a185c5aa
LP
33#define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE)
34
20263082
LP
35Session* session_new(Manager *m, User *u, const char *id) {
36 Session *s;
37
38 assert(m);
39 assert(id);
40
14c3baca 41 s = new0(Session, 1);
20263082
LP
42 if (!s)
43 return NULL;
44
98a28fef 45 s->state_file = strappend("/run/systemd/sessions/", id);
20263082
LP
46 if (!s->state_file) {
47 free(s);
48 return NULL;
49 }
50
51 s->id = file_name_from_path(s->state_file);
52
53 if (hashmap_put(m->sessions, s->id, s) < 0) {
54 free(s->id);
55 free(s);
56 return NULL;
57 }
58
59 s->manager = m;
932e3ee7 60 s->fifo_fd = -1;
20263082
LP
61 s->user = u;
62
14c3baca 63 LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
20263082
LP
64
65 return s;
66}
67
68void session_free(Session *s) {
69 assert(s);
70
14c3baca
LP
71 if (s->in_gc_queue)
72 LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
73
20263082
LP
74 if (s->user) {
75 LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
76
77 if (s->user->display == s)
78 s->user->display = NULL;
79 }
80
9418f147
LP
81 if (s->seat) {
82 if (s->seat->active == s)
83 s->seat->active = NULL;
84
20263082 85 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
9418f147 86 }
20263082 87
1713813d
LP
88 if (s->cgroup_path)
89 hashmap_remove(s->manager->cgroups, s->cgroup_path);
90
20263082
LP
91 free(s->cgroup_path);
92 strv_free(s->controllers);
93
94 free(s->tty);
95 free(s->display);
96 free(s->remote_host);
3f49d45a 97 free(s->remote_user);
98a28fef 98 free(s->service);
20263082
LP
99
100 hashmap_remove(s->manager->sessions, s->id);
101
932e3ee7 102 session_remove_fifo(s);
98a28fef 103
d2f92cdf 104 free(s->state_file);
20263082
LP
105 free(s);
106}
107
108int session_save(Session *s) {
109 FILE *f;
110 int r = 0;
14c3baca 111 char *temp_path;
20263082
LP
112
113 assert(s);
114
accaeded
LP
115 if (!s->started)
116 return 0;
117
98a28fef 118 r = safe_mkdir("/run/systemd/sessions", 0755, 0, 0);
20263082 119 if (r < 0)
14c3baca 120 goto finish;
20263082 121
14c3baca
LP
122 r = fopen_temporary(s->state_file, &f, &temp_path);
123 if (r < 0)
124 goto finish;
20263082
LP
125
126 assert(s->user);
127
14c3baca
LP
128 fchmod(fileno(f), 0644);
129
20263082
LP
130 fprintf(f,
131 "# This is private data. Do not parse.\n"
132 "UID=%lu\n"
133 "USER=%s\n"
134 "ACTIVE=%i\n"
135 "REMOTE=%i\n"
136 "KILL_PROCESSES=%i\n",
137 (unsigned long) s->user->uid,
138 s->user->name,
139 session_is_active(s),
140 s->remote,
141 s->kill_processes);
142
a91e4e53
LP
143 if (s->type >= 0)
144 fprintf(f,
145 "TYPE=%s\n",
146 session_type_to_string(s->type));
147
20263082
LP
148 if (s->cgroup_path)
149 fprintf(f,
150 "CGROUP=%s\n",
151 s->cgroup_path);
152
932e3ee7
LP
153 if (s->fifo_path)
154 fprintf(f,
155 "FIFO=%s\n",
156 s->fifo_path);
157
20263082
LP
158 if (s->seat)
159 fprintf(f,
160 "SEAT=%s\n",
161 s->seat->id);
162
163 if (s->tty)
164 fprintf(f,
165 "TTY=%s\n",
166 s->tty);
167
168 if (s->display)
169 fprintf(f,
170 "DISPLAY=%s\n",
171 s->display);
172
173 if (s->remote_host)
174 fprintf(f,
175 "REMOTE_HOST=%s\n",
176 s->remote_host);
177
3f49d45a
LP
178 if (s->remote_user)
179 fprintf(f,
180 "REMOTE_USER=%s\n",
181 s->remote_user);
182
98a28fef
LP
183 if (s->service)
184 fprintf(f,
185 "SERVICE=%s\n",
186 s->service);
187
a185c5aa 188 if (s->seat && seat_is_vtconsole(s->seat))
20263082
LP
189 fprintf(f,
190 "VTNR=%i\n",
191 s->vtnr);
192
193 if (s->leader > 0)
194 fprintf(f,
195 "LEADER=%lu\n",
196 (unsigned long) s->leader);
197
198 if (s->audit_id > 0)
199 fprintf(f,
200 "AUDIT=%llu\n",
201 (unsigned long long) s->audit_id);
202
203 fflush(f);
14c3baca
LP
204
205 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
20263082
LP
206 r = -errno;
207 unlink(s->state_file);
14c3baca 208 unlink(temp_path);
20263082
LP
209 }
210
211 fclose(f);
14c3baca
LP
212 free(temp_path);
213
214finish:
215 if (r < 0)
216 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
217
20263082
LP
218 return r;
219}
220
221int session_load(Session *s) {
a185c5aa
LP
222 char *remote = NULL,
223 *kill_processes = NULL,
224 *seat = NULL,
225 *vtnr = NULL,
226 *leader = NULL,
a91e4e53
LP
227 *audit_id = NULL,
228 *type = NULL;
a185c5aa
LP
229
230 int k, r;
231
20263082
LP
232 assert(s);
233
a185c5aa
LP
234 r = parse_env_file(s->state_file, NEWLINE,
235 "REMOTE", &remote,
236 "KILL_PROCESSES", &kill_processes,
237 "CGROUP", &s->cgroup_path,
932e3ee7 238 "FIFO", &s->fifo_path,
a185c5aa
LP
239 "SEAT", &seat,
240 "TTY", &s->tty,
241 "DISPLAY", &s->display,
242 "REMOTE_HOST", &s->remote_host,
243 "REMOTE_USER", &s->remote_user,
98a28fef 244 "SERVICE", &s->service,
a185c5aa
LP
245 "VTNR", &vtnr,
246 "LEADER", &leader,
a91e4e53 247 "TYPE", &type,
a185c5aa
LP
248 NULL);
249
250 if (r < 0)
251 goto finish;
252
253 if (remote) {
254 k = parse_boolean(remote);
255 if (k >= 0)
256 s->remote = k;
257 }
258
259 if (kill_processes) {
260 k = parse_boolean(kill_processes);
261 if (k >= 0)
262 s->kill_processes = k;
263 }
264
9418f147 265 if (seat && !s->seat) {
a185c5aa
LP
266 Seat *o;
267
268 o = hashmap_get(s->manager->seats, seat);
269 if (o)
270 seat_attach_session(o, s);
271 }
272
273 if (vtnr && s->seat && seat_is_vtconsole(s->seat)) {
274 int v;
275
276 k = safe_atoi(vtnr, &v);
277 if (k >= 0 && v >= 1)
278 s->vtnr = v;
279 }
280
281 if (leader) {
282 pid_t pid;
283
284 k = parse_pid(leader, &pid);
98a28fef 285 if (k >= 0 && pid >= 1) {
a185c5aa 286 s->leader = pid;
a185c5aa 287
98a28fef
LP
288 audit_session_from_pid(pid, &s->audit_id);
289 }
a185c5aa
LP
290 }
291
a91e4e53
LP
292 if (type) {
293 SessionType t;
294
295 t = session_type_from_string(type);
296 if (t >= 0)
297 s->type = t;
298 }
299
932e3ee7
LP
300 session_open_fifo(s);
301
a185c5aa
LP
302finish:
303 free(remote);
304 free(kill_processes);
305 free(seat);
306 free(vtnr);
307 free(leader);
308 free(audit_id);
309
310 return r;
20263082
LP
311}
312
313int session_activate(Session *s) {
314 int r;
5eda94dd 315 Session *old_active;
20263082
LP
316
317 assert(s);
318
319 if (s->vtnr < 0)
320 return -ENOTSUP;
321
322 if (!s->seat)
323 return -ENOTSUP;
324
325 if (s->seat->active == s)
326 return 0;
327
a185c5aa 328 assert(seat_is_vtconsole(s->seat));
20263082
LP
329
330 r = chvt(s->vtnr);
331 if (r < 0)
332 return r;
333
5eda94dd 334 old_active = s->seat->active;
20263082
LP
335 s->seat->active = s;
336
14c3baca 337 return seat_apply_acls(s->seat, old_active);
20263082
LP
338}
339
20263082
LP
340static int session_link_x11_socket(Session *s) {
341 char *t, *f, *c;
342 size_t k;
343
344 assert(s);
345 assert(s->user);
346 assert(s->user->runtime_path);
347
348 if (s->user->display)
349 return 0;
350
4d6d6518 351 if (!s->display || !display_is_local(s->display))
20263082
LP
352 return 0;
353
354 k = strspn(s->display+1, "0123456789");
355 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
356 if (!f) {
357 log_error("Out of memory");
358 return -ENOMEM;
359 }
360
361 c = stpcpy(f, "/tmp/.X11-unix/X");
362 memcpy(c, s->display+1, k);
363 c[k] = 0;
364
365 if (access(f, F_OK) < 0) {
366 log_warning("Session %s has display %s with nonexisting socket %s.", s->id, s->display, f);
367 free(f);
368 return -ENOENT;
369 }
370
371 t = strappend(s->user->runtime_path, "/display");
372 if (!t) {
373 log_error("Out of memory");
374 free(f);
375 return -ENOMEM;
376 }
377
378 if (link(f, t) < 0) {
379 if (errno == EEXIST) {
380 unlink(t);
381
382 if (link(f, t) >= 0)
383 goto done;
384 }
385
386 if (symlink(f, t) < 0) {
387
388 if (errno == EEXIST) {
389 unlink(t);
390
391 if (symlink(f, t) >= 0)
392 goto done;
393 }
394
395 log_error("Failed to link %s to %s: %m", f, t);
396 free(f);
397 free(t);
398 return -errno;
399 }
400 }
401
402done:
403 log_info("Linked %s to %s.", f, t);
404 free(f);
405 free(t);
406
407 s->user->display = s;
408
409 return 0;
410}
411
98a28fef
LP
412static int session_create_one_group(Session *s, const char *controller, const char *path) {
413 int r;
414
415 assert(s);
416 assert(controller);
417 assert(path);
418
b6f68af1 419 if (s->leader > 0) {
98a28fef 420 r = cg_create_and_attach(controller, path, s->leader);
b6f68af1
LP
421 if (r < 0)
422 r = cg_create(controller, path);
423 } else
98a28fef
LP
424 r = cg_create(controller, path);
425
426 if (r < 0)
427 return r;
428
429 r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid);
430 if (r >= 0)
431 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
432
433 return r;
434}
435
20263082
LP
436static int session_create_cgroup(Session *s) {
437 char **k;
438 char *p;
439 int r;
440
441 assert(s);
442 assert(s->user);
443 assert(s->user->cgroup_path);
444
445 if (!s->cgroup_path) {
446 if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0) {
447 log_error("Out of memory");
448 return -ENOMEM;
449 }
450 } else
451 p = s->cgroup_path;
452
98a28fef 453 r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
20263082 454 if (r < 0) {
4d6d6518 455 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
20263082
LP
456 free(p);
457 s->cgroup_path = NULL;
20263082
LP
458 return r;
459 }
460
461 s->cgroup_path = p;
462
98a28fef
LP
463 STRV_FOREACH(k, s->controllers) {
464
465 if (strv_contains(s->reset_controllers, *k))
466 continue;
467
468 r = session_create_one_group(s, *k, p);
469 if (r < 0)
470 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
471 }
472
20263082 473 STRV_FOREACH(k, s->manager->controllers) {
20263082 474
98a28fef 475 if (strv_contains(s->reset_controllers, *k) ||
193197e8 476 strv_contains(s->manager->reset_controllers, *k) ||
98a28fef
LP
477 strv_contains(s->controllers, *k))
478 continue;
479
480 r = session_create_one_group(s, *k, p);
20263082 481 if (r < 0)
98a28fef
LP
482 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
483 }
484
485 if (s->leader > 0) {
486
487 STRV_FOREACH(k, s->reset_controllers) {
488 r = cg_attach(*k, "/", s->leader);
489 if (r < 0)
490 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
491
492 }
193197e8
LP
493
494 STRV_FOREACH(k, s->manager->reset_controllers) {
495
496 if (strv_contains(s->reset_controllers, *k) ||
497 strv_contains(s->controllers, *k))
498 continue;
499
500 r = cg_attach(*k, "/", s->leader);
501 if (r < 0)
502 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
503
504 }
20263082
LP
505 }
506
1713813d
LP
507 hashmap_put(s->manager->cgroups, s->cgroup_path, s);
508
20263082
LP
509 return 0;
510}
511
512int session_start(Session *s) {
513 int r;
514
515 assert(s);
516 assert(s->user);
517
9418f147
LP
518 if (s->started)
519 return 0;
520
ed18b08b
LP
521 r = user_start(s->user);
522 if (r < 0)
523 return r;
524
98a28fef
LP
525 log_info("New session %s of user %s.", s->id, s->user->name);
526
20263082
LP
527 /* Create cgroup */
528 r = session_create_cgroup(s);
529 if (r < 0)
530 return r;
531
532 /* Create X11 symlink */
533 session_link_x11_socket(s);
14c3baca 534
14c3baca
LP
535 dual_timestamp_get(&s->timestamp);
536
e9816c48
LP
537 if (s->seat)
538 seat_read_active_vt(s->seat);
539
9418f147
LP
540 s->started = true;
541
e9816c48
LP
542 /* Save session data */
543 session_save(s);
7f7bb946 544 user_save(s->user);
e9816c48 545
da119395
LP
546 session_send_signal(s, true);
547
9418f147 548 if (s->seat) {
7f7bb946
LP
549 seat_save(s->seat);
550
9418f147
LP
551 if (s->seat->active == s)
552 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
553 else
554 seat_send_changed(s->seat, "Sessions\0");
555 }
556
557 user_send_changed(s->user, "Sessions\0");
558
20263082
LP
559 return 0;
560}
561
562static bool session_shall_kill(Session *s) {
563 assert(s);
564
ed18b08b
LP
565 if (!s->kill_processes)
566 return false;
567
568 if (strv_contains(s->manager->kill_exclude_users, s->user->name))
569 return false;
570
571 if (strv_isempty(s->manager->kill_only_users))
572 return true;
573
574 return strv_contains(s->manager->kill_only_users, s->user->name);
20263082
LP
575}
576
577static int session_kill_cgroup(Session *s) {
578 int r;
579 char **k;
580
581 assert(s);
582
583 if (!s->cgroup_path)
584 return 0;
585
586 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
587
588 if (session_shall_kill(s)) {
589
590 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
591 if (r < 0)
592 log_error("Failed to kill session cgroup: %s", strerror(-r));
593
594 } else {
595 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
596 if (r < 0)
597 log_error("Failed to check session cgroup: %s", strerror(-r));
598 else if (r > 0) {
599 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
600 if (r < 0)
601 log_error("Failed to delete session cgroup: %s", strerror(-r));
602 } else
603 r = -EBUSY;
604 }
605
606 STRV_FOREACH(k, s->user->manager->controllers)
607 cg_trim(*k, s->cgroup_path, true);
608
1713813d
LP
609 hashmap_remove(s->manager->cgroups, s->cgroup_path);
610
20263082
LP
611 free(s->cgroup_path);
612 s->cgroup_path = NULL;
613
614 return r;
615}
616
617static int session_unlink_x11_socket(Session *s) {
618 char *t;
619 int r;
620
621 assert(s);
622 assert(s->user);
623
624 if (s->user->display != s)
625 return 0;
626
627 s->user->display = NULL;
628
629 t = strappend(s->user->runtime_path, "/display");
630 if (!t) {
631 log_error("Out of memory");
632 return -ENOMEM;
633 }
634
635 r = unlink(t);
636 free(t);
637
638 return r < 0 ? -errno : 0;
639}
640
641int session_stop(Session *s) {
642 int r = 0, k;
643
644 assert(s);
645
ed18b08b
LP
646 if (s->started)
647 log_info("Removed session %s.", s->id);
98a28fef 648
20263082
LP
649 /* Kill cgroup */
650 k = session_kill_cgroup(s);
651 if (k < 0)
652 r = k;
653
654 /* Remove X11 symlink */
655 session_unlink_x11_socket(s);
656
d2f92cdf
LP
657 unlink(s->state_file);
658 session_add_to_gc_queue(s);
ed18b08b 659 user_add_to_gc_queue(s->user);
14c3baca 660
ed18b08b
LP
661 if (s->started)
662 session_send_signal(s, false);
9418f147
LP
663
664 if (s->seat) {
665 if (s->seat->active == s)
666 seat_set_active(s->seat, NULL);
667
668 seat_send_changed(s->seat, "Sessions\0");
669 }
670
671 user_send_changed(s->user, "Sessions\0");
672
673 s->started = false;
674
20263082
LP
675 return r;
676}
677
678bool session_is_active(Session *s) {
679 assert(s);
680
681 if (!s->seat)
682 return true;
683
684 return s->seat->active == s;
685}
686
a185c5aa
LP
687int session_get_idle_hint(Session *s, dual_timestamp *t) {
688 char *p;
689 struct stat st;
690 usec_t u, n;
691 bool b;
692 int k;
693
694 assert(s);
695
696 if (s->idle_hint) {
697 if (t)
698 *t = s->idle_hint_timestamp;
699
700 return s->idle_hint;
701 }
702
703 if (isempty(s->tty))
704 goto dont_know;
705
706 if (s->tty[0] != '/') {
707 p = strappend("/dev/", s->tty);
708 if (!p)
709 return -ENOMEM;
710 } else
711 p = NULL;
712
713 if (!startswith(p ? p : s->tty, "/dev/")) {
714 free(p);
715 goto dont_know;
716 }
717
718 k = lstat(p ? p : s->tty, &st);
719 free(p);
720
721 if (k < 0)
722 goto dont_know;
723
724 u = timespec_load(&st.st_atim);
725 n = now(CLOCK_REALTIME);
726 b = u + IDLE_THRESHOLD_USEC < n;
727
728 if (t)
729 dual_timestamp_from_realtime(t, u + b ? IDLE_THRESHOLD_USEC : 0);
730
731 return b;
732
733dont_know:
734 if (t)
735 *t = s->idle_hint_timestamp;
736
737 return 0;
738}
739
bef422ae
LP
740void session_set_idle_hint(Session *s, bool b) {
741 assert(s);
742
743 if (s->idle_hint == b)
744 return;
745
746 s->idle_hint = b;
747 dual_timestamp_get(&s->idle_hint_timestamp);
9418f147
LP
748
749 session_send_changed(s,
750 "IdleHint\0"
751 "IdleSinceHint\0"
752 "IdleSinceHintMonotonic\0");
753
754 if (s->seat)
755 seat_send_changed(s->seat,
756 "IdleHint\0"
757 "IdleSinceHint\0"
758 "IdleSinceHintMonotonic\0");
759
760 user_send_changed(s->user,
761 "IdleHint\0"
762 "IdleSinceHint\0"
763 "IdleSinceHintMonotonic\0");
764
765 manager_send_changed(s->manager,
766 "IdleHint\0"
767 "IdleSinceHint\0"
768 "IdleSinceHintMonotonic\0");
bef422ae
LP
769}
770
932e3ee7 771int session_open_fifo(Session *s) {
31b79c2b
LP
772 struct epoll_event ev;
773 int r;
774
775 assert(s);
31b79c2b 776
932e3ee7
LP
777 if (s->fifo_fd >= 0)
778 return 0;
779
780 if (!s->fifo_path)
781 return -EINVAL;
782
783 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
784 if (s->fifo_fd < 0)
785 return -errno;
786
787 r = hashmap_put(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1), s);
31b79c2b
LP
788 if (r < 0)
789 return r;
790
791 zero(ev);
792 ev.events = 0;
932e3ee7 793 ev.data.u32 = FD_FIFO_BASE + s->fifo_fd;
31b79c2b 794
932e3ee7 795 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
31b79c2b 796 return -errno;
31b79c2b 797
31b79c2b
LP
798 return 0;
799}
800
932e3ee7
LP
801int session_create_fifo(Session *s) {
802 int r;
803
31b79c2b
LP
804 assert(s);
805
932e3ee7
LP
806 if (!s->fifo_path) {
807 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
808 return -ENOMEM;
31b79c2b 809
932e3ee7
LP
810 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
811 return -errno;
812 }
31b79c2b 813
932e3ee7
LP
814 /* Open reading side */
815 r = session_open_fifo(s);
816 if (r < 0)
817 return r;
818
819 /* Open writing side */
820 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
821 if (r < 0)
822 return -errno;
31b79c2b 823
932e3ee7
LP
824 return r;
825}
826
827void session_remove_fifo(Session *s) {
828 assert(s);
829
830 if (s->fifo_fd >= 0) {
831 assert_se(hashmap_remove(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
832 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
833 close_nointr_nofail(s->fifo_fd);
834 s->fifo_fd = -1;
835 }
836
837 if (s->fifo_path) {
838 unlink(s->fifo_path);
839 free(s->fifo_path);
840 s->fifo_path = NULL;
841 }
31b79c2b
LP
842}
843
4a4b033f 844int session_check_gc(Session *s, bool drop_not_started) {
20263082
LP
845 int r;
846
847 assert(s);
848
4a4b033f 849 if (drop_not_started && !s->started)
932e3ee7
LP
850 return 0;
851
852 if (s->fifo_fd >= 0) {
20263082 853
932e3ee7 854 r = pipe_eof(s->fifo_fd);
20263082
LP
855 if (r < 0)
856 return r;
857
14c3baca 858 if (r == 0)
20263082
LP
859 return 1;
860 }
861
862 if (s->cgroup_path) {
863
864 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
865 if (r < 0)
866 return r;
867
868 if (r <= 0)
869 return 1;
870 }
871
872 return 0;
873}
874
14c3baca
LP
875void session_add_to_gc_queue(Session *s) {
876 assert(s);
877
878 if (s->in_gc_queue)
879 return;
880
881 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
882 s->in_gc_queue = true;
883}
884
20263082 885static const char* const session_type_table[_SESSION_TYPE_MAX] = {
3f49d45a 886 [SESSION_TTY] = "tty",
98a28fef 887 [SESSION_X11] = "x11",
a91e4e53 888 [SESSION_UNSPECIFIED] = "unspecified"
20263082
LP
889};
890
891DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);