TL;DR:
$ sudo sh -c 'cat > /etc/udev/rules.d/99-libsane-panasonic.rules' <<'END'
ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04da", ATTRS{idProduct}=="0f0b", ENV{libsane_matched}="yes", RUN="/usr/local/bin/hack-panasonic $devnode"
END
$ sudo sh -c 'cat > /usr/local/bin/hack-panasonic' <<'END'
#!/bin/bash
[ $# -ne 1 -o ! -c "$1" ] && exit 1
exec /usr/bin/setfacl -m g:users:rw "$1"
END
$ sudo chmod +x /usr/local/bin/hack-panasonic
$ sudo reboot
Se busca escanear desde una impresora multifunción Panasonic KX-MB1520AG bajo Ubuntu 18.04. Para ver si la impresora es reconocida por sane se prueba utilizando el comando scanimage, verificando previamente que esté conectada al sistema (mediante lsusb):
$ lsusb | grep -i panasonic
Bus 001 Device 004: ID 04da:0f0b Panasonic (Matsushita)
Con esto se confirma que la impresora se encuentra conectada al sistema.
$ scanimage -L
el cual no devuelve ninguna impresora.
Utilizando por otro lado sudo
con el comando anterior se obtiene:
$ sudo scanimage -L
device `panamfs:libusb:001:004' is a Panasonic KX-MB1520AG sheetfed scanner
Lo que indica un problema de permisos que se corrobora comprobando los permisos
del archivo /dev/bus/usb/001/004
(obtenidos de la salida de lsusb
):
$ ls -lh /dev/bus/usb/001/004
crw-rw-r-- 1 root lp 189, 3 Sep 14 12:38 /dev/bus/usb/001/004
$ getfacl /dev/bus/usb/001/004
getfacl: Removing leading '/' from absolute path names
# file: dev/bus/usb/001/004
# owner: root
# group: lp
user::rw-
group::rw-
other::r--
Para solucionar el problema por lo menos hay dos soluciones:
-
Agregar el grupo
lp
al usuario (o los usuarios) del PC:$ sudo addgroup jmpc lp $ newgrp lp
La desventaja de esta solución es que solo aplica para los usuarios locales. Si la información de los usuarios es obtenida mediante ldap este cambio no es posible.
-
Utilizar udev y setfacl para dar permisos cuando se conecte el dispositivo.
Obviamente iremos por la opción 2., la cual es más general.
Para dar permisos al archivo de dispositivo (device file), se creará una regla
de udev en un archivo de reglas bajo /etc/udev/rules.d
que corresponde a las
reglas locales.
Sobre el orden de procesamiento de la regla, se utilizará el prefijo 99-
para
que la regla sea procesada al final (esta elección está basada en varios
ejemplos vistos en internet).
Con esto, el archivo que se creará para incluir la regla de udev será
/etc/udev/rules.d/99-libsane-panasonic.rules
.
La regla a utilizar, basada en los archivos de /lib/udev/rules.d
, será
inicialmente de la forma:
ATTRS{idVendor}=="04da", ATTRS{idProduct}=="0f0b", ENV{libsane_matched}="yes", RUN+="/usr/local/bin/hack-panasonic"
la cual al ser detectado el equipo panasonic:
- asigna la variable de entorno
libsane_matched
al valoryes
como hacen las reglas del archivo/lib/udev/rules.d/60-libsane1.rules
cuando detectan un scanner - agrega para ejecutar el programa
/usr/local/bin/hack-panasonic
que utilizaremos para darle permisos al archivo de dispositivo consetfacl
, aunque en esta etapa lo utilizaremos para comprobar que se está ejecutando la regla de forma correcta.
El programa /usr/local/bin/hack-panasonic
inicialmente tendrá el siguiente
contenido:
#!/bin/bash
set -e
echo "$(date -uIns) -- $@" >> /tmp/hack-panasonic
y su función será indicar mediante el archivo /tmp/hack-panasonic
que la regla
es ejecutada. Luego se modificará el programa para dar permisos al archivo de
dispositivo, pero para ello se requiere conocer la ruta del archivo, la que
puede variar con cada conexión. Por ello, se deben utilizar las sustituciones
de variables que se indican en la documentación de udev, las cuales son
pasadas al script por linea de comandos. El utilizar la variable de shell $@
ayudará a determinar de forma exacta como es realizada la sustitución de
variables realizadas por udev en la clave RUN
.
Para crear los archivos anteriores se puede utilizar el script setup-hack-panasonic-v1.sh.
Luego de creados los archivos se deben recargar las reglas de udev y verificar su ejecución.
Para recargar las reglas se debe invocar el comando udevadm de la forma
udevadm control --reload-rules
.
Para verificar la ejecución de la regla hay dos formas:
-
Desconectando y volviendo a conectar el cable usb de la impresora. Si bien esto es “sencillo”, en la práctica mientras se da con la regla y los parámetros a utilizar hay que realizarlo muchas veces. Otro punto en contra es que no puede realizarse de forma sencilla si se está brindando asistencia de forma remota.
-
Relanzando los eventos generados al conectar el cable usb utilizando el comando udevadm con la opción
trigger
.Hay que tener cuidado al utilizar la opción
trigger
, ya que esta por defecto no simula la conexión del usb.Para simular la conexión del usb debe utilizarse el comando:
$ sudo udevadm trigger --action=add --subsystem-match=usb
En este punto, ya se está en condiciones de probar si todo anda bien:
$ sudo udevadm control --reload-rules
$ sudo udevadm trigger --action=add --subsystem-match=usb
$ cat /tmp/hack-panasonic
2020-09-16T18:25:14,945230203+00:00 --
2020-09-16T18:25:14,952413377+00:00 --
2020-09-16T18:25:14,952848018+00:00 --
Con lo que se ve que casi está todo funcionando correctamente:
- La regla de udev y el script
hack-panasonic
funcionan, ya que se genera el archivo/tmp/hack-panasonic
. - Revisando el contenido del archivo
/tmp/hack-panasonic
se ve que la regla fué llamada tres veces, ya que se tienen tres entradas consecutivas.
Esto último no es deseado, ya que el evento de conexión debería ser uno solo.
Estudiando el archivo /lib/udev/rules.d/60-libsane1.rules
queda de manifiesto
que falta agregar a la regla que la acción sea add
y que se esté agregando un
dispositivo usb, lo cual se escribe como:
ACTION=="add", ENV{DEVTYPE}=="usb_device"
quedando la regla de la forma:
ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04da", ATTRS{idProduct}=="0f0b", ENV{libsane_matched}="yes", RUN="/usr/local/bin/hack-panasonic"
Actualizando el archivo /etc/udev/rules.d/99-libsane-panasonic.rules
con la
regla anterior, recargando las reglas y lanzando los eventos se tiene:
$ sudo rm /tmp/hack-panasonic
$ sudo udevadm control --reload-rules
$ sudo udevadm trigger --action=add --subsystem-match=usb
$ cat /tmp/hack-panasonic
2020-09-16T18:34:42,097239894+00:00 --
Y ahora si estamos seguros de que la regla captura correctamente el evento que estamos buscando.
Ahora hay que determinar los parámetros que se le deben pasar al script
hack-panasonic
para que este pueda dar permisos al archivo de dispositivo.
El archivo que se debe modificar (en este caso) es /dev/bus/usb/001/004
, por
lo que se debe encontrar que variable de udev tiene este valor o en su defecto
permite generarlo.
Revisando la documentación de udev se encuentran como disponibles las
sustituciones: $devpath
, $number
, $id
, $name
, $devnode
, entre otras.
Para no perder tiempo probando cada una se modifica la regla en el archivo
/etc/udev/rules.d/99-libsane-panasonic.rules
para agregarlas todas a la vez y
ver que valores se obtienen:
ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04da", ATTRS{idProduct}=="0f0b", ENV{libsane_matched}="yes", RUN="/usr/local/bin/hack-panasonic - $devpath - $number - $id - $name - $devnode -"
Luego de modificada la regla se recarga y se prueba:
$ sudo rm /tmp/hack-panasonic
$ sudo udevadm control --reload-rules
$ sudo udevadm trigger --action=add --subsystem-match=usb
$ cat /tmp/hack-panasonic
2020-09-16T18:45:03,627583256+00:00 -- - /devices/pci0000:00/0000:00:14.0/usb1/1-13 - 13 - 1-13 - bus/usb/001/004 - /dev/bus/usb/001/004 -
Del resultado anterior se encuentra que la sustitución buscada es $devnode
.
Con esta información ya es posible escribir la versión final del la regla y el script:
-
/etc/udev/rules.d/99-libsane-panasonic.rules
:ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04da", ATTRS{idProduct}=="0f0b", ENV{libsane_matched}="yes", RUN="/usr/local/bin/hack-panasonic $devnode"
-
/usr/local/bin/hack-panasonic
:#!/bin/bash [ $# -ne 1 -o ! -c "$1" ] && exit 1 exec /usr/bin/setfacl -m g:users:rw "$1"
Aquí se utiliza el grupo
users
, que por la característica de la instalación poseen todos los usuarios del sistema.
Para crear los archivos anteriores se puede utilizar el script setup-hack-panasonic-v2.sh.
Para probar que todo funciona correctamente luego de los cambios anteriores se
recargan las reglas, se generan los eventos y se prueban los archivos bajo
/dev
y la salida de scanimage
:
$ sudo udevadm control --reload-rules
$ sudo udevadm trigger --action=add --subsystem-match=usb
$ ls -lh /dev/bus/usb/001/004
crw-rw-r--+ 1 root lp 189, 3 set 16 15:56 /dev/bus/usb/001/004
$ getfacl /dev/bus/usb/001/004
getfacl: Removing leading '/' from absolute path names
# file: dev/bus/usb/001/004
# owner: root
# group: lp
user::rw-
group::rw-
group:users:rw-
mask::rw-
other::r--
$ scanimage -L
device `panamfs:libusb:001:004' is a Panasonic KX-MB1520AG sheetfed scanner
Sobre el uso de $attr
y $env
Para determinar las sustituciones de $attr
y $env
disponibles se utiliza el
comando udevadm info
con los parámetros -q
y -a
respectivamente:
$ lsusb | grep -i panasonic
Bus 001 Device 005: ID 04da:0f0b Panasonic (Matsushita)
$ udevadm info -a /dev/bus/usb/001/005
Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
looking at device '/devices/pci0000:00/0000:00:14.0/usb1/1-13':
KERNEL=="1-13"
SUBSYSTEM=="usb"
DRIVER=="usb"
ATTR{authorized}=="1"
ATTR{avoid_reset_quirk}=="0"
ATTR{bConfigurationValue}=="1"
...
$ udevadm info -q property /dev/bus/usb/001/005
BUSNUM=001
DEVNAME=/dev/bus/usb/001/005
DEVNUM=005
DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-13
DEVTYPE=usb_device
...
Nota: para el ejemplo anterior cambió el archivo de dispositivo que se venía utilizando como ejemplo previamente.