1

I have this UDEV rule, which gets activated when I plug in my keyboard:

ACTION=="add", DEVPATH=="/devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1:1.0/0003:046A:0011.00??/input/input??/event[0-9][0-9]*", ATTRS{name}=="HID 046a:0011", ATTRS{phys}=="usb-0000:00:14.0-1/input0", RUN+="/home/*user*/.udev_rule_scripts/cherry_keyboard.sh", SYMLINK+="cherrysymlink"

It should

  1. create a symlink /dev/cherrysymlink, which it does, and
  2. execute a shell script, which it doesn't.

Here's the debugging output of udevadm test /devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1:1.0/0003:046A:0011.0003/input/input18/event17:

This program is for debugging only, it does not run any program
specified by a RUN key. It may show incorrect results, because
some values may be different, or not available at a simulation run.

.INPUT_CLASS=kbd
ACTION=add
DEVLINKS=/dev/input/by-id/usb-046a_0011-event-kbd /dev/cherrysymlink /dev/input/by-path/pci-0000:00:14.0-usb-0:1:1.0-event-kbd
DEVNAME=/dev/input/event17
DEVPATH=/devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1:1.0/0003:046A:0011.0003/input/input18/event17
ID_BUS=usb
ID_INPUT=1
ID_INPUT_KEY=1
ID_INPUT_KEYBOARD=1
ID_MODEL=0011
ID_MODEL_ENC=0011
ID_MODEL_ID=0011
ID_PATH=pci-0000:00:14.0-usb-0:1:1.0
ID_PATH_TAG=pci-0000_00_14_0-usb-0_1_1_0
ID_REVISION=0100
ID_SERIAL=046a_0011
ID_TYPE=hid
ID_USB_DRIVER=usbhid
ID_USB_INTERFACES=:030101:
ID_USB_INTERFACE_NUM=00
ID_VENDOR=046a
ID_VENDOR_ENC=046a
ID_VENDOR_ID=046a
LIBINPUT_DEVICE_GROUP=3/46a/11/111:usb-0000:00:14.0-1
MAJOR=13
MINOR=81
SUBSYSTEM=input
USEC_INITIALIZED=31155231
run: '/usr/local/bin/cherry.sh'

When the keyboard is plugged in, /dev/cherrysymlink is created. Also the debugging output says in the last line that the script /usr/local/bin/cherry.sh did indeed run.

The problem is, the script doesn't get actually executed.

cherry_keyboard.sh:

#!/bin/bash

xset r rate 150 60

It should change the autorepeat of the keyboard keys but it stays the same.

I've also tried:

#!/bin/bash

slock

Nothing happens. When I execute the scripts manually in the shell they both work. What am I doing wrong?

EDIT:

After modifying my script like this I am able to pipe the echo output into dzen2 so it pops up on the screen:

#!/bin/bash

export DISPLAY=:0
export XAUTHORITY=/home/*user*/.Xauthority

echo 'test' > /home/*user*/.udev_rule_scripts/test
echo 'test' | dzen2 -p 4
xset r rate 150 60
slock

So far, the first two echo-lines work. The xset and slock commands still don't work.

EDIT2:

After some reading I am pretty certain it has something to do with DBUS and the environment variable "DBUS_SESSION_BUS_ADDRESS". Also, when I run printenv as user, there is DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus set. When I run printenv as root this variable is not set.

Therefore I made another modification to my script:

#!/bin/bash

export DISPLAY=:0
export XAUTHORITY=/home/*user*/.Xauthority
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus

echo 'test' > /home/*user*/.udev_rule_scripts/test
echo 'test' | dzen2 -p 4
xset r rate 150 60
slock

Unfortunately, it still doesn't work.

EDIT3:

After Gilles' suggestion I added a line to the script:

#!/bin/bash

exec >>/home/*user*/.udev_rule_scripts/test.log 2>&1; echo; date

export DISPLAY=:0
export XAUTHORITY=/home/*user*/.Xauthority

echo 'test' | dzen2 -p 4

xset r rate 150 60
slock

which produces the following error message in test.log

Tue Feb 23 10:14:17 UTC 2016
/home/*user*/.udev_rule_scripts/cherry_keyboard: line 11:   858 Segmentation fault      (core dumped) slock

which (kind of) explains why slock fails to execute. Sadly, there's nothing about xset.

EDIT4:

This time, I combined Gilles' and ojs' suggestions. Now the error messages are more interesting:

cherry_keyboard.sh:

#!/bin/bash

exec >>/home/*user*/.udev_rule_scripts/test.log 2>&1; echo; date

export DISPLAY=:0
export XAUTHORITY=/home/*user*/.Xauthority

echo 'test' | dzen2 -p 4

su *user* -c "DISPLAY=:0 xset r rate 150 60"
su *user* -c "DISPLAY=:0 slock"

test.log:

Tue Feb 23 10:37:22 UTC 2016
XIO:  fatal IO error 11 (Resource temporarily unavailable) on X server ":0"
      after 43 requests (37 known processed) with 0 events remaining.

Tue Feb 23 10:38:37 UTC 2016
dzen: cannot open display
xset:  unable to open display ":0"
slock: cannot open display

Tue Feb 23 10:40:54 UTC 2016

Now here's the thing: When I plugin my keyboard, dzen2 pops up on the screen, then the screen goes black. But not because of slock, it kind of crashes and when I type on the keyboard the screen stays black (which it shouldn't when slock was behind it). Other applications like moc are still running.

And now the strange part:

When I press the power button on my laptop to restart the system (which is the only option in this situation I think), before shutdown, the black screen disappears for half a second and instead a red screen appears (the red screen of slock when you type in a wrong password). So slock IS actually running. But why does the error message state that both dzen and slock "cannot open display", while they're in fact both running? And why does the screen crash? And in which way does xset's error message differ?

An alternative cherry_keyboard.sh:

#!/bin/bash

exec >>/home/*user*/.udev_rule_scripts/test.log 2>&1; echo; date

export DISPLAY=:0
export XAUTHORITY=/home/*user*/.Xauthority

echo 'test' | dzen2 -p 4

su *user* -c "DISPLAY=:0 xset r rate 150 60"
#su *user* -c "DISPLAY=:0 slock"

test.log:

Tue Feb 23 10:43:36 UTC 2016

So this time there are no error messages at all.

But, in both versions xset does not modify the autorepeat...

  • 1
    It could be that the script gets executed but by some reason the changes don't get applied. Try a simpler script, like echo "hello" > /tmp/test and see if the /tmp/test file exists and contains the word hello. – ojs Feb 21 '16 at 22:42
  • It could be that PATH is insufficient when executed via udev. – Ralph Rönnquist Feb 21 '16 at 22:47
  • @ojs: That actually worked. But how come 'echo' works but other commands don't? – Arthur Feb 22 '16 at 8:25
  • udev always runs scripts as root. Might it be that you need a simple sudo -u userXYZ for the xset settings? Also I had a problem recently with the export DISLPAY=:0 part in a udev script (for xmessages) and had to put it before every command (i.e. DISPLAY=:0 sudo -u me xmessage hello) – Fiximan Feb 22 '16 at 12:42
  • @Fiximan: Nope, DISPLAY=:0 sudo -u user xset r rate 150 60 didn't work. – Arthur Feb 22 '16 at 12:54
2

For a start, your matching directives are seriously wrong: a better rule should match just on the SUBSYSTEM and USB VID and PID.

Anyway, you cannot just have root run commands which are supposed to control your active X session. If you really have to do that then you must at the very least import $DISPLAY and $XAUTHORITY, but the correct solution is to use the native tools of your desktop environment to run these commands when appropriate.

  • What's wrong with them? The thing is, I can run the commands from the shell as root or as user, it works both ways. I thought, since udev is running as root it should work, too. I try to keep my os as lightweight as possible, that's why I don't have a desktop environment, just Xorg and XMonad. Can you explain what do you mean by importing $DISPLAY and $XAUTHORITY? – Arthur Feb 22 '16 at 8:31
  • @Arthur what I think Marco is talking about is that Linux is a server/client environment and when a udev rule runs a script, then it is not run from within the Xsession but just a random process from the server that does not know about Xsessions or what X is running (you can have multiple Xsession running on the same server for instance, so a script run by udev has no idea what Xsession to apply the xset command to). This is not a trivial task what you are trying to do and I don't have a solution to it unfortunately. – ojs Feb 22 '16 at 18:33
  • For example, if you go to a text terminal (tty1 for example, you can get there by pressing ctrl-alt-F1) and log in there and issue xset q then you will get an error saying that xset can't connect to terminal. If you do the same in an xterm then you will get lots of output. The same thing is happening to your script, it doesn't get any connection to a X server terminal. – ojs Feb 22 '16 at 20:30
1

Scripts executed from udev run in an almost empty environment. They aren't attached to any particular session or terminal.

The first thing you need to do is read the error messages. Add exec >>/var/log/my-udev-script.log 2>&1; echo; date at the beginning of your script just below the #! line and have a look at /var/log/my-udev-script.log after the script has been triggered.

The xset command is an X Window System client, so it needs to talk to an X server. It knows which X server to talk to (there could be many) from the value of the DISPLAY environment variable. If DISPLAY is not set, xset can't talk to any X server, so all it does is print an error message and exit.

To figure out how to set DISPLAY, and XAUTHORITY if necessary, see Can I launch a graphical program on another user's desktop as root? and Open a window on a remote X display (why "Cannot open display")? Note that it may be difficult to figure out what to do if there are multiple X servers.

Neither xset nor slock needs or cares about D-Bus. If you really need D-Bus, How to start dbus with a fixed address? is the easiest way to go.

  • In one of your linked questions you say on some systems one must find the actual cookie file of XAuthority. Using htop I located it /tmp/serverauth.cQuJ7XOujR. Since export XAUTHORITY=/home/*user*/Xauthority is not working, is there a way how I can tell the script to look for the actual cookie file in /tmp? – Arthur Feb 23 '16 at 10:29
  • @Arthur You tell the script where to look for the cookie file by setting XAUTHORITY. Take care that the location depends on whether a user is logged in (and if a user is just logging in it could change during the execution of the script). – Gilles Feb 23 '16 at 10:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.