USB – Running Code on Device (Un)plug Without Root Permissions

autorundbushotplugudevusb

I have a script that I wish to run whenever I plug/unplug a mouse or keyboard to my USB port.

There is already plenty of documentation on how to configure udev rules to run arbitrary scripts when a device is plugged or unplugged. But configuring those rules requires root permissions. And, although I do have root access on my machine, I'm looking for a solution that does not require sudo, root, or writing udev rules. (why? because it will be easier to run, maintain and distribute)

Most likely, the solution will use dbus, but I might be mistaken.

(By the way, I'm and advanced user and former Gentoo user, feel free to spit out technical details!)


Solutions that require root:

Seemingly outdated solutions that don't need root:

Best Answer

The "How can I listen for 'usb device inserted' events in Linux, in Python?" question has a very short sample Python script using pyudev. That script can easily detect when a device is connected or disconnected, by monitoring the device-event from the usb subsystem.

What's more, pyudev is pure-python implementation and is available on both Python 2 and Python 3.

Based on that sample code, I've written auto_exec_xinput_xset_upon_usb_device_change.py (see also the most recent version). Works on both Python 2 and Python 3.

#!/usr/bin/env python

import functools
import os.path
import pyudev
import subprocess


def main():
    BASE_PATH = os.path.abspath(os.path.dirname(__file__))
    path = functools.partial(os.path.join, BASE_PATH)
    call = lambda x, *args: subprocess.call([path(x)] + list(args))

    context = pyudev.Context()
    monitor = pyudev.Monitor.from_netlink(context)
    monitor.filter_by(subsystem='usb')  # Remove this line to listen for all devices.
    monitor.start()

    for device in iter(monitor.poll, None):
        # I can add more logic here, to run only certain kinds of devices are plugged.
        call('foobar.sh')


if __name__ == '__main__':
    main()