2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2011-05-23 23:55:06 +02:00
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2011 Lennart Poettering
|
|
|
|
|
|
|
|
systemd is free software; you can redistribute it and/or modify it
|
2012-04-12 00:20:58 +02:00
|
|
|
under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
2011-05-23 23:55:06 +02:00
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
systemd is distributed in the hope that it will be useful, but
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
2012-04-12 00:20:58 +02:00
|
|
|
Lesser General Public License for more details.
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2012-04-12 00:20:58 +02:00
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
2011-05-23 23:55:06 +02:00
|
|
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
2017-12-11 19:50:30 +01:00
|
|
|
#include <stdio_ext.h>
|
2011-05-24 04:20:35 +02:00
|
|
|
#include <string.h>
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <unistd.h>
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
#include "sd-messages.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2015-10-26 18:05:03 +01:00
|
|
|
#include "fileio.h"
|
2016-11-07 16:14:59 +01:00
|
|
|
#include "format-util.h"
|
2011-05-24 04:20:35 +02:00
|
|
|
#include "logind-acl.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "logind-seat.h"
|
2012-04-10 21:54:31 +02:00
|
|
|
#include "mkdir.h"
|
2015-10-26 16:18:16 +01:00
|
|
|
#include "parse-util.h"
|
2016-01-12 15:34:20 +01:00
|
|
|
#include "stdio-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "string-util.h"
|
2015-04-10 23:15:59 +02:00
|
|
|
#include "terminal-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "util.h"
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
Seat *seat_new(Manager *m, const char *id) {
|
|
|
|
Seat *s;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(id);
|
|
|
|
|
|
|
|
s = new0(Seat, 1);
|
|
|
|
if (!s)
|
|
|
|
return NULL;
|
|
|
|
|
2011-06-24 18:50:50 +02:00
|
|
|
s->state_file = strappend("/run/systemd/seats/", id);
|
2016-10-17 00:28:30 +02:00
|
|
|
if (!s->state_file)
|
|
|
|
return mfree(s);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2013-12-07 03:29:55 +01:00
|
|
|
s->id = basename(s->state_file);
|
2011-05-25 00:55:58 +02:00
|
|
|
s->manager = m;
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
if (hashmap_put(m->seats, s->id, s) < 0) {
|
2011-05-25 00:55:58 +02:00
|
|
|
free(s->state_file);
|
2016-10-17 00:28:30 +02:00
|
|
|
return mfree(s);
|
2011-05-23 23:55:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
void seat_free(Seat *s) {
|
|
|
|
assert(s);
|
|
|
|
|
2011-05-25 00:55:58 +02:00
|
|
|
if (s->in_gc_queue)
|
2013-10-14 06:10:14 +02:00
|
|
|
LIST_REMOVE(gc_queue, s->manager->seat_gc_queue, s);
|
2011-05-25 00:55:58 +02:00
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
while (s->sessions)
|
|
|
|
session_free(s->sessions);
|
|
|
|
|
|
|
|
assert(!s->active);
|
|
|
|
|
|
|
|
while (s->devices)
|
|
|
|
device_free(s->devices);
|
|
|
|
|
|
|
|
hashmap_remove(s->manager->seats, s->id);
|
|
|
|
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
free(s->positions);
|
2011-05-25 00:58:55 +02:00
|
|
|
free(s->state_file);
|
2011-05-23 23:55:06 +02:00
|
|
|
free(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
int seat_save(Seat *s) {
|
2013-11-05 01:10:21 +01:00
|
|
|
_cleanup_free_ char *temp_path = NULL;
|
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
2011-05-23 23:55:06 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2011-06-27 23:06:34 +02:00
|
|
|
if (!s->started)
|
|
|
|
return 0;
|
|
|
|
|
2017-10-06 09:03:33 +02:00
|
|
|
r = mkdir_safe_label("/run/systemd/seats", 0755, 0, 0, false);
|
2011-05-23 23:55:06 +02:00
|
|
|
if (r < 0)
|
2015-07-29 20:31:07 +02:00
|
|
|
goto fail;
|
2011-05-25 00:55:58 +02:00
|
|
|
|
|
|
|
r = fopen_temporary(s->state_file, &f, &temp_path);
|
|
|
|
if (r < 0)
|
2015-07-29 20:31:07 +02:00
|
|
|
goto fail;
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2017-12-11 19:50:30 +01:00
|
|
|
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
|
|
|
|
(void) fchmod(fileno(f), 0644);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
fprintf(f,
|
2011-05-25 00:55:58 +02:00
|
|
|
"# This is private data. Do not parse.\n"
|
2013-09-17 17:39:59 +02:00
|
|
|
"IS_SEAT0=%i\n"
|
2012-06-21 13:48:01 +02:00
|
|
|
"CAN_MULTI_SESSION=%i\n"
|
|
|
|
"CAN_TTY=%i\n"
|
|
|
|
"CAN_GRAPHICAL=%i\n",
|
2013-09-17 17:39:59 +02:00
|
|
|
seat_is_seat0(s),
|
2012-06-21 13:48:01 +02:00
|
|
|
seat_can_multi_session(s),
|
|
|
|
seat_can_tty(s),
|
|
|
|
seat_can_graphical(s));
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
if (s->active) {
|
|
|
|
assert(s->active->user);
|
|
|
|
|
|
|
|
fprintf(f,
|
|
|
|
"ACTIVE=%s\n"
|
2014-04-01 15:07:32 +02:00
|
|
|
"ACTIVE_UID="UID_FMT"\n",
|
2011-05-23 23:55:06 +02:00
|
|
|
s->active->id,
|
2014-04-01 15:07:32 +02:00
|
|
|
s->active->user->uid);
|
2011-05-23 23:55:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (s->sessions) {
|
|
|
|
Session *i;
|
|
|
|
|
2017-12-11 19:50:30 +01:00
|
|
|
fputs("SESSIONS=", f);
|
2011-05-23 23:55:06 +02:00
|
|
|
LIST_FOREACH(sessions_by_seat, i, s->sessions) {
|
2011-05-25 00:55:58 +02:00
|
|
|
fprintf(f,
|
|
|
|
"%s%c",
|
|
|
|
i->id,
|
|
|
|
i->sessions_by_seat_next ? ' ' : '\n');
|
|
|
|
}
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2017-12-11 19:50:30 +01:00
|
|
|
fputs("UIDS=", f);
|
2011-06-28 23:21:43 +02:00
|
|
|
LIST_FOREACH(sessions_by_seat, i, s->sessions)
|
2011-05-23 23:55:06 +02:00
|
|
|
fprintf(f,
|
2014-02-04 01:31:53 +01:00
|
|
|
UID_FMT"%c",
|
|
|
|
i->user->uid,
|
2011-05-25 00:55:58 +02:00
|
|
|
i->sessions_by_seat_next ? ' ' : '\n');
|
2011-05-23 23:55:06 +02:00
|
|
|
}
|
|
|
|
|
2015-07-29 20:31:07 +02:00
|
|
|
r = fflush_and_check(f);
|
|
|
|
if (r < 0)
|
|
|
|
goto fail;
|
2011-05-25 00:55:58 +02:00
|
|
|
|
2015-07-29 20:31:07 +02:00
|
|
|
if (rename(temp_path, s->state_file) < 0) {
|
2011-05-23 23:55:06 +02:00
|
|
|
r = -errno;
|
2015-07-29 20:31:07 +02:00
|
|
|
goto fail;
|
2011-05-23 23:55:06 +02:00
|
|
|
}
|
|
|
|
|
2015-07-29 20:31:07 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
(void) unlink(s->state_file);
|
|
|
|
|
|
|
|
if (temp_path)
|
|
|
|
(void) unlink(temp_path);
|
2011-05-25 00:55:58 +02:00
|
|
|
|
2015-07-29 20:31:07 +02:00
|
|
|
return log_error_errno(r, "Failed to save seat data %s: %m", s->state_file);
|
2011-05-23 23:55:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int seat_load(Seat *s) {
|
|
|
|
assert(s);
|
|
|
|
|
2011-06-17 15:59:18 +02:00
|
|
|
/* There isn't actually anything to read here ... */
|
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-11-28 17:05:34 +01:00
|
|
|
static int vt_allocate(unsigned int vtnr) {
|
2014-02-03 05:58:16 +01:00
|
|
|
char p[sizeof("/dev/tty") + DECIMAL_STR_MAX(unsigned int)];
|
2013-11-05 01:10:21 +01:00
|
|
|
_cleanup_close_ int fd = -1;
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
assert(vtnr >= 1);
|
|
|
|
|
2016-01-12 15:34:20 +01:00
|
|
|
xsprintf(p, "/dev/tty%u", vtnr);
|
2011-05-23 23:55:06 +02:00
|
|
|
fd = open_terminal(p, O_RDWR|O_NOCTTY|O_CLOEXEC);
|
2013-11-05 01:10:21 +01:00
|
|
|
if (fd < 0)
|
|
|
|
return -errno;
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
return 0;
|
2011-05-23 23:55:06 +02:00
|
|
|
}
|
|
|
|
|
2011-06-28 03:21:14 +02:00
|
|
|
int seat_preallocate_vts(Seat *s) {
|
2011-05-26 02:21:16 +02:00
|
|
|
int r = 0;
|
|
|
|
unsigned i;
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
assert(s->manager);
|
|
|
|
|
2011-06-28 03:21:14 +02:00
|
|
|
log_debug("Preallocating VTs...");
|
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
if (s->manager->n_autovts <= 0)
|
|
|
|
return 0;
|
|
|
|
|
2013-09-17 17:40:02 +02:00
|
|
|
if (!seat_has_vts(s))
|
2011-05-23 23:55:06 +02:00
|
|
|
return 0;
|
|
|
|
|
2011-06-28 02:53:49 +02:00
|
|
|
for (i = 1; i <= s->manager->n_autovts; i++) {
|
2011-05-23 23:55:06 +02:00
|
|
|
int q;
|
|
|
|
|
|
|
|
q = vt_allocate(i);
|
2011-05-25 00:55:58 +02:00
|
|
|
if (q < 0) {
|
2015-01-21 04:22:15 +01:00
|
|
|
log_error_errno(q, "Failed to preallocate VT %u: %m", i);
|
2011-05-23 23:55:06 +02:00
|
|
|
r = q;
|
2011-05-25 00:55:58 +02:00
|
|
|
}
|
2011-05-23 23:55:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2011-05-24 04:20:35 +02:00
|
|
|
int seat_apply_acls(Seat *s, Session *old_active) {
|
|
|
|
int r;
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2011-05-24 04:20:35 +02:00
|
|
|
assert(s);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2011-05-24 04:20:35 +02:00
|
|
|
r = devnode_acl_all(s->manager->udev,
|
|
|
|
s->id,
|
|
|
|
false,
|
|
|
|
!!old_active, old_active ? old_active->user->uid : 0,
|
|
|
|
!!s->active, s->active ? s->active->user->uid : 0);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2011-05-24 04:20:35 +02:00
|
|
|
if (r < 0)
|
2014-11-28 13:19:16 +01:00
|
|
|
log_error_errno(r, "Failed to apply ACLs: %m");
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2011-06-21 21:46:13 +02:00
|
|
|
int seat_set_active(Seat *s, Session *session) {
|
|
|
|
Session *old_active;
|
|
|
|
|
|
|
|
assert(s);
|
2011-06-21 22:29:25 +02:00
|
|
|
assert(!session || session->seat == s);
|
2011-06-21 21:46:13 +02:00
|
|
|
|
|
|
|
if (session == s->active)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
old_active = s->active;
|
|
|
|
s->active = session;
|
|
|
|
|
2013-10-01 17:58:58 +02:00
|
|
|
if (old_active) {
|
logind: introduce session-devices
A session-device is a device that is bound to a seat and used by a
session-controller to run the session. This currently includes DRM, fbdev
and evdev devices. A session-device can be created via RequestDevice() on
the dbus API of the session. You can drop it via ReleaseDevice() again.
Once the session is destroyed or you drop control of the session, all
session-devices are automatically destroyed.
Session devices follow the session "active" state. A device can be
active/running or inactive/paused. Whenever a session is not the active
session, no session-device of it can be active. That is, if a session is
not in foreground, all session-devices are paused.
Whenever a session becomes active, all devices are resumed/activated by
logind. If it fails, a device may stay paused.
With every session-device you request, you also get a file-descriptor
back. logind keeps a copy of this fd and uses kernel specific calls to
pause/resume the file-descriptors. For example, a DRM fd is muted
by logind as long as a given session is not active. Hence, the fd of the
application is also muted. Once the session gets active, logind unmutes
the fd and the application will get DRM access again.
This, however, requires kernel support. DRM devices provide DRM-Master for
synchronization, evdev devices have EVIOCREVOKE (pending on
linux-input-ML). fbdev devices do not provide such synchronization methods
(and never will).
Note that for evdev devices, we call EVIOCREVOKE once a session gets
inactive. However, this cannot be undone (the fd is still valid but mostly
unusable). So we reopen a new fd once the session is activated and send it
together with the ResumeDevice() signal.
With this infrastructure in place, compositors can now run without
CAP_SYS_ADMIN (that is, without being root). They use RequestControl() to
acquire a session and listen for devices via udev_monitor. For every
device they want to open, they call RequestDevice() on logind. This
returns a fd which they can use now. They no longer have to open the
devices themselves or call any privileged ioctls. This is all done by
logind.
Session-switches are still bound to VTs. Hence, compositors will get
notified via the usual VT mechanisms and can cleanup their state. Once the
VT switch is acknowledged as usual, logind will get notified via sysfs and
pause the old-session's devices and resume the devices of the new session.
To allow using this infrastructure with systems without VTs, we provide
notification signals. logind sends PauseDevice("force") dbus signals to
the current session controller for every device that it pauses. And it
sends ResumeDevice signals for every device that it resumes. For
seats with VTs this is sent _after_ the VT switch is acknowledged. Because
the compositor already acknowledged that it cleaned-up all devices.
However, for seats without VTs, this is used to notify the active
compositor that the session is about to be deactivated. That is, logind
sends PauseDevice("force") for each active device and then performs the
session-switch. The session-switch changes the "Active" property of the
session which can be monitored by the compositor. The new session is
activated and the ResumeDevice events are sent.
For seats without VTs, this is a forced session-switch. As this is not
backwards-compatible (xserver actually crashes, weston drops the related
devices, ..) we also provide an acknowledged session-switch. Note that
this is never used for sessions with VTs. You use the acknowledged
VT-switch on these seats.
An acknowledged session switch sends PauseDevice("pause") instead of
PauseDevice("force") to the active session. It schedules a short timeout
and waits for the session to acknowledge each of them with
PauseDeviceComplete(). Once all are acknowledged, or the session ran out
of time, a PauseDevice("force") is sent for all remaining active devices
and the session switch is performed.
Note that this is only partially implemented, yet, as we don't allow
multi-session without VTs, yet. A follow up commit will hook it up and
implemented the acknowledgements+timeout.
The implementation is quite simple. We use major/minor exclusively to
identify devices on the bus. On RequestDevice() we retrieve the
udev_device from the major/minor and search for an existing "Device"
object. If no exists, we create it. This guarantees us that we are
notified whenever the device changes seats or is removed.
We create a new SessionDevice object and link it to the related Session
and Device. Session->devices is a hashtable to lookup SessionDevice
objects via major/minor. Device->session_devices is a linked list so we
can release all linked session-devices once a device vanishes.
Now we only have to hook this up in seat_set_active() so we correctly
change device states during session-switches. As mentioned earlier, these
are forced state-changes as VTs are currently used exclusively for
multi-session implementations.
Everything else are hooks to release all session-devices once the
controller changes or a session is closed or removed.
2013-09-17 23:39:04 +02:00
|
|
|
session_device_pause_all(old_active);
|
2013-11-05 01:10:21 +01:00
|
|
|
session_send_changed(old_active, "Active", NULL);
|
2013-10-01 17:58:58 +02:00
|
|
|
}
|
logind: introduce session-devices
A session-device is a device that is bound to a seat and used by a
session-controller to run the session. This currently includes DRM, fbdev
and evdev devices. A session-device can be created via RequestDevice() on
the dbus API of the session. You can drop it via ReleaseDevice() again.
Once the session is destroyed or you drop control of the session, all
session-devices are automatically destroyed.
Session devices follow the session "active" state. A device can be
active/running or inactive/paused. Whenever a session is not the active
session, no session-device of it can be active. That is, if a session is
not in foreground, all session-devices are paused.
Whenever a session becomes active, all devices are resumed/activated by
logind. If it fails, a device may stay paused.
With every session-device you request, you also get a file-descriptor
back. logind keeps a copy of this fd and uses kernel specific calls to
pause/resume the file-descriptors. For example, a DRM fd is muted
by logind as long as a given session is not active. Hence, the fd of the
application is also muted. Once the session gets active, logind unmutes
the fd and the application will get DRM access again.
This, however, requires kernel support. DRM devices provide DRM-Master for
synchronization, evdev devices have EVIOCREVOKE (pending on
linux-input-ML). fbdev devices do not provide such synchronization methods
(and never will).
Note that for evdev devices, we call EVIOCREVOKE once a session gets
inactive. However, this cannot be undone (the fd is still valid but mostly
unusable). So we reopen a new fd once the session is activated and send it
together with the ResumeDevice() signal.
With this infrastructure in place, compositors can now run without
CAP_SYS_ADMIN (that is, without being root). They use RequestControl() to
acquire a session and listen for devices via udev_monitor. For every
device they want to open, they call RequestDevice() on logind. This
returns a fd which they can use now. They no longer have to open the
devices themselves or call any privileged ioctls. This is all done by
logind.
Session-switches are still bound to VTs. Hence, compositors will get
notified via the usual VT mechanisms and can cleanup their state. Once the
VT switch is acknowledged as usual, logind will get notified via sysfs and
pause the old-session's devices and resume the devices of the new session.
To allow using this infrastructure with systems without VTs, we provide
notification signals. logind sends PauseDevice("force") dbus signals to
the current session controller for every device that it pauses. And it
sends ResumeDevice signals for every device that it resumes. For
seats with VTs this is sent _after_ the VT switch is acknowledged. Because
the compositor already acknowledged that it cleaned-up all devices.
However, for seats without VTs, this is used to notify the active
compositor that the session is about to be deactivated. That is, logind
sends PauseDevice("force") for each active device and then performs the
session-switch. The session-switch changes the "Active" property of the
session which can be monitored by the compositor. The new session is
activated and the ResumeDevice events are sent.
For seats without VTs, this is a forced session-switch. As this is not
backwards-compatible (xserver actually crashes, weston drops the related
devices, ..) we also provide an acknowledged session-switch. Note that
this is never used for sessions with VTs. You use the acknowledged
VT-switch on these seats.
An acknowledged session switch sends PauseDevice("pause") instead of
PauseDevice("force") to the active session. It schedules a short timeout
and waits for the session to acknowledge each of them with
PauseDeviceComplete(). Once all are acknowledged, or the session ran out
of time, a PauseDevice("force") is sent for all remaining active devices
and the session switch is performed.
Note that this is only partially implemented, yet, as we don't allow
multi-session without VTs, yet. A follow up commit will hook it up and
implemented the acknowledgements+timeout.
The implementation is quite simple. We use major/minor exclusively to
identify devices on the bus. On RequestDevice() we retrieve the
udev_device from the major/minor and search for an existing "Device"
object. If no exists, we create it. This guarantees us that we are
notified whenever the device changes seats or is removed.
We create a new SessionDevice object and link it to the related Session
and Device. Session->devices is a hashtable to lookup SessionDevice
objects via major/minor. Device->session_devices is a linked list so we
can release all linked session-devices once a device vanishes.
Now we only have to hook this up in seat_set_active() so we correctly
change device states during session-switches. As mentioned earlier, these
are forced state-changes as VTs are currently used exclusively for
multi-session implementations.
Everything else are hooks to release all session-devices once the
controller changes or a session is closed or removed.
2013-09-17 23:39:04 +02:00
|
|
|
|
2011-06-21 21:46:13 +02:00
|
|
|
seat_apply_acls(s, old_active);
|
|
|
|
|
logind: introduce session-devices
A session-device is a device that is bound to a seat and used by a
session-controller to run the session. This currently includes DRM, fbdev
and evdev devices. A session-device can be created via RequestDevice() on
the dbus API of the session. You can drop it via ReleaseDevice() again.
Once the session is destroyed or you drop control of the session, all
session-devices are automatically destroyed.
Session devices follow the session "active" state. A device can be
active/running or inactive/paused. Whenever a session is not the active
session, no session-device of it can be active. That is, if a session is
not in foreground, all session-devices are paused.
Whenever a session becomes active, all devices are resumed/activated by
logind. If it fails, a device may stay paused.
With every session-device you request, you also get a file-descriptor
back. logind keeps a copy of this fd and uses kernel specific calls to
pause/resume the file-descriptors. For example, a DRM fd is muted
by logind as long as a given session is not active. Hence, the fd of the
application is also muted. Once the session gets active, logind unmutes
the fd and the application will get DRM access again.
This, however, requires kernel support. DRM devices provide DRM-Master for
synchronization, evdev devices have EVIOCREVOKE (pending on
linux-input-ML). fbdev devices do not provide such synchronization methods
(and never will).
Note that for evdev devices, we call EVIOCREVOKE once a session gets
inactive. However, this cannot be undone (the fd is still valid but mostly
unusable). So we reopen a new fd once the session is activated and send it
together with the ResumeDevice() signal.
With this infrastructure in place, compositors can now run without
CAP_SYS_ADMIN (that is, without being root). They use RequestControl() to
acquire a session and listen for devices via udev_monitor. For every
device they want to open, they call RequestDevice() on logind. This
returns a fd which they can use now. They no longer have to open the
devices themselves or call any privileged ioctls. This is all done by
logind.
Session-switches are still bound to VTs. Hence, compositors will get
notified via the usual VT mechanisms and can cleanup their state. Once the
VT switch is acknowledged as usual, logind will get notified via sysfs and
pause the old-session's devices and resume the devices of the new session.
To allow using this infrastructure with systems without VTs, we provide
notification signals. logind sends PauseDevice("force") dbus signals to
the current session controller for every device that it pauses. And it
sends ResumeDevice signals for every device that it resumes. For
seats with VTs this is sent _after_ the VT switch is acknowledged. Because
the compositor already acknowledged that it cleaned-up all devices.
However, for seats without VTs, this is used to notify the active
compositor that the session is about to be deactivated. That is, logind
sends PauseDevice("force") for each active device and then performs the
session-switch. The session-switch changes the "Active" property of the
session which can be monitored by the compositor. The new session is
activated and the ResumeDevice events are sent.
For seats without VTs, this is a forced session-switch. As this is not
backwards-compatible (xserver actually crashes, weston drops the related
devices, ..) we also provide an acknowledged session-switch. Note that
this is never used for sessions with VTs. You use the acknowledged
VT-switch on these seats.
An acknowledged session switch sends PauseDevice("pause") instead of
PauseDevice("force") to the active session. It schedules a short timeout
and waits for the session to acknowledge each of them with
PauseDeviceComplete(). Once all are acknowledged, or the session ran out
of time, a PauseDevice("force") is sent for all remaining active devices
and the session switch is performed.
Note that this is only partially implemented, yet, as we don't allow
multi-session without VTs, yet. A follow up commit will hook it up and
implemented the acknowledgements+timeout.
The implementation is quite simple. We use major/minor exclusively to
identify devices on the bus. On RequestDevice() we retrieve the
udev_device from the major/minor and search for an existing "Device"
object. If no exists, we create it. This guarantees us that we are
notified whenever the device changes seats or is removed.
We create a new SessionDevice object and link it to the related Session
and Device. Session->devices is a hashtable to lookup SessionDevice
objects via major/minor. Device->session_devices is a linked list so we
can release all linked session-devices once a device vanishes.
Now we only have to hook this up in seat_set_active() so we correctly
change device states during session-switches. As mentioned earlier, these
are forced state-changes as VTs are currently used exclusively for
multi-session implementations.
Everything else are hooks to release all session-devices once the
controller changes or a session is closed or removed.
2013-09-17 23:39:04 +02:00
|
|
|
if (session && session->started) {
|
2013-11-05 01:10:21 +01:00
|
|
|
session_send_changed(session, "Active", NULL);
|
logind: introduce session-devices
A session-device is a device that is bound to a seat and used by a
session-controller to run the session. This currently includes DRM, fbdev
and evdev devices. A session-device can be created via RequestDevice() on
the dbus API of the session. You can drop it via ReleaseDevice() again.
Once the session is destroyed or you drop control of the session, all
session-devices are automatically destroyed.
Session devices follow the session "active" state. A device can be
active/running or inactive/paused. Whenever a session is not the active
session, no session-device of it can be active. That is, if a session is
not in foreground, all session-devices are paused.
Whenever a session becomes active, all devices are resumed/activated by
logind. If it fails, a device may stay paused.
With every session-device you request, you also get a file-descriptor
back. logind keeps a copy of this fd and uses kernel specific calls to
pause/resume the file-descriptors. For example, a DRM fd is muted
by logind as long as a given session is not active. Hence, the fd of the
application is also muted. Once the session gets active, logind unmutes
the fd and the application will get DRM access again.
This, however, requires kernel support. DRM devices provide DRM-Master for
synchronization, evdev devices have EVIOCREVOKE (pending on
linux-input-ML). fbdev devices do not provide such synchronization methods
(and never will).
Note that for evdev devices, we call EVIOCREVOKE once a session gets
inactive. However, this cannot be undone (the fd is still valid but mostly
unusable). So we reopen a new fd once the session is activated and send it
together with the ResumeDevice() signal.
With this infrastructure in place, compositors can now run without
CAP_SYS_ADMIN (that is, without being root). They use RequestControl() to
acquire a session and listen for devices via udev_monitor. For every
device they want to open, they call RequestDevice() on logind. This
returns a fd which they can use now. They no longer have to open the
devices themselves or call any privileged ioctls. This is all done by
logind.
Session-switches are still bound to VTs. Hence, compositors will get
notified via the usual VT mechanisms and can cleanup their state. Once the
VT switch is acknowledged as usual, logind will get notified via sysfs and
pause the old-session's devices and resume the devices of the new session.
To allow using this infrastructure with systems without VTs, we provide
notification signals. logind sends PauseDevice("force") dbus signals to
the current session controller for every device that it pauses. And it
sends ResumeDevice signals for every device that it resumes. For
seats with VTs this is sent _after_ the VT switch is acknowledged. Because
the compositor already acknowledged that it cleaned-up all devices.
However, for seats without VTs, this is used to notify the active
compositor that the session is about to be deactivated. That is, logind
sends PauseDevice("force") for each active device and then performs the
session-switch. The session-switch changes the "Active" property of the
session which can be monitored by the compositor. The new session is
activated and the ResumeDevice events are sent.
For seats without VTs, this is a forced session-switch. As this is not
backwards-compatible (xserver actually crashes, weston drops the related
devices, ..) we also provide an acknowledged session-switch. Note that
this is never used for sessions with VTs. You use the acknowledged
VT-switch on these seats.
An acknowledged session switch sends PauseDevice("pause") instead of
PauseDevice("force") to the active session. It schedules a short timeout
and waits for the session to acknowledge each of them with
PauseDeviceComplete(). Once all are acknowledged, or the session ran out
of time, a PauseDevice("force") is sent for all remaining active devices
and the session switch is performed.
Note that this is only partially implemented, yet, as we don't allow
multi-session without VTs, yet. A follow up commit will hook it up and
implemented the acknowledgements+timeout.
The implementation is quite simple. We use major/minor exclusively to
identify devices on the bus. On RequestDevice() we retrieve the
udev_device from the major/minor and search for an existing "Device"
object. If no exists, we create it. This guarantees us that we are
notified whenever the device changes seats or is removed.
We create a new SessionDevice object and link it to the related Session
and Device. Session->devices is a hashtable to lookup SessionDevice
objects via major/minor. Device->session_devices is a linked list so we
can release all linked session-devices once a device vanishes.
Now we only have to hook this up in seat_set_active() so we correctly
change device states during session-switches. As mentioned earlier, these
are forced state-changes as VTs are currently used exclusively for
multi-session implementations.
Everything else are hooks to release all session-devices once the
controller changes or a session is closed or removed.
2013-09-17 23:39:04 +02:00
|
|
|
session_device_resume_all(session);
|
|
|
|
}
|
2011-06-21 21:46:13 +02:00
|
|
|
|
|
|
|
if (!session || session->started)
|
2013-11-05 01:10:21 +01:00
|
|
|
seat_send_changed(s, "ActiveSession", NULL);
|
2011-06-21 21:46:13 +02:00
|
|
|
|
2011-06-24 18:50:50 +02:00
|
|
|
seat_save(s);
|
|
|
|
|
2011-06-28 03:52:22 +02:00
|
|
|
if (session) {
|
2011-06-24 18:50:50 +02:00
|
|
|
session_save(session);
|
2011-06-28 03:52:22 +02:00
|
|
|
user_save(session->user);
|
|
|
|
}
|
2011-06-24 18:50:50 +02:00
|
|
|
|
2011-06-28 03:52:22 +02:00
|
|
|
if (old_active) {
|
2011-06-24 18:50:50 +02:00
|
|
|
session_save(old_active);
|
2012-09-04 02:37:28 +02:00
|
|
|
if (!session || session->user != old_active->user)
|
|
|
|
user_save(old_active->user);
|
2011-06-28 03:52:22 +02:00
|
|
|
}
|
2011-06-24 18:50:50 +02:00
|
|
|
|
2011-06-21 21:46:13 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
int seat_switch_to(Seat *s, unsigned int num) {
|
|
|
|
/* Public session positions skip 0 (there is only F1-F12). Maybe it
|
|
|
|
* will get reassigned in the future, so return error for now. */
|
2015-07-07 02:04:13 +02:00
|
|
|
if (num == 0)
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
return -EINVAL;
|
|
|
|
|
2014-07-08 12:56:55 +02:00
|
|
|
if (num >= s->position_count || !s->positions[num]) {
|
|
|
|
/* allow switching to unused VTs to trigger auto-activate */
|
|
|
|
if (seat_has_vts(s) && num < 64)
|
|
|
|
return chvt(num);
|
|
|
|
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
return -EINVAL;
|
2014-07-08 12:56:55 +02:00
|
|
|
}
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
|
|
|
|
return session_activate(s->positions[num]);
|
|
|
|
}
|
|
|
|
|
|
|
|
int seat_switch_to_next(Seat *s) {
|
|
|
|
unsigned int start, i;
|
|
|
|
|
2015-07-07 02:04:13 +02:00
|
|
|
if (s->position_count == 0)
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
start = 1;
|
2015-07-10 15:08:24 +02:00
|
|
|
if (s->active && s->active->position > 0)
|
|
|
|
start = s->active->position;
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
|
|
|
|
for (i = start + 1; i < s->position_count; ++i)
|
|
|
|
if (s->positions[i])
|
|
|
|
return session_activate(s->positions[i]);
|
|
|
|
|
|
|
|
for (i = 1; i < start; ++i)
|
|
|
|
if (s->positions[i])
|
|
|
|
return session_activate(s->positions[i]);
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int seat_switch_to_previous(Seat *s) {
|
|
|
|
unsigned int start, i;
|
|
|
|
|
2015-07-07 02:04:13 +02:00
|
|
|
if (s->position_count == 0)
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
start = 1;
|
2015-07-10 15:08:24 +02:00
|
|
|
if (s->active && s->active->position > 0)
|
|
|
|
start = s->active->position;
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
|
|
|
|
for (i = start - 1; i > 0; --i)
|
|
|
|
if (s->positions[i])
|
|
|
|
return session_activate(s->positions[i]);
|
|
|
|
|
|
|
|
for (i = s->position_count - 1; i > start; --i)
|
|
|
|
if (s->positions[i])
|
|
|
|
return session_activate(s->positions[i]);
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2013-11-28 17:05:34 +01:00
|
|
|
int seat_active_vt_changed(Seat *s, unsigned int vtnr) {
|
2011-06-21 21:46:13 +02:00
|
|
|
Session *i, *new_active = NULL;
|
|
|
|
int r;
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
assert(vtnr >= 1);
|
|
|
|
|
2013-09-17 17:40:02 +02:00
|
|
|
if (!seat_has_vts(s))
|
2011-05-25 00:55:58 +02:00
|
|
|
return -EINVAL;
|
|
|
|
|
2013-11-28 17:05:34 +01:00
|
|
|
log_debug("VT changed to %u", vtnr);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2015-01-28 18:14:01 +01:00
|
|
|
/* we might have earlier closing sessions on the same VT, so try to
|
|
|
|
* find a running one first */
|
2011-05-23 23:55:06 +02:00
|
|
|
LIST_FOREACH(sessions_by_seat, i, s->sessions)
|
2015-01-28 18:14:01 +01:00
|
|
|
if (i->vtnr == vtnr && !i->stopping) {
|
2011-05-25 00:55:58 +02:00
|
|
|
new_active = i;
|
2011-05-23 23:55:06 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-01-28 18:14:01 +01:00
|
|
|
if (!new_active) {
|
|
|
|
/* no running one? then we can't decide which one is the
|
|
|
|
* active one, let the first one win */
|
|
|
|
LIST_FOREACH(sessions_by_seat, i, s->sessions)
|
|
|
|
if (i->vtnr == vtnr) {
|
|
|
|
new_active = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-21 21:46:13 +02:00
|
|
|
r = seat_set_active(s, new_active);
|
2011-05-24 04:20:35 +02:00
|
|
|
manager_spawn_autovt(s->manager, vtnr);
|
2011-05-23 23:55:06 +02:00
|
|
|
|
2011-06-21 21:46:13 +02:00
|
|
|
return r;
|
2011-05-23 23:55:06 +02:00
|
|
|
}
|
|
|
|
|
2011-05-25 00:55:58 +02:00
|
|
|
int seat_read_active_vt(Seat *s) {
|
|
|
|
char t[64];
|
|
|
|
ssize_t k;
|
2013-11-28 17:05:34 +01:00
|
|
|
unsigned int vtnr;
|
|
|
|
int r;
|
2011-05-25 00:55:58 +02:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2013-09-17 17:40:02 +02:00
|
|
|
if (!seat_has_vts(s))
|
2011-05-25 00:55:58 +02:00
|
|
|
return 0;
|
|
|
|
|
2017-02-19 19:43:22 +01:00
|
|
|
if (lseek(s->manager->console_active_fd, SEEK_SET, 0) < 0)
|
|
|
|
return log_error_errno(errno, "lseek on console_active_fd failed: %m");
|
2011-05-25 00:55:58 +02:00
|
|
|
|
|
|
|
k = read(s->manager->console_active_fd, t, sizeof(t)-1);
|
|
|
|
if (k <= 0) {
|
|
|
|
log_error("Failed to read current console: %s", k < 0 ? strerror(-errno) : "EOF");
|
|
|
|
return k < 0 ? -errno : -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
t[k] = 0;
|
|
|
|
truncate_nl(t);
|
|
|
|
|
|
|
|
if (!startswith(t, "tty")) {
|
|
|
|
log_error("Hm, /sys/class/tty/tty0/active is badly formatted.");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
2013-11-28 17:05:34 +01:00
|
|
|
r = safe_atou(t+3, &vtnr);
|
2017-02-19 19:43:22 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to parse VT number \"%s\": %m", t+3);
|
2011-05-25 00:55:58 +02:00
|
|
|
|
2013-11-28 17:05:34 +01:00
|
|
|
if (!vtnr) {
|
2011-05-25 00:55:58 +02:00
|
|
|
log_error("VT number invalid: %s", t+3);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return seat_active_vt_changed(s, vtnr);
|
|
|
|
}
|
|
|
|
|
|
|
|
int seat_start(Seat *s) {
|
|
|
|
assert(s);
|
|
|
|
|
2011-05-26 02:21:16 +02:00
|
|
|
if (s->started)
|
|
|
|
return 0;
|
|
|
|
|
2012-08-24 22:21:20 +02:00
|
|
|
log_struct(LOG_INFO,
|
tree-wide: add SD_ID128_MAKE_STR, remove LOG_MESSAGE_ID
Embedding sd_id128_t's in constant strings was rather cumbersome. We had
SD_ID128_CONST_STR which returned a const char[], but it had two problems:
- it wasn't possible to statically concatanate this array with a normal string
- gcc wasn't really able to optimize this, and generated code to perform the
"conversion" at runtime.
Because of this, even our own code in coredumpctl wasn't using
SD_ID128_CONST_STR.
Add a new macro to generate a constant string: SD_ID128_MAKE_STR.
It is not as elegant as SD_ID128_CONST_STR, because it requires a repetition
of the numbers, but in practice it is more convenient to use, and allows gcc
to generate smarter code:
$ size .libs/systemd{,-logind,-journald}{.old,}
text data bss dec hex filename
1265204 149564 4808 1419576 15a938 .libs/systemd.old
1260268 149564 4808 1414640 1595f0 .libs/systemd
246805 13852 209 260866 3fb02 .libs/systemd-logind.old
240973 13852 209 255034 3e43a .libs/systemd-logind
146839 4984 34 151857 25131 .libs/systemd-journald.old
146391 4984 34 151409 24f71 .libs/systemd-journald
It is also much easier to check if a certain binary uses a certain MESSAGE_ID:
$ strings .libs/systemd.old|grep MESSAGE_ID
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
$ strings .libs/systemd|grep MESSAGE_ID
MESSAGE_ID=c7a787079b354eaaa9e77b371893cd27
MESSAGE_ID=b07a249cd024414a82dd00cd181378ff
MESSAGE_ID=641257651c1b4ec9a8624d7a40a9e1e7
MESSAGE_ID=de5b426a63be47a7b6ac3eaac82e2f6f
MESSAGE_ID=d34d037fff1847e6ae669a370e694725
MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5
MESSAGE_ID=1dee0369c7fc4736b7099b38ecb46ee7
MESSAGE_ID=39f53479d3a045ac8e11786248231fbf
MESSAGE_ID=be02cf6855d2428ba40df7e9d022f03d
MESSAGE_ID=7b05ebc668384222baa8881179cfda54
MESSAGE_ID=9d1aaa27d60140bd96365438aad20286
2016-11-06 18:48:23 +01:00
|
|
|
"MESSAGE_ID=" SD_MESSAGE_SEAT_START_STR,
|
2012-08-24 22:21:20 +02:00
|
|
|
"SEAT_ID=%s", s->id,
|
2014-11-28 02:05:14 +01:00
|
|
|
LOG_MESSAGE("New seat %s.", s->id),
|
2012-08-24 22:21:20 +02:00
|
|
|
NULL);
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2011-05-25 00:55:58 +02:00
|
|
|
/* Initialize VT magic stuff */
|
|
|
|
seat_preallocate_vts(s);
|
|
|
|
|
|
|
|
/* Read current VT */
|
|
|
|
seat_read_active_vt(s);
|
|
|
|
|
2011-06-28 03:52:22 +02:00
|
|
|
s->started = true;
|
|
|
|
|
2011-05-25 00:55:58 +02:00
|
|
|
/* Save seat data */
|
|
|
|
seat_save(s);
|
|
|
|
|
2011-06-21 20:43:34 +02:00
|
|
|
seat_send_signal(s, true);
|
|
|
|
|
2011-05-25 00:55:58 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-02-09 02:29:56 +01:00
|
|
|
int seat_stop(Seat *s, bool force) {
|
2011-06-17 15:59:18 +02:00
|
|
|
int r = 0;
|
2011-05-23 23:55:06 +02:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2011-06-24 19:42:45 +02:00
|
|
|
if (s->started)
|
2012-08-24 22:21:20 +02:00
|
|
|
log_struct(LOG_INFO,
|
tree-wide: add SD_ID128_MAKE_STR, remove LOG_MESSAGE_ID
Embedding sd_id128_t's in constant strings was rather cumbersome. We had
SD_ID128_CONST_STR which returned a const char[], but it had two problems:
- it wasn't possible to statically concatanate this array with a normal string
- gcc wasn't really able to optimize this, and generated code to perform the
"conversion" at runtime.
Because of this, even our own code in coredumpctl wasn't using
SD_ID128_CONST_STR.
Add a new macro to generate a constant string: SD_ID128_MAKE_STR.
It is not as elegant as SD_ID128_CONST_STR, because it requires a repetition
of the numbers, but in practice it is more convenient to use, and allows gcc
to generate smarter code:
$ size .libs/systemd{,-logind,-journald}{.old,}
text data bss dec hex filename
1265204 149564 4808 1419576 15a938 .libs/systemd.old
1260268 149564 4808 1414640 1595f0 .libs/systemd
246805 13852 209 260866 3fb02 .libs/systemd-logind.old
240973 13852 209 255034 3e43a .libs/systemd-logind
146839 4984 34 151857 25131 .libs/systemd-journald.old
146391 4984 34 151409 24f71 .libs/systemd-journald
It is also much easier to check if a certain binary uses a certain MESSAGE_ID:
$ strings .libs/systemd.old|grep MESSAGE_ID
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
$ strings .libs/systemd|grep MESSAGE_ID
MESSAGE_ID=c7a787079b354eaaa9e77b371893cd27
MESSAGE_ID=b07a249cd024414a82dd00cd181378ff
MESSAGE_ID=641257651c1b4ec9a8624d7a40a9e1e7
MESSAGE_ID=de5b426a63be47a7b6ac3eaac82e2f6f
MESSAGE_ID=d34d037fff1847e6ae669a370e694725
MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5
MESSAGE_ID=1dee0369c7fc4736b7099b38ecb46ee7
MESSAGE_ID=39f53479d3a045ac8e11786248231fbf
MESSAGE_ID=be02cf6855d2428ba40df7e9d022f03d
MESSAGE_ID=7b05ebc668384222baa8881179cfda54
MESSAGE_ID=9d1aaa27d60140bd96365438aad20286
2016-11-06 18:48:23 +01:00
|
|
|
"MESSAGE_ID=" SD_MESSAGE_SEAT_STOP_STR,
|
2012-08-24 22:21:20 +02:00
|
|
|
"SEAT_ID=%s", s->id,
|
2014-11-28 02:05:14 +01:00
|
|
|
LOG_MESSAGE("Removed seat %s.", s->id),
|
2012-08-24 22:21:20 +02:00
|
|
|
NULL);
|
2011-06-21 20:43:34 +02:00
|
|
|
|
2014-02-09 02:29:56 +01:00
|
|
|
seat_stop_sessions(s, force);
|
2011-06-17 15:59:18 +02:00
|
|
|
|
|
|
|
unlink(s->state_file);
|
|
|
|
seat_add_to_gc_queue(s);
|
|
|
|
|
2011-06-24 19:42:45 +02:00
|
|
|
if (s->started)
|
|
|
|
seat_send_signal(s, false);
|
|
|
|
|
2011-06-17 15:59:18 +02:00
|
|
|
s->started = false;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-02-09 02:29:56 +01:00
|
|
|
int seat_stop_sessions(Seat *s, bool force) {
|
2011-06-17 15:59:18 +02:00
|
|
|
Session *session;
|
|
|
|
int r = 0, k;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2011-05-23 23:55:06 +02:00
|
|
|
LIST_FOREACH(sessions_by_seat, session, s->sessions) {
|
2014-02-09 02:29:56 +01:00
|
|
|
k = session_stop(session, force);
|
2011-05-23 23:55:06 +02:00
|
|
|
if (k < 0)
|
|
|
|
r = k;
|
|
|
|
}
|
|
|
|
|
2011-06-17 15:59:18 +02:00
|
|
|
return r;
|
|
|
|
}
|
2011-05-25 00:55:58 +02:00
|
|
|
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
void seat_evict_position(Seat *s, Session *session) {
|
2014-02-25 13:08:24 +01:00
|
|
|
Session *iter;
|
2015-07-10 15:08:24 +02:00
|
|
|
unsigned int pos = session->position;
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
|
2015-07-10 15:08:24 +02:00
|
|
|
session->position = 0;
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
|
2015-07-07 02:04:13 +02:00
|
|
|
if (pos == 0)
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
return;
|
|
|
|
|
2014-02-25 13:08:24 +01:00
|
|
|
if (pos < s->position_count && s->positions[pos] == session) {
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
s->positions[pos] = NULL;
|
2014-02-25 13:08:24 +01:00
|
|
|
|
|
|
|
/* There might be another session claiming the same
|
2015-07-07 02:04:13 +02:00
|
|
|
* position (eg., during gdm->session transition), so let's look
|
2014-02-25 13:08:24 +01:00
|
|
|
* for it and set it on the free slot. */
|
|
|
|
LIST_FOREACH(sessions_by_seat, iter, s->sessions) {
|
2015-07-16 18:46:12 +02:00
|
|
|
if (iter->position == pos && session_get_state(iter) != SESSION_CLOSING) {
|
2014-02-25 13:08:24 +01:00
|
|
|
s->positions[pos] = iter;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void seat_claim_position(Seat *s, Session *session, unsigned int pos) {
|
|
|
|
/* with VTs, the position is always the same as the VTnr */
|
|
|
|
if (seat_has_vts(s))
|
|
|
|
pos = session->vtnr;
|
|
|
|
|
2014-04-10 15:48:59 +02:00
|
|
|
if (!GREEDY_REALLOC0(s->positions, s->position_count, pos + 1))
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
seat_evict_position(s, session);
|
|
|
|
|
2015-07-10 15:08:24 +02:00
|
|
|
session->position = pos;
|
logind: prefer new sessions over older ones on VT switches
Our seat->positions[] array keeps track of the 'preferred' session on a
VT. The only situation this is used, is to select the session to activate
when a VT is activated. In the normal case, there's only one session per
VT so the selection is trivial.
Older greeters, however, implement take-overs when they start sessions on
the same VT that the greeter ran on. We recently limited such take-overs
to VTs where a greeter is running on, to force people to never share VTs
in new code that is written.
For legacy reasons, we need to be compatible to old greeters, though.
Hence, we allow those greeters to implement take-over. In such take-overs,
however, we should really make sure that the new sessions gets preferred
over the old one under all circumstances. Hence, make sure we override
the previous preferred session with a new session.
2015-07-16 18:18:01 +02:00
|
|
|
if (pos > 0)
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
s->positions[pos] = session;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void seat_assign_position(Seat *s, Session *session) {
|
|
|
|
unsigned int pos;
|
|
|
|
|
2015-07-10 15:08:24 +02:00
|
|
|
if (session->position > 0)
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
for (pos = 1; pos < s->position_count; ++pos)
|
|
|
|
if (!s->positions[pos])
|
|
|
|
break;
|
|
|
|
|
|
|
|
seat_claim_position(s, session, pos);
|
|
|
|
}
|
|
|
|
|
2011-06-17 15:59:18 +02:00
|
|
|
int seat_attach_session(Seat *s, Session *session) {
|
|
|
|
assert(s);
|
|
|
|
assert(session);
|
|
|
|
assert(!session->seat);
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2013-11-28 17:25:25 +01:00
|
|
|
if (!seat_has_vts(s) != !session->vtnr)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2011-06-17 15:59:18 +02:00
|
|
|
session->seat = s;
|
2013-10-14 06:10:14 +02:00
|
|
|
LIST_PREPEND(sessions_by_seat, s->sessions, session);
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
seat_assign_position(s, session);
|
2011-06-17 15:59:18 +02:00
|
|
|
|
2013-09-17 17:40:02 +02:00
|
|
|
/* On seats with VTs, the VT logic defines which session is active. On
|
2013-11-28 10:52:18 +01:00
|
|
|
* seats without VTs, we automatically activate new sessions. */
|
|
|
|
if (!seat_has_vts(s))
|
2011-06-21 21:46:13 +02:00
|
|
|
seat_set_active(s, session);
|
|
|
|
|
2011-06-17 15:59:18 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-17 23:40:19 +02:00
|
|
|
void seat_complete_switch(Seat *s) {
|
|
|
|
Session *session;
|
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
/* if no session-switch is pending or if it got canceled, do nothing */
|
|
|
|
if (!s->pending_switch)
|
|
|
|
return;
|
|
|
|
|
2018-03-22 16:53:26 +01:00
|
|
|
session = TAKE_PTR(s->pending_switch);
|
2013-09-17 23:40:19 +02:00
|
|
|
|
|
|
|
seat_set_active(s, session);
|
|
|
|
}
|
|
|
|
|
2013-09-17 17:40:02 +02:00
|
|
|
bool seat_has_vts(Seat *s) {
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
return seat_is_seat0(s) && s->manager->console_active_fd >= 0;
|
|
|
|
}
|
|
|
|
|
2013-09-17 17:39:59 +02:00
|
|
|
bool seat_is_seat0(Seat *s) {
|
2011-06-17 15:59:18 +02:00
|
|
|
assert(s);
|
|
|
|
|
2013-09-17 17:39:59 +02:00
|
|
|
return s->manager->seat0 == s;
|
2011-06-17 15:59:18 +02:00
|
|
|
}
|
|
|
|
|
2012-01-03 21:47:54 +01:00
|
|
|
bool seat_can_multi_session(Seat *s) {
|
|
|
|
assert(s);
|
|
|
|
|
2013-09-17 17:40:02 +02:00
|
|
|
return seat_has_vts(s);
|
2012-01-03 21:47:54 +01:00
|
|
|
}
|
|
|
|
|
2012-06-21 13:48:01 +02:00
|
|
|
bool seat_can_tty(Seat *s) {
|
|
|
|
assert(s);
|
|
|
|
|
2013-09-17 17:40:02 +02:00
|
|
|
return seat_has_vts(s);
|
2012-06-21 13:48:01 +02:00
|
|
|
}
|
|
|
|
|
logind: listen actively for session devices
Session compositors need access to fbdev, DRM and evdev devices if they
control a session. To make logind pass them to sessions, we need to
listen for them actively.
However, we avoid creating new seats for non master-of-seat devices. Only
once a seat is created, we start remembering all other session devices. If
the last master-device is removed (even if there are other non-master
devices still available), we destroy the seat. This is the current
behavior, but we need to explicitly implement it now as there may be
non-master devices in the seat->devices list.
Unlike master devices, we don't care whether our list of non-master
devices is complete. We don't export this list but use it only as cache if
sessions request these devices. Hence, if a session requests a device that
is not in the list, we will simply look it up. However, once a session
requested a device, we must be notified of "remove" udev events. So we
must link the devices somehow into the device-list.
Regarding the implementation, we now sort the device list by the "master"
flag. This guarantees that master devices are at the front and non-master
devices at the tail of the list. Thus, we can easily test whether a seat
has a master device attached.
2013-09-17 17:39:54 +02:00
|
|
|
bool seat_has_master_device(Seat *s) {
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
/* device list is ordered by "master" flag */
|
|
|
|
return !!s->devices && s->devices->master;
|
|
|
|
}
|
|
|
|
|
2012-06-21 13:48:01 +02:00
|
|
|
bool seat_can_graphical(Seat *s) {
|
|
|
|
assert(s);
|
|
|
|
|
logind: listen actively for session devices
Session compositors need access to fbdev, DRM and evdev devices if they
control a session. To make logind pass them to sessions, we need to
listen for them actively.
However, we avoid creating new seats for non master-of-seat devices. Only
once a seat is created, we start remembering all other session devices. If
the last master-device is removed (even if there are other non-master
devices still available), we destroy the seat. This is the current
behavior, but we need to explicitly implement it now as there may be
non-master devices in the seat->devices list.
Unlike master devices, we don't care whether our list of non-master
devices is complete. We don't export this list but use it only as cache if
sessions request these devices. Hence, if a session requests a device that
is not in the list, we will simply look it up. However, once a session
requested a device, we must be notified of "remove" udev events. So we
must link the devices somehow into the device-list.
Regarding the implementation, we now sort the device list by the "master"
flag. This guarantees that master devices are at the front and non-master
devices at the tail of the list. Thus, we can easily test whether a seat
has a master device attached.
2013-09-17 17:39:54 +02:00
|
|
|
return seat_has_master_device(s);
|
2012-06-21 13:48:01 +02:00
|
|
|
}
|
|
|
|
|
2011-06-17 15:59:18 +02:00
|
|
|
int seat_get_idle_hint(Seat *s, dual_timestamp *t) {
|
|
|
|
Session *session;
|
|
|
|
bool idle_hint = true;
|
2015-06-16 01:08:12 +02:00
|
|
|
dual_timestamp ts = DUAL_TIMESTAMP_NULL;
|
2011-06-17 15:59:18 +02:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
LIST_FOREACH(sessions_by_seat, session, s->sessions) {
|
|
|
|
dual_timestamp k;
|
|
|
|
int ih;
|
|
|
|
|
|
|
|
ih = session_get_idle_hint(session, &k);
|
|
|
|
if (ih < 0)
|
|
|
|
return ih;
|
|
|
|
|
|
|
|
if (!ih) {
|
|
|
|
if (!idle_hint) {
|
2012-07-22 15:39:37 +02:00
|
|
|
if (k.monotonic > ts.monotonic)
|
2011-06-17 15:59:18 +02:00
|
|
|
ts = k;
|
|
|
|
} else {
|
|
|
|
idle_hint = false;
|
|
|
|
ts = k;
|
|
|
|
}
|
|
|
|
} else if (idle_hint) {
|
|
|
|
|
|
|
|
if (k.monotonic > ts.monotonic)
|
|
|
|
ts = k;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (t)
|
|
|
|
*t = ts;
|
|
|
|
|
|
|
|
return idle_hint;
|
2011-05-23 23:55:06 +02:00
|
|
|
}
|
2011-05-25 00:55:58 +02:00
|
|
|
|
2018-02-15 13:14:35 +01:00
|
|
|
bool seat_may_gc(Seat *s, bool drop_not_started) {
|
2011-05-25 00:55:58 +02:00
|
|
|
assert(s);
|
|
|
|
|
2011-06-29 03:48:16 +02:00
|
|
|
if (drop_not_started && !s->started)
|
2018-02-15 13:14:35 +01:00
|
|
|
return true;
|
2011-06-29 00:06:04 +02:00
|
|
|
|
2013-09-17 17:39:59 +02:00
|
|
|
if (seat_is_seat0(s))
|
2018-02-15 13:14:35 +01:00
|
|
|
return false;
|
2011-05-25 00:55:58 +02:00
|
|
|
|
2018-02-15 13:14:35 +01:00
|
|
|
return !seat_has_master_device(s);
|
2011-05-25 00:55:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void seat_add_to_gc_queue(Seat *s) {
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
if (s->in_gc_queue)
|
|
|
|
return;
|
|
|
|
|
2013-10-14 06:10:14 +02:00
|
|
|
LIST_PREPEND(gc_queue, s->manager->seat_gc_queue, s);
|
2011-05-25 00:55:58 +02:00
|
|
|
s->in_gc_queue = true;
|
|
|
|
}
|
2011-05-26 02:21:16 +02:00
|
|
|
|
|
|
|
static bool seat_name_valid_char(char c) {
|
|
|
|
return
|
|
|
|
(c >= 'a' && c <= 'z') ||
|
|
|
|
(c >= 'A' && c <= 'Z') ||
|
|
|
|
(c >= '0' && c <= '9') ||
|
2017-10-04 16:01:32 +02:00
|
|
|
IN_SET(c, '-', '_');
|
2011-05-26 02:21:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool seat_name_is_valid(const char *name) {
|
|
|
|
const char *p;
|
|
|
|
|
|
|
|
assert(name);
|
|
|
|
|
|
|
|
if (!startswith(name, "seat"))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!name[4])
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for (p = name; *p; p++)
|
|
|
|
if (!seat_name_valid_char(*p))
|
|
|
|
return false;
|
|
|
|
|
2011-06-29 01:48:59 +02:00
|
|
|
if (strlen(name) > 255)
|
|
|
|
return false;
|
|
|
|
|
2011-05-26 02:21:16 +02:00
|
|
|
return true;
|
|
|
|
}
|