Multi-seat on Linux, demystified
1. What is multi-seat, anyway?
According to Wikipedia, multi-seat is the ability for one physical computer to serve multiple local users at the same time.
This may seem a bit confusing, because we also have terms multi-user and multi-tasking.
Multi-tasking is the obvious thing of doing multiple tasks at the same time, like browsing and playing mp3, serving HTTP request and simulating weather patterns).
Multi-user is also obvious - the system can support multiple users using it at the same time. Example: When you are accessing a website on a certain webserver running on a certain machine, you are (loosely speaking) a "user" of that machine. That machine will happily serve a thousand users like you. Likewise, you connect to your home PC using SSH (or your other favorite remote connection software) at the same time that your kid is playin games on it, then your home PC is serving multiple-users - you and your kid. (There are other more obscure use of "users", but that is beside the point so I won't talk about it).
That seems to cover everything, so where does that leave us? what makes "multi-user" different from "multi-seat"? The key difference here is the word "local". A "multi-seat" system enables on physical computer to server multiple "local" users, that is, users with monitors and keyboards connected directly to that computer.
This is indeed a rare configuration. Most systems only have one monitor and one keyboard/mouse attached to is, so at most there can only be one "local" user (=single-seat systems). Some systems may have multiple monitors, but only one keyboard/mouse and still at most one person using it at the same time - so it still qualifies as a single-seat system.
Some systems may even have multiple monitors and multiple keyboards/mice, but there is only one person using it (the keyboards/mice are located in different places for convenience, e.g. one near the monitor and one on the bed for bed-time browsing for example). This is still considered as single-seat systems too.
So what exactly is multi-seat system?
A multi-seat system is a system with multiple input/output devices where each monitor/keyboard/mouse combination works as if it is independent computer. A three-seat system is one physical computer, with 3 screens and 3 keyboards and 3 mice, and each screen/keyboard/mouse acts as if they are separate computers (ie each screen will have its own mouse pointer, moving a mouse only moves the pointer on its own screen and not the others, same thing for keyboard input etc).
If this is difficult to imagine, then imagine a server with 3 different laptops connected to it through the network, and all of these laptops SSH into the server. All the commands inside that SSH session are executed by the server, and the laptops effectively only act as input/output device (screen and keyboard). Now imagine the exact same thing - without the laptops, only with the monitors and keyboards. Then you have multi-seat.
Hang-on, Linux has multiple virtual terminals (VT) that enables multiple user to work on it. User A can login on VT1, user B can only on VT2, and so on. Isn't this considered multi-seat too?
Nope, not really. With Linux virtual terminals, only one person can work at the same time because all these VTs eventually share one monitor, one keyboard. User A and user B can't type at the same time, for example.
Okay, got it, but what good is multi-seat for?
It's good when you need to share one powerful resource (your over-engineered home PC e.g 16-cores and 64GB RAM) with multiple users at the same time (e.g. your kids). Or other situations similar to that - I'd let your imagination soar :)
Of course, it only makes sense to do this when your computer is powerful. If all you have is an Atom-powered netbook with 1GB RAM - you would be better off getting another netbook.
Multi-seating isn't new. In days past, people had one large computer (time-sharing system) with multiple video terminals attached to it, sometimes directly, sometimes through terminal concentrator. These video terminals were "dumb" devices, they were the equivalent of monitor/keyboard combo (plus a bit of hardware to handle serial communication with the computer) and connected "locally" to this large computer. Among these terminal one was special and is called as the "console" - this was the terminal that got initialised first and was always enabled for troubleshooting purposes; but other than this, this "console" and the rest of the terminals were identical in purpose and design.
For all intent and purposes, large time-sharing systems were the original multi-seat systems.
When Unix system came with its networking interface (TCP/IP), along came a new kind of "terminal" - those that instead of serial communication, used networking to connect to the main computer. These enables the terminals to be more geographically spread - instead of all terminals being in the same room, you can now have it spread across the entire building (or sometimes, across buildings too), and with growing computing power one could attach more of these network terminals.
As these "network terminals" grew in computing power, more and more tasks are done locally on the terminals instead on the main computer itself. This gave rise to the "client-server" architecture where the "client" it not just a simple "dumb terminal" acting as input-output device but instead a real machine with processing capability, offloading work from the main computer - something that the directly attached terminals can't do and putting them at serious disadvantage.
This, with the fact that directly attached terminals were vendor-specific (IBM terminals only worked for IBM computers, obviously) - as opposed to "clients" which were able to with multiple vendor platforms due their emulation capability (=thus born the term "open systems"), spelled death to directly attached terminals. After a while, the only directly attached terminal that survives is the "console", and sometimes, even this console is not used (in this case system is said to run headless).
The return to multi-seat marks the time that PCs (="network terminals") themselves have grown so much in computing power that they can act as a little time-sharing systems that they used to serve. This time around, though, there were no dedicated "terminals" - just monitors and keyboards (and mice).
2. How does multi-seat work?
If you have read until here, it should be clear that multi-seating is just another aspect of resource allocation, just like multi-user (=mainly disk resources) and multi-tasking (mainly memory / CPU resources). This time around, the system needs to manage physical resources associated with input/output device.
A multi-seat system (obviously) must have multiple monitors, let's say 3 for the same of discussion. It must also have 3 keyboards and potentially 3 mice. All of these must be managed and treated as one to give the illusion that each monitor/keyboard/mouse combo is a separate terminal.
How do these resources get managed and/or splitted? There are so many many ways to do it - I'll just outline the basics.
In modern Linux system, input devices are managed by evdev infastrcture
(evdev = event device = devices that creates events such as mouse move,
keypress, etc). Every input system will have its own evdev device.
(If you have
evtest program you can run it in terminal to see what
evdev devices are available on your system; if you don't have it you can
cat /proc/bus/input/devices to see similar information).
Every keyboard and every mouse plugged will have its own evdev devices. To enable multi-seat, it is enough to create a logical group somewhere that says "evdev devices for keyboard #1 and mouse #1" is for seat 1, "evdev devices for keyboard #2 and mouse #2" is for seat 2; and when it is time to combine output/input together, just use this configuration.
The situation for output devices is a little more complicated. Firstly, you have two choices - do you want to have a regular text-only output devices (like terminals of yore) or graphical output devices? Secondly, to have a multi-monitor set-up you can use either:
- multiple graphic cards each supporting a single monitor (=multi-heads), or
- one graphic card with support for multiple monitors (=zaphod heads), or
- a combination of the above.
In any case, however, the resource management is done by X (Xorg) server for graphical output. There is no equivalent resource management for text-output - but we'll look at the alternatives later.
Multi-seating configuration for graphical output
For now, lets assume you want to use graphical terminals (they are more useful, more modern, and of course can support text terminals too use terminal emulator like xterm and the like).
If you have (1), things are easy. You just run multiple X (Xorg) server, one for each graphic cards. You can use a single xorg.conf, containing multiple ServerLayout sections. Each ServerLayout defines the physical video card to use, as well as the input devices to be used (in terms of evdev devices as discussed earlier). An Xorg server running a given layout will only output to that given video card, and only accepts input from the given evdev devices, thus each ServerLayout corresponds exactly to a "seat".
To start the first seat, you just need to run "X :1 -layout seat1", to start the second seat, you just need to run "X :2 -layout seat2", etc.
If you have (2), which is more common these days (you have one card with multiple outputs - one VGA, one DVI, one HDMI for example), then this is a little more complicated - but only a little.
With one physical card, you cannot run multiple Xorg servers. What you can do, though is run one master Xorg server which manages the physical hardware (one card and all the 3 monitors) and multiple virtual slave Xorg servers (using Xephyrs), each running its own maximised window, each on its own monitor (slave server #1 displays window #1 maximised on monitor #1, slave server #2 displays window #2 maximised on monitor #2, etc).
To do this, configure the master Xorg server not to grab/accept input from any devices (unless you have a spare keyboard/monitor you want to use for troubleshooting). Also, disable Xinerama - this will give you three screens to work with (:0.0, :0.1 and :0.2) instead of one big combined screen. Then configure each slave server with the correct input using its "-keybd" and "-mouse" flags).
Thus, here, each slave Xephyr server configuration represents the "seat".
If you have (3), then you'll just have to combine (1) and (2) together.
Multi-seating configuration for text-only output
I wonder why you'd want this, since the graphical output can handle text-output as well using terminal emulation, but let's say you need this.
The most obvious option, using Linux VTs, won't work. Linux VTs only work on seat0 - the first seat; and if you try to use it, it will display the same contents on all monitors and take input form all keyboards, so not good. (Linux VT is rather simple and was designed for use as system-console, not really as "terminals" in the traditional sense. Its simplicity is good because it avoid unnecessary bugs and making sure it is available when I really need it, e.g when I need to troubleshoot non-working multi-seat configuration).
The infrastructure for multi-seat text console is already there: the same evdev input subsystem can be used, and for output, instead Xorg, Linux kernel provides DRM interface (via libdrm) which can be used to control independent output to individual monitor (in fact modern Xorg these days make use of the same libdrm - they no longer control graphics hardware directly).
All that is needed is simple terminal-emulator, using libdrm for output, which accepts flags telling it which DRM device to use for output and which evdev device(s) to use for input. If you want to get fancy, you can get these configuration information from udev and configure these devices based on ID_SEAT property, like what Xorg does.
The closest one we have is "kmscon", a libdrm-based terminal emulator (with nice features such as UTF-8 support), but when configured with multi-seat support it will totally unnecessarily cluttered itself with systemd library to do what should be just a simple configuration flag. It should be straightforward to remove this dependency, however.
Assuming that a patched kmscon works, then all that is needed is to
run multiple kmscon instances (one for each "seat", configured to use
specific display and input devices); and tell kmscon to run
when started. Add this to your inittab and you'll have no-fuss
multi-seat text login :)
3. Other devices
We have discussed about the primary input devices: keyboards and mice, and the primary output device: the display. How about other input/output devices, such as sound input/output, USB hubs, etc?
The basic of multi-seat is the ability to manage individual devices and assign them to a controlling entity that manages it on per-seat basis. There is no such thing for sound cards.
If you have a single soundcard this is not an issue as by default, ALSA will mix outputs from all users to the soundcard, regardless of on which seat the request comes from (note: PulseAudio is not needed).
In theory you can have multiple soundcards, and configure that every seat only access a certain soundcard - but Xorg does not do this, and ALSA configuration is on per-user basis rather than per-seat; so you have to create some sort of session login script (which detects the seat you're on) and creates ALSA configuration that points to the correct soundcard.
USB devices (e.g. USB hubs, flash drives, etc) are shared devices; and there is no controlling mechanism for them; so by default you will have to treat them as shared devices.
If you need to treat them as private device, then you will need set-up udev rules to control the permission of these USB devices - making sure that e.g. a USB devices tagged for "seat1" is only made available for a user currently logged in "seat1" and no one else.
This works if all the users on all seats are not root users. Root users can easily bypass this restriction, so it's not perfect. That being said, when one goes with multi-seat, one is running a "multi-user" computer in the truest sense so running as "root" should not be taken lightly and should only be done when it is really necessary (i.e. to fix problems or to setup the system).
Other devices can be managed in more or less the same way.
3. Other possibilities
Using Xorg and Xephyr to make a "seat" is not the only option. There are plenty others. Recent Xorg server for example has a multi-master mode where a single Xorg server can have multiple independent controls from independent devices (ie multiple mouse cursors, each for each mouse; and multiple input focus). With this mode, each "master" can be made to represent the "seat". This is very recent however and support from other supporting programs (window managers, etc) are still lacking, so it's not a workable solution at the moment. May be in the future.
A more immediate possibility is to run a virtualised environment, either full virtualisation (qemu) or lightweight one (lxc). With qemu, for example, it can be configured to take input from certain device, and output to a certain display (fullscreen on :1 or :2 for multi-heads or :0.2 or :0.3 for zaphod-heads). It can also be configured to "grab" certain USB devices for excluse use in its VM - thus making USB devices as part of "seat-managed" devices. Same for audio devices. In this case, each qemu configuration represents a "seat".
We can do the similar things through a combination of LXC and Xephyr. The granularity of control is perhaps not as good as qemu but lxc has less overheads.
Of course, you can do the same with VirtualBox and probably other virtualisation solutions too.
By now it should be clear that multi-seat is just resource management, grouping of resource to work together so they give the illusion that a group of monitor/keyboard/mouse are acting together as a terminal. It is the same illusion that a single-core CPU can run multiple tasks at the same time.
All that is needed is the ability to tell a program that controls both input and output, of where to get its input and where to do its output. Xorg is a program that does it, Xephyr is another, and qemu is yet another.
It is not magical, it is not mysterious, and it works now, no other components is needed: just your basic desktop setup.
And if you're asking me, where is systemd's place in all this, the answer is - nowhere. Except in relation to kmscon, you don't see any reference to systemd because systemd is not needed for multi-seat (on contrary to common belief); and even kmscon can be patched to be independent of systemd. See reference (2) where multi-seat was done successfully as far back as 2006, long before systemd was even conceived.
- Arch forum: Xorg multi-master
- Arch Wiki: Xorg multi-pointer