]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/logind-session.c
systemctl: fix parsing of LoadError property for systemctl show
[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
b4f78aea
LP
300 if (s->fifo_path) {
301 int fd;
302
303 /* If we open an unopened pipe for reading we will not
304 get an EOF. to trigger an EOF we hence open it for
305 reading, but close it right-away which then will
306 trigger the EOF. */
307
308 fd = session_create_fifo(s);
309 if (fd >= 0)
310 close_nointr_nofail(fd);
311 }
312
932e3ee7 313
a185c5aa
LP
314finish:
315 free(remote);
316 free(kill_processes);
317 free(seat);
318 free(vtnr);
319 free(leader);
320 free(audit_id);
321
322 return r;
20263082
LP
323}
324
325int session_activate(Session *s) {
326 int r;
5eda94dd 327 Session *old_active;
20263082
LP
328
329 assert(s);
330
331 if (s->vtnr < 0)
332 return -ENOTSUP;
333
334 if (!s->seat)
335 return -ENOTSUP;
336
337 if (s->seat->active == s)
338 return 0;
339
a185c5aa 340 assert(seat_is_vtconsole(s->seat));
20263082
LP
341
342 r = chvt(s->vtnr);
343 if (r < 0)
344 return r;
345
5eda94dd 346 old_active = s->seat->active;
20263082
LP
347 s->seat->active = s;
348
14c3baca 349 return seat_apply_acls(s->seat, old_active);
20263082
LP
350}
351
20263082
LP
352static int session_link_x11_socket(Session *s) {
353 char *t, *f, *c;
354 size_t k;
355
356 assert(s);
357 assert(s->user);
358 assert(s->user->runtime_path);
359
360 if (s->user->display)
361 return 0;
362
4d6d6518 363 if (!s->display || !display_is_local(s->display))
20263082
LP
364 return 0;
365
366 k = strspn(s->display+1, "0123456789");
367 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
368 if (!f) {
369 log_error("Out of memory");
370 return -ENOMEM;
371 }
372
373 c = stpcpy(f, "/tmp/.X11-unix/X");
374 memcpy(c, s->display+1, k);
375 c[k] = 0;
376
377 if (access(f, F_OK) < 0) {
378 log_warning("Session %s has display %s with nonexisting socket %s.", s->id, s->display, f);
379 free(f);
380 return -ENOENT;
381 }
382
0254daed 383 t = strappend(s->user->runtime_path, "/X11/display");
20263082
LP
384 if (!t) {
385 log_error("Out of memory");
386 free(f);
387 return -ENOMEM;
388 }
389
0254daed
LP
390 mkdir_parents(t, 0755);
391
20263082
LP
392 if (link(f, t) < 0) {
393 if (errno == EEXIST) {
394 unlink(t);
395
396 if (link(f, t) >= 0)
397 goto done;
398 }
399
400 if (symlink(f, t) < 0) {
401
402 if (errno == EEXIST) {
403 unlink(t);
404
405 if (symlink(f, t) >= 0)
406 goto done;
407 }
408
409 log_error("Failed to link %s to %s: %m", f, t);
410 free(f);
411 free(t);
412 return -errno;
413 }
414 }
415
416done:
417 log_info("Linked %s to %s.", f, t);
418 free(f);
419 free(t);
420
421 s->user->display = s;
422
423 return 0;
424}
425
98a28fef
LP
426static int session_create_one_group(Session *s, const char *controller, const char *path) {
427 int r;
428
429 assert(s);
430 assert(controller);
431 assert(path);
432
b6f68af1 433 if (s->leader > 0) {
98a28fef 434 r = cg_create_and_attach(controller, path, s->leader);
b6f68af1
LP
435 if (r < 0)
436 r = cg_create(controller, path);
437 } else
98a28fef
LP
438 r = cg_create(controller, path);
439
440 if (r < 0)
441 return r;
442
443 r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid);
444 if (r >= 0)
445 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
446
447 return r;
448}
449
20263082
LP
450static int session_create_cgroup(Session *s) {
451 char **k;
452 char *p;
453 int r;
454
455 assert(s);
456 assert(s->user);
457 assert(s->user->cgroup_path);
458
459 if (!s->cgroup_path) {
460 if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0) {
461 log_error("Out of memory");
462 return -ENOMEM;
463 }
464 } else
465 p = s->cgroup_path;
466
98a28fef 467 r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
20263082 468 if (r < 0) {
4d6d6518 469 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
20263082
LP
470 free(p);
471 s->cgroup_path = NULL;
20263082
LP
472 return r;
473 }
474
475 s->cgroup_path = p;
476
98a28fef
LP
477 STRV_FOREACH(k, s->controllers) {
478
479 if (strv_contains(s->reset_controllers, *k))
480 continue;
481
482 r = session_create_one_group(s, *k, p);
483 if (r < 0)
484 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
485 }
486
20263082 487 STRV_FOREACH(k, s->manager->controllers) {
20263082 488
98a28fef 489 if (strv_contains(s->reset_controllers, *k) ||
193197e8 490 strv_contains(s->manager->reset_controllers, *k) ||
98a28fef
LP
491 strv_contains(s->controllers, *k))
492 continue;
493
494 r = session_create_one_group(s, *k, p);
20263082 495 if (r < 0)
98a28fef
LP
496 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
497 }
498
499 if (s->leader > 0) {
500
501 STRV_FOREACH(k, s->reset_controllers) {
502 r = cg_attach(*k, "/", s->leader);
503 if (r < 0)
504 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
505
506 }
193197e8
LP
507
508 STRV_FOREACH(k, s->manager->reset_controllers) {
509
510 if (strv_contains(s->reset_controllers, *k) ||
511 strv_contains(s->controllers, *k))
512 continue;
513
514 r = cg_attach(*k, "/", s->leader);
515 if (r < 0)
516 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
517
518 }
20263082
LP
519 }
520
1713813d
LP
521 hashmap_put(s->manager->cgroups, s->cgroup_path, s);
522
20263082
LP
523 return 0;
524}
525
526int session_start(Session *s) {
527 int r;
528
529 assert(s);
530 assert(s->user);
531
9418f147
LP
532 if (s->started)
533 return 0;
534
ed18b08b
LP
535 r = user_start(s->user);
536 if (r < 0)
537 return r;
538
98a28fef
LP
539 log_info("New session %s of user %s.", s->id, s->user->name);
540
20263082
LP
541 /* Create cgroup */
542 r = session_create_cgroup(s);
543 if (r < 0)
544 return r;
545
546 /* Create X11 symlink */
547 session_link_x11_socket(s);
14c3baca 548
14c3baca
LP
549 dual_timestamp_get(&s->timestamp);
550
e9816c48
LP
551 if (s->seat)
552 seat_read_active_vt(s->seat);
553
9418f147
LP
554 s->started = true;
555
e9816c48
LP
556 /* Save session data */
557 session_save(s);
7f7bb946 558 user_save(s->user);
e9816c48 559
da119395
LP
560 session_send_signal(s, true);
561
9418f147 562 if (s->seat) {
7f7bb946
LP
563 seat_save(s->seat);
564
9418f147
LP
565 if (s->seat->active == s)
566 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
567 else
568 seat_send_changed(s->seat, "Sessions\0");
569 }
570
571 user_send_changed(s->user, "Sessions\0");
572
20263082
LP
573 return 0;
574}
575
576static bool session_shall_kill(Session *s) {
577 assert(s);
578
ed18b08b
LP
579 if (!s->kill_processes)
580 return false;
581
582 if (strv_contains(s->manager->kill_exclude_users, s->user->name))
583 return false;
584
585 if (strv_isempty(s->manager->kill_only_users))
586 return true;
587
588 return strv_contains(s->manager->kill_only_users, s->user->name);
20263082
LP
589}
590
de07ab16 591static int session_terminate_cgroup(Session *s) {
20263082
LP
592 int r;
593 char **k;
594
595 assert(s);
596
597 if (!s->cgroup_path)
598 return 0;
599
600 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
601
602 if (session_shall_kill(s)) {
603
604 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
605 if (r < 0)
606 log_error("Failed to kill session cgroup: %s", strerror(-r));
607
608 } else {
609 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
610 if (r < 0)
611 log_error("Failed to check session cgroup: %s", strerror(-r));
612 else if (r > 0) {
613 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
614 if (r < 0)
615 log_error("Failed to delete session cgroup: %s", strerror(-r));
616 } else
617 r = -EBUSY;
618 }
619
620 STRV_FOREACH(k, s->user->manager->controllers)
621 cg_trim(*k, s->cgroup_path, true);
622
1713813d
LP
623 hashmap_remove(s->manager->cgroups, s->cgroup_path);
624
20263082
LP
625 free(s->cgroup_path);
626 s->cgroup_path = NULL;
627
628 return r;
629}
630
631static int session_unlink_x11_socket(Session *s) {
632 char *t;
633 int r;
634
635 assert(s);
636 assert(s->user);
637
638 if (s->user->display != s)
639 return 0;
640
641 s->user->display = NULL;
642
0254daed 643 t = strappend(s->user->runtime_path, "/X11/display");
20263082
LP
644 if (!t) {
645 log_error("Out of memory");
646 return -ENOMEM;
647 }
648
649 r = unlink(t);
650 free(t);
651
652 return r < 0 ? -errno : 0;
653}
654
655int session_stop(Session *s) {
656 int r = 0, k;
657
658 assert(s);
659
ed18b08b
LP
660 if (s->started)
661 log_info("Removed session %s.", s->id);
98a28fef 662
20263082 663 /* Kill cgroup */
de07ab16 664 k = session_terminate_cgroup(s);
20263082
LP
665 if (k < 0)
666 r = k;
667
668 /* Remove X11 symlink */
669 session_unlink_x11_socket(s);
670
d2f92cdf
LP
671 unlink(s->state_file);
672 session_add_to_gc_queue(s);
ed18b08b 673 user_add_to_gc_queue(s->user);
14c3baca 674
ed18b08b
LP
675 if (s->started)
676 session_send_signal(s, false);
9418f147
LP
677
678 if (s->seat) {
679 if (s->seat->active == s)
680 seat_set_active(s->seat, NULL);
681
682 seat_send_changed(s->seat, "Sessions\0");
683 }
684
685 user_send_changed(s->user, "Sessions\0");
686
687 s->started = false;
688
20263082
LP
689 return r;
690}
691
692bool session_is_active(Session *s) {
693 assert(s);
694
695 if (!s->seat)
696 return true;
697
698 return s->seat->active == s;
699}
700
a185c5aa
LP
701int session_get_idle_hint(Session *s, dual_timestamp *t) {
702 char *p;
703 struct stat st;
704 usec_t u, n;
705 bool b;
706 int k;
707
708 assert(s);
709
710 if (s->idle_hint) {
711 if (t)
712 *t = s->idle_hint_timestamp;
713
714 return s->idle_hint;
715 }
716
717 if (isempty(s->tty))
718 goto dont_know;
719
720 if (s->tty[0] != '/') {
721 p = strappend("/dev/", s->tty);
722 if (!p)
723 return -ENOMEM;
724 } else
725 p = NULL;
726
727 if (!startswith(p ? p : s->tty, "/dev/")) {
728 free(p);
729 goto dont_know;
730 }
731
732 k = lstat(p ? p : s->tty, &st);
733 free(p);
734
735 if (k < 0)
736 goto dont_know;
737
738 u = timespec_load(&st.st_atim);
739 n = now(CLOCK_REALTIME);
740 b = u + IDLE_THRESHOLD_USEC < n;
741
742 if (t)
743 dual_timestamp_from_realtime(t, u + b ? IDLE_THRESHOLD_USEC : 0);
744
745 return b;
746
747dont_know:
748 if (t)
749 *t = s->idle_hint_timestamp;
750
751 return 0;
752}
753
bef422ae
LP
754void session_set_idle_hint(Session *s, bool b) {
755 assert(s);
756
757 if (s->idle_hint == b)
758 return;
759
760 s->idle_hint = b;
761 dual_timestamp_get(&s->idle_hint_timestamp);
9418f147
LP
762
763 session_send_changed(s,
764 "IdleHint\0"
765 "IdleSinceHint\0"
766 "IdleSinceHintMonotonic\0");
767
768 if (s->seat)
769 seat_send_changed(s->seat,
770 "IdleHint\0"
771 "IdleSinceHint\0"
772 "IdleSinceHintMonotonic\0");
773
774 user_send_changed(s->user,
775 "IdleHint\0"
776 "IdleSinceHint\0"
777 "IdleSinceHintMonotonic\0");
778
779 manager_send_changed(s->manager,
780 "IdleHint\0"
781 "IdleSinceHint\0"
782 "IdleSinceHintMonotonic\0");
bef422ae
LP
783}
784
932e3ee7
LP
785int session_create_fifo(Session *s) {
786 int r;
787
31b79c2b
LP
788 assert(s);
789
b4f78aea 790 /* Create FIFO */
932e3ee7 791 if (!s->fifo_path) {
e6061ab2
LP
792 r = safe_mkdir("/run/systemd/sessions", 0755, 0, 0);
793 if (r < 0)
794 return r;
795
932e3ee7
LP
796 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
797 return -ENOMEM;
31b79c2b 798
932e3ee7
LP
799 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
800 return -errno;
801 }
31b79c2b 802
932e3ee7 803 /* Open reading side */
b4f78aea
LP
804 if (s->fifo_fd < 0) {
805 struct epoll_event ev;
806
807 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
808 if (s->fifo_fd < 0)
809 return -errno;
810
811 r = hashmap_put(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1), s);
812 if (r < 0)
813 return r;
814
815 zero(ev);
816 ev.events = 0;
817 ev.data.u32 = FD_FIFO_BASE + s->fifo_fd;
818
819 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
820 return -errno;
821 }
932e3ee7
LP
822
823 /* Open writing side */
824 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
825 if (r < 0)
826 return -errno;
31b79c2b 827
932e3ee7
LP
828 return r;
829}
830
831void session_remove_fifo(Session *s) {
832 assert(s);
833
834 if (s->fifo_fd >= 0) {
835 assert_se(hashmap_remove(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
836 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
837 close_nointr_nofail(s->fifo_fd);
838 s->fifo_fd = -1;
839 }
840
841 if (s->fifo_path) {
842 unlink(s->fifo_path);
843 free(s->fifo_path);
844 s->fifo_path = NULL;
845 }
31b79c2b
LP
846}
847
4a4b033f 848int session_check_gc(Session *s, bool drop_not_started) {
20263082
LP
849 int r;
850
851 assert(s);
852
4a4b033f 853 if (drop_not_started && !s->started)
932e3ee7
LP
854 return 0;
855
856 if (s->fifo_fd >= 0) {
20263082 857
932e3ee7 858 r = pipe_eof(s->fifo_fd);
20263082
LP
859 if (r < 0)
860 return r;
861
14c3baca 862 if (r == 0)
20263082
LP
863 return 1;
864 }
865
866 if (s->cgroup_path) {
867
868 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
869 if (r < 0)
870 return r;
871
872 if (r <= 0)
873 return 1;
874 }
875
876 return 0;
877}
878
14c3baca
LP
879void session_add_to_gc_queue(Session *s) {
880 assert(s);
881
882 if (s->in_gc_queue)
883 return;
884
885 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
886 s->in_gc_queue = true;
887}
888
de07ab16
LP
889int session_kill(Session *s, KillWho who, int signo) {
890 int r = 0;
891 Set *pid_set = NULL;
892
893 assert(s);
894
895 if (!s->cgroup_path)
896 return -ESRCH;
897
898 if (s->leader <= 0 && who == KILL_LEADER)
899 return -ESRCH;
900
901 if (s->leader > 0)
902 if (kill(s->leader, signo) < 0)
903 r = -errno;
904
905 if (who == KILL_ALL) {
906 int q;
907
908 pid_set = set_new(trivial_hash_func, trivial_compare_func);
909 if (!pid_set)
910 return -ENOMEM;
911
912 if (s->leader > 0) {
913 q = set_put(pid_set, LONG_TO_PTR(s->leader));
914 if (q < 0)
915 r = q;
916 }
917
918 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
919 if (q < 0)
920 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
921 r = q;
922 }
923
de07ab16
LP
924 if (pid_set)
925 set_free(pid_set);
926
927 return r;
928}
929
20263082 930static const char* const session_type_table[_SESSION_TYPE_MAX] = {
3f49d45a 931 [SESSION_TTY] = "tty",
98a28fef 932 [SESSION_X11] = "x11",
a91e4e53 933 [SESSION_UNSPECIFIED] = "unspecified"
20263082
LP
934};
935
936DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
de07ab16
LP
937
938static const char* const kill_who_table[_KILL_WHO_MAX] = {
939 [KILL_LEADER] = "leader",
940 [KILL_ALL] = "all"
941};
942
943DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);