Home

Multi-seat is a generic term that refers to an operating system capable of,  and configured for,  supporting multiple workstations per computer. It is usually associated with the Linux operating system since Microsoft Server has a proprietary name for this functionality, as do other proprietary systems that build on top of Microsoft Server such as nComputing’s,  and the proprietary version of Linux called Userful Multiplier.

Advantages of multi-seat are centralization of administration and load sharing. Most of the time a computer is idling while waiting for you to type or move the mouse. With multiple workstations connected, the computer supporting these workstations can be productive for a larger percentage of the time. It doesn’t have to be n times more powerful than a standalone computer because the individual workstations don’t all require simultaneous support. Then too, for accessing a library catalog, browsing the web, or writing a term paper, modern computers are much faster than a single user can utilize.  Another consideration is reduced electricity consumption .  The UD-160-A draws only 5.0-5.3 watts each with 1920 x 1080 resolution  compared to providing a separate computer for each workstation.

An additional reason is security.  A USB zeroclient has no cpu and its only memory is its display internal  frame buffer.  Upon logout, this frame buffer is overwritten with the login wallpaper and login form, eliminating any visual  desktop data from the previous user session. The workstation can be in an attractive creative space, while its server is in a separate physically secure utility room or closet. The Plugable UD-160-A is advertised as a USB  docking station because many people now have laptops and like to add additional larger monitors, full size keyboard, mouse, and speakers.  A USB zero client is just a docking station used instead for multi-seat.

View 2012 video interview with Bernie Thompson: http://Phoronix

11-29-2019  two units of Plugable UD-160-A, donated by Bernie Thompson, arrive.  These self configure their unique seats, whether connected at boot,  or later when hot-plugged when running Manjaro Linux 18.  I am using the XFCE version. See links for both:

https://plugable.com/products/UD-160-A

https://manjaro.org/

This image has an empty alt attribute; its file name is IMG_2413-cropped-1024x604.jpg

Here they are connected to a 2012 vintage Dell Precision T160 with Intel i3-2120 (@ 3.30 Ghz, 2 cores, each with hyperthreading) and 8 GB of DDR3. The left monitor user is watching the MJQ play “Bag’s Groove” full screen on Youtube while the middle user is watching Barbara Dennerlein playing Hammond B3 organ, “Jimmie’s Walk”  full screen on Youtube.  The third monitor on right is connected directly to the computer and is running task manager to report cpu and memory usage.  Before the two users on the UD-160-A logged in, and the main computer was only running task manager, it was idling with cpu usage of 1% and memory usage of 11%. Once the two users on the UD-160-A logged in and were playing Youtube videos full screen, cpu usage ran 34-39% and memory usage 32% so additional UD-160-A based workstations could be supported.

Once you have a computer running Manjaro and one or more Plugable UD-160-A USB 2.0 docking stations (zeroclients), multi-seat is as simple and automatic as connecting the UD-160-A units. However, if you have different zeroclient hardware or want to understand  how this works, read on.  Following a detour about manually creating seats, I will end with a method to determine the idVendor and idProduct values needed to create an entry in /usr/lib/udev/rules.d/71-seat.rules so that your specific brand and model of usb zeroclient can be enabled to automatically create its own seat when hot plugged.

Automatic seat creation is a function of the file, /usr/lib/udev/rules.d/71-seat.rules

# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# /usr/lib/udev/rules.d/71-seat.rules
#
# systemd is free software; you can redistribute it and/or modify it
# 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
# (at your option) any later version.

ACTION=="remove", GOTO="seat_end"

TAG=="uaccess", SUBSYSTEM!="sound", TAG+="seat"
SUBSYSTEM=="sound", KERNEL=="card*", TAG+="seat"
SUBSYSTEM=="input", KERNEL=="input*", TAG+="seat"
SUBSYSTEM=="graphics", KERNEL=="fb[0-9]*", TAG+="seat"

SUBSYSTEM=="drm", KERNEL=="card[0-9]*", TAG+="seat", TAG+="master-of-seat"
SUBSYSTEM=="usb", ATTR{bDeviceClass}=="09", TAG+="seat"

# 'Plugable' USB hub, sound, network, graphics adapter - note "000[13]" = "0001" or "0003"
SUBSYSTEM=="usb", ATTR{idVendor}=="2230", ATTR{idProduct}=="000[13]", ENV{ID_AUTOSEAT}="1"

TAG=="seat", ENV{ID_PATH}=="", IMPORT{builtin}="path_id"
TAG=="seat", ENV{ID_FOR_SEAT}=="", ENV{ID_PATH_TAG}!="", ENV{ID_FOR_SEAT}="$env{SUBSYSTEM}-$env{ID_PATH_TAG}"

LABEL="seat_end"

To understand how the UD-160-A automatically creates its seat, I have edited out code for other hardware. Note the comment for ‘Plugable’ and the line that follows. == is a comparison. If the comparison matches, then the assignment,=, at the end of the line is made. In the case of the UD-160-A, the idVendor is 2230 and the idProduct is 0001, so it will automatically create its own seat. 2230:0001 is the TERMINUS TECHNOLOGY INC. usb 2.0 hub in the UD-160-A whose children are the 4 USB 2.0 ports, the DisplayLink DL-165 usb to DVI adapter, and the USB audio device.

Note that seats created automatically in /usr/lib/udev/rules.d/71-seat.rules also automatically disappear when their zero clients are unplugged. Thus you can not use a UD-160-A to create a seat and then substitute a different brand and model at the same USB port. In contrast, seats manually created with the loginctl attach command persist across booting and after removed, providing they are not enabled in

/usr/lib/udev/rules.d/71-seat.rules

Before I had any Plugable UD-160-A, I only had HP T100/150/200 USB zeroclients so had to manually create their seats with loginctl attach seatNAME DEVICE. I will discuss manual creation of seats for these which are not yet supported in 71-seat.rules.

I initially liked Mint Linux (first above with HP T150 zero cients) and CentOS (second above with Atrust network attached m220 zero clients)  best until  Mark Gress alerted me that Manjaro Linux (below)  allows hot-plugging USB connected zero clients.

The background image of each workstation login screen is configurable based on default user for that workstation. The rightmost display is connected directly to the desktop integrated video and its default login user has customized its background.

Here you can see three zero clients connected to a Plugable brand unpowered USB 3.0 hub (with unused gigabit network port). This permits connecting all three zero client to the computer with a single USB 3.0 cable.

The leftmost two zero clients are HP T150. The rightmost zero client is an HP T100. It contains no USB ports for keyboard and mouse, only the legacy PS2 connectors, so I have connected it through an external Belkin USB 2.0 hub so I can connect a wireless Logitech unifying receiver for this zero client too. For monitors with built in 2 port USB hub, you could use that instead. Normally you would mount each USB zero client on the back of its display.

Currently, there is no non-proprietary linux driver for the SMSC FX6000 USB to VGA chip in an HP T200, but it can be used as a gigabit network 4 port USB hub for creating 4 HP NL571AA multi-seats on CentOS Linux for which there is a free USB server package for the EST chip in the T200.

The command below gives full documentation of the loginctl command. First read its manual.

[asm32@mamjaro-asus ~]$  man loginctl

The second step is to create new named seats for your zero clients. Seat0 is the motherboard seat and already exists. To create a new seat, you must identify potential hardware to attach to it. Seat names may consist only of a–z, A–Z, 0–9, “-” and “_” and must be prefixed with “seat”. Don’t attempt to recreate seat0 nor try to attach any of its essential hardware to a new seat! A seat must have a video device attached to it.

[asm32@mamjaro-asus ~]$  loginctl seat-status

This will list all relevant hardware. Initially there is only seat 0. Each multi-seat zeroclient will have its own USB connected video device. Seat 0 will be the onboard integrated video – you don’t want to do anything with it! All the other video devices will be USB ones (including any that are connected by a network cable using a USB server) and will have “usb” in their device path. If you can identify each zero client video device, attaching it will pull in any thing attached to its internal USB hub like keyboard, mouse, and audio. Each video device has the word “drm” in its device path. You can use the linux command, “grep” to search for lines containing only both usb and drm.

grep is a very useful filter for editing text. With two more steps I can in addition eliminate the lines with DVI and remove the stuff before /sys/.

[asm32@mamjaro-asus ~]$  loginctl seat-status -l |grep drm |grep usb|grep -v "DVI"|grep -o '/.*'    

Card numbers are unique to the system. Unfortunately, you can’t count on card0 being the integrated video. On my Dell Precision T1600, integrated video is card1 and my three USB zero clients are card0, 2, and 3. Thus you can’t just name the zeroclient seats after their card number. cat -n will add line numbers that we can use for seat names. Unfortunately, it right justifies the numbers and precedes them with spaces. After the line number, it uses a tab instead of a space which loginctl won’t be able to parse correctly. Sed ‘s/^\s*/ seat/g’ will replace the 5 leading spaces (assuming that there are at most 1-9 zeroclients) with the string ” seat”. Expand -t 1 expands the tab to a space (tab stops at 1 character intervals). The last use of sed will preface each line of the output of loginctl seat-status -l with loginctl attach.

[asm32@mamjaro-asus ~]$ loginctl seat-status -l |grep drm |grep usb|grep -v "DVI"|grep -o '/.*'|cat -n|sed 's/^\s*/ seat/g'|expand -t 1|sed -e 's/^\(.*\)$/loginctl attach\1/'

Now lets run this command on two zeroclient hardware configurations to illustrate the final step. My motherbhoard has two USB 3.0 ports and lots more USB 2.0 ports. Above was a picture of three USB zero clients, each attached through a USB 3.0 hub to a single USB 3.0 cable back to the computer. Let’s make it a little more complex by adding a 4th USB zero client connected directly to the computer, either its second USB 3.0 port, or one of its many USB 2.0 ports. One of my USB 2.0 ports has a logitech unifying receiver for the computer seat0. I have to be careful not to assign my seat0 input devices to a new USB zeroclient!

Let’s start with attaching the 4th USB zero client to my second unused USB 3.0. It is necessary to have root privileges to make changes.

[asm32@mamjaro-asus ~]$ loginctl seat-status -l |grep drm |grep usb|grep -v "DVI"|grep -o '/.*'|cat -n|sed 's/^\s*/ seat/g'|expand -t 1|sed -e 's/^\(.*\)$/loginctl attach\1/'
 loginctl attach seat1 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/drm/card0
 loginctl attach seat2 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.3/1-1.3.1/1-1.3.1:1.0/drm/card1
 loginctl attach seat3 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.4/1-1.4.2/1-1.4.2.1/1-1.4.2.1:1.0/drm/card4
 loginctl attach seat4 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-2/1-2.3/1-2.3:1.0/drm/card2

Looking for the first unique character differentiating each of these lines, they are the ones I have made bold. These (-1.2, -1.3, -1.4) are the three ports of my USB 3.0 hub that each of the three zero clients are plugged into. I am not interested in the rest of the device path to the USB to VGA device inside the zero client because I want to automatically attach every device internal to the zero client with a single attach statement. Truncating each line after the bold unique character leaves the proper commands.

loginctl attach seat1 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.2
loginctl attach seat2 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.3
loginctl attach seat3 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.4
loginctl attach seat4 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-2

Note that the fourth USB zero client has a shorter path because it alone is attached to that port, whereas the first three go through an intermediate USB 3.0 hub.
Executing these four commands from the terminal on Manjaro sets up four usb zeroclients which will display new login screens immediately as each command executes. The result can be seen below.

 [manjaro asm32]# loginctl list-seats
 SEAT 
 seat0
 seat2
 seat3
 seat4
 4 seats listed.
 [manjaro asm32]#

Now let’s try connecting the fourth USB zeroclient to a USB 2.0 port. After first checking which USB 2.0 port my motherboard input devices are connected to and avoiding any of those sub-ports, and flushing my previous attached seats, I try:

[asm32@mamjaro-asus ~]$ loginctl flush-devices

[asm32@mamjaro-asus ~]$ loginctl seat-status -l |grep drm |grep usb|grep -v "DVI"|grep -o '/.*'|cat -n|sed 's/^\s*/ seat/g'|expand -j 1|sed -e 's/^\(.*\)$/loginctl attach\1/'
 loginctl attach seat1 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/drm/card0
 loginctl attach seat2 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.3/1-1.3.1/1-1.3.1:1.0/drm/card1
 loginctl attach seat3 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.4/1-1.4.2/1-1.4.2.1/1-1.4.2.1:1.0/drm/card4
 loginctl attach seat4 /sys/devices/pci0000:00/0000:00:12.2/usb3/3-2/3-2.3/3-2.3:1.0/drm/card2
 loginctl attach seat1 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.2
 loginctl attach seat2 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.3
 loginctl attach seat3 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.4
 loginctl attach seat4 /sys/devices/pci0000:00/0000:00:12.2/usb3

Note that this time the device path to the fourth USB zero client is even shorter because no other device is connected to the usb3 device. If anything else were attached to the other ports of usb3, then they would be attached to the fourth USB zero client. If that is not what is desired, it would be necessary to specify which of the multiple usb3 ports the fourth USB zero client is attached to. USB zero clients are nice because the process of configuring them can be entirely automated. Linux devices are organized just like a file system with multiple sub-directories. A program to configure them reads a text file of resource device paths and looks for the shorted common prefix that includes at least …/usb?. If that is the only USB zeroclient attached to that USB port, it attaches it to a seat and eliminates that line from the resource list of potential USB zeroclients. In our first example, two USB 3.0 ports were serviced by one motherboard USB device and one of those two USB 3.0 ports had an external USB 3.0 hub between the motherboard device and the first three USB zero clients. so the device paths are longer.

Rather than looking for the first character distinguishing each seat, an equivalent approach that is easier to parse would be to discard the rest of each line. We know that each zero client has an internal usb hub to which the usb to vga device is connected. Examining the previous example, we know that exactly the last 4 “/” characters and the content following each of them can be discarded. This is easily done with four applications of sed ‘s|\(.*\)/.*|\1|’, each of which removes the last one. Considering the previous two hardware examples produces:

[asm32@mamjaro-asus ~]$ loginctl seat-status -l |grep drm |grep usb|grep -v "DVI"|grep -o '/.*'|sed 's|\(.*\)/.*|\1|'|sed 's|\(.*\)/.*|\1|'|sed 's|\(.*\)/.*|\1|'|sed 's|\(.*\)/.*|\1|'|cat -n|sed 's/^\s*/ seat/g'|expand -t 1|sed -e 's/^\(.*\)$/loginctl attach\1/'
loginctl attach seat1 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.2
loginctl attach seat2 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.3
loginctl attach seat3 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.4/1-1.4.2
loginctl attach seat4 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-2

[asm32@mamjaro-asus ~]$ loginctl seat-status -l |grep drm |grep usb|grep -v "DVI"|grep -o '/.*'|sed 's|\(.*\)/.*|\1|'|sed 's|\(.*\)/.*|\1|'|sed 's|\(.*\)/.*|\1|'|sed 's|\(.*\)/.*|\1|'|cat -n|sed 's/^\s*/ seat/g'|expand -t 1|sed -e 's/^\(.*\)$/loginctl attach\1/'
loginctl attach seat1 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.2
loginctl attach seat2 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.3
loginctl attach seat3 /sys/devices/pci0000:00/0000:00:07.0/0000:02:00.0/usb1/1-1/1-1.4/1-1.4.2
loginctl attach seat4 /sys/devices/pci0000:00/0000:00:12.2/usb3/3-2

Notice the /1-1.4.2 above. This is the silver Belkin USB 2.0 hub that I inserted the Logitech unifying receiver for the HP T100 zero client that only had PS2 input ports. If, as I do, I want that to be part of the HP T100 zero client, I have to manually edit out that
/1-1.4.2 so that those become part of the HP T100 zeroclient. The HP T100 came out before the HP T150 model was available. You wouldn’t buy one of these now unless it was much cheaper than the T150 and only if your monitors had USB hubs so you could use USB keyboards and mice, but since I had the Belkin hub it illustrates how you could handle that situation.

We now have an automatic method to parse the output from loginctl seat-status -l to create a text file containing the commands we need to create a bash script and give the file execute privileges. As soon as it is executed with root privileges, the system will remember this multi-seat configuration. If you hot plug the same zeroclients into the same ports, they will each display a login screen. If you wish to return to single seat just execute as root, loginctl flush-devices to return all hardware to the default seat0. You should also execute loginctl flush-devices if you want to add additional zeroclients or plug them into different USB ports. Then start over creating a new script based on the new zeroclient configuration.

As a first approach, it made sense to use loginctl to get the resource information required to create seats with loginctl. For USB zeroclients, I only need to identify the path to the internal USB hub and this is most uniquely done by looking for its child device, the USB to video chip connected internally. For this, loginctl seat-status generated much more information than I need which has to be edited out. Where does loginctl get its information? Can I more selectively get that information directly? See this link:

https://www.kernel.org/doc/html/latest/admin-guide/sysfs-rules.html

The sysfs is a database in the form of a directory and file hierarchy built at each boot. The main branch descends from /sys/devices. If you look at the /sys/ directory, you will see other subdirectories. Think of these as selective views connected by symbolic links to /sys/devices/…

I am particularly interested in /sys/class/drm because there will be symbolic links to all the video devices in /sys/devices. There is a utility, readlink, for converting these symbolic links into the full path in /sys/devices.

[asm32@manjaro-t1600 ~]$ readlink -f /sys/class/drm/card? |grep usb

Now I need to truncate the result by cutting off the 4th to last / and all the follows:

[asm32@manjaro-t1600 ~]$ readlink -f /sys/class/drm/card?|grep usb|sed 's|\(.*\)/.*|\1|'|sed 's|\(.*\)/.*|\1|'|sed 's|\(.*\)/.*|\1|'|sed 's|\(.*\)/.*|\1|'

Finally I want to create seat names and preface each output line with sudo loginctl attach seat.

[asm32@mamjaro-asus ~]$ readlink -f /sys/class/drm/card?|grep usb|sed 's|\(.*\)/.*|\1|'|sed 's|\(.*\)/.*|\1|'|sed 's|\(.*\)/.*|\1|'|sed 's|\(.*\)/.*|\1|'|cat -n|sed 's/^\s*/ seat/g'|expand -t 1|sed -e 's/^\(.*\)$/sudo loginctl attach\1/'

My seat naming is not ideal because once some seats have been created, adding more seats has no history of existing seats so the seat numbering would start again at seat1 redefining a previously existing seat rather than adding the new one as intended. To use this requires flushing all seat definitions and starting over. A better approach would be to name created seats uniquely based on their device path as is done by zero clients specified in 71-seat.rules. Having prototyped a solution with existing utility filter programs, it is now an easy matter to write a filter specifically for configuring usb zero clients which could both generate the required loginctl attach commands and internally execute these commands.

Before doing that, let’s revisit /usr/lib/udev/rules.d/71-seat.rules and see if we can write entries for currently unsupported usb zero clients such as the HP T100/T150 models I already have. What would their idVendor and idProduct be? It would be awfully nice to let systemd create the seat names. With that objective let’s shorten my previous command and remove the filters that created seat1-9

[asm32@mamjaro-asus ~]$ readlink -f /sys/class/drm/card?|grep usb|sed 's|\(.*\)/.*|\1|'|sed 's|\(.*\)/.*|\1|'|sed 's|\(.*\)/.*|\1|'|sed 's|\(.*\)/.*|\1|'

Executing this command will create a list of paths for each zeroclient plugged in but not yet supported in 71-seat.rules. If you list the directory of each of these paths, you will see text files named idVendor and idProduct. These files have the numbers that you need to add to 71-seat.rules for them to automatically create their own seats.

For my own HP T100 and HP T150 zero clients, I need to add these lines to 71-seat.rules after the existing two lines for Plugable:

# 'HP T150' USB hub, sound, graphics adapter 
SUBSYSTEM=="usb", ATTR{idVendor}=="03f0", ATTR{idProduct}=="0032", ENV{ID_AUTOSEAT}="1"

# 'HP T100' USB hub, sound, graphics adapter 
SUBSYSTEM=="usb", ATTR{idVendor}=="0424", ATTR{idProduct}=="2514", ENV{ID_AUTOSEAT}="1"

The HP T100 zeroclient has PS2 ports, but no USB ports for a modern keyboard/mouse. You can connect the T100 through an intermediate usb hub to provide USB ports for this seat. In this case you want to use the idVendor and idProduct of the external hub instead of the T100. All along I have been using a BelkinUSB 2.0 hub to connect my Logitech unifying wireless receiver for this HP T100 seat. You could also use any USB hub incorporated in your monitor, using one of its ports for connecting the HP T100 and the other for a unifying receiver. In this case, the idVendor and idProduct needed for 71-seat-rules would be that of the external USB hub. Not only would this work for the HP T100, but it would work for any other USB zeroclient without having to have a specific entry in 71-seat.rules for a specific USB zeroclient. Manjaro will descend to the depth necessary to find the usb to video sub device and create a seat for everything.

That is the beauty of USB zeroclients – they can automatically create their own unique seat names and display login screens on their attached monitors.

There is no way to automatically create seats based on extra internal video cards, sound cards, and usb ports with input devices because these can be combined in arbitrary ways requiring administrative choices. Before audio was part of a zero client, one method was to display a screen on each seat asking for a key press and mouse click to link specific keyboards and mice pairs to a specific seat. Perhaps this idea could be extended to linking audio by speaking into a mic connected to each seat.

In the meantime. Mark Gress has written a java GUI app for attaching devices to seats which can be downloaded here: https://easy-seats.weebly.com/