]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-session.c
logind: expose CanGraphical and CanTTY properties on seat objects
[thirdparty/systemd.git] / src / login / 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
5430f7f2
LP
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
20263082
LP
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
5430f7f2 16 Lesser General Public License for more details.
20263082 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
20263082
LP
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
20263082
LP
28#include "strv.h"
29#include "util.h"
49e942b2 30#include "mkdir.h"
9eb977db 31#include "path-util.h"
20263082 32#include "cgroup-util.h"
f8e2fb7b 33#include "logind-session.h"
20263082 34
a185c5aa
LP
35#define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE)
36
20263082
LP
37Session* session_new(Manager *m, User *u, const char *id) {
38 Session *s;
39
40 assert(m);
41 assert(id);
42
14c3baca 43 s = new0(Session, 1);
20263082
LP
44 if (!s)
45 return NULL;
46
98a28fef 47 s->state_file = strappend("/run/systemd/sessions/", id);
20263082
LP
48 if (!s->state_file) {
49 free(s);
50 return NULL;
51 }
52
9eb977db 53 s->id = path_get_file_name(s->state_file);
20263082
LP
54
55 if (hashmap_put(m->sessions, s->id, s) < 0) {
f8e2fb7b 56 free(s->state_file);
20263082
LP
57 free(s);
58 return NULL;
59 }
60
61 s->manager = m;
932e3ee7 62 s->fifo_fd = -1;
20263082
LP
63 s->user = u;
64
14c3baca 65 LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
20263082
LP
66
67 return s;
68}
69
70void session_free(Session *s) {
71 assert(s);
72
14c3baca
LP
73 if (s->in_gc_queue)
74 LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
75
20263082
LP
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
9418f147
LP
83 if (s->seat) {
84 if (s->seat->active == s)
85 s->seat->active = NULL;
86
20263082 87 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
9418f147 88 }
20263082 89
1713813d 90 if (s->cgroup_path)
8c8c4351 91 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
1713813d 92
20263082
LP
93 free(s->cgroup_path);
94 strv_free(s->controllers);
95
96 free(s->tty);
97 free(s->display);
98 free(s->remote_host);
3f49d45a 99 free(s->remote_user);
98a28fef 100 free(s->service);
20263082
LP
101
102 hashmap_remove(s->manager->sessions, s->id);
932e3ee7 103 session_remove_fifo(s);
98a28fef 104
d2f92cdf 105 free(s->state_file);
20263082
LP
106 free(s);
107}
108
109int session_save(Session *s) {
110 FILE *f;
111 int r = 0;
14c3baca 112 char *temp_path;
20263082
LP
113
114 assert(s);
115
accaeded
LP
116 if (!s->started)
117 return 0;
118
d2e54fae 119 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
20263082 120 if (r < 0)
14c3baca 121 goto finish;
20263082 122
14c3baca
LP
123 r = fopen_temporary(s->state_file, &f, &temp_path);
124 if (r < 0)
125 goto finish;
20263082
LP
126
127 assert(s->user);
128
14c3baca
LP
129 fchmod(fileno(f), 0644);
130
20263082
LP
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 "REMOTE=%i\n"
137 "KILL_PROCESSES=%i\n",
138 (unsigned long) s->user->uid,
139 s->user->name,
140 session_is_active(s),
141 s->remote,
142 s->kill_processes);
143
a91e4e53
LP
144 if (s->type >= 0)
145 fprintf(f,
146 "TYPE=%s\n",
147 session_type_to_string(s->type));
148
55efac6c
LP
149 if (s->class >= 0)
150 fprintf(f,
151 "CLASS=%s\n",
152 session_class_to_string(s->class));
153
20263082
LP
154 if (s->cgroup_path)
155 fprintf(f,
156 "CGROUP=%s\n",
157 s->cgroup_path);
158
932e3ee7
LP
159 if (s->fifo_path)
160 fprintf(f,
161 "FIFO=%s\n",
162 s->fifo_path);
163
20263082
LP
164 if (s->seat)
165 fprintf(f,
166 "SEAT=%s\n",
167 s->seat->id);
168
169 if (s->tty)
170 fprintf(f,
171 "TTY=%s\n",
172 s->tty);
173
174 if (s->display)
175 fprintf(f,
176 "DISPLAY=%s\n",
177 s->display);
178
179 if (s->remote_host)
180 fprintf(f,
181 "REMOTE_HOST=%s\n",
182 s->remote_host);
183
3f49d45a
LP
184 if (s->remote_user)
185 fprintf(f,
186 "REMOTE_USER=%s\n",
187 s->remote_user);
188
98a28fef
LP
189 if (s->service)
190 fprintf(f,
191 "SERVICE=%s\n",
192 s->service);
193
addedec4 194 if (s->seat && seat_can_multi_session(s->seat))
20263082
LP
195 fprintf(f,
196 "VTNR=%i\n",
197 s->vtnr);
198
199 if (s->leader > 0)
200 fprintf(f,
201 "LEADER=%lu\n",
202 (unsigned long) s->leader);
203
204 if (s->audit_id > 0)
205 fprintf(f,
206 "AUDIT=%llu\n",
207 (unsigned long long) s->audit_id);
208
209 fflush(f);
14c3baca
LP
210
211 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
20263082
LP
212 r = -errno;
213 unlink(s->state_file);
14c3baca 214 unlink(temp_path);
20263082
LP
215 }
216
217 fclose(f);
14c3baca
LP
218 free(temp_path);
219
220finish:
221 if (r < 0)
222 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
223
20263082
LP
224 return r;
225}
226
227int session_load(Session *s) {
a185c5aa
LP
228 char *remote = NULL,
229 *kill_processes = NULL,
230 *seat = NULL,
231 *vtnr = NULL,
232 *leader = NULL,
a91e4e53 233 *audit_id = NULL,
55efac6c
LP
234 *type = NULL,
235 *class = NULL;
a185c5aa
LP
236
237 int k, r;
238
20263082
LP
239 assert(s);
240
a185c5aa
LP
241 r = parse_env_file(s->state_file, NEWLINE,
242 "REMOTE", &remote,
243 "KILL_PROCESSES", &kill_processes,
244 "CGROUP", &s->cgroup_path,
932e3ee7 245 "FIFO", &s->fifo_path,
a185c5aa
LP
246 "SEAT", &seat,
247 "TTY", &s->tty,
248 "DISPLAY", &s->display,
249 "REMOTE_HOST", &s->remote_host,
250 "REMOTE_USER", &s->remote_user,
98a28fef 251 "SERVICE", &s->service,
a185c5aa
LP
252 "VTNR", &vtnr,
253 "LEADER", &leader,
a91e4e53 254 "TYPE", &type,
55efac6c 255 "CLASS", &class,
a185c5aa
LP
256 NULL);
257
258 if (r < 0)
259 goto finish;
260
261 if (remote) {
262 k = parse_boolean(remote);
263 if (k >= 0)
264 s->remote = k;
265 }
266
267 if (kill_processes) {
268 k = parse_boolean(kill_processes);
269 if (k >= 0)
270 s->kill_processes = k;
271 }
272
9418f147 273 if (seat && !s->seat) {
a185c5aa
LP
274 Seat *o;
275
276 o = hashmap_get(s->manager->seats, seat);
277 if (o)
278 seat_attach_session(o, s);
279 }
280
addedec4 281 if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
a185c5aa
LP
282 int v;
283
284 k = safe_atoi(vtnr, &v);
285 if (k >= 0 && v >= 1)
286 s->vtnr = v;
287 }
288
289 if (leader) {
f8e2fb7b
LP
290 k = parse_pid(leader, &s->leader);
291 if (k >= 0)
292 audit_session_from_pid(s->leader, &s->audit_id);
a185c5aa
LP
293 }
294
a91e4e53
LP
295 if (type) {
296 SessionType t;
297
298 t = session_type_from_string(type);
299 if (t >= 0)
300 s->type = t;
301 }
302
55efac6c
LP
303 if (class) {
304 SessionClass c;
305
306 c = session_class_from_string(class);
307 if (c >= 0)
308 s->class = c;
309 }
310
b4f78aea
LP
311 if (s->fifo_path) {
312 int fd;
313
314 /* If we open an unopened pipe for reading we will not
315 get an EOF. to trigger an EOF we hence open it for
316 reading, but close it right-away which then will
317 trigger the EOF. */
318
319 fd = session_create_fifo(s);
320 if (fd >= 0)
321 close_nointr_nofail(fd);
322 }
323
a185c5aa
LP
324finish:
325 free(remote);
326 free(kill_processes);
327 free(seat);
328 free(vtnr);
329 free(leader);
330 free(audit_id);
b80efeb9 331 free(class);
a185c5aa
LP
332
333 return r;
20263082
LP
334}
335
336int session_activate(Session *s) {
337 int r;
338
339 assert(s);
340
341 if (s->vtnr < 0)
342 return -ENOTSUP;
343
344 if (!s->seat)
345 return -ENOTSUP;
346
347 if (s->seat->active == s)
348 return 0;
349
a185c5aa 350 assert(seat_is_vtconsole(s->seat));
20263082
LP
351
352 r = chvt(s->vtnr);
353 if (r < 0)
354 return r;
355
129eebe0 356 return seat_set_active(s->seat, s);
20263082
LP
357}
358
20263082
LP
359static int session_link_x11_socket(Session *s) {
360 char *t, *f, *c;
361 size_t k;
362
363 assert(s);
364 assert(s->user);
365 assert(s->user->runtime_path);
366
367 if (s->user->display)
368 return 0;
369
4d6d6518 370 if (!s->display || !display_is_local(s->display))
20263082
LP
371 return 0;
372
373 k = strspn(s->display+1, "0123456789");
374 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
375 if (!f) {
376 log_error("Out of memory");
377 return -ENOMEM;
378 }
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) {
6ccf7562 385 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
20263082
LP
386 free(f);
387 return -ENOENT;
388 }
389
c9d8629b
LP
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
fc3c1c6e 394 t = strappend(s->user->runtime_path, "/X11-display");
20263082
LP
395 if (!t) {
396 log_error("Out of memory");
397 free(f);
398 return -ENOMEM;
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
425done:
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
98a28fef
LP
435static 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
b6f68af1 442 if (s->leader > 0) {
98a28fef 443 r = cg_create_and_attach(controller, path, s->leader);
b6f68af1
LP
444 if (r < 0)
445 r = cg_create(controller, path);
446 } else
98a28fef
LP
447 r = cg_create(controller, path);
448
449 if (r < 0)
450 return r;
451
8d53b453 452 r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid, -1);
98a28fef
LP
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
20263082
LP
459static 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 log_error("Out of memory");
471 return -ENOMEM;
472 }
473 } else
474 p = s->cgroup_path;
475
98a28fef 476 r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
20263082 477 if (r < 0) {
4d6d6518 478 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
20263082
LP
479 free(p);
480 s->cgroup_path = NULL;
20263082
LP
481 return r;
482 }
483
484 s->cgroup_path = p;
485
98a28fef
LP
486 STRV_FOREACH(k, s->controllers) {
487
488 if (strv_contains(s->reset_controllers, *k))
489 continue;
490
491 r = session_create_one_group(s, *k, p);
492 if (r < 0)
493 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
494 }
495
20263082 496 STRV_FOREACH(k, s->manager->controllers) {
20263082 497
98a28fef 498 if (strv_contains(s->reset_controllers, *k) ||
193197e8 499 strv_contains(s->manager->reset_controllers, *k) ||
98a28fef
LP
500 strv_contains(s->controllers, *k))
501 continue;
502
503 r = session_create_one_group(s, *k, p);
20263082 504 if (r < 0)
98a28fef
LP
505 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
506 }
507
508 if (s->leader > 0) {
509
510 STRV_FOREACH(k, s->reset_controllers) {
511 r = cg_attach(*k, "/", s->leader);
512 if (r < 0)
513 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
514
515 }
193197e8
LP
516
517 STRV_FOREACH(k, s->manager->reset_controllers) {
518
519 if (strv_contains(s->reset_controllers, *k) ||
520 strv_contains(s->controllers, *k))
521 continue;
522
523 r = cg_attach(*k, "/", s->leader);
524 if (r < 0)
525 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
526
527 }
20263082
LP
528 }
529
8c8c4351 530 hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
1713813d 531
20263082
LP
532 return 0;
533}
534
535int session_start(Session *s) {
536 int r;
537
538 assert(s);
539 assert(s->user);
540
9418f147
LP
541 if (s->started)
542 return 0;
543
ed18b08b
LP
544 r = user_start(s->user);
545 if (r < 0)
546 return r;
547
1a4459d6 548 log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
990a1aba 549 "New session %s of user %s.", s->id, s->user->name);
98a28fef 550
20263082
LP
551 /* Create cgroup */
552 r = session_create_cgroup(s);
553 if (r < 0)
554 return r;
555
556 /* Create X11 symlink */
557 session_link_x11_socket(s);
14c3baca 558
14c3baca
LP
559 dual_timestamp_get(&s->timestamp);
560
e9816c48
LP
561 if (s->seat)
562 seat_read_active_vt(s->seat);
563
9418f147
LP
564 s->started = true;
565
e9816c48
LP
566 /* Save session data */
567 session_save(s);
7f7bb946 568 user_save(s->user);
e9816c48 569
da119395
LP
570 session_send_signal(s, true);
571
9418f147 572 if (s->seat) {
7f7bb946
LP
573 seat_save(s->seat);
574
9418f147
LP
575 if (s->seat->active == s)
576 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
577 else
578 seat_send_changed(s->seat, "Sessions\0");
579 }
580
581 user_send_changed(s->user, "Sessions\0");
582
20263082
LP
583 return 0;
584}
585
586static bool session_shall_kill(Session *s) {
587 assert(s);
588
ed18b08b
LP
589 if (!s->kill_processes)
590 return false;
591
592 if (strv_contains(s->manager->kill_exclude_users, s->user->name))
593 return false;
594
595 if (strv_isempty(s->manager->kill_only_users))
596 return true;
597
598 return strv_contains(s->manager->kill_only_users, s->user->name);
20263082
LP
599}
600
de07ab16 601static int session_terminate_cgroup(Session *s) {
20263082
LP
602 int r;
603 char **k;
604
605 assert(s);
606
607 if (!s->cgroup_path)
608 return 0;
609
610 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
611
612 if (session_shall_kill(s)) {
613
614 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
615 if (r < 0)
616 log_error("Failed to kill session cgroup: %s", strerror(-r));
617
618 } else {
9b221b63
LP
619 if (s->leader > 0) {
620 Session *t;
621
622 /* We still send a HUP to the leader process,
623 * even if we are not supposed to kill the
624 * whole cgroup. But let's first check the
625 * leader still exists and belongs to our
626 * session... */
627
628 r = manager_get_session_by_pid(s->manager, s->leader, &t);
629 if (r > 0 && t == s) {
630 kill(s->leader, SIGTERM); /* for normal processes */
631 kill(s->leader, SIGHUP); /* for shells */
632 kill(s->leader, SIGCONT); /* in case they are stopped */
633 }
634 }
635
20263082
LP
636 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
637 if (r < 0)
638 log_error("Failed to check session cgroup: %s", strerror(-r));
639 else if (r > 0) {
640 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
641 if (r < 0)
642 log_error("Failed to delete session cgroup: %s", strerror(-r));
9b221b63 643 }
20263082
LP
644 }
645
646 STRV_FOREACH(k, s->user->manager->controllers)
647 cg_trim(*k, s->cgroup_path, true);
648
8c8c4351 649 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
1713813d 650
20263082
LP
651 free(s->cgroup_path);
652 s->cgroup_path = NULL;
653
9b221b63 654 return 0;
20263082
LP
655}
656
657static int session_unlink_x11_socket(Session *s) {
658 char *t;
659 int r;
660
661 assert(s);
662 assert(s->user);
663
664 if (s->user->display != s)
665 return 0;
666
667 s->user->display = NULL;
668
fc3c1c6e 669 t = strappend(s->user->runtime_path, "/X11-display");
20263082
LP
670 if (!t) {
671 log_error("Out of memory");
672 return -ENOMEM;
673 }
674
675 r = unlink(t);
676 free(t);
677
678 return r < 0 ? -errno : 0;
679}
680
681int session_stop(Session *s) {
682 int r = 0, k;
683
684 assert(s);
685
ed18b08b 686 if (s->started)
1a4459d6 687 log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
990a1aba 688 "Removed session %s.", s->id);
98a28fef 689
20263082 690 /* Kill cgroup */
de07ab16 691 k = session_terminate_cgroup(s);
20263082
LP
692 if (k < 0)
693 r = k;
694
695 /* Remove X11 symlink */
696 session_unlink_x11_socket(s);
697
d2f92cdf
LP
698 unlink(s->state_file);
699 session_add_to_gc_queue(s);
ed18b08b 700 user_add_to_gc_queue(s->user);
14c3baca 701
ed18b08b
LP
702 if (s->started)
703 session_send_signal(s, false);
9418f147
LP
704
705 if (s->seat) {
706 if (s->seat->active == s)
707 seat_set_active(s->seat, NULL);
708
709 seat_send_changed(s->seat, "Sessions\0");
710 }
711
712 user_send_changed(s->user, "Sessions\0");
713
714 s->started = false;
715
20263082
LP
716 return r;
717}
718
719bool session_is_active(Session *s) {
720 assert(s);
721
722 if (!s->seat)
723 return true;
724
725 return s->seat->active == s;
726}
727
a185c5aa
LP
728int session_get_idle_hint(Session *s, dual_timestamp *t) {
729 char *p;
730 struct stat st;
731 usec_t u, n;
732 bool b;
733 int k;
734
735 assert(s);
736
737 if (s->idle_hint) {
738 if (t)
739 *t = s->idle_hint_timestamp;
740
741 return s->idle_hint;
742 }
743
744 if (isempty(s->tty))
745 goto dont_know;
746
747 if (s->tty[0] != '/') {
748 p = strappend("/dev/", s->tty);
749 if (!p)
750 return -ENOMEM;
751 } else
752 p = NULL;
753
754 if (!startswith(p ? p : s->tty, "/dev/")) {
755 free(p);
756 goto dont_know;
757 }
758
759 k = lstat(p ? p : s->tty, &st);
760 free(p);
761
762 if (k < 0)
763 goto dont_know;
764
765 u = timespec_load(&st.st_atim);
766 n = now(CLOCK_REALTIME);
767 b = u + IDLE_THRESHOLD_USEC < n;
768
769 if (t)
770 dual_timestamp_from_realtime(t, u + b ? IDLE_THRESHOLD_USEC : 0);
771
772 return b;
773
774dont_know:
775 if (t)
776 *t = s->idle_hint_timestamp;
777
778 return 0;
779}
780
bef422ae
LP
781void session_set_idle_hint(Session *s, bool b) {
782 assert(s);
783
784 if (s->idle_hint == b)
785 return;
786
787 s->idle_hint = b;
788 dual_timestamp_get(&s->idle_hint_timestamp);
9418f147
LP
789
790 session_send_changed(s,
791 "IdleHint\0"
792 "IdleSinceHint\0"
793 "IdleSinceHintMonotonic\0");
794
795 if (s->seat)
796 seat_send_changed(s->seat,
797 "IdleHint\0"
798 "IdleSinceHint\0"
799 "IdleSinceHintMonotonic\0");
800
801 user_send_changed(s->user,
802 "IdleHint\0"
803 "IdleSinceHint\0"
804 "IdleSinceHintMonotonic\0");
805
806 manager_send_changed(s->manager,
807 "IdleHint\0"
808 "IdleSinceHint\0"
809 "IdleSinceHintMonotonic\0");
bef422ae
LP
810}
811
932e3ee7
LP
812int session_create_fifo(Session *s) {
813 int r;
814
31b79c2b
LP
815 assert(s);
816
b4f78aea 817 /* Create FIFO */
932e3ee7 818 if (!s->fifo_path) {
d2e54fae 819 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
e6061ab2
LP
820 if (r < 0)
821 return r;
822
932e3ee7
LP
823 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
824 return -ENOMEM;
31b79c2b 825
932e3ee7
LP
826 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
827 return -errno;
828 }
31b79c2b 829
932e3ee7 830 /* Open reading side */
b4f78aea
LP
831 if (s->fifo_fd < 0) {
832 struct epoll_event ev;
833
834 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
835 if (s->fifo_fd < 0)
836 return -errno;
837
f8e2fb7b 838 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
b4f78aea
LP
839 if (r < 0)
840 return r;
841
842 zero(ev);
843 ev.events = 0;
069cfc85 844 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
b4f78aea
LP
845
846 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
847 return -errno;
848 }
932e3ee7
LP
849
850 /* Open writing side */
851 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
852 if (r < 0)
853 return -errno;
31b79c2b 854
932e3ee7
LP
855 return r;
856}
857
858void session_remove_fifo(Session *s) {
859 assert(s);
860
861 if (s->fifo_fd >= 0) {
f8e2fb7b 862 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
932e3ee7
LP
863 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
864 close_nointr_nofail(s->fifo_fd);
865 s->fifo_fd = -1;
866 }
867
868 if (s->fifo_path) {
869 unlink(s->fifo_path);
870 free(s->fifo_path);
871 s->fifo_path = NULL;
872 }
31b79c2b
LP
873}
874
4a4b033f 875int session_check_gc(Session *s, bool drop_not_started) {
20263082
LP
876 int r;
877
878 assert(s);
879
4a4b033f 880 if (drop_not_started && !s->started)
932e3ee7
LP
881 return 0;
882
883 if (s->fifo_fd >= 0) {
20263082 884
932e3ee7 885 r = pipe_eof(s->fifo_fd);
20263082
LP
886 if (r < 0)
887 return r;
888
14c3baca 889 if (r == 0)
20263082
LP
890 return 1;
891 }
892
893 if (s->cgroup_path) {
894
895 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
896 if (r < 0)
897 return r;
898
899 if (r <= 0)
900 return 1;
901 }
902
903 return 0;
904}
905
14c3baca
LP
906void session_add_to_gc_queue(Session *s) {
907 assert(s);
908
909 if (s->in_gc_queue)
910 return;
911
912 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
913 s->in_gc_queue = true;
914}
915
de07ab16
LP
916int session_kill(Session *s, KillWho who, int signo) {
917 int r = 0;
918 Set *pid_set = NULL;
919
920 assert(s);
921
922 if (!s->cgroup_path)
923 return -ESRCH;
924
925 if (s->leader <= 0 && who == KILL_LEADER)
926 return -ESRCH;
927
928 if (s->leader > 0)
929 if (kill(s->leader, signo) < 0)
930 r = -errno;
931
932 if (who == KILL_ALL) {
933 int q;
934
935 pid_set = set_new(trivial_hash_func, trivial_compare_func);
936 if (!pid_set)
937 return -ENOMEM;
938
939 if (s->leader > 0) {
940 q = set_put(pid_set, LONG_TO_PTR(s->leader));
941 if (q < 0)
942 r = q;
943 }
944
945 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
946 if (q < 0)
947 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
948 r = q;
949 }
950
de07ab16
LP
951 if (pid_set)
952 set_free(pid_set);
953
954 return r;
955}
956
20263082 957static const char* const session_type_table[_SESSION_TYPE_MAX] = {
3f49d45a 958 [SESSION_TTY] = "tty",
98a28fef 959 [SESSION_X11] = "x11",
a91e4e53 960 [SESSION_UNSPECIFIED] = "unspecified"
20263082
LP
961};
962
963DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
de07ab16 964
55efac6c
LP
965static const char* const session_class_table[_SESSION_CLASS_MAX] = {
966 [SESSION_USER] = "user",
967 [SESSION_GREETER] = "greeter",
968 [SESSION_LOCK_SCREEN] = "lock-screen"
969};
970
971DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
972
de07ab16
LP
973static const char* const kill_who_table[_KILL_WHO_MAX] = {
974 [KILL_LEADER] = "leader",
975 [KILL_ALL] = "all"
976};
977
978DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);