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