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/>.
26 #include "logind-session.h"
29 #include "cgroup-util.h"
31 Session
* session_new(Manager
*m
, User
*u
, const char *id
) {
41 s
->state_file
= strappend("/run/systemd/session/", id
);
47 s
->id
= file_name_from_path(s
->state_file
);
49 if (hashmap_put(m
->sessions
, s
->id
, s
) < 0) {
59 LIST_PREPEND(Session
, sessions_by_user
, u
->sessions
, s
);
64 void session_free(Session
*s
) {
68 LIST_REMOVE(Session
, gc_queue
, s
->manager
->session_gc_queue
, s
);
71 LIST_REMOVE(Session
, sessions_by_user
, s
->user
->sessions
, s
);
73 if (s
->user
->display
== s
)
74 s
->user
->display
= NULL
;
78 LIST_REMOVE(Session
, sessions_by_seat
, s
->seat
->sessions
, s
);
81 strv_free(s
->controllers
);
87 hashmap_remove(s
->manager
->sessions
, s
->id
);
93 int session_save(Session
*s
) {
100 r
= safe_mkdir("/run/systemd/session", 0755, 0, 0);
104 r
= fopen_temporary(s
->state_file
, &f
, &temp_path
);
110 fchmod(fileno(f
), 0644);
113 "# This is private data. Do not parse.\n"
118 "KILL_PROCESSES=%i\n",
119 (unsigned long) s
->user
->uid
,
121 session_is_active(s
),
150 if (s
->seat
&& s
->seat
->manager
->vtconsole
== s
->seat
)
158 (unsigned long) s
->leader
);
163 (unsigned long long) s
->audit_id
);
167 if (ferror(f
) || rename(temp_path
, s
->state_file
) < 0) {
169 unlink(s
->state_file
);
178 log_error("Failed to save session data for %s: %s", s
->id
, strerror(-r
));
183 int session_load(Session
*s
) {
189 int session_activate(Session
*s
) {
201 if (s
->seat
->active
== s
)
204 assert(s
->manager
->vtconsole
== s
->seat
);
210 old_active
= s
->seat
->active
;
213 return seat_apply_acls(s
->seat
, old_active
);
216 bool x11_display_is_local(const char *display
) {
225 static int session_link_x11_socket(Session
*s
) {
231 assert(s
->user
->runtime_path
);
233 if (s
->user
->display
)
236 if (!s
->display
|| !x11_display_is_local(s
->display
))
239 k
= strspn(s
->display
+1, "0123456789");
240 f
= new(char, sizeof("/tmp/.X11-unix/X") + k
);
242 log_error("Out of memory");
246 c
= stpcpy(f
, "/tmp/.X11-unix/X");
247 memcpy(c
, s
->display
+1, k
);
250 if (access(f
, F_OK
) < 0) {
251 log_warning("Session %s has display %s with nonexisting socket %s.", s
->id
, s
->display
, f
);
256 t
= strappend(s
->user
->runtime_path
, "/display");
258 log_error("Out of memory");
263 if (link(f
, t
) < 0) {
264 if (errno
== EEXIST
) {
271 if (symlink(f
, t
) < 0) {
273 if (errno
== EEXIST
) {
276 if (symlink(f
, t
) >= 0)
280 log_error("Failed to link %s to %s: %m", f
, t
);
288 log_info("Linked %s to %s.", f
, t
);
292 s
->user
->display
= s
;
297 static int session_create_cgroup(Session
*s
) {
304 assert(s
->user
->cgroup_path
);
306 if (!s
->cgroup_path
) {
307 if (asprintf(&p
, "%s/%s", s
->user
->cgroup_path
, s
->id
) < 0) {
308 log_error("Out of memory");
315 r
= cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER
, p
, s
->leader
);
317 r
= cg_create(SYSTEMD_CGROUP_CONTROLLER
, p
);
321 s
->cgroup_path
= NULL
;
322 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER
":%s: %s", p
, strerror(-r
));
328 STRV_FOREACH(k
, s
->manager
->controllers
) {
330 r
= cg_create_and_attach(*k
, p
, s
->leader
);
332 r
= cg_create(*k
, p
);
335 log_warning("Failed to create cgroup %s:%s: %s", *k
, p
, strerror(-r
));
341 int session_start(Session
*s
) {
348 r
= session_create_cgroup(s
);
352 /* Create X11 symlink */
353 session_link_x11_socket(s
);
355 /* Save session data */
358 dual_timestamp_get(&s
->timestamp
);
363 static bool session_shall_kill(Session
*s
) {
366 return s
->kill_processes
;
369 static int session_kill_cgroup(Session
*s
) {
378 cg_trim(SYSTEMD_CGROUP_CONTROLLER
, s
->cgroup_path
, false);
380 if (session_shall_kill(s
)) {
382 r
= cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER
, s
->cgroup_path
, true);
384 log_error("Failed to kill session cgroup: %s", strerror(-r
));
387 r
= cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER
, s
->cgroup_path
, true);
389 log_error("Failed to check session cgroup: %s", strerror(-r
));
391 r
= cg_delete(SYSTEMD_CGROUP_CONTROLLER
, s
->cgroup_path
);
393 log_error("Failed to delete session cgroup: %s", strerror(-r
));
398 STRV_FOREACH(k
, s
->user
->manager
->controllers
)
399 cg_trim(*k
, s
->cgroup_path
, true);
401 free(s
->cgroup_path
);
402 s
->cgroup_path
= NULL
;
407 static int session_unlink_x11_socket(Session
*s
) {
414 if (s
->user
->display
!= s
)
417 s
->user
->display
= NULL
;
419 t
= strappend(s
->user
->runtime_path
, "/display");
421 log_error("Out of memory");
428 return r
< 0 ? -errno
: 0;
431 int session_stop(Session
*s
) {
437 k
= session_kill_cgroup(s
);
441 /* Remove X11 symlink */
442 session_unlink_x11_socket(s
);
444 unlink(s
->state_file
);
445 session_add_to_gc_queue(s
);
450 bool session_is_active(Session
*s
) {
456 return s
->seat
->active
== s
;
459 int session_check_gc(Session
*s
) {
464 if (s
->pipe_fd
>= 0) {
466 r
= pipe_eof(s
->pipe_fd
);
474 if (s
->cgroup_path
) {
476 r
= cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER
, s
->cgroup_path
, false);
487 void session_add_to_gc_queue(Session
*s
) {
493 LIST_PREPEND(Session
, gc_queue
, s
->manager
->session_gc_queue
, s
);
494 s
->in_gc_queue
= true;
497 static const char* const session_type_table
[_SESSION_TYPE_MAX
] = {
498 [SESSION_TERMINAL
] = "terminal",
499 [SESSION_X11
] = "x11"
502 DEFINE_STRING_TABLE_LOOKUP(session_type
, SessionType
);