]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/logind-seat.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
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 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include <sys/ioctl.h>
30 #include "logind-seat.h"
31 #include "logind-acl.h"
34 Seat
*seat_new(Manager
*m
, const char *id
) {
44 s
->state_file
= strappend("/run/systemd/seat/", id
);
50 s
->id
= file_name_from_path(s
->state_file
);
53 if (hashmap_put(m
->seats
, s
->id
, s
) < 0) {
62 void seat_free(Seat
*s
) {
66 LIST_REMOVE(Seat
, gc_queue
, s
->manager
->seat_gc_queue
, s
);
69 session_free(s
->sessions
);
74 device_free(s
->devices
);
76 hashmap_remove(s
->manager
->seats
, s
->id
);
82 int seat_save(Seat
*s
) {
89 r
= safe_mkdir("/run/systemd/seat", 0755, 0, 0);
93 r
= fopen_temporary(s
->state_file
, &f
, &temp_path
);
97 fchmod(fileno(f
), 0644);
100 "# This is private data. Do not parse.\n"
102 s
->manager
->vtconsole
== s
);
105 assert(s
->active
->user
);
111 (unsigned long) s
->active
->user
->uid
);
118 LIST_FOREACH(sessions_by_seat
, i
, s
->sessions
) {
125 i
->sessions_by_seat_next
? ' ' : '\n');
128 fputs("OTHER_UIDS=", f
);
129 LIST_FOREACH(sessions_by_seat
, i
, s
->sessions
) {
135 (unsigned long) i
->user
->uid
,
136 i
->sessions_by_seat_next
? ' ' : '\n');
142 if (ferror(f
) || rename(temp_path
, s
->state_file
) < 0) {
144 unlink(s
->state_file
);
153 log_error("Failed to save seat data for %s: %s", s
->id
, strerror(-r
));
158 int seat_load(Seat
*s
) {
164 static int vt_allocate(int vtnr
) {
170 if (asprintf(&p
, "/dev/tty%i", vtnr
) < 0)
173 fd
= open_terminal(p
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
176 r
= fd
< 0 ? -errno
: 0;
179 close_nointr_nofail(fd
);
184 static int seat_preallocate_vts(Seat
*s
) {
191 if (s
->manager
->n_autovts
<= 0)
194 if (s
->manager
->vtconsole
!= s
)
197 for (i
= 1; i
< s
->manager
->n_autovts
; i
++) {
202 log_error("Failed to preallocate VT %i: %s", i
, strerror(-q
));
210 int seat_apply_acls(Seat
*s
, Session
*old_active
) {
215 r
= devnode_acl_all(s
->manager
->udev
,
218 !!old_active
, old_active
? old_active
->user
->uid
: 0,
219 !!s
->active
, s
->active
? s
->active
->user
->uid
: 0);
222 log_error("Failed to apply ACLs: %s", strerror(-r
));
227 int seat_active_vt_changed(Seat
*s
, int vtnr
) {
228 Session
*i
, *new_active
= NULL
, *old_active
;
233 if (s
->manager
->vtconsole
!= s
)
236 log_debug("VT changed to %i", vtnr
);
238 LIST_FOREACH(sessions_by_seat
, i
, s
->sessions
)
239 if (i
->vtnr
== vtnr
) {
244 if (new_active
== s
->active
)
247 old_active
= s
->active
;
248 s
->active
= new_active
;
250 seat_apply_acls(s
, old_active
);
251 manager_spawn_autovt(s
->manager
, vtnr
);
256 int seat_read_active_vt(Seat
*s
) {
263 if (s
->manager
->vtconsole
!= s
)
266 lseek(s
->manager
->console_active_fd
, SEEK_SET
, 0);
268 k
= read(s
->manager
->console_active_fd
, t
, sizeof(t
)-1);
270 log_error("Failed to read current console: %s", k
< 0 ? strerror(-errno
) : "EOF");
271 return k
< 0 ? -errno
: -EIO
;
277 if (!startswith(t
, "tty")) {
278 log_error("Hm, /sys/class/tty/tty0/active is badly formatted.");
282 r
= safe_atoi(t
+3, &vtnr
);
284 log_error("Failed to parse VT number %s", t
+3);
289 log_error("VT number invalid: %s", t
+3);
293 return seat_active_vt_changed(s
, vtnr
);
296 int seat_start(Seat
*s
) {
302 log_info("New seat %s.", s
->id
);
304 /* Initialize VT magic stuff */
305 seat_preallocate_vts(s
);
307 /* Read current VT */
308 seat_read_active_vt(s
);
318 int seat_stop(Seat
*s
) {
327 log_info("Removed seat %s.", s
->id
);
329 LIST_FOREACH(sessions_by_seat
, session
, s
->sessions
) {
330 k
= session_stop(session
);
335 unlink(s
->state_file
);
336 seat_add_to_gc_queue(s
);
343 int seat_check_gc(Seat
*s
) {
346 if (s
->manager
->vtconsole
== s
)
352 void seat_add_to_gc_queue(Seat
*s
) {
358 LIST_PREPEND(Seat
, gc_queue
, s
->manager
->seat_gc_queue
, s
);
359 s
->in_gc_queue
= true;
362 static bool seat_name_valid_char(char c
) {
364 (c
>= 'a' && c
<= 'z') ||
365 (c
>= 'A' && c
<= 'Z') ||
366 (c
>= '0' && c
<= '9') ||
371 bool seat_name_is_valid(const char *name
) {
376 if (!startswith(name
, "seat"))
382 for (p
= name
; *p
; p
++)
383 if (!seat_name_valid_char(*p
))