]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-session.c
treewide: use log_*_errno whenever %m is in the format string
[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>
90a18413
DH
23#include <fcntl.h>
24#include <linux/vt.h>
25#include <linux/kd.h>
26#include <signal.h>
20263082 27#include <string.h>
90a18413 28#include <sys/ioctl.h>
20263082
LP
29#include <unistd.h>
30
cc377381
LP
31#include "sd-id128.h"
32#include "sd-messages.h"
20263082
LP
33#include "strv.h"
34#include "util.h"
49e942b2 35#include "mkdir.h"
9eb977db 36#include "path-util.h"
a5c32cff 37#include "fileio.h"
cc377381
LP
38#include "audit.h"
39#include "bus-util.h"
40#include "bus-error.h"
fb6becb4 41#include "logind-session.h"
20263082 42
5f41d1f1
LP
43#define RELEASE_USEC (20*USEC_PER_SEC)
44
45static void session_remove_fifo(Session *s);
46
9444b1f2 47Session* session_new(Manager *m, const char *id) {
20263082
LP
48 Session *s;
49
50 assert(m);
51 assert(id);
4b549144 52 assert(session_id_valid(id));
20263082 53
14c3baca 54 s = new0(Session, 1);
20263082
LP
55 if (!s)
56 return NULL;
57
98a28fef 58 s->state_file = strappend("/run/systemd/sessions/", id);
20263082
LP
59 if (!s->state_file) {
60 free(s);
61 return NULL;
62 }
63
d5099efc 64 s->devices = hashmap_new(&devt_hash_ops);
118ecf32
DH
65 if (!s->devices) {
66 free(s->state_file);
67 free(s);
68 return NULL;
69 }
70
2b6bf07d 71 s->id = basename(s->state_file);
20263082
LP
72
73 if (hashmap_put(m->sessions, s->id, s) < 0) {
118ecf32 74 hashmap_free(s->devices);
f8e2fb7b 75 free(s->state_file);
20263082
LP
76 free(s);
77 return NULL;
78 }
79
80 s->manager = m;
932e3ee7 81 s->fifo_fd = -1;
90a18413 82 s->vtfd = -1;
20263082
LP
83
84 return s;
85}
86
87void session_free(Session *s) {
118ecf32
DH
88 SessionDevice *sd;
89
20263082
LP
90 assert(s);
91
14c3baca 92 if (s->in_gc_queue)
71fda00f 93 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
14c3baca 94
5f41d1f1
LP
95 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
96
cc377381
LP
97 session_remove_fifo(s);
98
ae5e06bd
DH
99 session_drop_controller(s);
100
118ecf32
DH
101 while ((sd = hashmap_first(s->devices)))
102 session_device_free(sd);
103
104 hashmap_free(s->devices);
105
20263082 106 if (s->user) {
71fda00f 107 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
20263082
LP
108
109 if (s->user->display == s)
110 s->user->display = NULL;
111 }
112
9418f147
LP
113 if (s->seat) {
114 if (s->seat->active == s)
115 s->seat->active = NULL;
d7bd01b5
DH
116 if (s->seat->pending_switch == s)
117 s->seat->pending_switch = NULL;
9418f147 118
49e6fdbf 119 seat_evict_position(s->seat, s);
71fda00f 120 LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
9418f147 121 }
20263082 122
fb6becb4
LP
123 if (s->scope) {
124 hashmap_remove(s->manager->session_units, s->scope);
125 free(s->scope);
126 }
127
128 free(s->scope_job);
1713813d 129
cc377381 130 sd_bus_message_unref(s->create_message);
20263082
LP
131
132 free(s->tty);
133 free(s->display);
134 free(s->remote_host);
3f49d45a 135 free(s->remote_user);
98a28fef 136 free(s->service);
a4cd87e9 137 free(s->desktop);
20263082
LP
138
139 hashmap_remove(s->manager->sessions, s->id);
98a28fef 140
d2f92cdf 141 free(s->state_file);
20263082
LP
142 free(s);
143}
144
9444b1f2
LP
145void session_set_user(Session *s, User *u) {
146 assert(s);
147 assert(!s->user);
148
149 s->user = u;
71fda00f 150 LIST_PREPEND(sessions_by_user, u->sessions, s);
9444b1f2
LP
151}
152
20263082 153int session_save(Session *s) {
507f22bd 154 _cleanup_free_ char *temp_path = NULL;
cc377381 155 _cleanup_fclose_ FILE *f = NULL;
20263082
LP
156 int r = 0;
157
158 assert(s);
159
9444b1f2
LP
160 if (!s->user)
161 return -ESTALE;
162
accaeded
LP
163 if (!s->started)
164 return 0;
165
d2e54fae 166 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
20263082 167 if (r < 0)
14c3baca 168 goto finish;
20263082 169
14c3baca
LP
170 r = fopen_temporary(s->state_file, &f, &temp_path);
171 if (r < 0)
172 goto finish;
20263082
LP
173
174 assert(s->user);
175
14c3baca
LP
176 fchmod(fileno(f), 0644);
177
20263082
LP
178 fprintf(f,
179 "# This is private data. Do not parse.\n"
90b2de37 180 "UID="UID_FMT"\n"
20263082
LP
181 "USER=%s\n"
182 "ACTIVE=%i\n"
0604381b 183 "STATE=%s\n"
fb6becb4 184 "REMOTE=%i\n",
90b2de37 185 s->user->uid,
20263082
LP
186 s->user->name,
187 session_is_active(s),
0604381b 188 session_state_to_string(session_get_state(s)),
fb6becb4 189 s->remote);
20263082 190
a91e4e53 191 if (s->type >= 0)
507f22bd 192 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
a91e4e53 193
55efac6c 194 if (s->class >= 0)
507f22bd 195 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
55efac6c 196
fb6becb4
LP
197 if (s->scope)
198 fprintf(f, "SCOPE=%s\n", s->scope);
fb6becb4
LP
199 if (s->scope_job)
200 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
20263082 201
932e3ee7 202 if (s->fifo_path)
507f22bd 203 fprintf(f, "FIFO=%s\n", s->fifo_path);
932e3ee7 204
20263082 205 if (s->seat)
507f22bd 206 fprintf(f, "SEAT=%s\n", s->seat->id);
20263082
LP
207
208 if (s->tty)
507f22bd 209 fprintf(f, "TTY=%s\n", s->tty);
20263082
LP
210
211 if (s->display)
507f22bd 212 fprintf(f, "DISPLAY=%s\n", s->display);
20263082 213
558c6490
LP
214 if (s->remote_host) {
215 _cleanup_free_ char *escaped;
216
217 escaped = cescape(s->remote_host);
218 if (!escaped) {
219 r = -ENOMEM;
220 goto finish;
221 }
222
223 fprintf(f, "REMOTE_HOST=%s\n", escaped);
224 }
225
226 if (s->remote_user) {
227 _cleanup_free_ char *escaped;
228
229 escaped = cescape(s->remote_user);
230 if (!escaped) {
231 r = -ENOMEM;
232 goto finish;
233 }
234
235 fprintf(f, "REMOTE_USER=%s\n", escaped);
236 }
237
238 if (s->service) {
239 _cleanup_free_ char *escaped;
20263082 240
558c6490
LP
241 escaped = cescape(s->service);
242 if (!escaped) {
243 r = -ENOMEM;
244 goto finish;
245 }
246
247 fprintf(f, "SERVICE=%s\n", escaped);
248 }
3f49d45a 249
558c6490
LP
250 if (s->desktop) {
251 _cleanup_free_ char *escaped;
98a28fef 252
558c6490
LP
253
254 escaped = cescape(s->desktop);
255 if (!escaped) {
256 r = -ENOMEM;
257 goto finish;
258 }
259
260 fprintf(f, "DESKTOP=%s\n", escaped);
261 }
a4cd87e9 262
bf7825ae 263 if (s->seat && seat_has_vts(s->seat))
92bd5ff3 264 fprintf(f, "VTNR=%u\n", s->vtnr);
20263082 265
49e6fdbf
DH
266 if (!s->vtnr)
267 fprintf(f, "POS=%u\n", s->pos);
268
20263082 269 if (s->leader > 0)
90b2de37 270 fprintf(f, "LEADER="PID_FMT"\n", s->leader);
20263082
LP
271
272 if (s->audit_id > 0)
507f22bd 273 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
20263082 274
9444b1f2
LP
275 if (dual_timestamp_is_set(&s->timestamp))
276 fprintf(f,
90b2de37
ZJS
277 "REALTIME="USEC_FMT"\n"
278 "MONOTONIC="USEC_FMT"\n",
279 s->timestamp.realtime,
280 s->timestamp.monotonic);
9444b1f2 281
6d33772f
DH
282 if (s->controller)
283 fprintf(f, "CONTROLLER=%s\n", s->controller);
284
20263082 285 fflush(f);
14c3baca
LP
286
287 if (ferror(f) || rename(temp_path, s->state_file) < 0) {
20263082
LP
288 r = -errno;
289 unlink(s->state_file);
14c3baca 290 unlink(temp_path);
20263082
LP
291 }
292
14c3baca
LP
293finish:
294 if (r < 0)
da927ba9 295 log_error_errno(r, "Failed to save session data %s: %m", s->state_file);
14c3baca 296
20263082
LP
297 return r;
298}
299
300int session_load(Session *s) {
9444b1f2 301 _cleanup_free_ char *remote = NULL,
a185c5aa
LP
302 *seat = NULL,
303 *vtnr = NULL,
49e6fdbf 304 *pos = NULL,
a185c5aa 305 *leader = NULL,
55efac6c 306 *type = NULL,
9444b1f2
LP
307 *class = NULL,
308 *uid = NULL,
309 *realtime = NULL,
6d33772f
DH
310 *monotonic = NULL,
311 *controller = NULL;
a185c5aa
LP
312
313 int k, r;
314
20263082
LP
315 assert(s);
316
a185c5aa
LP
317 r = parse_env_file(s->state_file, NEWLINE,
318 "REMOTE", &remote,
fb6becb4
LP
319 "SCOPE", &s->scope,
320 "SCOPE_JOB", &s->scope_job,
932e3ee7 321 "FIFO", &s->fifo_path,
a185c5aa
LP
322 "SEAT", &seat,
323 "TTY", &s->tty,
324 "DISPLAY", &s->display,
325 "REMOTE_HOST", &s->remote_host,
326 "REMOTE_USER", &s->remote_user,
98a28fef 327 "SERVICE", &s->service,
a4cd87e9 328 "DESKTOP", &s->desktop,
a185c5aa 329 "VTNR", &vtnr,
49e6fdbf 330 "POS", &pos,
a185c5aa 331 "LEADER", &leader,
a91e4e53 332 "TYPE", &type,
55efac6c 333 "CLASS", &class,
9444b1f2
LP
334 "UID", &uid,
335 "REALTIME", &realtime,
336 "MONOTONIC", &monotonic,
6d33772f 337 "CONTROLLER", &controller,
a185c5aa
LP
338 NULL);
339
f647962d
MS
340 if (r < 0)
341 return log_error_errno(r, "Failed to read %s: %m", s->state_file);
9444b1f2
LP
342
343 if (!s->user) {
344 uid_t u;
345 User *user;
346
347 if (!uid) {
348 log_error("UID not specified for session %s", s->id);
349 return -ENOENT;
350 }
351
352 r = parse_uid(uid, &u);
353 if (r < 0) {
354 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
355 return r;
356 }
357
358 user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
359 if (!user) {
360 log_error("User of session %s not known.", s->id);
361 return -ENOENT;
362 }
363
364 session_set_user(s, user);
365 }
a185c5aa
LP
366
367 if (remote) {
368 k = parse_boolean(remote);
369 if (k >= 0)
370 s->remote = k;
371 }
372
c506027a
DH
373 if (vtnr)
374 safe_atou(vtnr, &s->vtnr);
375
9418f147 376 if (seat && !s->seat) {
a185c5aa
LP
377 Seat *o;
378
379 o = hashmap_get(s->manager->seats, seat);
380 if (o)
c506027a
DH
381 r = seat_attach_session(o, s);
382 if (!o || r < 0)
383 log_error("Cannot attach session %s to seat %s", s->id, seat);
a185c5aa
LP
384 }
385
c506027a
DH
386 if (!s->seat || !seat_has_vts(s->seat))
387 s->vtnr = 0;
a185c5aa 388
49e6fdbf
DH
389 if (pos && s->seat) {
390 unsigned int npos;
391
392 safe_atou(pos, &npos);
393 seat_claim_position(s->seat, s, npos);
394 }
395
a185c5aa 396 if (leader) {
f8e2fb7b
LP
397 k = parse_pid(leader, &s->leader);
398 if (k >= 0)
399 audit_session_from_pid(s->leader, &s->audit_id);
a185c5aa
LP
400 }
401
a91e4e53
LP
402 if (type) {
403 SessionType t;
404
405 t = session_type_from_string(type);
406 if (t >= 0)
407 s->type = t;
408 }
409
55efac6c
LP
410 if (class) {
411 SessionClass c;
412
413 c = session_class_from_string(class);
414 if (c >= 0)
415 s->class = c;
416 }
417
b4f78aea
LP
418 if (s->fifo_path) {
419 int fd;
420
421 /* If we open an unopened pipe for reading we will not
422 get an EOF. to trigger an EOF we hence open it for
423 reading, but close it right-away which then will
424 trigger the EOF. */
425
426 fd = session_create_fifo(s);
03e334a1 427 safe_close(fd);
b4f78aea
LP
428 }
429
9444b1f2
LP
430 if (realtime) {
431 unsigned long long l;
432 if (sscanf(realtime, "%llu", &l) > 0)
433 s->timestamp.realtime = l;
434 }
435
436 if (monotonic) {
437 unsigned long long l;
438 if (sscanf(monotonic, "%llu", &l) > 0)
439 s->timestamp.monotonic = l;
440 }
a185c5aa 441
6d33772f
DH
442 if (controller) {
443 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
444 session_set_controller(s, controller, false);
90a18413
DH
445 else
446 session_restore_vt(s);
6d33772f
DH
447 }
448
a185c5aa 449 return r;
20263082
LP
450}
451
452int session_activate(Session *s) {
d7bd01b5
DH
453 unsigned int num_pending;
454
20263082 455 assert(s);
9444b1f2 456 assert(s->user);
20263082 457
20263082
LP
458 if (!s->seat)
459 return -ENOTSUP;
460
461 if (s->seat->active == s)
462 return 0;
463
d7bd01b5
DH
464 /* on seats with VTs, we let VTs manage session-switching */
465 if (seat_has_vts(s->seat)) {
92bd5ff3 466 if (!s->vtnr)
d7bd01b5
DH
467 return -ENOTSUP;
468
469 return chvt(s->vtnr);
470 }
471
472 /* On seats without VTs, we implement session-switching in logind. We
473 * try to pause all session-devices and wait until the session
474 * controller acknowledged them. Once all devices are asleep, we simply
475 * switch the active session and be done.
476 * We save the session we want to switch to in seat->pending_switch and
477 * seat_complete_switch() will perform the final switch. */
478
479 s->seat->pending_switch = s;
480
481 /* if no devices are running, immediately perform the session switch */
482 num_pending = session_device_try_pause_all(s);
483 if (!num_pending)
484 seat_complete_switch(s->seat);
20263082 485
d7bd01b5 486 return 0;
20263082
LP
487}
488
fb6becb4 489static int session_start_scope(Session *s) {
98a28fef
LP
490 int r;
491
492 assert(s);
9444b1f2 493 assert(s->user);
fb6becb4 494 assert(s->user->slice);
98a28fef 495
fb6becb4 496 if (!s->scope) {
cc377381 497 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
d0af76e6 498 _cleanup_free_ char *description = NULL;
39883f62 499 char *scope, *job = NULL;
d0af76e6 500
405e0255
LP
501 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
502 if (!description)
503 return log_oom();
504
d0af76e6
LP
505 scope = strjoin("session-", s->id, ".scope", NULL);
506 if (!scope)
ae018d9b
LP
507 return log_oom();
508
646e392e 509 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job);
d0af76e6 510 if (r < 0) {
042f5988 511 log_error("Failed to start session scope %s: %s %s",
cc377381 512 scope, bus_error_message(&error, r), error.name);
d0af76e6 513 free(scope);
f2d4f98d 514 return r;
d0af76e6
LP
515 } else {
516 s->scope = scope;
517
518 free(s->scope_job);
519 s->scope_job = job;
520 }
20263082
LP
521 }
522
d0af76e6
LP
523 if (s->scope)
524 hashmap_put(s->manager->session_units, s->scope, s);
525
20263082
LP
526 return 0;
527}
528
529int session_start(Session *s) {
530 int r;
531
532 assert(s);
9444b1f2
LP
533
534 if (!s->user)
535 return -ESTALE;
20263082 536
9418f147
LP
537 if (s->started)
538 return 0;
539
ed18b08b
LP
540 r = user_start(s->user);
541 if (r < 0)
542 return r;
543
fb6becb4
LP
544 /* Create cgroup */
545 r = session_start_scope(s);
546 if (r < 0)
547 return r;
548
d9eb81f9 549 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
e2cc6eca 550 LOG_MESSAGE_ID(SD_MESSAGE_SESSION_START),
877d54e9
LP
551 "SESSION_ID=%s", s->id,
552 "USER_ID=%s", s->user->name,
de0671ee 553 "LEADER="PID_FMT, s->leader,
e2cc6eca 554 LOG_MESSAGE("New session %s of user %s.", s->id, s->user->name),
877d54e9 555 NULL);
98a28fef 556
9444b1f2
LP
557 if (!dual_timestamp_is_set(&s->timestamp))
558 dual_timestamp_get(&s->timestamp);
14c3baca 559
e9816c48
LP
560 if (s->seat)
561 seat_read_active_vt(s->seat);
562
9418f147
LP
563 s->started = true;
564
952d3260
LP
565 user_elect_display(s->user);
566
5f41d1f1 567 /* Save data */
e9816c48 568 session_save(s);
7f7bb946 569 user_save(s->user);
5f41d1f1
LP
570 if (s->seat)
571 seat_save(s->seat);
e9816c48 572
5f41d1f1 573 /* Send signals */
da119395 574 session_send_signal(s, true);
952d3260 575 user_send_changed(s->user, "Sessions", "Display", NULL);
9418f147
LP
576 if (s->seat) {
577 if (s->seat->active == s)
cc377381 578 seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
9418f147 579 else
cc377381 580 seat_send_changed(s->seat, "Sessions", NULL);
9418f147
LP
581 }
582
20263082
LP
583 return 0;
584}
585
9bb69af4 586static int session_stop_scope(Session *s, bool force) {
cc377381 587 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
39883f62 588 char *job = NULL;
20263082 589 int r;
20263082
LP
590
591 assert(s);
592
fb6becb4
LP
593 if (!s->scope)
594 return 0;
9b221b63 595
9bb69af4 596 if (force || manager_shall_kill(s->manager, s->user->name)) {
5f41d1f1
LP
597 r = manager_stop_unit(s->manager, s->scope, &error, &job);
598 if (r < 0) {
599 log_error("Failed to stop session scope: %s", bus_error_message(&error, r));
600 return r;
601 }
20263082 602
5f41d1f1
LP
603 free(s->scope_job);
604 s->scope_job = job;
605 } else {
606 r = manager_abandon_scope(s->manager, s->scope, &error);
607 if (r < 0) {
608 log_error("Failed to abandon session scope: %s", bus_error_message(&error, r));
609 return r;
610 }
611 }
20263082 612
9b221b63 613 return 0;
20263082
LP
614}
615
9bb69af4 616int session_stop(Session *s, bool force) {
405e0255
LP
617 int r;
618
619 assert(s);
620
621 if (!s->user)
622 return -ESTALE;
623
5f41d1f1
LP
624 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
625
626 /* We are going down, don't care about FIFOs anymore */
627 session_remove_fifo(s);
628
405e0255 629 /* Kill cgroup */
9bb69af4 630 r = session_stop_scope(s, force);
405e0255 631
5f41d1f1
LP
632 s->stopping = true;
633
952d3260
LP
634 user_elect_display(s->user);
635
405e0255 636 session_save(s);
cc377381 637 user_save(s->user);
405e0255
LP
638
639 return r;
640}
641
642int session_finalize(Session *s) {
643 int r = 0;
118ecf32 644 SessionDevice *sd;
20263082
LP
645
646 assert(s);
647
9444b1f2
LP
648 if (!s->user)
649 return -ESTALE;
650
ed18b08b 651 if (s->started)
d9eb81f9 652 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
e2cc6eca 653 LOG_MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
877d54e9
LP
654 "SESSION_ID=%s", s->id,
655 "USER_ID=%s", s->user->name,
de0671ee 656 "LEADER="PID_FMT, s->leader,
e2cc6eca 657 LOG_MESSAGE("Removed session %s.", s->id),
877d54e9 658 NULL);
98a28fef 659
5f41d1f1
LP
660 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
661
118ecf32
DH
662 /* Kill session devices */
663 while ((sd = hashmap_first(s->devices)))
664 session_device_free(sd);
665
d2f92cdf
LP
666 unlink(s->state_file);
667 session_add_to_gc_queue(s);
ed18b08b 668 user_add_to_gc_queue(s->user);
14c3baca 669
405e0255 670 if (s->started) {
ed18b08b 671 session_send_signal(s, false);
405e0255
LP
672 s->started = false;
673 }
50fb9793 674
9418f147
LP
675 if (s->seat) {
676 if (s->seat->active == s)
677 seat_set_active(s->seat, NULL);
678
23bd3b62 679 seat_save(s->seat);
5f41d1f1 680 seat_send_changed(s->seat, "Sessions", NULL);
9418f147
LP
681 }
682
23bd3b62 683 user_save(s->user);
952d3260 684 user_send_changed(s->user, "Sessions", "Display", NULL);
9418f147 685
20263082
LP
686 return r;
687}
688
5f41d1f1
LP
689static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
690 Session *s = userdata;
691
692 assert(es);
693 assert(s);
694
9bb69af4 695 session_stop(s, false);
5f41d1f1
LP
696 return 0;
697}
698
699void session_release(Session *s) {
700 assert(s);
701
702 if (!s->started || s->stopping)
703 return;
704
705 if (!s->timer_event_source)
6a0f1f6d
LP
706 sd_event_add_time(s->manager->event,
707 &s->timer_event_source,
708 CLOCK_MONOTONIC,
709 now(CLOCK_MONOTONIC) + RELEASE_USEC, 0,
710 release_timeout_callback, s);
5f41d1f1
LP
711}
712
20263082
LP
713bool session_is_active(Session *s) {
714 assert(s);
715
716 if (!s->seat)
717 return true;
718
719 return s->seat->active == s;
720}
721
23406ce5
LP
722static int get_tty_atime(const char *tty, usec_t *atime) {
723 _cleanup_free_ char *p = NULL;
a185c5aa 724 struct stat st;
23406ce5
LP
725
726 assert(tty);
727 assert(atime);
728
729 if (!path_is_absolute(tty)) {
730 p = strappend("/dev/", tty);
731 if (!p)
732 return -ENOMEM;
733
734 tty = p;
735 } else if (!path_startswith(tty, "/dev/"))
736 return -ENOENT;
737
738 if (lstat(tty, &st) < 0)
739 return -errno;
740
741 *atime = timespec_load(&st.st_atim);
742 return 0;
743}
744
745static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
746 _cleanup_free_ char *p = NULL;
747 int r;
748
749 assert(pid > 0);
750 assert(atime);
751
752 r = get_ctty(pid, NULL, &p);
753 if (r < 0)
754 return r;
755
756 return get_tty_atime(p, atime);
757}
758
759int session_get_idle_hint(Session *s, dual_timestamp *t) {
23406ce5
LP
760 usec_t atime = 0, n;
761 int r;
a185c5aa
LP
762
763 assert(s);
764
23406ce5 765 /* Explicit idle hint is set */
a185c5aa
LP
766 if (s->idle_hint) {
767 if (t)
768 *t = s->idle_hint_timestamp;
769
770 return s->idle_hint;
771 }
772
0762eaa3 773 /* Graphical sessions should really implement a real
23406ce5
LP
774 * idle hint logic */
775 if (s->display)
a185c5aa
LP
776 goto dont_know;
777
23406ce5
LP
778 /* For sessions with an explicitly configured tty, let's check
779 * its atime */
780 if (s->tty) {
781 r = get_tty_atime(s->tty, &atime);
782 if (r >= 0)
783 goto found_atime;
784 }
a185c5aa 785
23406ce5
LP
786 /* For sessions with a leader but no explicitly configured
787 * tty, let's check the controlling tty of the leader */
788 if (s->leader > 0) {
789 r = get_process_ctty_atime(s->leader, &atime);
790 if (r >= 0)
791 goto found_atime;
a185c5aa
LP
792 }
793
a185c5aa
LP
794dont_know:
795 if (t)
796 *t = s->idle_hint_timestamp;
797
798 return 0;
23406ce5
LP
799
800found_atime:
801 if (t)
802 dual_timestamp_from_realtime(t, atime);
803
804 n = now(CLOCK_REALTIME);
805
806 if (s->manager->idle_action_usec <= 0)
807 return 0;
808
809 return atime + s->manager->idle_action_usec <= n;
a185c5aa
LP
810}
811
bef422ae
LP
812void session_set_idle_hint(Session *s, bool b) {
813 assert(s);
814
815 if (s->idle_hint == b)
816 return;
817
818 s->idle_hint = b;
819 dual_timestamp_get(&s->idle_hint_timestamp);
9418f147 820
cc377381 821 session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
9418f147
LP
822
823 if (s->seat)
cc377381
LP
824 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
825
826 user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
827 manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
828}
829
830static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
831 Session *s = userdata;
832
833 assert(s);
834 assert(s->fifo_fd == fd);
835
836 /* EOF on the FIFO means the session died abnormally. */
837
838 session_remove_fifo(s);
9bb69af4 839 session_stop(s, false);
cc377381
LP
840
841 return 1;
bef422ae
LP
842}
843
932e3ee7
LP
844int session_create_fifo(Session *s) {
845 int r;
846
31b79c2b
LP
847 assert(s);
848
b4f78aea 849 /* Create FIFO */
932e3ee7 850 if (!s->fifo_path) {
d2e54fae 851 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
e6061ab2
LP
852 if (r < 0)
853 return r;
854
932e3ee7
LP
855 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
856 return -ENOMEM;
31b79c2b 857
932e3ee7
LP
858 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
859 return -errno;
860 }
31b79c2b 861
932e3ee7 862 /* Open reading side */
b4f78aea 863 if (s->fifo_fd < 0) {
b4f78aea
LP
864 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
865 if (s->fifo_fd < 0)
866 return -errno;
867
cc377381
LP
868 }
869
870 if (!s->fifo_event_source) {
151b9b96 871 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
b4f78aea
LP
872 if (r < 0)
873 return r;
874
718db961 875 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
cc377381
LP
876 if (r < 0)
877 return r;
b4f78aea 878 }
932e3ee7
LP
879
880 /* Open writing side */
881 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
882 if (r < 0)
883 return -errno;
31b79c2b 884
932e3ee7
LP
885 return r;
886}
887
5f41d1f1 888static void session_remove_fifo(Session *s) {
932e3ee7
LP
889 assert(s);
890
03e334a1
LP
891 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
892 s->fifo_fd = safe_close(s->fifo_fd);
932e3ee7
LP
893
894 if (s->fifo_path) {
895 unlink(s->fifo_path);
896 free(s->fifo_path);
897 s->fifo_path = NULL;
898 }
31b79c2b
LP
899}
900
cc377381 901bool session_check_gc(Session *s, bool drop_not_started) {
20263082
LP
902 assert(s);
903
4a4b033f 904 if (drop_not_started && !s->started)
cc377381 905 return false;
932e3ee7 906
9444b1f2 907 if (!s->user)
cc377381 908 return false;
9444b1f2 909
932e3ee7 910 if (s->fifo_fd >= 0) {
5f41d1f1 911 if (pipe_eof(s->fifo_fd) <= 0)
cc377381 912 return true;
20263082
LP
913 }
914
cc377381
LP
915 if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
916 return true;
20263082 917
cc377381
LP
918 if (s->scope && manager_unit_is_active(s->manager, s->scope))
919 return true;
20263082 920
cc377381 921 return false;
20263082
LP
922}
923
14c3baca
LP
924void session_add_to_gc_queue(Session *s) {
925 assert(s);
926
927 if (s->in_gc_queue)
928 return;
929
71fda00f 930 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
14c3baca
LP
931 s->in_gc_queue = true;
932}
933
0604381b
LP
934SessionState session_get_state(Session *s) {
935 assert(s);
936
8fe63cd4 937 /* always check closing first */
5f41d1f1
LP
938 if (s->stopping || s->timer_event_source)
939 return SESSION_CLOSING;
940
8fe63cd4 941 if (s->scope_job || s->fifo_fd < 0)
405e0255 942 return SESSION_OPENING;
fb6becb4 943
0604381b
LP
944 if (session_is_active(s))
945 return SESSION_ACTIVE;
946
947 return SESSION_ONLINE;
948}
949
de07ab16 950int session_kill(Session *s, KillWho who, int signo) {
de07ab16
LP
951 assert(s);
952
fb6becb4 953 if (!s->scope)
de07ab16
LP
954 return -ESRCH;
955
fb6becb4 956 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
de07ab16
LP
957}
958
90a18413 959static int session_open_vt(Session *s) {
5f41d1f1 960 char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
90a18413 961
baccf3e4
OB
962 if (s->vtnr < 1)
963 return -ENODEV;
90a18413
DH
964
965 if (s->vtfd >= 0)
966 return s->vtfd;
967
92bd5ff3 968 sprintf(path, "/dev/tty%u", s->vtnr);
90a18413
DH
969 s->vtfd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
970 if (s->vtfd < 0) {
56f64d95 971 log_error_errno(errno, "cannot open VT %s of session %s: %m", path, s->id);
03e334a1 972 return -errno;
90a18413
DH
973 }
974
975 return s->vtfd;
976}
977
baccf3e4 978int session_prepare_vt(Session *s) {
90a18413
DH
979 int vt, r;
980 struct vt_mode mode = { 0 };
90a18413 981
baccf3e4
OB
982 if (s->vtnr < 1)
983 return 0;
984
90a18413
DH
985 vt = session_open_vt(s);
986 if (vt < 0)
baccf3e4 987 return vt;
90a18413 988
d6176c6c 989 r = fchown(vt, s->user->uid, -1);
baccf3e4
OB
990 if (r < 0) {
991 r = -errno;
56f64d95 992 log_error_errno(errno, "Cannot change owner of /dev/tty%u: %m", s->vtnr);
d6176c6c 993 goto error;
baccf3e4 994 }
d6176c6c 995
90a18413 996 r = ioctl(vt, KDSKBMODE, K_OFF);
baccf3e4
OB
997 if (r < 0) {
998 r = -errno;
56f64d95 999 log_error_errno(errno, "Cannot set K_OFF on /dev/tty%u: %m", s->vtnr);
90a18413 1000 goto error;
baccf3e4 1001 }
90a18413
DH
1002
1003 r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
baccf3e4
OB
1004 if (r < 0) {
1005 r = -errno;
56f64d95 1006 log_error_errno(errno, "Cannot set KD_GRAPHICS on /dev/tty%u: %m", s->vtnr);
90a18413 1007 goto error;
baccf3e4 1008 }
90a18413 1009
90a18413
DH
1010 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1011 * So we need a dummy handler here which just acknowledges *all* VT
1012 * switch requests. */
1013 mode.mode = VT_PROCESS;
92683ad2
DH
1014 mode.relsig = SIGRTMIN;
1015 mode.acqsig = SIGRTMIN + 1;
90a18413 1016 r = ioctl(vt, VT_SETMODE, &mode);
baccf3e4
OB
1017 if (r < 0) {
1018 r = -errno;
56f64d95 1019 log_error_errno(errno, "Cannot set VT_PROCESS on /dev/tty%u: %m", s->vtnr);
90a18413 1020 goto error;
baccf3e4 1021 }
90a18413 1022
baccf3e4 1023 return 0;
90a18413
DH
1024
1025error:
90a18413 1026 session_restore_vt(s);
baccf3e4 1027 return r;
90a18413
DH
1028}
1029
1030void session_restore_vt(Session *s) {
a0eb2a75 1031 _cleanup_free_ char *utf8 = NULL;
90a18413
DH
1032 int vt, kb = K_XLATE;
1033 struct vt_mode mode = { 0 };
1034
1035 vt = session_open_vt(s);
1036 if (vt < 0)
1037 return;
1038
90a18413
DH
1039 ioctl(vt, KDSETMODE, KD_TEXT);
1040
1041 if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
1042 kb = K_UNICODE;
03e334a1 1043
90a18413
DH
1044 ioctl(vt, KDSKBMODE, kb);
1045
1046 mode.mode = VT_AUTO;
1047 ioctl(vt, VT_SETMODE, &mode);
1048
d6176c6c
RS
1049 fchown(vt, 0, -1);
1050
03e334a1 1051 s->vtfd = safe_close(s->vtfd);
90a18413
DH
1052}
1053
2ec3ff66 1054void session_leave_vt(Session *s) {
ce540a24
DH
1055 int r;
1056
2ec3ff66
DH
1057 assert(s);
1058
1059 /* This is called whenever we get a VT-switch signal from the kernel.
1060 * We acknowledge all of them unconditionally. Note that session are
1061 * free to overwrite those handlers and we only register them for
1062 * sessions with controllers. Legacy sessions are not affected.
1063 * However, if we switch from a non-legacy to a legacy session, we must
1064 * make sure to pause all device before acknowledging the switch. We
1065 * process the real switch only after we are notified via sysfs, so the
1066 * legacy session might have already started using the devices. If we
1067 * don't pause the devices before the switch, we might confuse the
1068 * session we switch to. */
1069
1070 if (s->vtfd < 0)
1071 return;
1072
1073 session_device_pause_all(s);
ce540a24
DH
1074 r = ioctl(s->vtfd, VT_RELDISP, 1);
1075 if (r < 0)
56f64d95 1076 log_debug_errno(errno, "Cannot release VT of session %s: %m", s->id);
2ec3ff66
DH
1077}
1078
cc377381 1079bool session_is_controller(Session *s, const char *sender) {
ae5e06bd
DH
1080 assert(s);
1081
1082 return streq_ptr(s->controller, sender);
1083}
1084
b12e5615
DH
1085static void session_release_controller(Session *s, bool notify) {
1086 _cleanup_free_ char *name = NULL;
6d33772f
DH
1087 SessionDevice *sd;
1088
b12e5615
DH
1089 if (!s->controller)
1090 return;
6d33772f 1091
b12e5615 1092 name = s->controller;
90a18413 1093
b12e5615
DH
1094 /* By resetting the controller before releasing the devices, we won't
1095 * send notification signals. This avoids sending useless notifications
1096 * if the controller is released on disconnects. */
1097 if (!notify)
1098 s->controller = NULL;
6d33772f 1099
b12e5615
DH
1100 while ((sd = hashmap_first(s->devices)))
1101 session_device_free(sd);
1102
1103 s->controller = NULL;
1104 manager_drop_busname(s->manager, name);
6d33772f
DH
1105}
1106
ae5e06bd 1107int session_set_controller(Session *s, const char *sender, bool force) {
b12e5615 1108 _cleanup_free_ char *name = NULL;
ae5e06bd
DH
1109 int r;
1110
1111 assert(s);
1112 assert(sender);
1113
1114 if (session_is_controller(s, sender))
1115 return 0;
1116 if (s->controller && !force)
1117 return -EBUSY;
1118
b12e5615
DH
1119 name = strdup(sender);
1120 if (!name)
ae5e06bd
DH
1121 return -ENOMEM;
1122
b12e5615
DH
1123 r = manager_watch_busname(s->manager, name);
1124 if (r)
ae5e06bd 1125 return r;
ae5e06bd 1126
90a18413
DH
1127 /* When setting a session controller, we forcibly mute the VT and set
1128 * it into graphics-mode. Applications can override that by changing
1129 * VT state after calling TakeControl(). However, this serves as a good
1130 * default and well-behaving controllers can now ignore VTs entirely.
1131 * Note that we reset the VT on ReleaseControl() and if the controller
1132 * exits.
1133 * If logind crashes/restarts, we restore the controller during restart
1134 * or reset the VT in case it crashed/exited, too. */
baccf3e4 1135 r = session_prepare_vt(s);
13f493dc 1136 if (r < 0) {
b12e5615 1137 manager_drop_busname(s->manager, name);
baccf3e4 1138 return r;
13f493dc 1139 }
baccf3e4 1140
b12e5615
DH
1141 session_release_controller(s, true);
1142 s->controller = name;
1143 name = NULL;
1144 session_save(s);
90a18413 1145
ae5e06bd
DH
1146 return 0;
1147}
1148
1149void session_drop_controller(Session *s) {
1150 assert(s);
1151
1152 if (!s->controller)
1153 return;
1154
b12e5615
DH
1155 session_release_controller(s, false);
1156 session_save(s);
1157 session_restore_vt(s);
ae5e06bd
DH
1158}
1159
fb6becb4
LP
1160static const char* const session_state_table[_SESSION_STATE_MAX] = {
1161 [SESSION_OPENING] = "opening",
0604381b
LP
1162 [SESSION_ONLINE] = "online",
1163 [SESSION_ACTIVE] = "active",
1164 [SESSION_CLOSING] = "closing"
1165};
1166
1167DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1168
20263082 1169static const char* const session_type_table[_SESSION_TYPE_MAX] = {
2c5859af 1170 [SESSION_UNSPECIFIED] = "unspecified",
3f49d45a 1171 [SESSION_TTY] = "tty",
98a28fef 1172 [SESSION_X11] = "x11",
d9eb81f9 1173 [SESSION_WAYLAND] = "wayland",
9541666b 1174 [SESSION_MIR] = "mir",
e9e74f28 1175 [SESSION_WEB] = "web",
20263082
LP
1176};
1177
1178DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
de07ab16 1179
55efac6c
LP
1180static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1181 [SESSION_USER] = "user",
1182 [SESSION_GREETER] = "greeter",
e2acb67b
LP
1183 [SESSION_LOCK_SCREEN] = "lock-screen",
1184 [SESSION_BACKGROUND] = "background"
55efac6c
LP
1185};
1186
1187DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1188
de07ab16
LP
1189static const char* const kill_who_table[_KILL_WHO_MAX] = {
1190 [KILL_LEADER] = "leader",
1191 [KILL_ALL] = "all"
1192};
1193
1194DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);