[libvirt] [PATCH] Implement path lookup for USB by vendor:product

Daniel P. Berrange berrange at redhat.com
Wed Jan 13 10:33:03 UTC 2010


On Tue, Jan 12, 2010 at 03:26:29PM -0500, Cole Robinson wrote:
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index deb8adc..f03ce91 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -2105,14 +2105,11 @@ static int qemuDomainSetHostdevUSBOwnership(virConnectPtr conn,
>      struct qemuFileOwner owner = { uid, gid };
>      int ret = -1;
>  
> -    /* XXX what todo for USB devs assigned based on product/vendor ? Doom :-( */
> -    if (!def->source.subsys.u.usb.bus ||
> -        !def->source.subsys.u.usb.device)
> -        return 0;
> -
>      usbDevice *dev = usbGetDevice(conn,
>                                    def->source.subsys.u.usb.bus,
> -                                  def->source.subsys.u.usb.device);
> +                                  def->source.subsys.u.usb.device,
> +                                  def->source.subsys.u.usb.vendor,
> +                                  def->source.subsys.u.usb.product);
>  
>      if (!dev)
>          goto cleanup;
> diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
> index 000bc8a..e015c06 100644
> --- a/src/security/security_selinux.c
> +++ b/src/security/security_selinux.c
> @@ -484,7 +484,9 @@ SELinuxSetSecurityHostdevLabel(virConnectPtr conn,
>          if (dev->source.subsys.u.usb.bus && dev->source.subsys.u.usb.device) {
>              usbDevice *usb = usbGetDevice(conn,
>                                            dev->source.subsys.u.usb.bus,
> -                                          dev->source.subsys.u.usb.device);
> +                                          dev->source.subsys.u.usb.device,
> +                                          dev->source.subsys.u.usb.vendor,
> +                                          dev->source.subsys.u.usb.product);
>  
>              if (!usb)
>                  goto done;

You need to remove the surrounding  if/else clause here


> diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
> index 35b29ad..6a52d4c 100644
> --- a/src/security/virt-aa-helper.c
> +++ b/src/security/virt-aa-helper.c
> @@ -839,8 +839,11 @@ get_files(vahControl * ctl)
>                  if (dev->source.subsys.u.usb.bus &&
>                      dev->source.subsys.u.usb.device) {
>                      usbDevice *usb = usbGetDevice(NULL,
> -                               dev->source.subsys.u.usb.bus,
> -                               dev->source.subsys.u.usb.device);
> +                                          dev->source.subsys.u.usb.bus,
> +                                          dev->source.subsys.u.usb.device,
> +                                          dev->source.subsys.u.usb.vendor,
> +                                          dev->source.subsys.u.usb.product);
> +
>                      if (usb == NULL)
>                          continue;
>                      rc = usbDeviceFileIterate(NULL, usb,

And likewise here.

> diff --git a/src/util/hostusb.c b/src/util/hostusb.c
> index 07e10b1..3e9ac83 100644
> --- a/src/util/hostusb.c
> +++ b/src/util/hostusb.c
> @@ -37,9 +37,10 @@
>  #include "util.h"
>  #include "virterror_internal.h"
>  
> +#define USB_SYSFS "/sys/bus/usb"
>  #define USB_DEVFS "/dev/bus/usb/"
> -#define USB_ID_LEN 10 /* "XXXX XXXX" */
> -#define USB_ADDR_LEN 8 /* "XXX:XXX" */
> +#define USB_ID_LEN 10 /* "1234 5678" */
> +#define USB_ADDR_LEN 8 /* "123:456" */
>  
>  struct _usbDevice {
>      unsigned      bus;
> @@ -57,11 +58,95 @@ struct _usbDevice {
>      virReportErrorHelper(conn, VIR_FROM_NONE, code, __FILE__,  \
>                           __FUNCTION__, __LINE__, fmt)
>  
> +static int usbSysReadFile(virConnectPtr conn,
> +                          const char *f_name, const char *d_name,
> +                          const char *fmt, unsigned *value)
> +{
> +    int ret = -1;
> +    char *buf = NULL;
> +    char filename[PATH_MAX];
> +
> +    snprintf(filename, PATH_MAX, USB_SYSFS "/devices/%s/%s", d_name, f_name);

Lets us virAsprintf() here.

> +
> +    if (virFileReadAll(filename, 1024, &buf) < 0)
> +        goto error;
> +
> +    if (sscanf(buf, fmt, value) != 1) {
> +        virReportSystemError(conn, errno,
> +                             _("Could not parse usb file %s"), filename);
> +        goto error;
> +    }

The callers all either pass in "%x" or "%d" to this, so how about just
using virStrToLong  and passing in the 'base' arg instead of format.

> +static int usbFindBusByVendor(virConnectPtr conn,
> +                              unsigned vendor, unsigned product,
> +                              unsigned *bus, unsigned *devno)
> +{
> +    DIR *dir = NULL;
> +    int ret = -1, found = 0;
> +    struct dirent *de;
> +
> +    dir = opendir(USB_SYSFS "/devices");
> +    if (!dir) {
> +        virReportSystemError(conn, errno,
> +                             _("Could not open directory %s"),
> +                             USB_SYSFS "/devices");
> +        goto error;
> +    }
> +
> +    while ((de = readdir(dir))) {
> +        unsigned found_prod, found_vend;
> +        if (de->d_name[0] == '.' || strchr(de->d_name, ':'))
> +            continue;
> +
> +        if (usbSysReadFile(conn, "idVendor", de->d_name,
> +                           "%x", &found_vend) < 0)
> +            goto error;
> +        if (usbSysReadFile(conn, "idProduct", de->d_name,
> +                           "%x", &found_prod) < 0)
> +            goto error;
> +
> +        if (found_prod == product && found_vend == vendor) {
> +            /* Lookup bus.addr info */
> +            char *tmpstr = de->d_name;
> +            unsigned found_bus, found_addr;
> +
> +            if (STREQ(de->d_name, "usb"))
> +                tmpstr += 3;
> +            found_bus = atoi(tmpstr);

This should be virStrToLong

> +
> +            if (usbSysReadFile(conn, "devnum", de->d_name,
> +                               "%d", &found_addr) < 0)
> +                goto error;
> +
> +            *bus = found_bus;
> +            *devno = found_addr;
> +            found = 1;
> +            break;
> +        }
> +    }
> +
> +    if (!found)
> +        usbReportError(conn, VIR_ERR_INTERNAL_ERROR,
> +                       _("Did not find USB device %x:%x"), vendor, product);
> +    else
> +        ret = 0;
> +
> +error:
> +    return ret;
> +}
>  
>  usbDevice *
>  usbGetDevice(virConnectPtr conn,
>               unsigned bus,
> -             unsigned devno)
> +             unsigned devno,
> +             unsigned vendor,
> +             unsigned product)
>  {
>      usbDevice *dev;
>  
> @@ -70,6 +155,12 @@ usbGetDevice(virConnectPtr conn,
>          return NULL;
>      }
>  
> +    if (vendor) {
> +        /* Look up bus.dev by vendor:product */
> +        if (usbFindBusByVendor(conn, vendor, product, &bus, &devno) < 0)
> +            return NULL;
> +    }
> +
>      dev->bus     = bus;
>      dev->dev     = devno;
>  
> diff --git a/src/util/hostusb.h b/src/util/hostusb.h
> index 7f75c8b..739a4aa 100644
> --- a/src/util/hostusb.h
> +++ b/src/util/hostusb.h
> @@ -28,7 +28,9 @@ typedef struct _usbDevice usbDevice;
>  
>  usbDevice *usbGetDevice      (virConnectPtr  conn,
>                                unsigned       bus,
> -                              unsigned       devno);
> +                              unsigned       devno,
> +                              unsigned       vendor,
> +                              unsigned       product);
>  void       usbFreeDevice     (virConnectPtr  conn,
>                                usbDevice     *dev);
>  
> -- 


Overall, it is alot simpler than I was expecting it to be which is nice ! 


Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list