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:
- Udev rules are triggered when the USB device is plugged/unplugged to create a file in '/tmp' named '.vlc_gui'.
- A systemd user service starts a script on startup.
- This script uses inotifywait to monitor a file's creation/deletion in the '/tmp' folder, and act accordingly;
- 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.
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/