1
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4
This file is part of systemd.
6
Copyright 2011 Lennart Poettering
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.
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.
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/>.
25
#include <sys/epoll.h>
28
#include "logind-session.h"
31
#include "cgroup-util.h"
33
#define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE)
35
Session* session_new(Manager *m, User *u, const char *id) {
45
s->state_file = strappend("/run/systemd/sessions/", id);
51
s->id = file_name_from_path(s->state_file);
53
if (hashmap_put(m->sessions, s->id, s) < 0) {
63
LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
68
void session_free(Session *s) {
72
LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
75
LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
77
if (s->user->display == s)
78
s->user->display = NULL;
82
if (s->seat->active == s)
83
s->seat->active = NULL;
85
LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
89
hashmap_remove(s->manager->cgroups, s->cgroup_path);
92
strv_free(s->controllers);
100
hashmap_remove(s->manager->sessions, s->id);
102
session_remove_fifo(s);
108
int session_save(Session *s) {
118
r = safe_mkdir("/run/systemd/sessions", 0755, 0, 0);
122
r = fopen_temporary(s->state_file, &f, &temp_path);
128
fchmod(fileno(f), 0644);
131
"# This is private data. Do not parse.\n"
136
"KILL_PROCESSES=%i\n",
137
(unsigned long) s->user->uid,
139
session_is_active(s),
146
session_type_to_string(s->type));
151
session_class_to_string(s->class));
193
if (s->seat && seat_can_multi_session(s->seat))
201
(unsigned long) s->leader);
206
(unsigned long long) s->audit_id);
210
if (ferror(f) || rename(temp_path, s->state_file) < 0) {
212
unlink(s->state_file);
221
log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
226
int session_load(Session *s) {
228
*kill_processes = NULL,
240
r = parse_env_file(s->state_file, NEWLINE,
242
"KILL_PROCESSES", &kill_processes,
243
"CGROUP", &s->cgroup_path,
244
"FIFO", &s->fifo_path,
247
"DISPLAY", &s->display,
248
"REMOTE_HOST", &s->remote_host,
249
"REMOTE_USER", &s->remote_user,
250
"SERVICE", &s->service,
261
k = parse_boolean(remote);
266
if (kill_processes) {
267
k = parse_boolean(kill_processes);
269
s->kill_processes = k;
272
if (seat && !s->seat) {
275
o = hashmap_get(s->manager->seats, seat);
277
seat_attach_session(o, s);
280
if (vtnr && s->seat && seat_can_multi_session(s->seat)) {
283
k = safe_atoi(vtnr, &v);
284
if (k >= 0 && v >= 1)
291
k = parse_pid(leader, &pid);
292
if (k >= 0 && pid >= 1) {
295
audit_session_from_pid(pid, &s->audit_id);
302
t = session_type_from_string(type);
310
c = session_class_from_string(class);
318
/* If we open an unopened pipe for reading we will not
319
get an EOF. to trigger an EOF we hence open it for
320
reading, but close it right-away which then will
323
fd = session_create_fifo(s);
325
close_nointr_nofail(fd);
331
free(kill_processes);
340
int session_activate(Session *s) {
351
if (s->seat->active == s)
354
assert(seat_is_vtconsole(s->seat));
360
return seat_set_active(s->seat, s);
363
static int session_link_x11_socket(Session *s) {
369
assert(s->user->runtime_path);
371
if (s->user->display)
374
if (!s->display || !display_is_local(s->display))
377
k = strspn(s->display+1, "0123456789");
378
f = new(char, sizeof("/tmp/.X11-unix/X") + k);
380
log_error("Out of memory");
384
c = stpcpy(f, "/tmp/.X11-unix/X");
385
memcpy(c, s->display+1, k);
388
if (access(f, F_OK) < 0) {
389
log_warning("Session %s has display %s with nonexisting socket %s.", s->id, s->display, f);
394
t = strappend(s->user->runtime_path, "/X11-display");
396
log_error("Out of memory");
401
if (link(f, t) < 0) {
402
if (errno == EEXIST) {
409
if (symlink(f, t) < 0) {
411
if (errno == EEXIST) {
414
if (symlink(f, t) >= 0)
418
log_error("Failed to link %s to %s: %m", f, t);
426
log_info("Linked %s to %s.", f, t);
430
s->user->display = s;
435
static int session_create_one_group(Session *s, const char *controller, const char *path) {
443
r = cg_create_and_attach(controller, path, s->leader);
445
r = cg_create(controller, path);
447
r = cg_create(controller, path);
452
r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid, -1);
454
r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid);
459
static int session_create_cgroup(Session *s) {
466
assert(s->user->cgroup_path);
468
if (!s->cgroup_path) {
469
if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0) {
470
log_error("Out of memory");
476
r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p);
478
log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
480
s->cgroup_path = NULL;
486
STRV_FOREACH(k, s->controllers) {
488
if (strv_contains(s->reset_controllers, *k))
491
r = session_create_one_group(s, *k, p);
493
log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
496
STRV_FOREACH(k, s->manager->controllers) {
498
if (strv_contains(s->reset_controllers, *k) ||
499
strv_contains(s->manager->reset_controllers, *k) ||
500
strv_contains(s->controllers, *k))
503
r = session_create_one_group(s, *k, p);
505
log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r));
510
STRV_FOREACH(k, s->reset_controllers) {
511
r = cg_attach(*k, "/", s->leader);
513
log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
517
STRV_FOREACH(k, s->manager->reset_controllers) {
519
if (strv_contains(s->reset_controllers, *k) ||
520
strv_contains(s->controllers, *k))
523
r = cg_attach(*k, "/", s->leader);
525
log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
530
hashmap_put(s->manager->cgroups, s->cgroup_path, s);
535
int session_start(Session *s) {
544
r = user_start(s->user);
548
log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
549
"New session %s of user %s.", s->id, s->user->name);
552
r = session_create_cgroup(s);
556
/* Create X11 symlink */
557
session_link_x11_socket(s);
559
dual_timestamp_get(&s->timestamp);
562
seat_read_active_vt(s->seat);
566
/* Save session data */
570
session_send_signal(s, true);
575
if (s->seat->active == s)
576
seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
578
seat_send_changed(s->seat, "Sessions\0");
581
user_send_changed(s->user, "Sessions\0");
586
static bool session_shall_kill(Session *s) {
589
if (!s->kill_processes)
592
if (strv_contains(s->manager->kill_exclude_users, s->user->name))
595
if (strv_isempty(s->manager->kill_only_users))
598
return strv_contains(s->manager->kill_only_users, s->user->name);
601
static int session_terminate_cgroup(Session *s) {
610
cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
612
if (session_shall_kill(s)) {
614
r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
616
log_error("Failed to kill session cgroup: %s", strerror(-r));
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
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 */
636
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
638
log_error("Failed to check session cgroup: %s", strerror(-r));
640
r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
642
log_error("Failed to delete session cgroup: %s", strerror(-r));
646
STRV_FOREACH(k, s->user->manager->controllers)
647
cg_trim(*k, s->cgroup_path, true);
649
hashmap_remove(s->manager->cgroups, s->cgroup_path);
651
free(s->cgroup_path);
652
s->cgroup_path = NULL;
657
static int session_unlink_x11_socket(Session *s) {
664
if (s->user->display != s)
667
s->user->display = NULL;
669
t = strappend(s->user->runtime_path, "/X11-display");
671
log_error("Out of memory");
678
return r < 0 ? -errno : 0;
681
int session_stop(Session *s) {
687
log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
688
"Removed session %s.", s->id);
691
k = session_terminate_cgroup(s);
695
/* Remove X11 symlink */
696
session_unlink_x11_socket(s);
698
unlink(s->state_file);
699
session_add_to_gc_queue(s);
700
user_add_to_gc_queue(s->user);
703
session_send_signal(s, false);
706
if (s->seat->active == s)
707
seat_set_active(s->seat, NULL);
709
seat_send_changed(s->seat, "Sessions\0");
712
user_send_changed(s->user, "Sessions\0");
719
bool session_is_active(Session *s) {
725
return s->seat->active == s;
728
int session_get_idle_hint(Session *s, dual_timestamp *t) {
739
*t = s->idle_hint_timestamp;
747
if (s->tty[0] != '/') {
748
p = strappend("/dev/", s->tty);
754
if (!startswith(p ? p : s->tty, "/dev/")) {
759
k = lstat(p ? p : s->tty, &st);
765
u = timespec_load(&st.st_atim);
766
n = now(CLOCK_REALTIME);
767
b = u + IDLE_THRESHOLD_USEC < n;
770
dual_timestamp_from_realtime(t, u + b ? IDLE_THRESHOLD_USEC : 0);
776
*t = s->idle_hint_timestamp;
781
void session_set_idle_hint(Session *s, bool b) {
784
if (s->idle_hint == b)
788
dual_timestamp_get(&s->idle_hint_timestamp);
790
session_send_changed(s,
793
"IdleSinceHintMonotonic\0");
796
seat_send_changed(s->seat,
799
"IdleSinceHintMonotonic\0");
801
user_send_changed(s->user,
804
"IdleSinceHintMonotonic\0");
806
manager_send_changed(s->manager,
809
"IdleSinceHintMonotonic\0");
812
int session_create_fifo(Session *s) {
819
r = safe_mkdir("/run/systemd/sessions", 0755, 0, 0);
823
if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
826
if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
830
/* Open reading side */
831
if (s->fifo_fd < 0) {
832
struct epoll_event ev;
834
s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
838
r = hashmap_put(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1), s);
844
ev.data.u32 = FD_FIFO_BASE + s->fifo_fd;
846
if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0)
850
/* Open writing side */
851
r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
858
void session_remove_fifo(Session *s) {
861
if (s->fifo_fd >= 0) {
862
assert_se(hashmap_remove(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1)) == s);
863
assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
864
close_nointr_nofail(s->fifo_fd);
869
unlink(s->fifo_path);
875
int session_check_gc(Session *s, bool drop_not_started) {
880
if (drop_not_started && !s->started)
883
if (s->fifo_fd >= 0) {
885
r = pipe_eof(s->fifo_fd);
893
if (s->cgroup_path) {
895
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
906
void session_add_to_gc_queue(Session *s) {
912
LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
913
s->in_gc_queue = true;
916
int session_kill(Session *s, KillWho who, int signo) {
925
if (s->leader <= 0 && who == KILL_LEADER)
929
if (kill(s->leader, signo) < 0)
932
if (who == KILL_ALL) {
935
pid_set = set_new(trivial_hash_func, trivial_compare_func);
940
q = set_put(pid_set, LONG_TO_PTR(s->leader));
945
q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
947
if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
957
static const char* const session_type_table[_SESSION_TYPE_MAX] = {
958
[SESSION_TTY] = "tty",
959
[SESSION_X11] = "x11",
960
[SESSION_UNSPECIFIED] = "unspecified"
963
DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
965
static const char* const session_class_table[_SESSION_CLASS_MAX] = {
966
[SESSION_USER] = "user",
967
[SESSION_GREETER] = "greeter",
968
[SESSION_LOCK_SCREEN] = "lock-screen"
971
DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
973
static const char* const kill_who_table[_KILL_WHO_MAX] = {
974
[KILL_LEADER] = "leader",
978
DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);