Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions hotplug-setup
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!/bin/bash

if [ $EUID -ne 0 ]
then echo "Please run as root"
exit
fi



HOTPLUG_SCRIPT="/usr/bin/usb-libvirt-hotplug"



echo "Checking if usb-libvirt-hotplug script is installed..."
if [ ! -f "$HOTPLUG_SCRIPT" ]
then
echo "Didn't detect usb-libvirt-hotplug installed. Installing..."
cp usb-libvirt-hotplug $HOTPLUG_SCRIPT
sudo chmod +x $HOTPLUG_SCRIPT
else
echo "Skipping script installation: usb-libvirt-hotplug is installed."
fi



python3 monitor.py


# check if portlist file is empty
if [[ ! -z $(grep '[^[:space:]]' usb.portlist) ]]
then
echo "Do you want to add found usb ports automatically to udev rules? Y/n"
read YN

if [ -z $YN ]; then YN=y; fi
if [ $YN = n ]
then
echo ""
echo "Alright. If you want to add udev rules later, find the list of usb ports in usb.portlist, and add them manually to udev."


else
echo ""
echo "Proceeding with automatic addition of udev rules..."
echo "USB devices will be attached to the first started VM on your host. If you want to change this behaviour,"
echo "go to your udev rules, find 99-libvirt-usb-hotplug.rules and add the name of the vm you want to reroute devices to as an option to the RUN script."
echo ""

while IFS= read -r line; do
devpath=$(echo $line | sed "s/DEVPATH=//")
echo "Adding udev rule for $devpath..."
echo "SUBSYSTEM==\"usb\",DEVPATH==\"$devpath\",RUN+=\"$HOTPLUG_SCRIPT\"" >> /etc/udev/rules.d/99-libvirt-usb-hotplug.rules
done < usb.portlist
fi

echo ""
echo "All devices from usb.portlist file were added to udev rules, and it is not necessary for the rerouting to function properly."
echo "Should the script remove usb.portlist file? Y/n"
read YN

if [ -z $YN ]; then YN=y; fi
if [ $YN = n ]
then
echo "Skipping usb.portlist file removal..."
else
echo "Ok, removing usb.portlist file..."
rm usb.portlist
fi
else
echo "No ports were found, skipping..."
echo "Removing usb.portlist file, since it's empty..."
rm usb.portlist
fi
echo ""



echo "Done."

90 changes: 90 additions & 0 deletions monitor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/usr/bin/python3
# origin: https://github.com/darkguy2008/hotplugger
import sys
import signal
import subprocess

print("")
print("Using both an USB 3.0 and an USB 2.0 device (could be a thumb drive,")
print("an audio device or any other simple USB device), plug and unplug the")
print("device in the ports that you are interested for VM passthrough.")
print("")
print("Press Control + C when finished. The app will then print the device")
print("path of the USB ports. Also make sure that 'udevadm' is installed.")
print("")
print("Monitoring USB ports...")

###########################
# This gets the UDEV events
###########################

listout = []


def handle(sig, _):
if sig == signal.SIGINT:
print("")


signal.signal(signal.SIGINT, handle)
proc = subprocess.Popen(
["udevadm", "monitor", "-k", "-u", "-p", "-s", "usb"], stdout=subprocess.PIPE)

while True:
line = proc.stdout.readline()
if not line:
break
if line.startswith(b'DEVPATH'):
listout.append(line)

proc.wait()

######################################
# This gets an unique list of DEVPATHs
######################################



# function to get unique values

def unique(input_list):

# leave only unique entries
return list(dict.fromkeys(input_list))



# function to remove the netries that are not useful for udev

def remove_unnecessary(input_list):

# copy to avoid modifying the input list
output_list = list(input_list)

# traverse for all elements
for element in output_list:
# remove long entries as they are not useful for udev
for potential_prefix in output_list:
if element != potential_prefix and element.startswith(potential_prefix):
output_list.remove(element)

return output_list


if __name__ == '__main__':
listout = [x.decode('utf-8').strip() for x in listout]
uniq = unique(listout)
filtered = remove_unnecessary(uniq)

print("\nFound these USB ports:")
print(*filtered, sep='\n')
print("")

orig_stdout = sys.stdout
with open("usb.portlist", "w+") as f:
sys.stdout = f
print(*filtered, sep='\n')
sys.stdout = orig_stdout

print("Results were saved to 'usb.portlist'.")

16 changes: 11 additions & 5 deletions usb-libvirt-hotplug.sh → usb-libvirt-hotplug
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,14 @@ fi

DOMAIN="$1"
if [ -z "${DOMAIN}" ]; then
echo "Missing libvirt domain parameter for ${PROG}." >&2
exit 1
DOMAIN=$(virsh list --name)
if [ -z "${DOMAIN}" ]; then
echo "No running libvirt domain found for ${PROG}." >&2
exit 1
else
# set the longest running VM as a target domain
DOMAIN=$(echo $DOMAIN | head -n 1)
fi
fi


Expand Down Expand Up @@ -62,12 +68,12 @@ if [ -z "${ACTION}" ]; then
echo "Missing udev ACTION environment variable." >&2
exit 1
fi
if [ "${ACTION}" == 'add' ]; then
if [ "${ACTION}" == 'bind' ]; then
COMMAND='attach-device'
elif [ "${ACTION}" == 'remove' ]; then
elif [ "${ACTION}" == 'unbind' ]; then
COMMAND='detach-device'
else
echo "Invalid udev ACTION: ${ACTION}" >&2
echo "Unsupported udev ACTION: ${ACTION}" >&2
exit 1
fi

Expand Down