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