]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/logind-session.c
dbus: add dbus introspection extraction
[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>
25
90821c93 26#include "logind-session.h"
20263082
LP
27#include "strv.h"
28#include "util.h"
29#include "cgroup-util.h"
30
31Session* session_new(Manager *m, User *u, const char *id) {
32 Session *s;
33
34 assert(m);
35 assert(id);
36
14c3baca 37 s = new0(Session, 1);
20263082
LP
38 if (!s)
39 return NULL;
40
41 s->state_file = strappend("/run/systemd/session/", id);
42 if (!s->state_file) {
43 free(s);
44 return NULL;
45 }
46
47 s->id = file_name_from_path(s->state_file);
48
49 if (hashmap_put(m->sessions, s->id, s) < 0) {
50 free(s->id);
51 free(s);
52 return NULL;
53 }
54
55 s->manager = m;
56 s->pipe_fd = -1;
57 s->user = u;
58
14c3baca 59 LIST_PREPEND(Session, sessions_by_user, u->sessions, s);
20263082
LP
60
61 return s;
62}
63
64void session_free(Session *s) {
65 assert(s);
66
14c3baca
LP
67 if (s->in_gc_queue)
68 LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s);
69
20263082
LP
70 if (s->user) {
71 LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s);
72
73 if (s->user->display == s)
74 s->user->display = NULL;
75 }
76
77 if (s->seat)
78 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
79
80 free(s->cgroup_path);
81 strv_free(s->controllers);
82
83 free(s->tty);
84 free(s->display);
85 free(s->remote_host);
3f49d45a 86 free(s->remote_user);
20263082
LP
87
88 hashmap_remove(s->manager->sessions, s->id);
89
d2f92cdf 90 free(s->state_file);
20263082
LP
91 free(s);
92}
93
94int session_save(Session *s) {
95 FILE *f;
96 int r = 0;
14c3baca 97 char *temp_path;
20263082
LP
98
99 assert(s);
100
101 r = safe_mkdir("/run/systemd/session", 0755, 0, 0);
102 if (r < 0)
14c3baca 103 goto finish;
20263082 104
14c3baca
LP
105 r = fopen_temporary(s->state_file, &f, &temp_path);
106 if (r < 0)
107 goto finish;
20263082
LP
108
109 assert(s->user);
110
14c3baca
LP
111 fchmod(fileno(f), 0644);
112
20263082
LP
113 fprintf(f,
114 "# This is private data. Do not parse.\n"
115 "UID=%lu\n"
116 "USER=%s\n"
117 "ACTIVE=%i\n"
118 "REMOTE=%i\n"
119 "KILL_PROCESSES=%i\n",
120 (unsigned long) s->user->uid,
121 s->user->name,
122 session_is_active(s),
123 s->remote,
124 s->kill_processes);
125
126 if (s->cgroup_path)
127 fprintf(f,
128 "CGROUP=%s\n",
129 s->cgroup_path);
130
131 if (s->seat)
132 fprintf(f,
133 "SEAT=%s\n",
134 s->seat->id);
135
136 if (s->tty)
137 fprintf(f,
138 "TTY=%s\n",
139 s->tty);
140
141 if (s->display)
142 fprintf(f,
143 "DISPLAY=%s\n",
144 s->display);
145
146 if (s->remote_host)
147 fprintf(f,
148 "REMOTE_HOST=%s\n",
149 s->remote_host);
150
3f49d45a
LP
151 if (s->remote_user)
152 fprintf(f,
153 "REMOTE_USER=%s\n",
154 s->remote_user);
155
20263082
LP
156 if (s->seat && s->seat->manager->vtconsole == s->seat)
157 fprintf(f,
158 "VTNR=%i\n",
159 s->vtnr);
160
161 if (s->leader > 0)
162 fprintf(f,
163 "LEADER=%lu\n",
164 (unsigned long) s->leader);
165
166 if (s->audit_id > 0)
167 fprintf(f,
168 "AUDIT=%llu\n",
169 (unsigned long long) s->audit_id);
170
171 fflush(f);
14c3baca
LP
172
173 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
20263082
LP
174 r = -errno;
175 unlink(s->state_file);
14c3baca 176 unlink(temp_path);
20263082
LP
177 }
178
179 fclose(f);
14c3baca
LP
180 free(temp_path);
181
182finish:
183 if (r < 0)
184 log_error("Failed to save session data for %s: %s", s->id, strerror(-r));
185
20263082
LP
186 return r;
187}
188
189int session_load(Session *s) {
190 assert(s);
191
192 return 0;
193}
194
195int session_activate(Session *s) {
196 int r;
5eda94dd 197 Session *old_active;
20263082
LP
198
199 assert(s);
200
201 if (s->vtnr < 0)
202 return -ENOTSUP;
203
204 if (!s->seat)
205 return -ENOTSUP;
206
207 if (s->seat->active == s)
208 return 0;
209
210 assert(s->manager->vtconsole == s->seat);
211
212 r = chvt(s->vtnr);
213 if (r < 0)
214 return r;
215
5eda94dd 216 old_active = s->seat->active;
20263082
LP
217 s->seat->active = s;
218
14c3baca 219 return seat_apply_acls(s->seat, old_active);
20263082
LP
220}
221
222bool x11_display_is_local(const char *display) {
223 assert(display);
224
225 return
226 display[0] == ':' &&
227 display[1] >= '0' &&
228 display[1] <= '9';
229}
230
231static int session_link_x11_socket(Session *s) {
232 char *t, *f, *c;
233 size_t k;
234
235 assert(s);
236 assert(s->user);
237 assert(s->user->runtime_path);
238
239 if (s->user->display)
240 return 0;
241
242 if (!s->display || !x11_display_is_local(s->display))
243 return 0;
244
245 k = strspn(s->display+1, "0123456789");
246 f = new(char, sizeof("/tmp/.X11-unix/X") + k);
247 if (!f) {
248 log_error("Out of memory");
249 return -ENOMEM;
250 }
251
252 c = stpcpy(f, "/tmp/.X11-unix/X");
253 memcpy(c, s->display+1, k);
254 c[k] = 0;
255
256 if (access(f, F_OK) < 0) {
257 log_warning("Session %s has display %s with nonexisting socket %s.", s->id, s->display, f);
258 free(f);
259 return -ENOENT;
260 }
261
262 t = strappend(s->user->runtime_path, "/display");
263 if (!t) {
264 log_error("Out of memory");
265 free(f);
266 return -ENOMEM;
267 }
268
269 if (link(f, t) < 0) {
270 if (errno == EEXIST) {
271 unlink(t);
272
273 if (link(f, t) >= 0)
274 goto done;
275 }
276
277 if (symlink(f, t) < 0) {
278
279 if (errno == EEXIST) {
280 unlink(t);
281
282 if (symlink(f, t) >= 0)
283 goto done;
284 }
285
286 log_error("Failed to link %s to %s: %m", f, t);
287 free(f);
288 free(t);
289 return -errno;
290 }
291 }
292
293done:
294 log_info("Linked %s to %s.", f, t);
295 free(f);
296 free(t);
297
298 s->user->display = s;
299
300 return 0;
301}
302
303static int session_create_cgroup(Session *s) {
304 char **k;
305 char *p;
306 int r;
307
308 assert(s);
309 assert(s->user);
310 assert(s->user->cgroup_path);
311
312 if (!s->cgroup_path) {
313 if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0) {
314 log_error("Out of memory");
315 return -ENOMEM;
316 }
317 } else
318 p = s->cgroup_path;
319
320 if (s->leader > 0)
321 r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, p, s->leader);
322 else
323 r = cg_create(SYSTEMD_CGROUP_CONTROLLER, p);
324
325 if (r < 0) {
326 free(p);
327 s->cgroup_path = NULL;
328 log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r));
329 return r;
330 }
331
332 s->cgroup_path = p;
333
334 STRV_FOREACH(k, s->manager->controllers) {
335 if (s->leader > 0)
336 r = cg_create_and_attach(*k, p, s->leader);
337 else
338 r = cg_create(*k, p);
339
340 if (r < 0)
341 log_warning("Failed to create cgroup %s:%s: %s", *k, p, strerror(-r));
342 }
343
344 return 0;
345}
346
347int session_start(Session *s) {
348 int r;
349
350 assert(s);
351 assert(s->user);
352
20263082
LP
353 /* Create cgroup */
354 r = session_create_cgroup(s);
355 if (r < 0)
356 return r;
357
358 /* Create X11 symlink */
359 session_link_x11_socket(s);
14c3baca
LP
360
361 /* Save session data */
362 session_save(s);
363
364 dual_timestamp_get(&s->timestamp);
365
20263082
LP
366 return 0;
367}
368
369static bool session_shall_kill(Session *s) {
370 assert(s);
371
372 return s->kill_processes;
373}
374
375static int session_kill_cgroup(Session *s) {
376 int r;
377 char **k;
378
379 assert(s);
380
381 if (!s->cgroup_path)
382 return 0;
383
384 cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
385
386 if (session_shall_kill(s)) {
387
388 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
389 if (r < 0)
390 log_error("Failed to kill session cgroup: %s", strerror(-r));
391
392 } else {
393 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true);
394 if (r < 0)
395 log_error("Failed to check session cgroup: %s", strerror(-r));
396 else if (r > 0) {
397 r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path);
398 if (r < 0)
399 log_error("Failed to delete session cgroup: %s", strerror(-r));
400 } else
401 r = -EBUSY;
402 }
403
404 STRV_FOREACH(k, s->user->manager->controllers)
405 cg_trim(*k, s->cgroup_path, true);
406
407 free(s->cgroup_path);
408 s->cgroup_path = NULL;
409
410 return r;
411}
412
413static int session_unlink_x11_socket(Session *s) {
414 char *t;
415 int r;
416
417 assert(s);
418 assert(s->user);
419
420 if (s->user->display != s)
421 return 0;
422
423 s->user->display = NULL;
424
425 t = strappend(s->user->runtime_path, "/display");
426 if (!t) {
427 log_error("Out of memory");
428 return -ENOMEM;
429 }
430
431 r = unlink(t);
432 free(t);
433
434 return r < 0 ? -errno : 0;
435}
436
437int session_stop(Session *s) {
438 int r = 0, k;
439
440 assert(s);
441
442 /* Kill cgroup */
443 k = session_kill_cgroup(s);
444 if (k < 0)
445 r = k;
446
447 /* Remove X11 symlink */
448 session_unlink_x11_socket(s);
449
d2f92cdf
LP
450 unlink(s->state_file);
451 session_add_to_gc_queue(s);
14c3baca 452
20263082
LP
453 return r;
454}
455
456bool session_is_active(Session *s) {
457 assert(s);
458
459 if (!s->seat)
460 return true;
461
462 return s->seat->active == s;
463}
464
465int session_check_gc(Session *s) {
466 int r;
467
468 assert(s);
469
470 if (s->pipe_fd >= 0) {
471
472 r = pipe_eof(s->pipe_fd);
473 if (r < 0)
474 return r;
475
14c3baca 476 if (r == 0)
20263082
LP
477 return 1;
478 }
479
480 if (s->cgroup_path) {
481
482 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false);
483 if (r < 0)
484 return r;
485
486 if (r <= 0)
487 return 1;
488 }
489
490 return 0;
491}
492
14c3baca
LP
493void session_add_to_gc_queue(Session *s) {
494 assert(s);
495
496 if (s->in_gc_queue)
497 return;
498
499 LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s);
500 s->in_gc_queue = true;
501}
502
20263082 503static const char* const session_type_table[_SESSION_TYPE_MAX] = {
3f49d45a 504 [SESSION_TTY] = "tty",
20263082
LP
505 [SESSION_X11] = "x11"
506};
507
508DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);