Installer for udev rules in Linux

Nominal Animal

Well-known member
If the installation of udev rules causes trouble for developers new to Linux, it might make sense to create an installer for it.

As an example, I saved the following Bash script at http://www.nominal-animal.net/answers/install-teensy-rules:
Code:
#!/bin/bash
RULENAME=49-teensy.rules
RULEDIRS=( /lib/udev/rules.d \
           /etc/udev/rules.d )
if [ -z "$RULES" ]; then
    for ruledir in $RULEDIRS ; do
        if [ -d "$ruledir" ]; then
            RULES="$ruledir"
        fi
    done
    if [ -z "$RULES" ]; then
        printf '\n'
        printf 'Cannot locate the udev rules directory on your system.\n'
        printf '\n'
        printf 'If you know where it should be, run this script using\n'
        printf '    RULES=/etc/udev/rules.d bash %s\n' "$0"
        printf '\n'
        exit 1
    fi
fi
if [ ! -d "$RULES" ]; then
    printf '\n'
    printf 'udev rules directory  %s  does not exist.\n' "$RULES"
    printf '\n'
    exit 1
fi

TEMPRULE=$(mktemp) || exit 1
trap "rm -f '$TEMPRULE'" EXIT

cat >"$TEMPRULE" <<ENDRULE
# UDEV Rules for Teensy boards, http://www.pjrc.com/teensy/
#
# The latest version of this file may be found at:
#   http://www.pjrc.com/teensy/49-teensy.rules
#
# This file must be placed at:
#
# /etc/udev/rules.d/49-teensy.rules    (preferred location)
#   or
# /lib/udev/rules.d/49-teensy.rules    (req'd on some broken systems)
#
# To install, type this command in a terminal:
#   sudo cp 49-teensy.rules /etc/udev/rules.d/49-teensy.rules
#
# After this file is installed, physically unplug and reconnect Teensy.
#
ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789B]?", ENV{ID_MM_DEVICE_IGNORE}="1"
ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789A]?", ENV{MTP_NO_PROBE}="1"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789ABCD]?", MODE:="0666"
KERNEL=="ttyACM*", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789B]?", MODE:="0666"
#
# If you share your linux system with other users, or just don't like the
# idea of write permission for everybody, you can replace MODE:="0666" with
# OWNER:="yourusername" to create the device owned by you, or with
# GROUP:="somegroupname" and mange access using standard unix groups.
#
#
# If using USB Serial you get a new device each time (Ubuntu 9.10)
# eg: /dev/ttyACM0, ttyACM1, ttyACM2, ttyACM3, ttyACM4, etc
#    apt-get remove --purge modemmanager     (reboot may be necessary)
#
# Older modem proding (eg, Ubuntu 9.04) caused very slow serial device detection.
# To fix, add this near top of /lib/udev/rules.d/77-nm-probe-modem-capabilities.rules
#   SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789]?", GOTO="nm_modem_probe_end" 
#
ENDRULE

printf '\n'
printf 'To install the udev rules file, superuser privileges are needed.\n'
printf 'To cancel the installation, just press Ctrl+C here.\n'
printf '\n'
sudo true || exit 0

sudo rm -f "$RULES/$RULENAME"

sudo install -o 0 -g 0 -m 0664 "$TEMPRULE" "$RULES/$RULENAME" || exit 1
sudo udevadm control --reload-rules || exit 1
sudo udevadm trigger || exit 1

printf '\n'
printf 'udev rule file successfully installed to\n'
printf '    %s\n' "$RULES/$RULENAME"
printf 'and activated.\n'
printf '\n'

exit 0
The part between cat >"$TEMPRULE" <<ENDRULE and ENDRULE should be exactly the latest version of the 49-teensy.rules file.

The idea is that to install the udev rule safely (that is, if you trust the script -- I have not ponied up the money to secure my web host), you only need to run
Code:
wget -O - http://www.nominal-animal.net/answers/install-teensy-rules | bash --
or, if you want to examine the script first, then
Code:
rm -f install-teensy-rules
wget http://www.nominal-animal.net/answers/install-teensy-rules
# Examine install-teensy-rules
bash install-teensy-rules
rm -f install-teensy-rules



Similarly, you could install all three Linux teensy binaries as /usr/lib/teensy/i686/teensy, /usr/lib/teensy/x86_64/teensy, and /usr/lib/teensy/armv6l/teensy (for Raspberry Pi), and use a startup script /usr/bin/teensy to launch the correct one:
Code:
#!/bin/bash
case "$(uname -m)" in
    i386|i486|i586|i686)
        cd /usr/lib/teensy/i686/ && exec teensy "$@" || exit 1
        ;;
    x86_64)
        cd /usr/lib/teensy/x86_64/ && exec teensy "$@" || exit 1
        ;;
    armv6l)
        cd /usr/lib/teensy/armv6l/ && exec teensy "$@" || exit 1
        ;;
esac
printf '\n'
printf 'Unsupported hardware architecture; sorry.\n'
printf '\n'
exit 1
 
I have checking (but not installing) the udev rules on my TODO list for the Teensyduino installer.

The tough part about actually installing udev rules is how to securely prompt for the root password and elevate permissions for only that part of the installation. How to do this in a way that works (and tends to remain working long-term) across all or most Linux distros is also a good question. Remember, the installer is a native app built with the FLTK toolkit (version 1.1), so it needs to be built with integration to the FLTK-based GUI and using native C++.

Realistically, Linux accounts for a small fraction of all users, but it's already is 3 of the 5 builds. Linux also includes some really problematic tech-support-nightmare distros like Gentoo. Officially, PJRC only tests and supports Ubuntu (x86) and Raspberry Pi (ARM), but I do try to be mindful of distro-neutral design to maximize the chances things will "just work" on the others.

Looking for ideas to improve the udev situation for new Linux users.
 
I sympathize with the challenge of finding a method to manage root privilege in a general manner. Any GUI application asking me for my password makes me nervous and I would tend to look for a way to do whatever-it-is from the command-line...but then I'm probably not representative of the majority of Teensy users in that regard.

For general usage I wonder if it isn't better to address this particular issue with an FAQ entry or Sticky thread.
An FAQ can present a few different good ways to skin this cat. And, of course, forum posts like this are always helpful to me when I'm looking for ways to solve problems.

In that spirit, here's another one of the ways to get a feline rug.
Code:
# apt-get remove --purge modemmanager 
# adduser my_user_name dialout

I have other kinds of different similar serial/usb devices I use (msp430, AVR, Teensy...), so instead of making specific rules for each device, I just let my user access anything group dialout owns. Actually because I was already setup, accessing the Teensy was automagic because it already had permission.

I don't know if that helps much, but that is my "drop-in-the-bucket" comment about how 'one' user likes to do things :)
 
For the linux installer, what about just dropping a shell script for the user to run? Even if it just handles ubuntu that's fine. Better yet, have the script output some relevant info so that the user could post the output on the forum.
 
how to securely prompt for the root password and elevate permissions for only that part of the installation
Use pkexec, a part of PolicyKit, a FreeDesktop project designed to solve exactly this problem, and is installed and used by services in all normal Linux distributions. It's also available for FreeBSDs. (FreeBSDs do not have pkexec or sudo installed by default.) On Macs, you need to run the scriptlet using osascript -e 'do shell script \" ... commands && commands ... \" with administrator privileges' I believe (but have not verified, since I don't have a Mac).

In my opinion, users can be classified into roughly two categories. One category is those users who are not interested or do not have the knowledge about any of the low-level details, and just want an icon to doubleclick to have Everything Just Work. The other category is those users who detest monolithic binaries that demand superuser privileges, and want to see what would happen before they agree to anything (preferably in enough detail so that they can do it themselves, and get the same results).

In my experience, the way to cater for both would be to have the installer self-extract, or generate, the privileged commands as POSIX sh scripts (on Linux, FreeBSD, and Mac), or batch files or something on Windows, and then let the user decide whether they should be executed immediately (which would cater for users who just want it to install), or inspect and execute the installation script themselves.

Note that in Linux, FreeBSD, and Mac, shell interpreters can execute files whether or not they are marked as executable, or even reside on a noexec mount, if you invoke the script via the shell interpreter; i.e. sh path/to/file (and not sh -c path/to/file or path/to/file).

(Because of how POSIX popen() works, this means popen("sh path/to/file", "r") in a binary program.)

Remember, the installer is a native app built with the FLTK toolkit (version 1.1), so it needs to be built with integration to the FLTK-based GUI and using native C++.
Wouldn't separate GUI binaries, with the installation actions in external scripts, be easier to manage?

That way you could offer either one big fat installer, with helper binaries and scripts for each architecture and OS; or an architecture-and-OS-specific self-extracting installer, that only includes the relevant files (by just leaving everything else out).

You would need a build farm, though. An SSH account on each OS type (Linux, Mac, FreeBSD, Windows) and hardware architecture, with a build environment installed. A central account on some machine uses ssh (and private keys) to connect to each build account, downloading/updating the source tree, building the local binaries; and if successful, the central account pulls the binaries to a local tree (via scp), and generates the packages.

Not only could you test the GUIs separately (using safe test installation scripts), but you could publish the scripts, and even accept user contributions, to keep them up to date. (As far as I can tell, the installation scripts should only contain file names and paths.)

Realistically, Linux accounts for a small fraction of all users, but it's already is 3 of the 5 builds.
I fully trust (and support) any business decisions you make, even if means rejecting every suggestion I make. I've already burned out once trying to keep my head in business matters. Besides, I'm a happy repeat customer already.

For the linux installer, what about just dropping a shell script for the user to run?
That is basically what I suggested at the beginning of the thread for the udev rule. For the entire Teensyduino installer, the problem is that the location of the Arduino installation (and possibly other details) vary, so either the script gets very complex, or you use a script that requires those locations (and options) to be pre-set as environment variables.

The latter is what I'm suggesting in this message, with the GUI as a separate binary that basically just runs a few scripts (some privileged), and lets the user edit the probed values before executing the actual final installation script itself.
 
Last edited:
In that spirit, here's another one of the ways to get a feline rug.
Code:
# apt-get remove --purge modemmanager 
# adduser my_user_name dialout

Teensy uses HID protocol for uploading, not Serial. It also implements more types of USB communication if you click Tools > USB Type. The udev rules file is meant to allow all Teensy features to work. This approach works fine for normal Serial-only Arduino boards, but it's not enough for boards like Teensy which do so much more.
 
Thanks for clarifying. I haven't run into any "can't do's" yet so it must be anything I have done so far is correctly handled by Debian defaults:
1) Basic programming sketches to the target.
2) Serial Monitoring outputs from sketches.
3) USB Audio -- "just works" with no tweaks.

So maybe there are other modes that would cause me grief if I were to avoid installing the udev rules -- in which case, this thread will be a valuable resource to me.

Thanks Nominal Animal!
And thanks Paul for making Teensy such an easy experience. Just starting to scratch the surface but I can see a lot of care was put into the development of the Audio library, and of course, Arduino compatibility was a really good idea :)
 
Back
Top