How to add or workaround a udev rule

Hey Everyone,

I have a strictly confined snap I’m working on but I am having a permissions/sudo/udev issue.

I am snapping a Go binary that talks to a USB-C monitor in order to adjust brightness. The standalone binary works just fine as long as I use sudo with it. Under the hood it’s using libusb to do it’s work.

When creating the snap, I had to use the plugs raw-usb and hardware-observe in order to get it to work, though again I have to prefix the snap with sudo when running.

I’d like to get this to run without sudo so that I/someone can run this snap from a keyboard shortcut in order to adjust brightness.

I have been able to get both the standalone binary and the snap to not require sudo if I first setup the udev rule:

SUBSYSTEM=="usb", ATTRS{idVendor}=="043e", ATTRS{idProduct}=="9a40", MODE="0666", GROUP="plugdev"

on my Ubuntu 18.04 Desktop.

How do I get my snap to pre-install that udev rule?

As of now, to get my snap to work a user would have to run:

sudo snap install lguf-cli
sudo snap connect lguf-cli:raw-usb
sudo snap connect lguf-cli:hardware-observe

which is more steps than I’d like but I get it. I would like to not have to add another step or two for them to setup the udev rule. I see the UBPorts folks had a similar issue and the solution there was a custom interface created for their/adb needs. That’s clearly overkill here but I haven’t figured out a solution.

The current snapcraft.yml is here.

one option is to split your app in two halves … one daemon part that does all the work, one cli part to have the user send commands… make the cli part talk to the daemon via a socket or some such.

daemons in snaps always run as root so you wont need sudo …

1 Like

Hmm interesting. That might work. Especially if I can maybe use the same binary but have it run in different modes.

Do you happen to have an example to point me to?

Thanks for the idea.

I was thinking about the same question. I think this could be done by the install hook, adding the file to /etc/udev/rules.d/. Can someone confirm that this is a proper way?

An install hook could do this provided you used the system-files interface to allow write access to /etc/udev/rules.d, but this is not the proper way. A classic snap could do the same, but again, that isn’t the proper way.

The way to do this within the ecosystem is add a new/modify an existing interface to update the udev backend for the hardware in question so snapd can put the udev rule(s) in place on behalf of the snap that plugs the interface.

1 Like

But I think it’s quite hard to convince anybody to add a very specific interface for a private snap (symlink Sony PS4 controller to /dev/input/psc instead of /dev/input/js*) to snapd…

The Sony PS4 controller is not snap-specific though. If a new or modified interface could handle this controller, that would benefit the private snap as well as any other snaps that might use one.

If you are only concerned about a private snap, those few individuals can update their udev rules accordingly. I suggest filing a bug at https://launchpad.net/snapd/+filebug with specific details about the controller. It may be a bug in the distro (eg systemd’s udev rules) that the symlink isn’t being setup correctly.

There is a little bit of a misunderstanding. There is the joystick interface and the PS4 controller acts as a joystick and is mounted to /dev/input/js*. This works fine. There’s no bug at all.

However, the definition of joystick is quite broad (which makes totally sense for this interface). In my case this can sometimes mean that a touchscreen is interpreted as js* and I don’t know which js* is my PS4 controller. Therefore, I have this udev rule which identifies the device and symlinks to /dev/input/psc. I think the best solution I found is to add this specific udev rule to a gadget snap. Or just let the users do it manually.

If someone is till interested in how to work around the problem of a Snap not being able to install UDEV rules into the system, I have found a solution, as I need UDEV for my printing-related Snaps.

I have applied my solution in the ipp-usb Snap (in the Snap Store), which is a daemon which allows connecting driverless IPP printers via USB and use them driverless also this way.

The classic installation of ipp-usb installs a UDEV rules file to trigger the launch of the daemon as soon as an appropriate printer gets connected to USB (or if such a device is already connected). The Snap cannot install such a file.

So I wrote an auxiliary daemon (a shell script) which runs udevadm monitor and checks the output lines for USB devices which are appearing. On these it does udevadm info to get the properties of the device and if it is IPP-over-USB (has 7/1/4 USB interface) the ipp-usb daemon gets launched. Do check for an already connected device udevadm trigger is run on startup. With this it behaves exactly like the classic installation, without needing its own UDEV rules. Note that it has to plug hardware-observe for this.

More detailed info here, in the end of the section.

I hope this workaround helps anyone in the desire of having a Snap adding UDEV rules.

Now I have applied my method to another Snap, the HPLIP Printer Application. HPLIP in its classic installation uses UDEV rules to trigger its firmware load tool when an HP printer appears on USB (some of them need their firmware uploaded every time when they are turned on).

To make this working in the Snap I used the same method as I described above for ipp-usb. See the commit and the snap/local/run-hplip-printer-app-server file.

1 Like

I’m using similar setups utilizing udevadm (and udiskctl) monitor here:

and here:

since it is unlikely snaps will every get direct access to udev, this is probably the best way to handle such cases currently …

1 Like