示例#1
0
/**
 * "Unplug" a device from a VM.
 * vusb_unassign() will "unassign" it, then
 * xenstore_create_usb() will be called to "detach" the device.
 *
 * @param domid The domid of the VM to unplug the device from
 * @param bus The bus ID of the device
 * @param device The ID of the device on the bus
 *
 * @return 0 for success, 1 for failure
 */
int
usbowls_unplug_device(int domid, int bus, int device)
{
  dominfo_t di;
  usbinfo_t ui;
  int ret;

  ret = xenstore_get_dominfo(domid, &di);
  if (ret != 0) {
    xd_log(LOG_ERR, "Invalid domid %d", domid);
    return 1;
  }
  ret = get_usbinfo(bus, device, &ui);
  if (ret != 0) {
    xd_log(LOG_ERR, "Invalid device %d-%d", bus, device);
    return 1;
  }

  ret = vusb_assign(ui.usb_vendor, ui.usb_product, 0);
  if (ret != 0) {
    xd_log(LOG_ERR, "Failed to unassign device");
    return 1;
  }

  ret = xenstore_destroy_usb(&di, &ui);
  if (ret != 0) {
    xd_log(LOG_ERR, "Failed to detach device");
    return 1;
  }

  return 0;
}
示例#2
0
int get_usbinfo(int bus, int dev, usbinfo_t *ui)
{
  struct udev *udev;
  struct udev_enumerate *enumerate;
  struct udev_list_entry *devices, *dev_list_entry;
  struct udev_device *udev_dev;
  char bus_str[16], dev_str[16];
  int found = 0;

  memset(ui, 0, sizeof(usbinfo_t));

  /* construct xenstore dev id */
  if (dev > 0xFFF) {
    xd_log(LOG_ERR, "bad device id %d", dev);
    return -EINVAL;
  }

  ui->usb_virtid = bus << 12 | (dev & 0xFFF);
  ui->usb_bus = bus;
  ui->usb_device = dev;

  /* udev scan */
  udev = udev_new();
  if (!udev) {
    xd_log(LOG_ERR, "Can't create udev");
    return -ENOMEM;
  }
  enumerate = udev_enumerate_new(udev);
  if (!enumerate) {
    xd_log(LOG_ERR, "Can't create enumeration");
    return -ENOMEM;
  }

  snprintf(bus_str, sizeof(bus_str), "%d", bus);
  snprintf(dev_str, sizeof(dev_str), "%d", dev);

  udev_enumerate_add_match_subsystem(enumerate, "usb");
  udev_enumerate_add_match_sysattr(enumerate, "busnum", bus_str);
  udev_enumerate_add_match_sysattr(enumerate, "devnum", dev_str);
  udev_enumerate_scan_devices(enumerate);
  devices = udev_enumerate_get_list_entry(enumerate);
  udev_list_entry_foreach(dev_list_entry, devices) {
    const char *path;
    path = udev_list_entry_get_name(dev_list_entry);
    udev_dev = udev_device_new_from_syspath(udev, path);
    sscanf(udev_device_get_sysattr_value(udev_dev, "idVendor"), "%x", &ui->usb_vendor);
    sscanf(udev_device_get_sysattr_value(udev_dev, "idProduct"), "%x", &ui->usb_product);
    udev_device_unref(udev_dev);
    udev_enumerate_unref(enumerate);
    udev_unref(udev);
    return 0;
  }
  udev_enumerate_unref(enumerate);
  udev_unref(udev);
  return -ENOENT;
}
示例#3
0
/*
 * Remove information about a usb device for this domain from Xenstore
 */
int
xenstore_destroy_usb(dominfo_t *domp, usbinfo_t *usbp)
{
  char value[32];
  char *bepath;
  char *fepath;
  int i;

  xd_log(LOG_INFO, "Deleting VUSB node %d for %d.%d",
	 usbp->usb_virtid, usbp->usb_bus, usbp->usb_device);

  bepath = xs_dev_bepath(domp, "vusb", usbp->usb_virtid);
  fepath = xs_dev_fepath(domp, "vusb", usbp->usb_virtid);

  /* Notify the backend that the device is being shut down */
  xs_set_keyval(XBT_NULL, bepath, "online", "0");
  xs_set_keyval(XBT_NULL, bepath, "physical-device", "0.0");
  snprintf(value, sizeof (value), "%d", XB_CLOSING);
  xs_set_keyval(XBT_NULL, bepath, "state", value);

  for (i = 0; i < 30; ++i) {
    usleep(100000);
    if (test_offline(domp, usbp)) {
      xs_rm(xs_handle, XBT_NULL, fepath);
      xs_rm(xs_handle, XBT_NULL, bepath);
      break;
    }
  }


  free(bepath);
  free(fepath);

  return (0);
}
示例#4
0
/*
 * Write a single value into Xenstore.
 */
int
xs_set_keyval(xs_transaction_t xt, char *path, char *key, char *val)
{
  char tmppath[256];

  if (key != NULL) {
    snprintf(tmppath, sizeof (tmppath), "%s/%s", path, key);
    path = tmppath;
  }
  xd_log(LOG_VERBOSE_DEBUG, "Writing to XenStore: %s = %s", path, val);

  if (xs_write(xs_handle, xt, path, val, strlen(val)) == false) {
    xd_log(LOG_ERR, "XenStore error writing %s", path);
    return (-1);
  }

  return (0);
}
示例#5
0
int get_dominfo(int domid, dominfo_t *di)
{
  di->di_domid = domid;
  di->di_dompath = xs_get_domain_path(xs_handle, di->di_domid);
  if (!di->di_dompath) {
    xd_log(LOG_ERR, "Could not get domain %d path from xenstore", domid);
    return -ENOENT;
  }
  di->di_name = xasprintf("Domain-%d", domid);
  return 0;
}
示例#6
0
void *
xmalloc(size_t size)
{
  void *p;

  if ((p = malloc(size)) == NULL) {
    xd_log(LOG_CRIT, "Out of memory");
    exit(2);
  }

  return (p);
}
示例#7
0
/**
 * "Plug" a device to a VM.
 * xenstore_create_usb() will be called to "attach" the device, then
 * vusb_assign() will "assign" it.
 *
 * @param domid The domid of the VM to plug the device to
 * @param bus The bus ID of the device
 * @param device The ID of the device on the bus
 *
 * @return 0 for success, 1 for failure
 */
int
usbowls_plug_device(int domid, int bus, int device)
{
  dominfo_t di;
  usbinfo_t ui;
  int ret;

  ret = xenstore_get_dominfo(domid, &di);
  if (ret != 0) {
    xd_log(LOG_ERR, "Invalid domid %d", domid);
    return 1;
  }
  ret = get_usbinfo(bus, device, &ui);
  if (ret != 0) {
    xd_log(LOG_ERR, "Invalid device %d-%d", bus, device);
    return 1;
  }

  /* FIXME: nicely unbind dom0 drivers on interfaces?
   * Or not, USB supports hot unplug doesn't it? :)
   */

  ret = xenstore_create_usb(&di, &ui);
  if (ret != 0) {
    xd_log(LOG_ERR, "Failed to attach device");
    return 1;
  }

  if (xenstore_wait_for_online(&di, &ui) < 0)
    xd_log(LOG_ERR, "The frontend or the backend didn't go online, continue anyway");

  ret = vusb_assign(ui.usb_vendor, ui.usb_product, 1);
  if (ret != 0) {
    xd_log(LOG_ERR, "Failed to assign device");
    xenstore_destroy_usb(&di, &ui);
    return 1;
  }

  return 0;
}
示例#8
0
/*
 * Create a new directory in Xenstore
 */
static int
xs_add_dir(xs_transaction_t xt, char *path, int d0, int p0, int d1, int p1)
{
  struct xs_permissions perms[2];

  xd_log(LOG_VERBOSE_DEBUG, "Making %s in XenStore", path);
  if (xs_mkdir(xs_handle, xt, path) == false) {
    xd_log(LOG_ERR, "XenStore error mkdir()ing %s", path);
    return (-1);
  }

  perms[0].perms = p0;
  perms[0].id = d0;
  perms[1].perms = p1;
  perms[1].id = d1;
  if (xs_set_permissions(xs_handle, xt, path, perms, 2) == false) {
    xd_log(LOG_ERR, "XenStore error setting permissions on %s",
	   path);
    xs_remove(xt, path);
    return (-1);
  }

  return (0);
}
示例#9
0
/**
 * Build a usbinfo_t from a udev device handle
 *
 * @param udev_dev Udev device handle
 * @param bus Bus ID
 * @param dev Device ID on the bus
 * @param ui The structure to fill (must be already allocated)
 *
 * @return 0 on success
 */
int
usbowls_build_usbinfo(int bus, int dev, int vendor, int product, usbinfo_t *ui)
{
  memset(ui, 0, sizeof(usbinfo_t));

  /* construct xenstore dev id */
  if (dev > 0xFFF) {
    xd_log(LOG_ERR, "bad device id %d", dev);
    return -EINVAL;
  }

  ui->usb_virtid = bus << 12 | (dev & 0xFFF);
  ui->usb_bus = bus;
  ui->usb_device = dev;

  ui->usb_vendor = vendor;
  ui->usb_product = product;

  return 0;
}
示例#10
0
static int
vusb_assign(int vendor, int product, int add)
{
  char command[64];
  int fd;
  int ret = 0;
  char *path = add ? VUSB_ADD_DEV : VUSB_DEL_DEV;

  fd = open(path, O_WRONLY);
  if (fd == -1) {
    xd_log(LOG_ERR, "%s: failed to open %s", __func__, path);
    return (-1);
  }

  snprintf(command, sizeof (command), "%x %x\n", vendor, product);

  if (write(fd, command, strlen(command)) == -1)
    ret = -1;
  if (close(fd) == -1)
    ret = -1;

  return (ret);
}
示例#11
0
static int
get_usbinfo(int bus, int dev, usbinfo_t *ui)
{
  struct udev_enumerate *enumerate;
  struct udev_list_entry *devices, *dev_list_entry;
  struct udev_device *udev_dev;
  char bus_str[16], dev_str[16];
  int vendor, product;

  enumerate = udev_enumerate_new(udev_handle);
  if (!enumerate) {
    xd_log(LOG_ERR, "Can't create enumeration");
    return -ENOMEM;
  }

  snprintf(bus_str, sizeof(bus_str), "%d", bus);
  snprintf(dev_str, sizeof(dev_str), "%d", dev);

  udev_enumerate_add_match_subsystem(enumerate, "usb");
  udev_enumerate_add_match_sysattr(enumerate, "busnum", bus_str);
  udev_enumerate_add_match_sysattr(enumerate, "devnum", dev_str);
  udev_enumerate_scan_devices(enumerate);
  devices = udev_enumerate_get_list_entry(enumerate);
  udev_list_entry_foreach(dev_list_entry, devices) {
    const char *path;

    path = udev_list_entry_get_name(dev_list_entry);
    udev_dev = udev_device_new_from_syspath(udev_handle, path);
    sscanf(udev_device_get_sysattr_value(udev_dev, "idVendor"), "%x", &vendor);
    sscanf(udev_device_get_sysattr_value(udev_dev, "idProduct"), "%x", &product);
    udev_device_unref(udev_dev);
    udev_enumerate_unref(enumerate);
    return usbowls_build_usbinfo(bus, dev, vendor, product, ui);
  }
  udev_enumerate_unref(enumerate);
  return -ENOENT;
}
示例#12
0
static void
dump_dev(usbinfo_t *ui)
{
  xd_log(LOG_INFO, "bus %d device %d vendor %04x product %04x virtid %06x",
         ui->usb_bus, ui->usb_device, ui->usb_vendor, ui->usb_product, ui->usb_virtid);
}
示例#13
0
static void
xs_remove(xs_transaction_t xt, char *path)
{
  xd_log(LOG_VERBOSE_DEBUG, "XenStore removing %s", path);
  xs_rm(xs_handle, xt, path);
}
示例#14
0
int main(int argc, char **argv)
{
  int option = 0;
  int domid = -1, bus = -1, device = -1;
  int vassign = 0, vunassign = 0, attach = 0, detach = 0, list = 0, dump = 0;
  char *action = NULL;
  dominfo_t di;
  usbinfo_t ui;
  int ret = 0;

  xs_handle = xs_daemon_open();
  if (xs_handle == NULL) {
    xd_log(LOG_ERR, "Failed to connect to xenstore");
    exit(1);
  }

  if ((xs_dom0path = xs_get_domain_path(xs_handle, 0)) == NULL) {
    xd_log(LOG_ERR, "Could not get domain 0 path from XenStore");
    exit(1);
  }

  while ((option = getopt(argc, argv, "D:b:d:")) != -1) {
    switch (option) {
    case 'D':
      domid = atoi(optarg);
      if (get_dominfo(domid, &di))
        exit(1);
      break;
    case 'b':
      bus = atoi(optarg);
      break;
    case 'd':
      device = atoi(optarg);
      break;
    }
  }

  if (optind != argc-1) {
    usage();
  }

  action = argv[optind];
  vassign = !strcmp(action, "assign");
  vunassign = !strcmp(action, "unassign");
  attach = !strcmp(action, "attach");
  detach = !strcmp(action, "detach");
  list = !strcmp(action, "list");
  dump = !strcmp(action, "dump");

  if (vassign || vunassign || attach || detach || dump) {
    if (bus < 0 || device < 0)
      usage();

    if (get_usbinfo(bus, device, &ui)) {
      if (detach) {
        /* can proceed detaching without detailed device info, we only need bus & dev num */
      } else if (vunassign) {
        /* no device so nothing to unassign */
        exit(0);
      } else {
        xd_log(LOG_ERR, "Failed to find device %d:%d", bus, device);
        exit(1);
      }
    }
  }

  if (optind == argc) {
    dump_dev(&ui);
    return 0;
  }

  if (dump)
    dump_dev(&ui);
  else if (vassign)
    ret = vusb_assign(ui.usb_vendor, ui.usb_product, 1);
  else if (vunassign)
    ret = vusb_assign(ui.usb_vendor, ui.usb_product, 0);
  else if (attach) {
    if (domid < 0)
      usage();
    ret = xenstore_create_usb(&di, &ui);
  }
  else if (detach) {
    if (domid < 0)
      usage();
    ret = xenstore_destroy_usb(&di, &ui);
  }
  else if (list) {
    if (domid < 0)
      usage();
    list_domain_devs(&di);
  }

  if (ret)
    xd_log(LOG_ERR, "Operation failed");
  return ret == 0 ? 0 : 1;
}
示例#15
0
/*
 * Populate Xenstore with the information about a usb device for this domain
 */
int
xenstore_create_usb(dominfo_t *domp, usbinfo_t *usbp)
{
  char *bepath, *fepath;
  char value[32];
  xs_transaction_t trans;

  xd_log(LOG_DEBUG, "Creating VUSB node for %d.%d",
	 usbp->usb_bus, usbp->usb_device);

  /*
   * Construct Xenstore paths for both the front and back ends.
   */
  fepath = xs_dev_fepath(domp, "vusb", usbp->usb_virtid);
  bepath = xs_dev_bepath(domp, "vusb", usbp->usb_virtid);

  for (;;) {
    trans = xs_transaction_start(xs_handle);

    /*
     * Make directories for both front and back ends
     */
    if (xs_add_dir(trans, bepath, 0, XS_PERM_NONE, domp->di_domid,
		   XS_PERM_READ))
      break;
    if (xs_add_dir(trans, fepath, domp->di_domid, XS_PERM_NONE, 0,
		   XS_PERM_READ))
      break;

    /*
     * Populate frontend device info
     */
    if (xs_set_keyval(trans, fepath, "backend-id", "0"))
      break;
    snprintf(value, sizeof (value), "%d", usbp->usb_virtid);
    if (xs_set_keyval(trans, fepath, "virtual-device", value))
      break;
    if (xs_set_keyval(trans, fepath, "backend", bepath))
      break;
    snprintf(value, sizeof (value), "%d", XB_INITTING);
    if (xs_set_keyval(trans, fepath, "state", value))
      break;

    /*
     * Populate backend device info
     */
    if (xs_set_keyval(trans, bepath, "domain", domp->di_name))
      break;
    if (xs_set_keyval(trans, bepath, "frontend", fepath))
      break;
    snprintf(value, sizeof (value), "%d", XB_INITTING);
    if (xs_set_keyval(trans, bepath, "state", value))
      break;
    if (xs_set_keyval(trans, bepath, "online", "1"))
      break;
    snprintf(value, sizeof (value), "%d", domp->di_domid);
    if (xs_set_keyval(trans, bepath, "frontend-id", value))
      break;
    snprintf(value, sizeof (value), "%d.%d", usbp->usb_bus,
	     usbp->usb_device);
    if (xs_set_keyval(trans, bepath, "physical-device", value))
      break;

    if (xs_transaction_end(xs_handle, trans, false) == false) {
      if (errno == EAGAIN)
	continue;
      break;
    }
    free(fepath);
    free(bepath);

    xd_log(LOG_DEBUG, "Finished creating VUSB node for %d.%d",
	   usbp->usb_bus, usbp->usb_device);

    return (0);
  }

  xs_transaction_end(xs_handle, trans, true);
  xd_log(LOG_ERR, "Failed to write usb info to XenStore");
  free(fepath);
  free(bepath);
  return (-1);
}