Initial Commit

This commit is contained in:
David Thurstenson 2020-07-04 20:19:50 -05:00
commit c896225cbd
5 changed files with 189 additions and 0 deletions

33
PKGBUILD Normal file
View File

@ -0,0 +1,33 @@
# Maintainer: David Thurstenson (thurstylark@gmail.com)
pkgname=libvirt-usb-hotplug
pkgver=0.1
pkgrel=1
pkgdesc="Attach and detach USB devices from libvirt guests based on udev rules"
arch=(any)
url="https://git.thurstylark.com/libvirt-usb-hotplug.git"
license=('GPL')
depends=('systemd'
'udev'
'libvirt')
backup=()
source=("libvirt-usb-hotplug.bash"
"libvirt-usb-hotplug.conf"
"libvirt-usb-hotplug.rules"
"libvirt-usb-hotplug@.service"
)
sha256sums=()
package() {
install -Dm755 \
"${srcdir}"/libvirt-usb-hotplug.bash \
"${pkgdir}"/usr/bin/libvirt-usb-hotplug
install -Dm644 \
"${srcdir}"/libvirt-usb-hotplug.conf \
"${pkgdir}"/etc/libvirt-usb-hotplug.conf
install -Dm644 \
"${srcdir}"/libvirt-usb-hotplug.rules \
"${pkgdir}"/usr/lib/udev/rules.d/99-libvirt-usb-hotplug.rules
install -Dm644 \
"${srcdir}"/libvirt-usb-hotplug@.service \
"${pkgdir}"/usr/lib/systemd/system/libvirt-usb-hotplug@.service
}

103
libvirt-usb-hotplug.bash Normal file
View File

@ -0,0 +1,103 @@
#!/bin/bash
# libvirt-usb-hotplug.bash
# This script can be used to hotplug USB devices to libvirt virtual
# machines from udev rules with systemd services.
# References:
# - https://github.com/olavmrk/usb-libvirt-hotplug
# - http://kicherer.org/joomla/index.php/en/blog/48-automatic-hotplugging-of-usb-devices-for-libvirt-managed-vms
# - https://blog.tjll.net/systemd-for-device-activation-and-media-archiving/
# Abort script execution on errors
set -e
readvars() {
PROG="$(basename "$0")"
ACTION=$1
IFS='_' read DOMAIN ID_VENDOR_ID ID_MODEL_ID <<< "$2"
if [ -z "${DOMAIN}" ]; then
echo "Missing libvirt domain parameter for ${PROG}." >&2
exit 1
fi
}
findmatch() {
# Iterate through devlist to find match
for i in "${devlist[@]}"; do
# If we find a match, return successfully
[ "${ID_VENDOR_ID}:${ID_MODEL_ID}" = "$i" ] && return 0
# If a match can't be found, keep looping
continue
done
# If no match was found, return unsuccessfully
return 1
}
case ${ACTION} in
add)
readvars
COMMAND='attach-device'
;;
remove)
readvars
COMMAND='detach-device'
;;
match)
# This section is responsible for determining if the corresponding udev rule
# matches against the device in question. Udev watches exit code to determine
# if a match was made.
#
# Ref: udev(7) manpage
# Read the config file
source /etc/libvirt-usb-hotplug.conf
# If we should match against any usb device, just exit successfully
[ "$matchall" = "true" ] && exit 0
# If the devlist array is empty, no matches can be made
[ ${#devlist[@]} = 0 ] && exit 1
# If targetdomain is unset or empty, exit unsuccessfully
[ ! -v targetdomain ] && exit 1
[ "$targetdomain" = "" ] && exit 1
# Print the targetdomain so it can be picked back up by the udev rule
printf "%s" "$targetdomain"
case $listmode in
whitelist)
# findmatch() returns 0 if match found, and 1 if match not found
findmatch
exit $?
;;
blacklist)
# Reverse the exit status of findmatch() for blacklist mode
! findmatch
exit $?
;;
*)
# If listmode is unset, or set improperly, exit unsuccessfully
exit 1
;;
esac
;;
*)
echo "Invalid script ACTION: ${ACTION}" >&2
exit 1
;;
esac
# Run the appropriate virsh-command, and ask it to read the update XML from stdin.
echo "Running virsh ${COMMAND} ${DOMAIN} --persistent for USB vendor=0x${ID_VENDOR_ID} product=0x${ID_MODEL_ID}:" >&2
(virsh "${COMMAND}" "${DOMAIN}" /dev/stdin --persistent || true) <<END
<hostdev mode='subsystem' type='usb' managed='yes'>
<source startupPolicy='optional'>
<vendor id='0x${ID_VENDOR_ID}' />
<product id='0x${ID_MODEL_ID}' />
</source>
</hostdev>
END

25
libvirt-usb-hotplug.conf Normal file
View File

@ -0,0 +1,25 @@
# libvirt-usb-hotplug.conf
# Name of libvirt domain to which the device in question will be attached
# Default if unset: <none> (disables matching)
targetdomain=win10
# Match against every usb device
# Valid values: true, false
# Default if unset: false
matchall=true
# Should the list be a whitelist, or blacklist?
# Valid values: whitelist, blacklist
# Default if unset: <none> (disables matching)
listmode=blacklist
# List of devices to match against
# Value format: '<vendor_id>:<device_id>'
devlist=(
'0b05:1872' # ASUSTek Computer, Inc. AURA LED Controller
'0b05:185c' # ASUSTek Computer, Inc. Bluetooth Radio
)
# vim: set ft=bash:

13
libvirt-usb-hotplug.rules Normal file
View File

@ -0,0 +1,13 @@
# libvirt-usb-hotplug.rules
ACTION=="add", \
SUBSYSTEM=="usb", \
PROGRAM=="/usr/bin/libvirt-usb-hotplug match" \
SYMLINK+="libvirt_%c_%E{ID_VENDOR_ID}_%E{ID_MODEL_ID}", \
TAG+="systemd", \
ENV{SYSTEMD_WANTS}="libvirt_%c_%E{ID_VENDOR_ID}_%E{ID_MODEL_ID}"
ACTION=="remove", \
SUBSYSTEM=="usb", \
ENV{PRODUCT}=="46d/c215/*", \
TAG+="systemd"

View File

@ -0,0 +1,15 @@
[Unit]
Description=Libvirt guest usb hotplug: %I
After=libvirtd.service
BindsTo=dev-libvirt_%i.device
After=dev-libvirt_%i.device
Requisite=dev-libvirt_%i.device
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/libvirt-usb-hotplug add %I
ExecStop=/usr/bin/libvirt-usb-hotplug remove %I
[Install]
WantedBy=dev-libvirt_%i.device