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