
Tengo el siguiente script para definir las asignaciones de botones de mi Wacom Intuos S 2:
/usr/local/bin/wacom_intuos_s_2_pad_button_mapping.sh
#!/bin/bash
export DISPLAY=:0
export XAUTHORITY=/home/scriptim/.Xauthority
/usr/bin/sleep 1 # wait for device to be ready
/usr/bin/xsetwacom set 'Wacom Intuos S 2 Pad pad' Button 1 'key -'
/usr/bin/xsetwacom set 'Wacom Intuos S 2 Pad pad' Button 3 'key +'
/usr/bin/xsetwacom set 'Wacom Intuos S 2 Pad pad' Button 8 'key +Ctrl z -Ctrl'
/usr/bin/xsetwacom set 'Wacom Intuos S 2 Pad pad' Button 9 'key +Ctrl +Shift z -Ctrl -Shift'
Este script funciona bien si lo ejecuto manualmente.
Mi objetivo es ejecutar este script automáticamente cada vez que el pad esté conectado. Lo intenté con la siguiente udev
regla:
/etc/udev/rules.d/10-wacom_intuos_s_2_pad.rules
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="056a", ATTRS{idProduct}=="033b", RUN+="/usr/local/bin/wacom_intuos_s_2_pad_button_mapping.sh"
Sin embargo, el script no asigna los botones si conecto el pad.
Estoy ejecutando Arch Linux ( 5.5.10-arch1-1
)
$ lsusb
...
Bus 004 Device 015: ID 056a:033b Wacom Co., Ltd CTL-490 [Intuos Draw (S)]
...
$ udevadm info -a -n hidraw0
...
looking at parent device '/devices/pci0000:00/0000:00:10.0/usb4/4-2':
KERNELS=="4-2"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{authorized}=="1"
ATTRS{bcdDevice}=="0100"
ATTRS{bmAttributes}=="80"
ATTRS{bMaxPower}=="498mA"
ATTRS{manufacturer}=="Wacom Co.,Ltd."
ATTRS{quirks}=="0x0"
ATTRS{maxchild}=="0"
ATTRS{bNumInterfaces}==" 3"
ATTRS{bMaxPacketSize0}=="64"
ATTRS{devpath}=="2"
ATTRS{ltm_capable}=="no"
ATTRS{busnum}=="4"
ATTRS{devnum}=="15"
ATTRS{tx_lanes}=="1"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bDeviceClass}=="00"
ATTRS{bDeviceProtocol}=="00"
ATTRS{bNumConfigurations}=="1"
ATTRS{speed}=="12"
ATTRS{version}==" 2.00"
ATTRS{product}=="Intuos PS"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{idVendor}=="056a"
ATTRS{configuration}==""
ATTRS{devspec}=="(null)"
ATTRS{urbnum}=="174"
ATTRS{bConfigurationValue}=="1"
ATTRS{removable}=="unknown"
ATTRS{rx_lanes}=="1"
ATTRS{idProduct}=="033b"
...
$ udevadm test --action="add" /devices/pci0000:00/0000:00:10.0/usb4/4-2
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.
Load module index
Parsed configuration file /usr/lib/systemd/network/99-default.link
Created link configuration context.
Reading rules file: /usr/lib/udev/rules.d/10-dm.rules
Reading rules file: /etc/udev/rules.d/10-wacom_intuos_s_2_pad.rules
...
Reading rules file: /usr/lib/udev/rules.d/65-libwacom.rules
...
Reading rules file: /usr/lib/udev/rules.d/wacom.rules
Invalid inotify descriptor.
DEVPATH=/devices/pci0000:00/0000:00:10.0/usb4/4-2
DEVNAME=/dev/bus/usb/004/015
DEVTYPE=usb_device
DRIVER=usb
PRODUCT=56a/33b/100
TYPE=0/0/0
BUSNUM=004
DEVNUM=015
MAJOR=189
MINOR=398
ACTION=add
SUBSYSTEM=usb
ID_VENDOR=Wacom_Co._Ltd.
ID_VENDOR_ENC=Wacom\x20Co.\x2cLtd.
ID_VENDOR_ID=056a
ID_MODEL=Intuos_PS
ID_MODEL_ENC=Intuos\x20PS
ID_MODEL_ID=033b
ID_REVISION=0100
ID_SERIAL=Wacom_Co._Ltd._Intuos_PS
ID_BUS=usb
ID_USB_INTERFACES=:030000:030102:
ID_VENDOR_FROM_DATABASE=Wacom Co., Ltd
ID_MODEL_FROM_DATABASE=CTL-490 [Intuos Draw (S)]
ID_PATH=pci-0000:00:10.0-usb-0:2
ID_PATH_TAG=pci-0000_00_10_0-usb-0_2
USEC_INITIALIZED=4102997566
run: '/usr/local/bin/wacom_intuos_s_2_pad_button_mapping.sh'
Unload module index
Unloaded link configuration context.
$ journalctl -xe
Mar 22 17:38:55 scriptim systemd-udevd[5927]: 1-1: Process '/usr/local/bin/wacom_intuos_s_2_pad_button_mapping.sh' failed with exit code 255.
Respuesta1
Esencialmente, se trata de una combinación de una condición de carrera y la diferencia en el comportamiento xsetwacom
cuando se ejecuta desde una regla udev en comparación con cuando se ejecuta desde una terminal gráfica familiar, debido, por ejemplo, a diferencias en las variables de entorno.
Problema 1: variable de entorno.
Abordando primero la segunda cuestión: esto es similar a la situación en la queLos scripts de Shell se comportan de manera diferente cuando se ejecutan desde un cronjob..
Para comparar su entorno con el entorno udev, ejecutecualquiera env
o printenv
:
printenv > my-env.txt
desde una terminal gráfica, y luego agregue este script udev:
/usr/bin/printenv > /tmp/udev-env.txt
Entonces puedes comparar my-env.txt
y udev-env.txt
.
Para inferir qué variables de entorno xsetwacom
se están utilizando,instalarltrace
yejecutar un comando como este:
ltrace -f -e getenv -o my-ltrace-01.log xsetwacom set 'Wacom Intuos S 2 Pad pad' Button 1 'key -'
Como no tengo un dispositivo Wacom, no puedo ejecutar el comando completo.
$ xsetwacom set 'Wacom Intuos S 2 Pad pad' Button 1 'key -'
Cannot find device 'Wacom Intuos S 2 Pad pad'.
Sin embargo, basándome únicamente en qué tan lejos xsetwacom
llega antes de salir, puedo decir que usa DISPLAY
y XAUTHORITY
.
15447 libX11.so.6->getenv("DISPLAY") = ":0"
15447 libxcb.so.1->getenv("DISPLAY") = ":0"
15447 libxcb.so.1->getenv("DISPLAY") = ":0"
15447 libXau.so.6->getenv("XAUTHORITY") = "/home/nathaniel/.Xauthority"
15447 libX11.so.6->getenv("XLIBBUFFERSIZE") = nil
15447 libX11.so.6->getenv("XLIB_SKIP_ARGB_VISUALS") = nil
15447 libX11.so.6->getenv("XKB_DEBUG") = nil
15447 libX11.so.6->getenv("_XKB_OPTIONS_ENABLE") = nil
15447 libX11.so.6->getenv("XKB_DISABLE") = nil
15447 +++ exited (status 0) +++
Puede encontrar estos valores imprimiéndolos.
$ printf 'DISPLAY=%q\n' "$DISPLAY"
DISPLAY=:0
$ printf 'XAUTHORITY=%q\n' "$XAUTHORITY"
XAUTHORITY=/home/nathaniel/.Xauthority
Luego defínelos en la parte superior del guión.
#!/bin/bash
# Just an example, yours will be different.
export DISPLAY=:0
export XAUTHORITY=/home/nathaniel/.Xauthority
sleep 1
# The rest of the script.
El script aún podría no funcionar por otras razones, pero eliminar las diferencias en las variables de entorno parece haber sido suficiente para otras personas. Otro usuario en unpregunta relacionadaPude hacerlo funcionar en Ubuntu 18.04 de esta manera:
Debe agregar dos exportaciones de variables a su secuencia de comandos, una para
DISPLAY
yXAUTHORITY
. Se utilizan para identificar y acceder a la sesión X correcta. Puede obtener los valores adecuados ejecutándoloenv
mientras está conectado como usuario habitual.
Problema 2: condición de carrera.
Ahora, para la condición de carrera: el xsetwacom
comando depende de que el servidor X reconozca el hardware, por lo que ejecutarlo antes de que esté listo provocará que falle. sleep 1
Al parecer, en algún momento fue suficiente, pero ya no lo es . (A veces la gente usasleep 2
,sleep 3
, osleep 4
, sin ningún motivo concreto. En términos generales, me preocupa que sleep 1
sea incluso necesario.)
Cuando conectas el dispositivo:
- Linux detecta el dispositivo y crea una entrada de dispositivo basada en las reglas de udev.
- El servidor X detecta el dispositivo.
No puedes ejecutarlo
xsetwacom
antes de la etapa 2. Tu script falla porque lo estás ejecutando en la etapa 1, cuando X aún no conoce el dispositivo.
—Gilles 'SO- deja de ser malvado',https://unix.stackexchange.com/a/65792/30049
Todo esto está muy bien, pero cuando la gente intenta esto, ya no funciona:
Voté a favor de su respuesta para conocer los detalles, pero no estoy seguro de que sea correcta por el siguiente motivo: intenté usarla
sleep
con unos segundos. Cuando se conecta, la tableta funciona en menos de un segundo, por lo que cuando se ejecutan los comandos, el dispositivo ya está detectado y en usoX
. ¿Pero todavía no funciona?
Como no tengo su hardware ni su sistema operativo, no puedo replicar su problema. Pero esto es lo que he deducido de otros hilos: el sleep
retraso por sí solo no es suficiente. Algunas personas tienen soluciones como:
usando una subcapa y haciendo un bucle hasta que el dispositivo aparezca en la listaen
xsetwacom --list devices
.usando el
at
comando, pensó que no está claro por qué esto funciona.
Quizás la solución más completa que he visto esté en elhilo vinculadousando archivos de servicio systemd:
Terminé teniendo que iniciar el script con un servicio systemd activado por una regla udev:
$ cat /etc/udev/rules.d/99-wacom.rules SUBSYSTEM=="usb", ENV{ID_VENDOR_ID}=="056a", ENV{ID_MODEL_ID}=="0302", TAG+="systemd"
[...]
Permite
TAG+="systemd"
que otros servicios systemd (sistema o usuario) dependan del dispositivo (lo registra como una unidad de dispositivo, consulte mansystemd.device
).