]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-session.c
treewide: auto-convert the simple cases to log_*_errno()
[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)
0a1beeb6 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
9444b1f2 340 if (r < 0) {
0a1beeb6 341 log_error_errno(-r, "Failed to read %s: %m", s->state_file);
9444b1f2
LP
342 return r;
343 }
344
345 if (!s->user) {
346 uid_t u;
347 User *user;
348
349 if (!uid) {
350 log_error("UID not specified for session %s", s->id);
351 return -ENOENT;
352 }
353
354 r = parse_uid(uid, &u);
355 if (r < 0) {
356 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
357 return r;
358 }
359
360 user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u));
361 if (!user) {
362 log_error("User of session %s not known.", s->id);
363 return -ENOENT;
364 }
365
366 session_set_user(s, user);
367 }
a185c5aa
LP
368
369 if (remote) {
370 k = parse_boolean(remote);
371 if (k >= 0)
372 s->remote = k;
373 }
374
c506027a
DH
375 if (vtnr)
376 safe_atou(vtnr, &s->vtnr);
377
9418f147 378 if (seat && !s->seat) {
a185c5aa
LP
379 Seat *o;
380
381 o = hashmap_get(s->manager->seats, seat);
382 if (o)
c506027a
DH
383 r = seat_attach_session(o, s);
384 if (!o || r < 0)
385 log_error("Cannot attach session %s to seat %s", s->id, seat);
a185c5aa
LP
386 }
387
c506027a
DH
388 if (!s->seat || !seat_has_vts(s->seat))
389 s->vtnr = 0;
a185c5aa 390
49e6fdbf
DH
391 if (pos && s->seat) {
392 unsigned int npos;
393
394 safe_atou(pos, &npos);
395 seat_claim_position(s->seat, s, npos);
396 }
397
a185c5aa 398 if (leader) {
f8e2fb7b
LP
399 k = parse_pid(leader, &s->leader);
400 if (k >= 0)
401 audit_session_from_pid(s->leader, &s->audit_id);
a185c5aa
LP
402 }
403
a91e4e53
LP
404 if (type) {
405 SessionType t;
406
407 t = session_type_from_string(type);
408 if (t >= 0)
409 s->type = t;
410 }
411
55efac6c
LP
412 if (class) {
413 SessionClass c;
414
415 c = session_class_from_string(class);
416 if (c >= 0)
417 s->class = c;
418 }
419
b4f78aea
LP
420 if (s->fifo_path) {
421 int fd;
422
423 /* If we open an unopened pipe for reading we will not
424 get an EOF. to trigger an EOF we hence open it for
425 reading, but close it right-away which then will
426 trigger the EOF. */
427
428 fd = session_create_fifo(s);
03e334a1 429 safe_close(fd);
b4f78aea
LP
430 }
431
9444b1f2
LP
432 if (realtime) {
433 unsigned long long l;
434 if (sscanf(realtime, "%llu", &l) > 0)
435 s->timestamp.realtime = l;
436 }
437
438 if (monotonic) {
439 unsigned long long l;
440 if (sscanf(monotonic, "%llu", &l) > 0)
441 s->timestamp.monotonic = l;
442 }
a185c5aa 443
6d33772f
DH
444 if (controller) {
445 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
446 session_set_controller(s, controller, false);
90a18413
DH
447 else
448 session_restore_vt(s);
6d33772f
DH
449 }
450
a185c5aa 451 return r;
20263082
LP
452}
453
454int session_activate(Session *s) {
d7bd01b5
DH
455 unsigned int num_pending;
456
20263082 457 assert(s);
9444b1f2 458 assert(s->user);
20263082 459
20263082
LP
460 if (!s->seat)
461 return -ENOTSUP;
462
463 if (s->seat->active == s)
464 return 0;
465
d7bd01b5
DH
466 /* on seats with VTs, we let VTs manage session-switching */
467 if (seat_has_vts(s->seat)) {
92bd5ff3 468 if (!s->vtnr)
d7bd01b5
DH
469 return -ENOTSUP;
470
471 return chvt(s->vtnr);
472 }
473
474 /* On seats without VTs, we implement session-switching in logind. We
475 * try to pause all session-devices and wait until the session
476 * controller acknowledged them. Once all devices are asleep, we simply
477 * switch the active session and be done.
478 * We save the session we want to switch to in seat->pending_switch and
479 * seat_complete_switch() will perform the final switch. */
480
481 s->seat->pending_switch = s;
482
483 /* if no devices are running, immediately perform the session switch */
484 num_pending = session_device_try_pause_all(s);
485 if (!num_pending)
486 seat_complete_switch(s->seat);
20263082 487
d7bd01b5 488 return 0;
20263082
LP
489}
490
fb6becb4 491static int session_start_scope(Session *s) {
98a28fef
LP
492 int r;
493
494 assert(s);
9444b1f2 495 assert(s->user);
fb6becb4 496 assert(s->user->slice);
98a28fef 497
fb6becb4 498 if (!s->scope) {
cc377381 499 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
d0af76e6 500 _cleanup_free_ char *description = NULL;
39883f62 501 char *scope, *job = NULL;
d0af76e6 502
405e0255
LP
503 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
504 if (!description)
505 return log_oom();
506
d0af76e6
LP
507 scope = strjoin("session-", s->id, ".scope", NULL);
508 if (!scope)
ae018d9b
LP
509 return log_oom();
510
646e392e 511 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job);
d0af76e6 512 if (r < 0) {
042f5988 513 log_error("Failed to start session scope %s: %s %s",
cc377381 514 scope, bus_error_message(&error, r), error.name);
d0af76e6 515 free(scope);
f2d4f98d 516 return r;
d0af76e6
LP
517 } else {
518 s->scope = scope;
519
520 free(s->scope_job);
521 s->scope_job = job;
522 }
20263082
LP
523 }
524
d0af76e6
LP
525 if (s->scope)
526 hashmap_put(s->manager->session_units, s->scope, s);
527
20263082
LP
528 return 0;
529}
530
531int session_start(Session *s) {
532 int r;
533
534 assert(s);
9444b1f2
LP
535
536 if (!s->user)
537 return -ESTALE;
20263082 538
9418f147
LP
539 if (s->started)
540 return 0;
541
ed18b08b
LP
542 r = user_start(s->user);
543 if (r < 0)
544 return r;
545
fb6becb4
LP
546 /* Create cgroup */
547 r = session_start_scope(s);
548 if (r < 0)
549 return r;
550
d9eb81f9 551 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
e2cc6eca 552 LOG_MESSAGE_ID(SD_MESSAGE_SESSION_START),
877d54e9
LP
553 "SESSION_ID=%s", s->id,
554 "USER_ID=%s", s->user->name,
de0671ee 555 "LEADER="PID_FMT, s->leader,
e2cc6eca 556 LOG_MESSAGE("New session %s of user %s.", s->id, s->user->name),
877d54e9 557 NULL);
98a28fef 558
9444b1f2
LP
559 if (!dual_timestamp_is_set(&s->timestamp))
560 dual_timestamp_get(&s->timestamp);
14c3baca 561
e9816c48
LP
562 if (s->seat)
563 seat_read_active_vt(s->seat);
564
9418f147
LP
565 s->started = true;
566
952d3260
LP
567 user_elect_display(s->user);
568
5f41d1f1 569 /* Save data */
e9816c48 570 session_save(s);
7f7bb946 571 user_save(s->user);
5f41d1f1
LP
572 if (s->seat)
573 seat_save(s->seat);
e9816c48 574
5f41d1f1 575 /* Send signals */
da119395 576 session_send_signal(s, true);
952d3260 577 user_send_changed(s->user, "Sessions", "Display", NULL);
9418f147
LP
578 if (s->seat) {
579 if (s->seat->active == s)
cc377381 580 seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
9418f147 581 else
cc377381 582 seat_send_changed(s->seat, "Sessions", NULL);
9418f147
LP
583 }
584
20263082
LP
585 return 0;
586}
587
9bb69af4 588static int session_stop_scope(Session *s, bool force) {
cc377381 589 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
39883f62 590 char *job = NULL;
20263082 591 int r;
20263082
LP
592
593 assert(s);
594
fb6becb4
LP
595 if (!s->scope)
596 return 0;
9b221b63 597
9bb69af4 598 if (force || manager_shall_kill(s->manager, s->user->name)) {
5f41d1f1
LP
599 r = manager_stop_unit(s->manager, s->scope, &error, &job);
600 if (r < 0) {
601 log_error("Failed to stop session scope: %s", bus_error_message(&error, r));
602 return r;
603 }
20263082 604
5f41d1f1
LP
605 free(s->scope_job);
606 s->scope_job = job;
607 } else {
608 r = manager_abandon_scope(s->manager, s->scope, &error);
609 if (r < 0) {
610 log_error("Failed to abandon session scope: %s", bus_error_message(&error, r));
611 return r;
612 }
613 }
20263082 614
9b221b63 615 return 0;
20263082
LP
616}
617
9bb69af4 618int session_stop(Session *s, bool force) {
405e0255
LP
619 int r;
620
621 assert(s);
622
623 if (!s->user)
624 return -ESTALE;
625
5f41d1f1
LP
626 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
627
628 /* We are going down, don't care about FIFOs anymore */
629 session_remove_fifo(s);
630
405e0255 631 /* Kill cgroup */
9bb69af4 632 r = session_stop_scope(s, force);
405e0255 633
5f41d1f1
LP
634 s->stopping = true;
635
952d3260
LP
636 user_elect_display(s->user);
637
405e0255 638 session_save(s);
cc377381 639 user_save(s->user);
405e0255
LP
640
641 return r;
642}
643
644int session_finalize(Session *s) {
645 int r = 0;
118ecf32 646 SessionDevice *sd;
20263082
LP
647
648 assert(s);
649
9444b1f2
LP
650 if (!s->user)
651 return -ESTALE;
652
ed18b08b 653 if (s->started)
d9eb81f9 654 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
e2cc6eca 655 LOG_MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
877d54e9
LP
656 "SESSION_ID=%s", s->id,
657 "USER_ID=%s", s->user->name,
de0671ee 658 "LEADER="PID_FMT, s->leader,
e2cc6eca 659 LOG_MESSAGE("Removed session %s.", s->id),
877d54e9 660 NULL);
98a28fef 661
5f41d1f1
LP
662 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
663
118ecf32
DH
664 /* Kill session devices */
665 while ((sd = hashmap_first(s->devices)))
666 session_device_free(sd);
667
d2f92cdf
LP
668 unlink(s->state_file);
669 session_add_to_gc_queue(s);
ed18b08b 670 user_add_to_gc_queue(s->user);
14c3baca 671
405e0255 672 if (s->started) {
ed18b08b 673 session_send_signal(s, false);
405e0255
LP
674 s->started = false;
675 }
50fb9793 676
9418f147
LP
677 if (s->seat) {
678 if (s->seat->active == s)
679 seat_set_active(s->seat, NULL);
680
23bd3b62 681 seat_save(s->seat);
5f41d1f1 682 seat_send_changed(s->seat, "Sessions", NULL);
9418f147
LP
683 }
684
23bd3b62 685 user_save(s->user);
952d3260 686 user_send_changed(s->user, "Sessions", "Display", NULL);
9418f147 687
20263082
LP
688 return r;
689}
690
5f41d1f1
LP
691static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
692 Session *s = userdata;
693
694 assert(es);
695 assert(s);
696
9bb69af4 697 session_stop(s, false);
5f41d1f1
LP
698 return 0;
699}
700
701void session_release(Session *s) {
702 assert(s);
703
704 if (!s->started || s->stopping)
705 return;
706
707 if (!s->timer_event_source)
6a0f1f6d
LP
708 sd_event_add_time(s->manager->event,
709 &s->timer_event_source,
710 CLOCK_MONOTONIC,
711 now(CLOCK_MONOTONIC) + RELEASE_USEC, 0,
712 release_timeout_callback, s);
5f41d1f1
LP
713}
714
20263082
LP
715bool session_is_active(Session *s) {
716 assert(s);
717
718 if (!s->seat)
719 return true;
720
721 return s->seat->active == s;
722}
723
23406ce5
LP
724static int get_tty_atime(const char *tty, usec_t *atime) {
725 _cleanup_free_ char *p = NULL;
a185c5aa 726 struct stat st;
23406ce5
LP
727
728 assert(tty);
729 assert(atime);
730
731 if (!path_is_absolute(tty)) {
732 p = strappend("/dev/", tty);
733 if (!p)
734 return -ENOMEM;
735
736 tty = p;
737 } else if (!path_startswith(tty, "/dev/"))
738 return -ENOENT;
739
740 if (lstat(tty, &st) < 0)
741 return -errno;
742
743 *atime = timespec_load(&st.st_atim);
744 return 0;
745}
746
747static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
748 _cleanup_free_ char *p = NULL;
749 int r;
750
751 assert(pid > 0);
752 assert(atime);
753
754 r = get_ctty(pid, NULL, &p);
755 if (r < 0)
756 return r;
757
758 return get_tty_atime(p, atime);
759}
760
761int session_get_idle_hint(Session *s, dual_timestamp *t) {
23406ce5
LP
762 usec_t atime = 0, n;
763 int r;
a185c5aa
LP
764
765 assert(s);
766
23406ce5 767 /* Explicit idle hint is set */
a185c5aa
LP
768 if (s->idle_hint) {
769 if (t)
770 *t = s->idle_hint_timestamp;
771
772 return s->idle_hint;
773 }
774
0762eaa3 775 /* Graphical sessions should really implement a real
23406ce5
LP
776 * idle hint logic */
777 if (s->display)
a185c5aa
LP
778 goto dont_know;
779
23406ce5
LP
780 /* For sessions with an explicitly configured tty, let's check
781 * its atime */
782 if (s->tty) {
783 r = get_tty_atime(s->tty, &atime);
784 if (r >= 0)
785 goto found_atime;
786 }
a185c5aa 787
23406ce5
LP
788 /* For sessions with a leader but no explicitly configured
789 * tty, let's check the controlling tty of the leader */
790 if (s->leader > 0) {
791 r = get_process_ctty_atime(s->leader, &atime);
792 if (r >= 0)
793 goto found_atime;
a185c5aa
LP
794 }
795
a185c5aa
LP
796dont_know:
797 if (t)
798 *t = s->idle_hint_timestamp;
799
800 return 0;
23406ce5
LP
801
802found_atime:
803 if (t)
804 dual_timestamp_from_realtime(t, atime);
805
806 n = now(CLOCK_REALTIME);
807
808 if (s->manager->idle_action_usec <= 0)
809 return 0;
810
811 return atime + s->manager->idle_action_usec <= n;
a185c5aa
LP
812}
813
bef422ae
LP
814void session_set_idle_hint(Session *s, bool b) {
815 assert(s);
816
817 if (s->idle_hint == b)
818 return;
819
820 s->idle_hint = b;
821 dual_timestamp_get(&s->idle_hint_timestamp);
9418f147 822
cc377381 823 session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
9418f147
LP
824
825 if (s->seat)
cc377381
LP
826 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
827
828 user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
829 manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
830}
831
832static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
833 Session *s = userdata;
834
835 assert(s);
836 assert(s->fifo_fd == fd);
837
838 /* EOF on the FIFO means the session died abnormally. */
839
840 session_remove_fifo(s);
9bb69af4 841 session_stop(s, false);
cc377381
LP
842
843 return 1;
bef422ae
LP
844}
845
932e3ee7
LP
846int session_create_fifo(Session *s) {
847 int r;
848
31b79c2b
LP
849 assert(s);
850
b4f78aea 851 /* Create FIFO */
932e3ee7 852 if (!s->fifo_path) {
d2e54fae 853 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
e6061ab2
LP
854 if (r < 0)
855 return r;
856
932e3ee7
LP
857 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
858 return -ENOMEM;
31b79c2b 859
932e3ee7
LP
860 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
861 return -errno;
862 }
31b79c2b 863
932e3ee7 864 /* Open reading side */
b4f78aea 865 if (s->fifo_fd < 0) {
b4f78aea
LP
866 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
867 if (s->fifo_fd < 0)
868 return -errno;
869
cc377381
LP
870 }
871
872 if (!s->fifo_event_source) {
151b9b96 873 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
b4f78aea
LP
874 if (r < 0)
875 return r;
876
718db961 877 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
cc377381
LP
878 if (r < 0)
879 return r;
b4f78aea 880 }
932e3ee7
LP
881
882 /* Open writing side */
883 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
884 if (r < 0)
885 return -errno;
31b79c2b 886
932e3ee7
LP
887 return r;
888}
889
5f41d1f1 890static void session_remove_fifo(Session *s) {
932e3ee7
LP
891 assert(s);
892
03e334a1
LP
893 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
894 s->fifo_fd = safe_close(s->fifo_fd);
932e3ee7
LP
895
896 if (s->fifo_path) {
897 unlink(s->fifo_path);
898 free(s->fifo_path);
899 s->fifo_path = NULL;
900 }
31b79c2b
LP
901}
902
cc377381 903bool session_check_gc(Session *s, bool drop_not_started) {
20263082
LP
904 assert(s);
905
4a4b033f 906 if (drop_not_started && !s->started)
cc377381 907 return false;
932e3ee7 908
9444b1f2 909 if (!s->user)
cc377381 910 return false;
9444b1f2 911
932e3ee7 912 if (s->fifo_fd >= 0) {
5f41d1f1 913 if (pipe_eof(s->fifo_fd) <= 0)
cc377381 914 return true;
20263082
LP
915 }
916
cc377381
LP
917 if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
918 return true;
20263082 919
cc377381
LP
920 if (s->scope && manager_unit_is_active(s->manager, s->scope))
921 return true;
20263082 922
cc377381 923 return false;
20263082
LP
924}
925
14c3baca
LP
926void session_add_to_gc_queue(Session *s) {
927 assert(s);
928
929 if (s->in_gc_queue)
930 return;
931
71fda00f 932 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
14c3baca
LP
933 s->in_gc_queue = true;
934}
935
0604381b
LP
936SessionState session_get_state(Session *s) {
937 assert(s);
938
8fe63cd4 939 /* always check closing first */
5f41d1f1
LP
940 if (s->stopping || s->timer_event_source)
941 return SESSION_CLOSING;
942
8fe63cd4 943 if (s->scope_job || s->fifo_fd < 0)
405e0255 944 return SESSION_OPENING;
fb6becb4 945
0604381b
LP
946 if (session_is_active(s))
947 return SESSION_ACTIVE;
948
949 return SESSION_ONLINE;
950}
951
de07ab16 952int session_kill(Session *s, KillWho who, int signo) {
de07ab16
LP
953 assert(s);
954
fb6becb4 955 if (!s->scope)
de07ab16
LP
956 return -ESRCH;
957
fb6becb4 958 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
de07ab16
LP
959}
960
90a18413 961static int session_open_vt(Session *s) {
5f41d1f1 962 char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
90a18413 963
baccf3e4
OB
964 if (s->vtnr < 1)
965 return -ENODEV;
90a18413
DH
966
967 if (s->vtfd >= 0)
968 return s->vtfd;
969
92bd5ff3 970 sprintf(path, "/dev/tty%u", s->vtnr);
90a18413
DH
971 s->vtfd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
972 if (s->vtfd < 0) {
973 log_error("cannot open VT %s of session %s: %m", path, s->id);
03e334a1 974 return -errno;
90a18413
DH
975 }
976
977 return s->vtfd;
978}
979
baccf3e4 980int session_prepare_vt(Session *s) {
90a18413
DH
981 int vt, r;
982 struct vt_mode mode = { 0 };
90a18413 983
baccf3e4
OB
984 if (s->vtnr < 1)
985 return 0;
986
90a18413
DH
987 vt = session_open_vt(s);
988 if (vt < 0)
baccf3e4 989 return vt;
90a18413 990
d6176c6c 991 r = fchown(vt, s->user->uid, -1);
baccf3e4
OB
992 if (r < 0) {
993 r = -errno;
994 log_error("Cannot change owner of /dev/tty%u: %m", s->vtnr);
d6176c6c 995 goto error;
baccf3e4 996 }
d6176c6c 997
90a18413 998 r = ioctl(vt, KDSKBMODE, K_OFF);
baccf3e4
OB
999 if (r < 0) {
1000 r = -errno;
1001 log_error("Cannot set K_OFF on /dev/tty%u: %m", s->vtnr);
90a18413 1002 goto error;
baccf3e4 1003 }
90a18413
DH
1004
1005 r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
baccf3e4
OB
1006 if (r < 0) {
1007 r = -errno;
1008 log_error("Cannot set KD_GRAPHICS on /dev/tty%u: %m", s->vtnr);
90a18413 1009 goto error;
baccf3e4 1010 }
90a18413 1011
90a18413
DH
1012 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1013 * So we need a dummy handler here which just acknowledges *all* VT
1014 * switch requests. */
1015 mode.mode = VT_PROCESS;
92683ad2
DH
1016 mode.relsig = SIGRTMIN;
1017 mode.acqsig = SIGRTMIN + 1;
90a18413 1018 r = ioctl(vt, VT_SETMODE, &mode);
baccf3e4
OB
1019 if (r < 0) {
1020 r = -errno;
1021 log_error("Cannot set VT_PROCESS on /dev/tty%u: %m", s->vtnr);
90a18413 1022 goto error;
baccf3e4 1023 }
90a18413 1024
baccf3e4 1025 return 0;
90a18413
DH
1026
1027error:
90a18413 1028 session_restore_vt(s);
baccf3e4 1029 return r;
90a18413
DH
1030}
1031
1032void session_restore_vt(Session *s) {
a0eb2a75 1033 _cleanup_free_ char *utf8 = NULL;
90a18413
DH
1034 int vt, kb = K_XLATE;
1035 struct vt_mode mode = { 0 };
1036
1037 vt = session_open_vt(s);
1038 if (vt < 0)
1039 return;
1040
90a18413
DH
1041 ioctl(vt, KDSETMODE, KD_TEXT);
1042
1043 if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
1044 kb = K_UNICODE;
03e334a1 1045
90a18413
DH
1046 ioctl(vt, KDSKBMODE, kb);
1047
1048 mode.mode = VT_AUTO;
1049 ioctl(vt, VT_SETMODE, &mode);
1050
d6176c6c
RS
1051 fchown(vt, 0, -1);
1052
03e334a1 1053 s->vtfd = safe_close(s->vtfd);
90a18413
DH
1054}
1055
2ec3ff66 1056void session_leave_vt(Session *s) {
ce540a24
DH
1057 int r;
1058
2ec3ff66
DH
1059 assert(s);
1060
1061 /* This is called whenever we get a VT-switch signal from the kernel.
1062 * We acknowledge all of them unconditionally. Note that session are
1063 * free to overwrite those handlers and we only register them for
1064 * sessions with controllers. Legacy sessions are not affected.
1065 * However, if we switch from a non-legacy to a legacy session, we must
1066 * make sure to pause all device before acknowledging the switch. We
1067 * process the real switch only after we are notified via sysfs, so the
1068 * legacy session might have already started using the devices. If we
1069 * don't pause the devices before the switch, we might confuse the
1070 * session we switch to. */
1071
1072 if (s->vtfd < 0)
1073 return;
1074
1075 session_device_pause_all(s);
ce540a24
DH
1076 r = ioctl(s->vtfd, VT_RELDISP, 1);
1077 if (r < 0)
1078 log_debug("Cannot release VT of session %s: %m", s->id);
2ec3ff66
DH
1079}
1080
cc377381 1081bool session_is_controller(Session *s, const char *sender) {
ae5e06bd
DH
1082 assert(s);
1083
1084 return streq_ptr(s->controller, sender);
1085}
1086
b12e5615
DH
1087static void session_release_controller(Session *s, bool notify) {
1088 _cleanup_free_ char *name = NULL;
6d33772f
DH
1089 SessionDevice *sd;
1090
b12e5615
DH
1091 if (!s->controller)
1092 return;
6d33772f 1093
b12e5615 1094 name = s->controller;
90a18413 1095
b12e5615
DH
1096 /* By resetting the controller before releasing the devices, we won't
1097 * send notification signals. This avoids sending useless notifications
1098 * if the controller is released on disconnects. */
1099 if (!notify)
1100 s->controller = NULL;
6d33772f 1101
b12e5615
DH
1102 while ((sd = hashmap_first(s->devices)))
1103 session_device_free(sd);
1104
1105 s->controller = NULL;
1106 manager_drop_busname(s->manager, name);
6d33772f
DH
1107}
1108
ae5e06bd 1109int session_set_controller(Session *s, const char *sender, bool force) {
b12e5615 1110 _cleanup_free_ char *name = NULL;
ae5e06bd
DH
1111 int r;
1112
1113 assert(s);
1114 assert(sender);
1115
1116 if (session_is_controller(s, sender))
1117 return 0;
1118 if (s->controller && !force)
1119 return -EBUSY;
1120
b12e5615
DH
1121 name = strdup(sender);
1122 if (!name)
ae5e06bd
DH
1123 return -ENOMEM;
1124
b12e5615
DH
1125 r = manager_watch_busname(s->manager, name);
1126 if (r)
ae5e06bd 1127 return r;
ae5e06bd 1128
90a18413
DH
1129 /* When setting a session controller, we forcibly mute the VT and set
1130 * it into graphics-mode. Applications can override that by changing
1131 * VT state after calling TakeControl(). However, this serves as a good
1132 * default and well-behaving controllers can now ignore VTs entirely.
1133 * Note that we reset the VT on ReleaseControl() and if the controller
1134 * exits.
1135 * If logind crashes/restarts, we restore the controller during restart
1136 * or reset the VT in case it crashed/exited, too. */
baccf3e4 1137 r = session_prepare_vt(s);
13f493dc 1138 if (r < 0) {
b12e5615 1139 manager_drop_busname(s->manager, name);
baccf3e4 1140 return r;
13f493dc 1141 }
baccf3e4 1142
b12e5615
DH
1143 session_release_controller(s, true);
1144 s->controller = name;
1145 name = NULL;
1146 session_save(s);
90a18413 1147
ae5e06bd
DH
1148 return 0;
1149}
1150
1151void session_drop_controller(Session *s) {
1152 assert(s);
1153
1154 if (!s->controller)
1155 return;
1156
b12e5615
DH
1157 session_release_controller(s, false);
1158 session_save(s);
1159 session_restore_vt(s);
ae5e06bd
DH
1160}
1161
fb6becb4
LP
1162static const char* const session_state_table[_SESSION_STATE_MAX] = {
1163 [SESSION_OPENING] = "opening",
0604381b
LP
1164 [SESSION_ONLINE] = "online",
1165 [SESSION_ACTIVE] = "active",
1166 [SESSION_CLOSING] = "closing"
1167};
1168
1169DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1170
20263082 1171static const char* const session_type_table[_SESSION_TYPE_MAX] = {
2c5859af 1172 [SESSION_UNSPECIFIED] = "unspecified",
3f49d45a 1173 [SESSION_TTY] = "tty",
98a28fef 1174 [SESSION_X11] = "x11",
d9eb81f9 1175 [SESSION_WAYLAND] = "wayland",
9541666b 1176 [SESSION_MIR] = "mir",
e9e74f28 1177 [SESSION_WEB] = "web",
20263082
LP
1178};
1179
1180DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
de07ab16 1181
55efac6c
LP
1182static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1183 [SESSION_USER] = "user",
1184 [SESSION_GREETER] = "greeter",
e2acb67b
LP
1185 [SESSION_LOCK_SCREEN] = "lock-screen",
1186 [SESSION_BACKGROUND] = "background"
55efac6c
LP
1187};
1188
1189DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1190
de07ab16
LP
1191static const char* const kill_who_table[_KILL_WHO_MAX] = {
1192 [KILL_LEADER] = "leader",
1193 [KILL_ALL] = "all"
1194};
1195
1196DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);