GNU/Linux - Udev & systemd - Running a graphic environment when a USB device is plugged in

Summary :

At a GNU/Linux console prompt, no GUI. When a USB device of type HID (keyboard/mouse mainly) is plugged in, we want the X server to start and launch VLC's graphical interface, fullscreen, no borders. When this device is removed, VLC is shut down and the X server too, and we end up back at the console prompt.

Proposed solution:

  1. Udev rules are triggered when the USB device is plugged/unplugged to create a file in '/tmp' named '.vlc_gui'.
  2. A systemd user service starts a script on startup.
  3. This script uses inotifywait to monitor a file's creation/deletion in the '/tmp' folder, and act accordingly;
  4. Start/close a minimal graphical environment with openbox running VLC.

1. Udev configuration

Run script on USB HID (mouse/kb) connect

We want a rule that triggers when a device has SUBSYSTEM=="usb" and DRIVER=="usbhid".

In '/etc/udev/rules.d/01-vlc_gui.rules' :

# On plug
ACTION=="add" SUBSYSTEM=="usb", DRIVER=="usbhid", RUN+="/usr/bin/touch /tmp/.vlc_gui"
# On un-plug
ACTION=="remove" SUBSYSTEM=="usb", RUN+="/usr/bin/rm -f /tmp/.vlc_gui"

The rules above create a '.vlc_gui' file in '/tmp' when a usbhid device is plugged in, and removes it when unplugged.

Change read permissions on tty7

By default, permissions on '/dev/tty*' are 0620 (crw--w----). So members of group tty can write, but not read to ttys. This will be a problem for the X server, so we need to change those permissions to have read writes for our group too.

Let's change the permissions on the tty that we need to 0660 (crw-rw----) so that we can run our X session on it.

Inspect how udev sees your TTY (tty7 here):

udevadm info --attribute-walk --path=/sys/class/tty/tty7

looking at device '/devices/virtual/tty/tty7':
    KERNEL=="tty7"
    SUBSYSTEM=="tty"
    DRIVER==""
    ATTR{power/control}=="auto"
    ATTR{power/runtime_active_time}=="0"
    ATTR{power/runtime_status}=="unsupported"
    ATTR{power/runtime_suspended_time}=="0

So we want a rule that matches 'KERNEL=="tty7"' and 'SUBSYSTEM=="tty"' and set it to mode '0660':

SUBSYSTEM=="tty", KERNEL=="tty7", MODE:="0660"

Notice the immutable operator ":=" for "MODE"; it makes shure this won't be changed by another rule.

Udev rules order read

Test which rules are triggered by a specific device with :

udevadm test /class/tty/tty7

Reload and apply the new rules with :

udevadm control --reload-rules
udevadm trigger

Of course, don't forget to add your user to the 'tty' group :

sudo adduser USERNAME tty

On some system, you might have to use usermod :

sudo usermod -a -G tty USERNAME

then log out/in and check with groups that 'tty' appears in the listed groups.

2. Systemd user unit

We can create user units in '~/.config/systemd/user/', e.g :

nano ~/.config/systemd/user/vlc_gui.service

[Unit]
Description=VLC GUI launcher service

[Service]
# %h specifier resolves to user home (~ equivalent)
ExecStart="%h"/vlc_gui.sh
Restart=always

[Install]
WantedBy=default.target

Reload the units with systemctl --user daemon-reload
and start/enable the service with
systemctl --user start vlc_gui.service / systemctl --user enable vlc_gui.service.

More about systemd specifiers:
https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers

Starting a user unit as root

If running systemd version >= 248 (2021-03), you can start a user unit as root, i.e ;
using sudo systemctl or in a root shell, with e.g:

sudo systemctl --user --machine USERNAME@ start foo.service

On prior versions, you have to use either
su - USERNAME -c 'systemctl --user start foo.service' or
runuser -l USERNAME -c 'systemctl --user start foo.service' instead.

3. inotifywait : watch for a file's creation/deletion

Install the tool :

sudo apt-get install inotify-tools

Create the script :

In '~/vlc_gui.sh' :

#!/usr/bin/env bash

inotifywait -m /tmp -e create -e delete |
while read directory action file; do
    if [[ "$file" == ".vlc_gui" ]]; then 
        if [[ "$action" == "CREATE" ]]; then
            echo "Starting VLC GUI."
            # Start X environment on tty7
            DISPLAY=:0 startx -- vt7 &
        elif [[ "$action" == "DELETE" ]]; then
            echo "Killing VLC GUI"
            pkill vlc
        fi
    fi
done

Don't forget to set execution bit : sudo chmod +x ~/vlc_gui.sh

4. Minimal X environment & Launching VLC

Install the following packages :

sudo apt-get install -y --no-install-recommends --no-install-suggests xinit xserver-xorg xserver-xorg-core xserver-xorg-input-evdev xserver-xorg-input-kbd openbox feh

Xinit config

We start the X environment with startx, which sources "~/.xinitrc".
Let's start openbox session there.

cp /etc/X11/xinit/xinitrc ~/.xinitrc

Then in "~/.xinitrc" :

#!/bin/sh

# /etc/X11/xinit/xinitrc
#
# global xinitrc file, used by all X sessions started by xinit (startx)

# invoke global X session script
. /etc/X11/Xsession
exec openbox-session

Set execution bit :

sudo chmod +x ~/.xinitrc

Openbox configuration

Now Openbox config files are in '~/.config/openbox' and there are two of them :

autostart.sh

In '~/.config/openbox/autostart.sh' :

#!/bin/bash

# Exit openbox when VLC is closed
vlc --vout=gles2 && openbox --exit
# on rpi with 3d kms driver, can be --vout=drm_vout 

Set execution bit :

sudo chmod +x ~/.config/openbox/autostart.sh

rc.xml

cp /etc/xdg/openbox/rc.xml ~/.config/openbox/

We want the VLC gui launching fullscreen, with no window decoration. In openbox's <applications> section of '~/.config/openbox/rc.xml', l.656, add:

    <application name="vlc" role="vlc-main">
        <decor>no</decor>
        <maximized>yes</maximized>
    </application>

Troubleshooting

Udev rules

You can increase udev's log verbosity with sudo udevadm control --log-priority=debug
then run journalctl -f to see if an error message comes up when plugging/unplugging the USB HID.

Xserver

You can see what's going on by launching journalctl -f in a SSH session, then plug/unplug the USB HID.
If you encounter an error with the X server complaining about permission to tty7 like this

(EE) xf86OpenConsole: Cannot open virtual console 7 (Permission denied)

try rebooting.

Slow mouse cursor

If you experience laggy mouse cursor movements, you can try adding usbhid.mousepoll=0 to '/boot/cmdline.txt'.

Other values you might want to try are :

value speed
0 device request
X 1000/X Hz

source: https://peppe8o.com/fixing-slow-mouse-with-raspberry-pi-os/

0 comments

Write a comment