Skip to content

Instantly share code, notes, and snippets.

Last active May 25, 2016
What would you like to do?
usb-modeswitch: run dispatcher through init system
From: Daniel Drake <>
Careful rework of usb_modeswitch_dispatcher udev activation to solve
these problems:
1. Current code passes stdout/stderr descriptors all the way from udev's
worker to the usb_modeswitch_dispatcher process. udev monitors those
descriptors, and since they remain active, udev is blocked until
usb_modeswitch_dispatcher exits.
So, usb_modeswitch_dispatcher does the modeswitch and then
waits a while to see if udev udev auto-loads any modem drivers at that
point. But udev is blocked because usb_modeswitch_dispatcher is still
running. This results in usb_modeswitch_dispatcher deciding that no
driver was auto-loaded, and force-loading the wrong driver in some
2. The obvious fix of closing those file descriptors reveals the 2nd problem,
that udev will kill all the child processes that were launched by
/lib/udev/usb_modeswitch once that exits, and this is now clearly
documented in the udev man page.
A change of approach is needed here and I think the best option is to use
the init system to launch the dispatcher, with the following considerations:
1. The versions of Fedora and Ubuntu that I have in front of me (F23, U16.04)
don't install the systemd unit file. They will have to start doing so now.
And they will install it in /lib, so the current systemd check has to be
reworked. Hopefully this new approach is reasonable but it could be tricky.
2. Don't fork a background subshell, don't attempt to background anything.
We need to ensure that the init system has been successfully instructed
to start the modeswitch service before this script exits. If we exit while
that is ongoing in the background, those background processes will likely
be killed before they complete.
--- usb-modeswitch-2.3.0/ 2016-01-11 13:18:57.000000000 -0600
+++ usb-modeswitch-2.3.0/ 2016-05-25 13:07:05.106359971 -0600
@@ -73,26 +73,27 @@ case "$1" in
exit 0
IFS='/' read -r p1 p2 <<EOF
+init_path=`readlink /sbin/init`
while [ $count != 0 ]; do
if [ ! -e "/usr/sbin/usb_modeswitch_dispatcher" ]; then
sleep 1
count=$(($count - 1))
- if [ -e "/etc/systemd/system/usb_modeswitch@.service" ]; then
- exec systemctl --no-block start usb_modeswitch@$p1'_'$p2.service
+ if [ `basename $init_path` = "systemd" ]; then
+ systemctl --no-block start usb_modeswitch@$p1'_'$p2.service
elif [ -e "/etc/init/usb-modeswitch-upstart.conf" ]; then
- exec initctl emit --no-wait usb-modeswitch-upstart UMS_PARAM=$1
- else
- exec usb_modeswitch_dispatcher --switch-mode $1 &
+ initctl emit --no-wait usb-modeswitch-upstart UMS_PARAM=$1
- exit 0
+ break
-) &
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment