]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-session.c
use "Out of memory." consistantly (or with "\n")
[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"
0604381b 136 "STATE=%s\n"
20263082
LP
137 "REMOTE=%i\n"
138 "KILL_PROCESSES=%i\n",
139 (unsigned long) s->user->uid,
140 s->user->name,
141 session_is_active(s),
0604381b 142 session_state_to_string(session_get_state(s)),
20263082
LP
143 s->remote,
144 s->kill_processes);
145
a91e4e53
LP
146 if (s->type >= 0)
147 fprintf(f,
148 "TYPE=%s\n",
149 session_type_to_string(s->type));
150
55efac6c
LP
151 if (s->class >= 0)
152 fprintf(f,
153 "CLASS=%s\n",
154 session_class_to_string(s->class));
155
20263082
LP
156 if (s->cgroup_path)
157 fprintf(f,
158 "CGROUP=%s\n",
159 s->cgroup_path);
160
932e3ee7
LP
161 if (s->fifo_path)
162 fprintf(f,
163 "FIFO=%s\n",
164 s->fifo_path);
165
20263082
LP
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
3f49d45a
LP
186 if (s->remote_user)
187 fprintf(f,
188 "REMOTE_USER=%s\n",
189 s->remote_user);
190
98a28fef
LP
191 if (s->service)
192 fprintf(f,
193 "SERVICE=%s\n",
194 s->service);
195
addedec4 196 if (s->seat && seat_can_multi_session(s->seat))
20263082
LP
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);
14c3baca
LP
212
213 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
20263082
LP
214 r = -errno;
215 unlink(s->state_file);
14c3baca 216 unlink(temp_path);
20263082
LP
217 }
218
219 fclose(f);
14c3baca
LP
220 free(temp_path);
221
222finish:
223 if (r < 0)
224 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
225
20263082
LP
226 return r;
227}
228
229int session_load(Session *s) {
a185c5aa
LP
230 char *remote = NULL,
231 *kill_processes = NULL,
232 *seat = NULL,
233 *vtnr = NULL,
234 *leader = NULL,
a91e4e53 235 *audit_id = NULL,
55efac6c
LP
236 *type = NULL,
237 *class = NULL;
a185c5aa
LP
238
239 int k, r;
240
20263082
LP
241 assert(s);
242
a185c5aa
LP
243 r = parse_env_file(s->state_file, NEWLINE,
244 "REMOTE", &remote,
245 "KILL_PROCESSES", &kill_processes,
246 "CGROUP", &s->cgroup_path,
932e3ee7 247 "FIFO", &s->fifo_path,
a185c5aa
LP
248 "SEAT", &seat,
249 "TTY", &s->tty,
250 "DISPLAY", &s->display,
251 "REMOTE_HOST", &s->remote_host,
252 "REMOTE_USER", &s->remote_user,
98a28fef 253 "SERVICE", &s->service,
a185c5aa
LP
254 "VTNR", &vtnr,
255 "LEADER", &leader,
a91e4e53 256 "TYPE", &type,
55efac6c 257 "CLASS", &class,
a185c5aa
LP
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
9418f147 275 if (seat && !s->seat) {
a185c5aa
LP
276 Seat *o;
277
278 o = hashmap_get(s->manager->seats, seat);
279 if (o)
280 seat_attach_session(o, s);
281 }
282
addedec4 283 if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
a185c5aa
LP
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) {
f8e2fb7b
LP
292 k = parse_pid(leader, &s->leader);
293 if (k >= 0)
294 audit_session_from_pid(s->leader, &s->audit_id);
a185c5aa
LP
295 }
296
a91e4e53
LP
297 if (type) {
298 SessionType t;
299
300 t = session_type_from_string(type);
301 if (t >= 0)
302 s->type = t;
303 }
304
55efac6c
LP
305 if (class) {
306 SessionClass c;
307
308 c = session_class_from_string(class);
309 if (c >= 0)
310 s->class = c;
311 }
312
b4f78aea
LP
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
a185c5aa
LP
326finish:
327 free(remote);
328 free(kill_processes);
329 free(seat);
330 free(vtnr);
331 free(leader);
332 free(audit_id);
b80efeb9 333 free(class);
a185c5aa
LP
334
335 return r;
20263082
LP
336}
337
338int 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
a185c5aa 352 assert(seat_is_vtconsole(s->seat));
20263082
LP
353
354 r = chvt(s->vtnr);
355 if (r < 0)
356 return r;
357
129eebe0 358 return seat_set_active(s->seat, s);
20263082
LP
359}
360
20263082
LP
361static 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
4d6d6518 372 if (!s->display || !display_is_local(s->display))
20263082
LP
373 return 0;
374
375 k = strspn(s->display+1, "0123456789");
376 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
377 if (!f) {
669241a0 378 log_error("Out of memory.");
20263082
LP
379 return -ENOMEM;
380 }
381
382 c = stpcpy(f, "/tmp/.X11-unix/X");
383 memcpy(c, s->display+1, k);
384 c[k] = 0;
385
386 if (access(f, F_OK) < 0) {
6ccf7562 387 log_warning("Session %s has display %s with non-existing socket %s.", s->id, s->display, f);
20263082
LP
388 free(f);
389 return -ENOENT;
390 }
391
c9d8629b
LP
392 /* Note that this cannot be in a subdir to avoid
393 * vulnerabilities since we are privileged but the runtime
394 * path is owned by the user */
395
fc3c1c6e 396 t = strappend(s->user->runtime_path, "/X11-display");
20263082 397 if (!t) {
669241a0 398 log_error("Out of memory.");
20263082
LP
399 free(f);
400 return -ENOMEM;
401 }
402
403 if (link(f, t) < 0) {
404 if (errno == EEXIST) {
405 unlink(t);
406
407 if (link(f, t) >= 0)
408 goto done;
409 }
410
411 if (symlink(f, t) < 0) {
412
413 if (errno == EEXIST) {
414 unlink(t);
415
416 if (symlink(f, t) >= 0)
417 goto done;
418 }
419
420 log_error("Failed to link %s to %s: %m", f, t);
421 free(f);
422 free(t);
423 return -errno;
424 }
425 }
426
427done:
428 log_info("Linked %s to %s.", f, t);
429 free(f);
430 free(t);
431
432 s->user->display = s;
433
434 return 0;
435}
436
98a28fef
LP
437static int session_create_one_group(Session *s, const char *controller, const char *path) {
438 int r;
439
440 assert(s);
441 assert(controller);
442 assert(path);
443
b6f68af1 444 if (s->leader > 0) {
98a28fef 445 r = cg_create_and_attach(controller, path, s->leader);
b6f68af1
LP
446 if (r < 0)
447 r = cg_create(controller, path);
448 } else
98a28fef
LP
449 r = cg_create(controller, path);
450
451 if (r < 0)
452 return r;
453
8d53b453 454 r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid, -1);
98a28fef
LP
455 if (r >= 0)
456 r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
457
458 return r;
459}
460
20263082
LP
461static int session_create_cgroup(Session *s) {
462 char **k;
463 char *p;
464 int r;
465
466 assert(s);
467 assert(s->user);
468 assert(s->user->cgroup_path);
469
470 if (!s->cgroup_path) {
471 if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0) {
669241a0 472 log_error("Out of memory.");
20263082
LP
473 return -ENOMEM;
474 }
475 } else
476 p = s->cgroup_path;
477
98a28fef 478 r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
20263082 479 if (r < 0) {
4d6d6518 480 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
20263082
LP
481 free(p);
482 s->cgroup_path = NULL;
20263082
LP
483 return r;
484 }
485
486 s->cgroup_path = p;
487
98a28fef
LP
488 STRV_FOREACH(k, s->controllers) {
489
490 if (strv_contains(s->reset_controllers, *k))
491 continue;
492
493 r = session_create_one_group(s, *k, p);
494 if (r < 0)
495 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
496 }
497
20263082 498 STRV_FOREACH(k, s->manager->controllers) {
20263082 499
98a28fef 500 if (strv_contains(s->reset_controllers, *k) ||
193197e8 501 strv_contains(s->manager->reset_controllers, *k) ||
98a28fef
LP
502 strv_contains(s->controllers, *k))
503 continue;
504
505 r = session_create_one_group(s, *k, p);
20263082 506 if (r < 0)
98a28fef
LP
507 log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
508 }
509
510 if (s->leader > 0) {
511
512 STRV_FOREACH(k, s->reset_controllers) {
513 r = cg_attach(*k, "/", s->leader);
514 if (r < 0)
515 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
516
517 }
193197e8
LP
518
519 STRV_FOREACH(k, s->manager->reset_controllers) {
520
521 if (strv_contains(s->reset_controllers, *k) ||
522 strv_contains(s->controllers, *k))
523 continue;
524
525 r = cg_attach(*k, "/", s->leader);
526 if (r < 0)
527 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
528
529 }
20263082
LP
530 }
531
8c8c4351 532 hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
1713813d 533
20263082
LP
534 return 0;
535}
536
537int session_start(Session *s) {
538 int r;
539
540 assert(s);
541 assert(s->user);
542
9418f147
LP
543 if (s->started)
544 return 0;
545
ed18b08b
LP
546 r = user_start(s->user);
547 if (r < 0)
548 return r;
549
1a4459d6 550 log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
990a1aba 551 "New session %s of user %s.", s->id, s->user->name);
98a28fef 552
20263082
LP
553 /* Create cgroup */
554 r = session_create_cgroup(s);
555 if (r < 0)
556 return r;
557
558 /* Create X11 symlink */
559 session_link_x11_socket(s);
14c3baca 560
14c3baca
LP
561 dual_timestamp_get(&s->timestamp);
562
e9816c48
LP
563 if (s->seat)
564 seat_read_active_vt(s->seat);
565
9418f147
LP
566 s->started = true;
567
e9816c48
LP
568 /* Save session data */
569 session_save(s);
7f7bb946 570 user_save(s->user);
e9816c48 571
da119395
LP
572 session_send_signal(s, true);
573
9418f147 574 if (s->seat) {
7f7bb946
LP
575 seat_save(s->seat);
576
9418f147
LP
577 if (s->seat->active == s)
578 seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
579 else
580 seat_send_changed(s->seat, "Sessions\0");
581 }
582
583 user_send_changed(s->user, "Sessions\0");
584
20263082
LP
585 return 0;
586}
587
588static bool session_shall_kill(Session *s) {
589 assert(s);
590
ed18b08b
LP
591 if (!s->kill_processes)
592 return false;
593
594 if (strv_contains(s->manager->kill_exclude_users, s->user->name))
595 return false;
596
597 if (strv_isempty(s->manager->kill_only_users))
598 return true;
599
600 return strv_contains(s->manager->kill_only_users, s->user->name);
20263082
LP
601}
602
de07ab16 603static int session_terminate_cgroup(Session *s) {
20263082
LP
604 int r;
605 char **k;
606
607 assert(s);
608
609 if (!s->cgroup_path)
610 return 0;
611
612 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
613
614 if (session_shall_kill(s)) {
615
616 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
617 if (r < 0)
618 log_error("Failed to kill session cgroup: %s", strerror(-r));
619
620 } else {
9b221b63
LP
621 if (s->leader > 0) {
622 Session *t;
623
624 /* We still send a HUP to the leader process,
625 * even if we are not supposed to kill the
626 * whole cgroup. But let's first check the
627 * leader still exists and belongs to our
628 * session... */
629
630 r = manager_get_session_by_pid(s->manager, s->leader, &t);
631 if (r > 0 && t == s) {
632 kill(s->leader, SIGTERM); /* for normal processes */
633 kill(s->leader, SIGHUP); /* for shells */
634 kill(s->leader, SIGCONT); /* in case they are stopped */
635 }
636 }
637
20263082
LP
638 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
639 if (r < 0)
640 log_error("Failed to check session cgroup: %s", strerror(-r));
641 else if (r > 0) {
642 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
643 if (r < 0)
644 log_error("Failed to delete session cgroup: %s", strerror(-r));
9b221b63 645 }
20263082
LP
646 }
647
648 STRV_FOREACH(k, s->user->manager->controllers)
649 cg_trim(*k, s->cgroup_path, true);
650
8c8c4351 651 hashmap_remove(s->manager->session_cgroups, s->cgroup_path);
1713813d 652
20263082
LP
653 free(s->cgroup_path);
654 s->cgroup_path = NULL;
655
9b221b63 656 return 0;
20263082
LP
657}
658
659static int session_unlink_x11_socket(Session *s) {
660 char *t;
661 int r;
662
663 assert(s);
664 assert(s->user);
665
666 if (s->user->display != s)
667 return 0;
668
669 s->user->display = NULL;
670
fc3c1c6e 671 t = strappend(s->user->runtime_path, "/X11-display");
20263082 672 if (!t) {
669241a0 673 log_error("Out of memory.");
20263082
LP
674 return -ENOMEM;
675 }
676
677 r = unlink(t);
678 free(t);
679
680 return r < 0 ? -errno : 0;
681}
682
683int session_stop(Session *s) {
684 int r = 0, k;
685
686 assert(s);
687
ed18b08b 688 if (s->started)
1a4459d6 689 log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
990a1aba 690 "Removed session %s.", s->id);
98a28fef 691
20263082 692 /* Kill cgroup */
de07ab16 693 k = session_terminate_cgroup(s);
20263082
LP
694 if (k < 0)
695 r = k;
696
697 /* Remove X11 symlink */
698 session_unlink_x11_socket(s);
699
d2f92cdf
LP
700 unlink(s->state_file);
701 session_add_to_gc_queue(s);
ed18b08b 702 user_add_to_gc_queue(s->user);
14c3baca 703
ed18b08b
LP
704 if (s->started)
705 session_send_signal(s, false);
9418f147
LP
706
707 if (s->seat) {
708 if (s->seat->active == s)
709 seat_set_active(s->seat, NULL);
710
711 seat_send_changed(s->seat, "Sessions\0");
712 }
713
714 user_send_changed(s->user, "Sessions\0");
715
716 s->started = false;
717
20263082
LP
718 return r;
719}
720
721bool session_is_active(Session *s) {
722 assert(s);
723
724 if (!s->seat)
725 return true;
726
727 return s->seat->active == s;
728}
729
a185c5aa
LP
730int session_get_idle_hint(Session *s, dual_timestamp *t) {
731 char *p;
732 struct stat st;
733 usec_t u, n;
734 bool b;
735 int k;
736
737 assert(s);
738
739 if (s->idle_hint) {
740 if (t)
741 *t = s->idle_hint_timestamp;
742
743 return s->idle_hint;
744 }
745
746 if (isempty(s->tty))
747 goto dont_know;
748
749 if (s->tty[0] != '/') {
750 p = strappend("/dev/", s->tty);
751 if (!p)
752 return -ENOMEM;
753 } else
754 p = NULL;
755
756 if (!startswith(p ? p : s->tty, "/dev/")) {
757 free(p);
758 goto dont_know;
759 }
760
761 k = lstat(p ? p : s->tty, &st);
762 free(p);
763
764 if (k < 0)
765 goto dont_know;
766
767 u = timespec_load(&st.st_atim);
768 n = now(CLOCK_REALTIME);
769 b = u + IDLE_THRESHOLD_USEC < n;
770
771 if (t)
17804d7f 772 dual_timestamp_from_realtime(t, u + b*IDLE_THRESHOLD_USEC);
a185c5aa
LP
773
774 return b;
775
776dont_know:
777 if (t)
778 *t = s->idle_hint_timestamp;
779
780 return 0;
781}
782
bef422ae
LP
783void session_set_idle_hint(Session *s, bool b) {
784 assert(s);
785
786 if (s->idle_hint == b)
787 return;
788
789 s->idle_hint = b;
790 dual_timestamp_get(&s->idle_hint_timestamp);
9418f147
LP
791
792 session_send_changed(s,
793 "IdleHint\0"
794 "IdleSinceHint\0"
795 "IdleSinceHintMonotonic\0");
796
797 if (s->seat)
798 seat_send_changed(s->seat,
799 "IdleHint\0"
800 "IdleSinceHint\0"
801 "IdleSinceHintMonotonic\0");
802
803 user_send_changed(s->user,
804 "IdleHint\0"
805 "IdleSinceHint\0"
806 "IdleSinceHintMonotonic\0");
807
808 manager_send_changed(s->manager,
809 "IdleHint\0"
810 "IdleSinceHint\0"
811 "IdleSinceHintMonotonic\0");
bef422ae
LP
812}
813
932e3ee7
LP
814int session_create_fifo(Session *s) {
815 int r;
816
31b79c2b
LP
817 assert(s);
818
b4f78aea 819 /* Create FIFO */
932e3ee7 820 if (!s->fifo_path) {
d2e54fae 821 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
e6061ab2
LP
822 if (r < 0)
823 return r;
824
932e3ee7
LP
825 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
826 return -ENOMEM;
31b79c2b 827
932e3ee7
LP
828 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
829 return -errno;
830 }
31b79c2b 831
932e3ee7 832 /* Open reading side */
b4f78aea
LP
833 if (s->fifo_fd < 0) {
834 struct epoll_event ev;
835
836 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
837 if (s->fifo_fd < 0)
838 return -errno;
839
f8e2fb7b 840 r = hashmap_put(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1), s);
b4f78aea
LP
841 if (r < 0)
842 return r;
843
844 zero(ev);
845 ev.events = 0;
069cfc85 846 ev.data.u32 = FD_OTHER_BASE + s->fifo_fd;
b4f78aea
LP
847
848 if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
849 return -errno;
850 }
932e3ee7
LP
851
852 /* Open writing side */
853 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
854 if (r < 0)
855 return -errno;
31b79c2b 856
932e3ee7
LP
857 return r;
858}
859
860void session_remove_fifo(Session *s) {
861 assert(s);
862
863 if (s->fifo_fd >= 0) {
f8e2fb7b 864 assert_se(hashmap_remove(s->manager->session_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
932e3ee7
LP
865 assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
866 close_nointr_nofail(s->fifo_fd);
867 s->fifo_fd = -1;
868 }
869
870 if (s->fifo_path) {
871 unlink(s->fifo_path);
872 free(s->fifo_path);
873 s->fifo_path = NULL;
874 }
31b79c2b
LP
875}
876
4a4b033f 877int session_check_gc(Session *s, bool drop_not_started) {
20263082
LP
878 int r;
879
880 assert(s);
881
4a4b033f 882 if (drop_not_started && !s->started)
932e3ee7
LP
883 return 0;
884
885 if (s->fifo_fd >= 0) {
20263082 886
932e3ee7 887 r = pipe_eof(s->fifo_fd);
20263082
LP
888 if (r < 0)
889 return r;
890
14c3baca 891 if (r == 0)
20263082
LP
892 return 1;
893 }
894
895 if (s->cgroup_path) {
896
897 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
898 if (r < 0)
899 return r;
900
901 if (r <= 0)
902 return 1;
903 }
904
905 return 0;
906}
907
14c3baca
LP
908void session_add_to_gc_queue(Session *s) {
909 assert(s);
910
911 if (s->in_gc_queue)
912 return;
913
914 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
915 s->in_gc_queue = true;
916}
917
0604381b
LP
918SessionState session_get_state(Session *s) {
919 assert(s);
920
921 if (s->fifo_fd < 0)
922 return SESSION_CLOSING;
923
924 if (session_is_active(s))
925 return SESSION_ACTIVE;
926
927 return SESSION_ONLINE;
928}
929
de07ab16
LP
930int session_kill(Session *s, KillWho who, int signo) {
931 int r = 0;
932 Set *pid_set = NULL;
933
934 assert(s);
935
936 if (!s->cgroup_path)
937 return -ESRCH;
938
939 if (s->leader <= 0 && who == KILL_LEADER)
940 return -ESRCH;
941
942 if (s->leader > 0)
943 if (kill(s->leader, signo) < 0)
944 r = -errno;
945
946 if (who == KILL_ALL) {
947 int q;
948
949 pid_set = set_new(trivial_hash_func, trivial_compare_func);
950 if (!pid_set)
951 return -ENOMEM;
952
953 if (s->leader > 0) {
954 q = set_put(pid_set, LONG_TO_PTR(s->leader));
955 if (q < 0)
956 r = q;
957 }
958
959 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
960 if (q < 0)
961 if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
962 r = q;
963 }
964
de07ab16
LP
965 if (pid_set)
966 set_free(pid_set);
967
968 return r;
969}
970
0604381b
LP
971static const char* const session_state_table[_SESSION_TYPE_MAX] = {
972 [SESSION_ONLINE] = "online",
973 [SESSION_ACTIVE] = "active",
974 [SESSION_CLOSING] = "closing"
975};
976
977DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
978
20263082 979static const char* const session_type_table[_SESSION_TYPE_MAX] = {
3f49d45a 980 [SESSION_TTY] = "tty",
98a28fef 981 [SESSION_X11] = "x11",
a91e4e53 982 [SESSION_UNSPECIFIED] = "unspecified"
20263082
LP
983};
984
985DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
de07ab16 986
55efac6c
LP
987static const char* const session_class_table[_SESSION_CLASS_MAX] = {
988 [SESSION_USER] = "user",
989 [SESSION_GREETER] = "greeter",
990 [SESSION_LOCK_SCREEN] = "lock-screen"
991};
992
993DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
994
de07ab16
LP
995static const char* const kill_who_table[_KILL_WHO_MAX] = {
996 [KILL_LEADER] = "leader",
997 [KILL_ALL] = "all"
998};
999
1000DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);