]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-session.c
man: revise entry about specifying a file path (#3739)
[thirdparty/systemd.git] / src / login / logind-session.c
CommitLineData
20263082
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2011 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
20263082
LP
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 14 Lesser General Public License for more details.
20263082 15
5430f7f2 16 You should have received a copy of the GNU Lesser General Public License
20263082
LP
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
20#include <errno.h>
90a18413 21#include <fcntl.h>
90a18413 22#include <linux/kd.h>
4f5dd394 23#include <linux/vt.h>
90a18413 24#include <signal.h>
20263082 25#include <string.h>
90a18413 26#include <sys/ioctl.h>
20263082
LP
27#include <unistd.h>
28
cc377381 29#include "sd-messages.h"
4f5dd394 30
b5efdb8a 31#include "alloc-util.h"
430f0182 32#include "audit-util.h"
cc377381 33#include "bus-error.h"
4f5dd394
LP
34#include "bus-util.h"
35#include "escape.h"
3ffd4af2 36#include "fd-util.h"
4f5dd394 37#include "fileio.h"
6482f626 38#include "formats-util.h"
c004493c 39#include "io-util.h"
3ffd4af2 40#include "logind-session.h"
4f5dd394 41#include "mkdir.h"
6bedfcbb 42#include "parse-util.h"
4f5dd394 43#include "path-util.h"
8b43440b 44#include "string-table.h"
288a74cc 45#include "terminal-util.h"
b1d4f8e1 46#include "user-util.h"
4f5dd394 47#include "util.h"
20263082 48
5f41d1f1
LP
49#define RELEASE_USEC (20*USEC_PER_SEC)
50
51static void session_remove_fifo(Session *s);
52
9444b1f2 53Session* session_new(Manager *m, const char *id) {
20263082
LP
54 Session *s;
55
56 assert(m);
57 assert(id);
4b549144 58 assert(session_id_valid(id));
20263082 59
14c3baca 60 s = new0(Session, 1);
20263082
LP
61 if (!s)
62 return NULL;
63
98a28fef 64 s->state_file = strappend("/run/systemd/sessions/", id);
20263082
LP
65 if (!s->state_file) {
66 free(s);
67 return NULL;
68 }
69
d5099efc 70 s->devices = hashmap_new(&devt_hash_ops);
118ecf32
DH
71 if (!s->devices) {
72 free(s->state_file);
73 free(s);
74 return NULL;
75 }
76
2b6bf07d 77 s->id = basename(s->state_file);
20263082
LP
78
79 if (hashmap_put(m->sessions, s->id, s) < 0) {
118ecf32 80 hashmap_free(s->devices);
f8e2fb7b 81 free(s->state_file);
20263082
LP
82 free(s);
83 return NULL;
84 }
85
86 s->manager = m;
932e3ee7 87 s->fifo_fd = -1;
90a18413 88 s->vtfd = -1;
20263082
LP
89
90 return s;
91}
92
93void session_free(Session *s) {
118ecf32
DH
94 SessionDevice *sd;
95
20263082
LP
96 assert(s);
97
14c3baca 98 if (s->in_gc_queue)
71fda00f 99 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
14c3baca 100
5f41d1f1
LP
101 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
102
cc377381
LP
103 session_remove_fifo(s);
104
ae5e06bd
DH
105 session_drop_controller(s);
106
118ecf32
DH
107 while ((sd = hashmap_first(s->devices)))
108 session_device_free(sd);
109
110 hashmap_free(s->devices);
111
20263082 112 if (s->user) {
71fda00f 113 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
20263082
LP
114
115 if (s->user->display == s)
116 s->user->display = NULL;
117 }
118
9418f147
LP
119 if (s->seat) {
120 if (s->seat->active == s)
121 s->seat->active = NULL;
d7bd01b5
DH
122 if (s->seat->pending_switch == s)
123 s->seat->pending_switch = NULL;
9418f147 124
49e6fdbf 125 seat_evict_position(s->seat, s);
71fda00f 126 LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
9418f147 127 }
20263082 128
fb6becb4
LP
129 if (s->scope) {
130 hashmap_remove(s->manager->session_units, s->scope);
131 free(s->scope);
132 }
133
134 free(s->scope_job);
1713813d 135
cc377381 136 sd_bus_message_unref(s->create_message);
20263082
LP
137
138 free(s->tty);
139 free(s->display);
140 free(s->remote_host);
3f49d45a 141 free(s->remote_user);
98a28fef 142 free(s->service);
a4cd87e9 143 free(s->desktop);
20263082
LP
144
145 hashmap_remove(s->manager->sessions, s->id);
98a28fef 146
d2f92cdf 147 free(s->state_file);
20263082
LP
148 free(s);
149}
150
9444b1f2
LP
151void session_set_user(Session *s, User *u) {
152 assert(s);
153 assert(!s->user);
154
155 s->user = u;
71fda00f 156 LIST_PREPEND(sessions_by_user, u->sessions, s);
9444b1f2
LP
157}
158
20263082 159int session_save(Session *s) {
507f22bd 160 _cleanup_free_ char *temp_path = NULL;
cc377381 161 _cleanup_fclose_ FILE *f = NULL;
20263082
LP
162 int r = 0;
163
164 assert(s);
165
9444b1f2
LP
166 if (!s->user)
167 return -ESTALE;
168
accaeded
LP
169 if (!s->started)
170 return 0;
171
d2e54fae 172 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
20263082 173 if (r < 0)
dacd6cee 174 goto fail;
20263082 175
14c3baca
LP
176 r = fopen_temporary(s->state_file, &f, &temp_path);
177 if (r < 0)
dacd6cee 178 goto fail;
20263082
LP
179
180 assert(s->user);
181
14c3baca
LP
182 fchmod(fileno(f), 0644);
183
20263082
LP
184 fprintf(f,
185 "# This is private data. Do not parse.\n"
90b2de37 186 "UID="UID_FMT"\n"
20263082
LP
187 "USER=%s\n"
188 "ACTIVE=%i\n"
0604381b 189 "STATE=%s\n"
fb6becb4 190 "REMOTE=%i\n",
90b2de37 191 s->user->uid,
20263082
LP
192 s->user->name,
193 session_is_active(s),
0604381b 194 session_state_to_string(session_get_state(s)),
fb6becb4 195 s->remote);
20263082 196
a91e4e53 197 if (s->type >= 0)
507f22bd 198 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
a91e4e53 199
55efac6c 200 if (s->class >= 0)
507f22bd 201 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
55efac6c 202
fb6becb4
LP
203 if (s->scope)
204 fprintf(f, "SCOPE=%s\n", s->scope);
fb6becb4
LP
205 if (s->scope_job)
206 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
20263082 207
932e3ee7 208 if (s->fifo_path)
507f22bd 209 fprintf(f, "FIFO=%s\n", s->fifo_path);
932e3ee7 210
20263082 211 if (s->seat)
507f22bd 212 fprintf(f, "SEAT=%s\n", s->seat->id);
20263082
LP
213
214 if (s->tty)
507f22bd 215 fprintf(f, "TTY=%s\n", s->tty);
20263082
LP
216
217 if (s->display)
507f22bd 218 fprintf(f, "DISPLAY=%s\n", s->display);
20263082 219
558c6490
LP
220 if (s->remote_host) {
221 _cleanup_free_ char *escaped;
222
223 escaped = cescape(s->remote_host);
224 if (!escaped) {
225 r = -ENOMEM;
dacd6cee 226 goto fail;
558c6490
LP
227 }
228
229 fprintf(f, "REMOTE_HOST=%s\n", escaped);
230 }
231
232 if (s->remote_user) {
233 _cleanup_free_ char *escaped;
234
235 escaped = cescape(s->remote_user);
236 if (!escaped) {
237 r = -ENOMEM;
dacd6cee 238 goto fail;
558c6490
LP
239 }
240
241 fprintf(f, "REMOTE_USER=%s\n", escaped);
242 }
243
244 if (s->service) {
245 _cleanup_free_ char *escaped;
20263082 246
558c6490
LP
247 escaped = cescape(s->service);
248 if (!escaped) {
249 r = -ENOMEM;
dacd6cee 250 goto fail;
558c6490
LP
251 }
252
253 fprintf(f, "SERVICE=%s\n", escaped);
254 }
3f49d45a 255
558c6490
LP
256 if (s->desktop) {
257 _cleanup_free_ char *escaped;
98a28fef 258
558c6490
LP
259
260 escaped = cescape(s->desktop);
261 if (!escaped) {
262 r = -ENOMEM;
dacd6cee 263 goto fail;
558c6490
LP
264 }
265
266 fprintf(f, "DESKTOP=%s\n", escaped);
267 }
a4cd87e9 268
bf7825ae 269 if (s->seat && seat_has_vts(s->seat))
92bd5ff3 270 fprintf(f, "VTNR=%u\n", s->vtnr);
20263082 271
49e6fdbf 272 if (!s->vtnr)
e6494a07 273 fprintf(f, "POSITION=%u\n", s->position);
49e6fdbf 274
20263082 275 if (s->leader > 0)
90b2de37 276 fprintf(f, "LEADER="PID_FMT"\n", s->leader);
20263082
LP
277
278 if (s->audit_id > 0)
507f22bd 279 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
20263082 280
9444b1f2
LP
281 if (dual_timestamp_is_set(&s->timestamp))
282 fprintf(f,
90b2de37
ZJS
283 "REALTIME="USEC_FMT"\n"
284 "MONOTONIC="USEC_FMT"\n",
285 s->timestamp.realtime,
286 s->timestamp.monotonic);
9444b1f2 287
6d33772f
DH
288 if (s->controller)
289 fprintf(f, "CONTROLLER=%s\n", s->controller);
290
dacd6cee
LP
291 r = fflush_and_check(f);
292 if (r < 0)
293 goto fail;
14c3baca 294
dacd6cee 295 if (rename(temp_path, s->state_file) < 0) {
20263082 296 r = -errno;
dacd6cee 297 goto fail;
20263082
LP
298 }
299
dacd6cee
LP
300 return 0;
301
302fail:
303 (void) unlink(s->state_file);
14c3baca 304
dacd6cee
LP
305 if (temp_path)
306 (void) unlink(temp_path);
307
308 return log_error_errno(r, "Failed to save session data %s: %m", s->state_file);
20263082
LP
309}
310
dacd6cee 311
20263082 312int session_load(Session *s) {
9444b1f2 313 _cleanup_free_ char *remote = NULL,
a185c5aa
LP
314 *seat = NULL,
315 *vtnr = NULL,
be94d954 316 *state = NULL,
e6494a07 317 *position = NULL,
a185c5aa 318 *leader = NULL,
55efac6c 319 *type = NULL,
9444b1f2
LP
320 *class = NULL,
321 *uid = NULL,
322 *realtime = NULL,
6d33772f
DH
323 *monotonic = NULL,
324 *controller = NULL;
a185c5aa
LP
325
326 int k, r;
327
20263082
LP
328 assert(s);
329
a185c5aa
LP
330 r = parse_env_file(s->state_file, NEWLINE,
331 "REMOTE", &remote,
fb6becb4
LP
332 "SCOPE", &s->scope,
333 "SCOPE_JOB", &s->scope_job,
932e3ee7 334 "FIFO", &s->fifo_path,
a185c5aa
LP
335 "SEAT", &seat,
336 "TTY", &s->tty,
337 "DISPLAY", &s->display,
338 "REMOTE_HOST", &s->remote_host,
339 "REMOTE_USER", &s->remote_user,
98a28fef 340 "SERVICE", &s->service,
a4cd87e9 341 "DESKTOP", &s->desktop,
a185c5aa 342 "VTNR", &vtnr,
be94d954 343 "STATE", &state,
e6494a07 344 "POSITION", &position,
a185c5aa 345 "LEADER", &leader,
a91e4e53 346 "TYPE", &type,
55efac6c 347 "CLASS", &class,
9444b1f2
LP
348 "UID", &uid,
349 "REALTIME", &realtime,
350 "MONOTONIC", &monotonic,
6d33772f 351 "CONTROLLER", &controller,
a185c5aa
LP
352 NULL);
353
f647962d
MS
354 if (r < 0)
355 return log_error_errno(r, "Failed to read %s: %m", s->state_file);
9444b1f2
LP
356
357 if (!s->user) {
358 uid_t u;
359 User *user;
360
361 if (!uid) {
362 log_error("UID not specified for session %s", s->id);
363 return -ENOENT;
364 }
365
366 r = parse_uid(uid, &u);
367 if (r < 0) {
368 log_error("Failed to parse UID value %s for session %s.", uid, s->id);
369 return r;
370 }
371
8cb4ab00 372 user = hashmap_get(s->manager->users, UID_TO_PTR(u));
9444b1f2
LP
373 if (!user) {
374 log_error("User of session %s not known.", s->id);
375 return -ENOENT;
376 }
377
378 session_set_user(s, user);
379 }
a185c5aa
LP
380
381 if (remote) {
382 k = parse_boolean(remote);
383 if (k >= 0)
384 s->remote = k;
385 }
386
c506027a
DH
387 if (vtnr)
388 safe_atou(vtnr, &s->vtnr);
389
9418f147 390 if (seat && !s->seat) {
a185c5aa
LP
391 Seat *o;
392
393 o = hashmap_get(s->manager->seats, seat);
394 if (o)
c506027a
DH
395 r = seat_attach_session(o, s);
396 if (!o || r < 0)
397 log_error("Cannot attach session %s to seat %s", s->id, seat);
a185c5aa
LP
398 }
399
c506027a
DH
400 if (!s->seat || !seat_has_vts(s->seat))
401 s->vtnr = 0;
a185c5aa 402
e6494a07 403 if (position && s->seat) {
49e6fdbf
DH
404 unsigned int npos;
405
e6494a07 406 safe_atou(position, &npos);
49e6fdbf
DH
407 seat_claim_position(s->seat, s, npos);
408 }
409
a185c5aa 410 if (leader) {
f8e2fb7b
LP
411 k = parse_pid(leader, &s->leader);
412 if (k >= 0)
413 audit_session_from_pid(s->leader, &s->audit_id);
a185c5aa
LP
414 }
415
a91e4e53
LP
416 if (type) {
417 SessionType t;
418
419 t = session_type_from_string(type);
420 if (t >= 0)
421 s->type = t;
422 }
423
55efac6c
LP
424 if (class) {
425 SessionClass c;
426
427 c = session_class_from_string(class);
428 if (c >= 0)
429 s->class = c;
430 }
431
be94d954
MP
432 if (state && streq(state, "closing"))
433 s->stopping = true;
434
b4f78aea
LP
435 if (s->fifo_path) {
436 int fd;
437
438 /* If we open an unopened pipe for reading we will not
439 get an EOF. to trigger an EOF we hence open it for
be94d954
MP
440 writing, but close it right away which then will
441 trigger the EOF. This will happen immediately if no
442 other process has the FIFO open for writing, i. e.
443 when the session died before logind (re)started. */
b4f78aea
LP
444
445 fd = session_create_fifo(s);
03e334a1 446 safe_close(fd);
b4f78aea
LP
447 }
448
b895a735
BR
449 if (realtime)
450 timestamp_deserialize(realtime, &s->timestamp.realtime);
451 if (monotonic)
452 timestamp_deserialize(monotonic, &s->timestamp.monotonic);
a185c5aa 453
6d33772f
DH
454 if (controller) {
455 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
456 session_set_controller(s, controller, false);
90a18413
DH
457 else
458 session_restore_vt(s);
6d33772f
DH
459 }
460
a185c5aa 461 return r;
20263082
LP
462}
463
464int session_activate(Session *s) {
d7bd01b5
DH
465 unsigned int num_pending;
466
20263082 467 assert(s);
9444b1f2 468 assert(s->user);
20263082 469
20263082 470 if (!s->seat)
15411c0c 471 return -EOPNOTSUPP;
20263082
LP
472
473 if (s->seat->active == s)
474 return 0;
475
d7bd01b5
DH
476 /* on seats with VTs, we let VTs manage session-switching */
477 if (seat_has_vts(s->seat)) {
92bd5ff3 478 if (!s->vtnr)
15411c0c 479 return -EOPNOTSUPP;
d7bd01b5
DH
480
481 return chvt(s->vtnr);
482 }
483
484 /* On seats without VTs, we implement session-switching in logind. We
485 * try to pause all session-devices and wait until the session
486 * controller acknowledged them. Once all devices are asleep, we simply
487 * switch the active session and be done.
488 * We save the session we want to switch to in seat->pending_switch and
489 * seat_complete_switch() will perform the final switch. */
490
491 s->seat->pending_switch = s;
492
493 /* if no devices are running, immediately perform the session switch */
494 num_pending = session_device_try_pause_all(s);
495 if (!num_pending)
496 seat_complete_switch(s->seat);
20263082 497
d7bd01b5 498 return 0;
20263082
LP
499}
500
fb6becb4 501static int session_start_scope(Session *s) {
98a28fef
LP
502 int r;
503
504 assert(s);
9444b1f2 505 assert(s->user);
98a28fef 506
fb6becb4 507 if (!s->scope) {
4afd3348 508 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
39883f62 509 char *scope, *job = NULL;
90558f31 510 const char *description;
405e0255 511
d0af76e6
LP
512 scope = strjoin("session-", s->id, ".scope", NULL);
513 if (!scope)
ae018d9b
LP
514 return log_oom();
515
81d62103 516 description = strjoina("Session ", s->id, " of user ", s->user->name);
90558f31
LP
517
518 r = manager_start_scope(
519 s->manager,
520 scope,
521 s->leader,
522 s->user->slice,
523 description,
524 "systemd-logind.service",
525 "systemd-user-sessions.service",
526 (uint64_t) -1, /* disable TasksMax= for the scope, rely on the slice setting for it */
527 &error,
528 &job);
d0af76e6 529 if (r < 0) {
90558f31 530 log_error_errno(r, "Failed to start session scope %s: %s", scope, bus_error_message(&error, r));
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 541 if (s->scope)
90558f31 542 (void) hashmap_put(s->manager->session_units, s->scope, s);
d0af76e6 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) {
4afd3348 605 _cleanup_(sd_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 799 * idle hint logic */
129baf1b 800 if (SESSION_TYPE_IS_GRAPHICAL(s->type))
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
42d35e13
VT
855int session_get_locked_hint(Session *s) {
856 assert(s);
857
858 return s->locked_hint;
859}
860
861void session_set_locked_hint(Session *s, bool b) {
862 assert(s);
863
864 if (s->locked_hint == b)
865 return;
866
867 s->locked_hint = b;
868
869 session_send_changed(s, "LockedHint", NULL);
870}
871
cc377381
LP
872static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
873 Session *s = userdata;
874
875 assert(s);
876 assert(s->fifo_fd == fd);
877
878 /* EOF on the FIFO means the session died abnormally. */
879
880 session_remove_fifo(s);
9bb69af4 881 session_stop(s, false);
cc377381
LP
882
883 return 1;
bef422ae
LP
884}
885
932e3ee7
LP
886int session_create_fifo(Session *s) {
887 int r;
888
31b79c2b
LP
889 assert(s);
890
b4f78aea 891 /* Create FIFO */
932e3ee7 892 if (!s->fifo_path) {
d2e54fae 893 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
e6061ab2
LP
894 if (r < 0)
895 return r;
896
932e3ee7
LP
897 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
898 return -ENOMEM;
31b79c2b 899
932e3ee7
LP
900 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
901 return -errno;
902 }
31b79c2b 903
932e3ee7 904 /* Open reading side */
b4f78aea 905 if (s->fifo_fd < 0) {
b4f78aea
LP
906 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
907 if (s->fifo_fd < 0)
908 return -errno;
909
cc377381
LP
910 }
911
912 if (!s->fifo_event_source) {
151b9b96 913 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
b4f78aea
LP
914 if (r < 0)
915 return r;
916
e11544a8
LP
917 /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new
918 * sessions). */
919 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10);
cc377381
LP
920 if (r < 0)
921 return r;
b4f78aea 922 }
932e3ee7
LP
923
924 /* Open writing side */
925 r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
926 if (r < 0)
927 return -errno;
31b79c2b 928
932e3ee7
LP
929 return r;
930}
931
5f41d1f1 932static void session_remove_fifo(Session *s) {
932e3ee7
LP
933 assert(s);
934
03e334a1
LP
935 s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
936 s->fifo_fd = safe_close(s->fifo_fd);
932e3ee7
LP
937
938 if (s->fifo_path) {
939 unlink(s->fifo_path);
a1e58e8e 940 s->fifo_path = mfree(s->fifo_path);
932e3ee7 941 }
31b79c2b
LP
942}
943
cc377381 944bool session_check_gc(Session *s, bool drop_not_started) {
20263082
LP
945 assert(s);
946
4a4b033f 947 if (drop_not_started && !s->started)
cc377381 948 return false;
932e3ee7 949
9444b1f2 950 if (!s->user)
cc377381 951 return false;
9444b1f2 952
932e3ee7 953 if (s->fifo_fd >= 0) {
5f41d1f1 954 if (pipe_eof(s->fifo_fd) <= 0)
cc377381 955 return true;
20263082
LP
956 }
957
cc377381
LP
958 if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
959 return true;
20263082 960
cc377381
LP
961 if (s->scope && manager_unit_is_active(s->manager, s->scope))
962 return true;
20263082 963
cc377381 964 return false;
20263082
LP
965}
966
14c3baca
LP
967void session_add_to_gc_queue(Session *s) {
968 assert(s);
969
970 if (s->in_gc_queue)
971 return;
972
71fda00f 973 LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
14c3baca
LP
974 s->in_gc_queue = true;
975}
976
0604381b
LP
977SessionState session_get_state(Session *s) {
978 assert(s);
979
8fe63cd4 980 /* always check closing first */
5f41d1f1
LP
981 if (s->stopping || s->timer_event_source)
982 return SESSION_CLOSING;
983
8fe63cd4 984 if (s->scope_job || s->fifo_fd < 0)
405e0255 985 return SESSION_OPENING;
fb6becb4 986
0604381b
LP
987 if (session_is_active(s))
988 return SESSION_ACTIVE;
989
990 return SESSION_ONLINE;
991}
992
de07ab16 993int session_kill(Session *s, KillWho who, int signo) {
de07ab16
LP
994 assert(s);
995
fb6becb4 996 if (!s->scope)
de07ab16
LP
997 return -ESRCH;
998
fb6becb4 999 return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
de07ab16
LP
1000}
1001
90a18413 1002static int session_open_vt(Session *s) {
5f41d1f1 1003 char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
90a18413 1004
baccf3e4
OB
1005 if (s->vtnr < 1)
1006 return -ENODEV;
90a18413
DH
1007
1008 if (s->vtfd >= 0)
1009 return s->vtfd;
1010
92bd5ff3 1011 sprintf(path, "/dev/tty%u", s->vtnr);
22356953 1012 s->vtfd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
4a62c710 1013 if (s->vtfd < 0)
709f6e46 1014 return log_error_errno(s->vtfd, "cannot open VT %s of session %s: %m", path, s->id);
90a18413
DH
1015
1016 return s->vtfd;
1017}
1018
baccf3e4 1019int session_prepare_vt(Session *s) {
90a18413
DH
1020 int vt, r;
1021 struct vt_mode mode = { 0 };
90a18413 1022
baccf3e4
OB
1023 if (s->vtnr < 1)
1024 return 0;
1025
90a18413
DH
1026 vt = session_open_vt(s);
1027 if (vt < 0)
baccf3e4 1028 return vt;
90a18413 1029
d6176c6c 1030 r = fchown(vt, s->user->uid, -1);
baccf3e4 1031 if (r < 0) {
94c156cd
LP
1032 r = log_error_errno(errno,
1033 "Cannot change owner of /dev/tty%u: %m",
1034 s->vtnr);
d6176c6c 1035 goto error;
baccf3e4 1036 }
d6176c6c 1037
90a18413 1038 r = ioctl(vt, KDSKBMODE, K_OFF);
baccf3e4 1039 if (r < 0) {
94c156cd
LP
1040 r = log_error_errno(errno,
1041 "Cannot set K_OFF on /dev/tty%u: %m",
1042 s->vtnr);
90a18413 1043 goto error;
baccf3e4 1044 }
90a18413
DH
1045
1046 r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
baccf3e4 1047 if (r < 0) {
94c156cd
LP
1048 r = log_error_errno(errno,
1049 "Cannot set KD_GRAPHICS on /dev/tty%u: %m",
1050 s->vtnr);
90a18413 1051 goto error;
baccf3e4 1052 }
90a18413 1053
90a18413
DH
1054 /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
1055 * So we need a dummy handler here which just acknowledges *all* VT
1056 * switch requests. */
1057 mode.mode = VT_PROCESS;
92683ad2
DH
1058 mode.relsig = SIGRTMIN;
1059 mode.acqsig = SIGRTMIN + 1;
90a18413 1060 r = ioctl(vt, VT_SETMODE, &mode);
baccf3e4 1061 if (r < 0) {
94c156cd
LP
1062 r = log_error_errno(errno,
1063 "Cannot set VT_PROCESS on /dev/tty%u: %m",
1064 s->vtnr);
90a18413 1065 goto error;
baccf3e4 1066 }
90a18413 1067
baccf3e4 1068 return 0;
90a18413
DH
1069
1070error:
90a18413 1071 session_restore_vt(s);
baccf3e4 1072 return r;
90a18413
DH
1073}
1074
1075void session_restore_vt(Session *s) {
16597ac3
LP
1076
1077 static const struct vt_mode mode = {
1078 .mode = VT_AUTO,
1079 };
1080
a0eb2a75 1081 _cleanup_free_ char *utf8 = NULL;
16597ac3 1082 int vt, kb, old_fd;
90a18413 1083
128df4cf
OT
1084 /* We need to get a fresh handle to the virtual terminal,
1085 * since the old file-descriptor is potentially in a hung-up
1086 * state after the controlling process exited; we do a
1087 * little dance to avoid having the terminal be available
1088 * for reuse before we've cleaned it up.
1089 */
16597ac3 1090 old_fd = s->vtfd;
128df4cf
OT
1091 s->vtfd = -1;
1092
90a18413 1093 vt = session_open_vt(s);
128df4cf
OT
1094 safe_close(old_fd);
1095
90a18413
DH
1096 if (vt < 0)
1097 return;
1098
2bf10523 1099 (void) ioctl(vt, KDSETMODE, KD_TEXT);
90a18413
DH
1100
1101 if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
1102 kb = K_UNICODE;
16597ac3
LP
1103 else
1104 kb = K_XLATE;
03e334a1 1105
2bf10523 1106 (void) ioctl(vt, KDSKBMODE, kb);
90a18413 1107
2bf10523 1108 (void) ioctl(vt, VT_SETMODE, &mode);
16597ac3 1109 (void) fchown(vt, 0, (gid_t) -1);
d6176c6c 1110
03e334a1 1111 s->vtfd = safe_close(s->vtfd);
90a18413
DH
1112}
1113
2ec3ff66 1114void session_leave_vt(Session *s) {
ce540a24
DH
1115 int r;
1116
2ec3ff66
DH
1117 assert(s);
1118
1119 /* This is called whenever we get a VT-switch signal from the kernel.
1120 * We acknowledge all of them unconditionally. Note that session are
1121 * free to overwrite those handlers and we only register them for
1122 * sessions with controllers. Legacy sessions are not affected.
1123 * However, if we switch from a non-legacy to a legacy session, we must
1124 * make sure to pause all device before acknowledging the switch. We
1125 * process the real switch only after we are notified via sysfs, so the
1126 * legacy session might have already started using the devices. If we
1127 * don't pause the devices before the switch, we might confuse the
1128 * session we switch to. */
1129
1130 if (s->vtfd < 0)
1131 return;
1132
1133 session_device_pause_all(s);
ce540a24
DH
1134 r = ioctl(s->vtfd, VT_RELDISP, 1);
1135 if (r < 0)
56f64d95 1136 log_debug_errno(errno, "Cannot release VT of session %s: %m", s->id);
2ec3ff66
DH
1137}
1138
cc377381 1139bool session_is_controller(Session *s, const char *sender) {
ae5e06bd
DH
1140 assert(s);
1141
1142 return streq_ptr(s->controller, sender);
1143}
1144
b12e5615
DH
1145static void session_release_controller(Session *s, bool notify) {
1146 _cleanup_free_ char *name = NULL;
6d33772f
DH
1147 SessionDevice *sd;
1148
b12e5615
DH
1149 if (!s->controller)
1150 return;
6d33772f 1151
b12e5615 1152 name = s->controller;
90a18413 1153
b12e5615
DH
1154 /* By resetting the controller before releasing the devices, we won't
1155 * send notification signals. This avoids sending useless notifications
1156 * if the controller is released on disconnects. */
1157 if (!notify)
1158 s->controller = NULL;
6d33772f 1159
b12e5615
DH
1160 while ((sd = hashmap_first(s->devices)))
1161 session_device_free(sd);
1162
1163 s->controller = NULL;
3cde9e8f
DM
1164 s->track = sd_bus_track_unref(s->track);
1165}
1166
1167static int on_bus_track(sd_bus_track *track, void *userdata) {
1168 Session *s = userdata;
1169
1170 assert(track);
1171 assert(s);
1172
1173 session_drop_controller(s);
1174
1175 return 0;
6d33772f
DH
1176}
1177
ae5e06bd 1178int session_set_controller(Session *s, const char *sender, bool force) {
b12e5615 1179 _cleanup_free_ char *name = NULL;
ae5e06bd
DH
1180 int r;
1181
1182 assert(s);
1183 assert(sender);
1184
1185 if (session_is_controller(s, sender))
1186 return 0;
1187 if (s->controller && !force)
1188 return -EBUSY;
1189
b12e5615
DH
1190 name = strdup(sender);
1191 if (!name)
ae5e06bd
DH
1192 return -ENOMEM;
1193
3cde9e8f
DM
1194 s->track = sd_bus_track_unref(s->track);
1195 r = sd_bus_track_new(s->manager->bus, &s->track, on_bus_track, s);
1196 if (r < 0)
1197 return r;
1198
1199 r = sd_bus_track_add_name(s->track, name);
1200 if (r < 0)
ae5e06bd 1201 return r;
ae5e06bd 1202
90a18413
DH
1203 /* When setting a session controller, we forcibly mute the VT and set
1204 * it into graphics-mode. Applications can override that by changing
1205 * VT state after calling TakeControl(). However, this serves as a good
1206 * default and well-behaving controllers can now ignore VTs entirely.
1207 * Note that we reset the VT on ReleaseControl() and if the controller
1208 * exits.
1209 * If logind crashes/restarts, we restore the controller during restart
1210 * or reset the VT in case it crashed/exited, too. */
baccf3e4 1211 r = session_prepare_vt(s);
13f493dc 1212 if (r < 0) {
3cde9e8f 1213 s->track = sd_bus_track_unref(s->track);
baccf3e4 1214 return r;
13f493dc 1215 }
baccf3e4 1216
b12e5615
DH
1217 session_release_controller(s, true);
1218 s->controller = name;
1219 name = NULL;
1220 session_save(s);
90a18413 1221
ae5e06bd
DH
1222 return 0;
1223}
1224
1225void session_drop_controller(Session *s) {
1226 assert(s);
1227
1228 if (!s->controller)
1229 return;
1230
3cde9e8f 1231 s->track = sd_bus_track_unref(s->track);
b12e5615
DH
1232 session_release_controller(s, false);
1233 session_save(s);
1234 session_restore_vt(s);
ae5e06bd
DH
1235}
1236
fb6becb4
LP
1237static const char* const session_state_table[_SESSION_STATE_MAX] = {
1238 [SESSION_OPENING] = "opening",
0604381b
LP
1239 [SESSION_ONLINE] = "online",
1240 [SESSION_ACTIVE] = "active",
1241 [SESSION_CLOSING] = "closing"
1242};
1243
1244DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
1245
20263082 1246static const char* const session_type_table[_SESSION_TYPE_MAX] = {
2c5859af 1247 [SESSION_UNSPECIFIED] = "unspecified",
3f49d45a 1248 [SESSION_TTY] = "tty",
98a28fef 1249 [SESSION_X11] = "x11",
d9eb81f9 1250 [SESSION_WAYLAND] = "wayland",
9541666b 1251 [SESSION_MIR] = "mir",
e9e74f28 1252 [SESSION_WEB] = "web",
20263082
LP
1253};
1254
1255DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
de07ab16 1256
55efac6c
LP
1257static const char* const session_class_table[_SESSION_CLASS_MAX] = {
1258 [SESSION_USER] = "user",
1259 [SESSION_GREETER] = "greeter",
e2acb67b
LP
1260 [SESSION_LOCK_SCREEN] = "lock-screen",
1261 [SESSION_BACKGROUND] = "background"
55efac6c
LP
1262};
1263
1264DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
1265
de07ab16
LP
1266static const char* const kill_who_table[_KILL_WHO_MAX] = {
1267 [KILL_LEADER] = "leader",
1268 [KILL_ALL] = "all"
1269};
1270
1271DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);