Skip to content

Instantly share code, notes, and snippets.

@capezotte
Last active November 11, 2023 00:08
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save capezotte/03ee5548218e819b06459819bb120b4b to your computer and use it in GitHub Desktop.
Save capezotte/03ee5548218e819b06459819bb120b4b to your computer and use it in GitHub Desktop.
Instructions on replacing udev/eudev on Artix

Replacing udev on Artix Linux

Reminder this is UNSUPPORTED. Reproduce bugs on a stock install with xudev/eudev before reporting them.

Preparations

Do not reboot until you've done them all.

Step 1 - remove udev

Due to some file conflicts, udev will have to be replaced first. This article's recommended substitute is nldev + smdev (AUR packages), as all of the "glue" has already been provided by phkr, and will assume you'll be installing them to make things easier.

mkinitcpio will run and will fail, don't mind it yet.

Step 2 - replace libudev

Install libudev-zero-git from the AUR, replacing lib{,e}udev.

To make hotplugging work, install smdev-libudev-zero from the AUR. A later update to nldev included hotplugging support right in the config.h, so installing libudev-zero is enough.

Step 3 - replace init services

On OpenRC, install nldev-openrc. Remove udev and udev-trigger from sysinit, and add nldev and nldev-trigger to that runlevel.

On runit, install nldev-runit.

On s6, the short and hackish way is to edit these files:

  • /etc/s6/sv/udevd-srv/run - so it invokes nldev -k instead of udevd.
  • /etc/s6/sv/udevadm/up - so it invokes nltrigger /sys add 500 instead of the multiple udevadm commands.*

Then rebuild the database with /usr/share/libalpm/scripts/s6-rc-db-update-hook. This allows us to not care about editing tons of dependencies files. Remember to add these files to the [options] NoUpgrade section of pacman.conf.

* The 500 argument makes nltrigger wait half a second before actually triggering the uevents. This is necessary because nldev does not work with s6 readiness notification, and s6-rc is often literally too fast for nldev (at least on my machine).

Step 4 - encrypted devices and/or LVM2

LVM2 and Libdevmapper (the latter of which is needed for cryptsetup) requires rebuilding these software components to remove the dependency on a deprecated udev API.

  • lvm2-noudev (AUR), device-mapper-noudev (AUR) - replace their udev-built equivalents.

Step 5 - replace initrd

To fix initramfs build errors, edit /etc/mkinitcpio.conf and replace udev with nldev in the hooks. Then rebuild initramfs with sudo mkinitcpio -P. Pay attention to build errors on this step!

Step 6 - add yourself to many groups.

See the sections on the consequences of the elogind-udev integration: first and second.

Help, something went wrong!

Add break=premount or break=postmount to your kernel command line. This will halt the initramfs before or after mounting your / partition, and will allow you to type commands in a Busybox shell.

Expected "errors"

These errors are harmless, and are related to many things on Linux revolving around udev.

Instructions for specific software

Audio, hardware acceleration, input devices...

Add yourself to groups video, audio and input and log out and log in. This is the easiest way while we don't have equivalents of udev rules that tag devices with uacess to notify elogind. They're currently being worked on at https://github.com/capezotte/artix-elogind-smdev.

USB devices

If a userspace component needs to talk to USB devices (for example, Android debugging tools), there are many ways to handle that:

  • Add yourself to group usb
  • Make the executable set-GID usb.
  • If it has a daemon (like ADB): start it with your init. Starting it as group usb + unpriviledged user will also work, if you're concerned with a possibly increased attack surface.

Android udev rules are unfortunately massive and make use of "udev rule language" 's goto, which makes translating to shell script quite hard.

lsblk -o UUID,PARTUUID

Apparently these properties are queried through udev, and a yet-unwritten patch would be required for it to work.

However, blkid can still be used to query device UUIDs, and smdev can be configured to create udev-style /dev/disk/by-{,part}uuid symlinks with the smdev-uuid rule (packaged on the AUR).

Bluetooth

Bluetoothd relies on a unimplemented udev interface (hwdb). Rebuilding without udev (bluez-noudev on the AUR) is necessary.

PulseAudio

PulseAudio doesn't properly recognize soundcards on neither on startup nor upon plugging them with libudev-zero. Pipewire is recommended, as, although it requires a patch as part of the initial set-up, once patched it works really well, including hotplug support.

If you don't plan on recompiling/switching to Pipewire, the easy fix is running pacmd load-module module-detect, which "asks" ALSA directly. To make this permanent, you can add this command so it runs upon X/Wayland startup, or create a file /etc/pulse/default.pa.d/noudev.pa with contents load-module module-detect.

A user script, pulseaudio-smdev-reload can be used to supplant the lack of hotplugging support.

Pipewire

A difference in "quirks" between a real udev and libudev-zero simulation results in Pipewire flagging devices as invalid when they aren't. A patched version of pipewire by libudev-zero's author (pipewire-libudev-zero on AUR) allows usage with libudev-zero, including device hotplugging.

Supplementary packages (pipewire-{jack,pulse,gst-plugin...}) don't need to be replaced.

Udisks2

Some people report udisks2 not working. pmount is a udev-less alternative with similar functionality (though no support for DE's).

NetworkManager

connman and iwd (as well as wpa_cli and its wrappers like setnet) do not link to libudev. If you have issues, you can try those.

Cryptsetup/LVM and Gparted

See step 4. Gparted also requires device-mapper, and seems to be less stable in a udev-free environment.

Thanks

  • Illiliti, the author of libudev-zero, in many ways responsible for this page existing.
  • Platon "phkr" Ryzhikov, maintainer of many of the packages featured here, and developer of the nldev initcpio hook and init services.
  • Senderman for testing and the PulseAudio hotplugging script.

I don't like smdev and nldev!

With the following glue, any device manager will work:

  • An mkinitcpio hook that adds the device manager's files to the initramfs, starts and "coldplugs" it.
  • For OpenRC: scripts that start and coldplug the daemon.
  • For runit: runit-rc (stage 1) scripts that start, "coldplug" and stop the daemon, and a stage 2 daemon service.
  • For s6: instructions on what to put on /etc/s6/sv/udevd and /etc/s6/sv/udevadm.
  • Compatibility with phkr's smdev scripts can be achieved by including phkr's processdev script in your package and adding it as an "always" rule, or by adding "run" instructions for individual /etc/smdev/add entries.

If you get these working, feel free to tell me.

@firasuke
Copy link

Impressive to say the least, but how viable is it really?

@capezotte
Copy link
Author

I've daily driving this setup ever since publishing this Gist.

@firasuke
Copy link

firasuke commented May 6, 2023

Did you try skarnet's mdevd?

@capezotte
Copy link
Author

Yes, though only on Gentoo. It doesn't seem to difficult to port it to Artix, though.

@firasuke
Copy link

firasuke commented May 7, 2023

I wonder what the state of these replacements is and if they are close to fully replace udev daemon + libudev. If not, what software still require udev itself, and why?

@capezotte
Copy link
Author

capezotte commented May 14, 2023

Read the "Instructions for specific software" section and "What doesn't work" in libudev-zero's readme.

That said, web browsers (Firefox and Chrome), games (Wine, emulators and native), Bluetooth, Wi-Fi (through Connman) and LibreOffice all work incl. hotplugging support. Friendlier GUIs for removable media and you could get a non-enthusiast Linux user to daily drive a udev-less setup.

@emmatebibyte
Copy link

No dinit? Is there an easy way to convert runit scripts to dinit?

@capezotte
Copy link
Author

capezotte commented Sep 6, 2023

Since dinit is dependency-based, the procedure would be closer to s6's.

I've never tried doing this on a dinit based system (in fact, I wrote this guide before dinit was even added to Artix), but AFAIK, it'd be something like:

  • Replace the command= in /etc/dinit.d/udev-trigger with nltrigger /sys add
  • Replace the command= in /etc/dinit.d/udev-settle with, IDK, sleep 2
  • Replace the command= in /etc/dinit.d/udev with nldev -k, replace the type= with process and delete the stop-command line (whatever happened to service supervision?)

Remember to NoUpgrade these files in pacman.conf so updates don't bring the original services back.

@emmatebibyte
Copy link

emmatebibyte commented Sep 7, 2023 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment