Exemple #1
0
/* read the 256 bytes PCI configuration space to check the multi-function bit */
static bool is_pci_multifunction(struct udev_device *dev) {
        char filename[256];
        FILE *f = NULL;
        char config[64];
        bool multi = false;

        snprintf(filename, sizeof(filename), "%s/config", udev_device_get_syspath(dev));
        f = fopen(filename, "re");
        if (!f)
                goto out;
        if (fread(&config, sizeof(config), 1, f) != 1)
                goto out;

        /* bit 0-6 header type, bit 7 multi/single function device */
        if ((config[PCI_HEADER_TYPE] & 0x80) != 0)
                multi = true;
out:
        if(f)
                fclose(f);
        return multi;
}
Exemple #2
0
static int get_ncontrollers(void)
{
	struct dirent **namelist;
	struct udev_device *platform;
	int n;

	platform = udev_device_get_parent(vhci_driver->hc_device);
	if (platform == NULL)
		return -1;

	n = scandir(udev_device_get_syspath(platform), &namelist, vhci_hcd_filter, NULL);
	if (n < 0)
		err("scandir failed");
	else {
		for (int i = 0; i < n; i++)
			free(namelist[i]);
		free(namelist);
	}

	return n;
}
Exemple #3
0
static struct udev_device *handle_scsi(struct udev_device *parent, char **path)
{
	const char *devtype;
	const char *name;
	const char *id;

	devtype = udev_device_get_devtype(parent);
	if (devtype == NULL || strcmp(devtype, "scsi_device") != 0)
		return parent;

	/* firewire */
	id = udev_device_get_sysattr_value(parent, "ieee1394_id");
	if (id != NULL) {
		parent = skip_subsystem(parent, "scsi");
		path_prepend(path, "ieee1394-0x%s", id);
		goto out;
	}

	/* lousy scsi sysfs does not have a "subsystem" for the transport */
	name = udev_device_get_syspath(parent);

	if (strstr(name, "/rport-") != NULL) {
		parent = handle_scsi_fibre_channel(parent, path);
		goto out;
	}

	if (strstr(name, "/end_device-") != NULL) {
		parent = handle_scsi_sas(parent, path);
		goto out;
	}

	if (strstr(name, "/session") != NULL) {
		parent = handle_scsi_iscsi(parent, path);
		goto out;
	}

	parent = handle_scsi_default(parent, path);
out:
	return parent;
}
/////////////////////////////////////////////////////////////////////////////
/// calculate disk indices using scsi_host unique_id
int DeviceMonitor::scsiHostIndex_( udev_device* device ) {
	udev* udev = udev_device_get_udev(device);
	std::string device_sys_path (udev_device_get_syspath(device));
	std::string bus_prefix ("");

	bool use_ata = false;
	int host_index = 0;
	int bus_index_correction = 0;

	size_t index_of = device_sys_path.find("/ata");
	if (index_of != std::string::npos) {
		bus_prefix.append(device_sys_path.substr(0, index_of + 4));
		host_index = device_sys_path.at(index_of + 10) - '0';
		bus_index_correction = device_sys_path.at(index_of + 4) - '0' - host_index;
		use_ata = true;
	} else {
		index_of = device_sys_path.find("/host");
		bus_prefix.append(device_sys_path.substr(0, index_of));
		host_index = device_sys_path.at(index_of) - '0';
	}

	int scsi_host_index = -1;
	for (int i = 0; i <= host_index; i++) {
		std::string dev_path (bus_prefix);

		if (use_ata) {
			dev_path.append(1, '0' + bus_index_correction + i);
		}

		dev_path.append("/host");
		dev_path.append(1, '0' + i);

		udev_device* dev_host = udev_device_new_from_syspath(udev, dev_path.c_str());
		if (dev_host) {
			scsi_host_index++;
		}
	}

	return scsi_host_index;
}
Exemple #5
0
static bool
_on_event(void *data, int fd, uint32_t cond)
{
    struct udev_data *mdata = data;
    struct udev_device *device;
    bool event, inform = true;
    const char *action;

    if (cond & (SOL_FD_FLAGS_ERR | SOL_FD_FLAGS_HUP)) {
        SOL_WRN("Error with the monitor");
        mdata->watch = NULL;
        sol_flow_send_error_packet(mdata->node, EIO, NULL);
        return false;
    }

    device = udev_monitor_receive_device(mdata->monitor);
    if (device == NULL)
        return true;

    if (mdata->addr && !streq(udev_device_get_syspath(device), mdata->addr))
        goto end;

    action = udev_device_get_action(device);
    if (streq(action, "add"))
        event = true;
    else if (streq(action, "remove"))
        event = false;
    else
        inform = false;

    if (inform)
        sol_flow_send_boolean_packet(mdata->node,
            SOL_FLOW_NODE_TYPE_UDEV_BOOLEAN__OUT__OUT,
            event);

end:
    udev_device_unref(device);
    return true;
}
Exemple #6
0
/*
 * Add 'legacy' device
 *
 * The term legacy is a bit misleading, but this adds devices according
 * to the original ofono model.
 *
 * - We cannot assume that these are USB devices
 * - The modem consists of only a single interface
 * - The device must have an OFONO_DRIVER property from udev
 */
static void add_serial_device(struct udev_device *dev)
{
	const char *syspath, *devpath, *devname, *devnode;
	struct modem_info *modem;
	struct serial_device_info *info;
	const char *subsystem;
	struct udev_device* mdev;
	const char* driver;

	mdev = get_serial_modem_device(dev);
	if (!mdev) {
		DBG("Device is missing required OFONO_DRIVER property");
		return;
	}

	driver = udev_device_get_property_value(mdev, "OFONO_DRIVER");

	syspath = udev_device_get_syspath(mdev);
	devname = udev_device_get_devnode(mdev);
	devpath = udev_device_get_devpath(mdev);

	devnode = udev_device_get_devnode(dev);

	if (!syspath || !devname || !devpath || !devnode)
		return;

	modem = g_hash_table_lookup(modem_list, syspath);
	if (modem == NULL) {
		modem = g_try_new0(struct modem_info, 1);
		if (modem == NULL)
			return;

		modem->type = MODEM_TYPE_SERIAL;
		modem->syspath = g_strdup(syspath);
		modem->devname = g_strdup(devname);
		modem->driver = g_strdup("legacy");

		g_hash_table_replace(modem_list, modem->syspath, modem);
	}
static int usb_dongle_probe_print_list(struct udev_enumerate *enumerate)
{
	struct udev_list_entry *list_entry;
	unsigned int vid, pid;
	int ret = -1;

	udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) {
		struct udev_device *device;

		device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate),
				udev_list_entry_get_name(list_entry));
		if (device != NULL) {
			mylog_info("device: '%s' (%s)\n",
					udev_device_get_syspath(device),
					udev_device_get_subsystem(device));
			get_vid_pid(device, &vid, &pid);
			ret = wlan_driver_match(vid, pid, wlan_driver_add_callback);
			udev_device_unref(device);
			if (!ret)
				break;
		}
	}
	return ret;
}
Exemple #8
0
/* private function to further filter watch results based on Eeze_Udev_Type
 * specified; helpful for new udev versions, but absolutely required for
 * old udev, which does not implement filtering in device monitors.
 */
static Eina_Bool
_get_syspath_from_watch(void             *data,
                        Ecore_Fd_Handler *fd_handler)
{
   struct _store_data *store = data;
   _udev_device *device = NULL, *parent, *tmpdev;
   const char *ret, *test;
   Eeze_Udev_Watch_Cb func = store->func;
   void *sdata = store->data;
   Eeze_Udev_Watch *watch = store->watch;
   int event = 0;

   if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
     return EINA_TRUE;

   device = udev_monitor_receive_device(store->mon);

   if (!device)
     return EINA_TRUE;

   if ((!(test = udev_device_get_action(device)))
       || (!(ret = udev_device_get_syspath(device))))
     goto error;

   if (store->event)
     {
        if (!strcmp(test, "add"))
          {
             if ((store->event != EEZE_UDEV_EVENT_NONE) &&
                 ((store->event & EEZE_UDEV_EVENT_ADD) != EEZE_UDEV_EVENT_ADD))
               goto error;

             event |= EEZE_UDEV_EVENT_ADD;
          }
        else if (!strcmp(test, "remove"))
          {
             if ((store->event != EEZE_UDEV_EVENT_NONE) &&
                 ((store->event & EEZE_UDEV_EVENT_REMOVE) != EEZE_UDEV_EVENT_REMOVE))
               goto error;

             event |= EEZE_UDEV_EVENT_REMOVE;
          }
        else if (!strcmp(test, "change"))
          {
             if ((store->event != EEZE_UDEV_EVENT_NONE) &&
                 ((store->event & EEZE_UDEV_EVENT_CHANGE) != EEZE_UDEV_EVENT_CHANGE))
               goto error;

             event |= EEZE_UDEV_EVENT_CHANGE;
          }
        else if (!strcmp(test, "online"))
          {
             if ((store->event != EEZE_UDEV_EVENT_NONE) &&
                 ((store->event & EEZE_UDEV_EVENT_ONLINE) != EEZE_UDEV_EVENT_ONLINE))
               goto error;

             event |= EEZE_UDEV_EVENT_ONLINE;
          }
        else
          {
             if ((store->event != EEZE_UDEV_EVENT_NONE) &&
                 ((store->event & EEZE_UDEV_EVENT_OFFLINE) != EEZE_UDEV_EVENT_OFFLINE))
               goto error;

             event |= EEZE_UDEV_EVENT_OFFLINE;
          }
     }

   if ((event & EEZE_UDEV_EVENT_OFFLINE) || (event & EEZE_UDEV_EVENT_REMOVE))
     goto out;
   switch (store->type)
     {
      case EEZE_UDEV_TYPE_KEYBOARD:
#ifdef OLD_UDEV_RRRRRRRRRRRRRR
        if ((!(test = udev_device_get_subsystem(device)))
            || (strcmp(test, "input")))
          goto error;

        test = udev_device_get_property_value(device, "ID_CLASS");

        if ((_walk_parents_test_attr(device, "bInterfaceProtocol", "01"))
            || ((test) && (!strcmp(test, "kbd"))))
          break;

        goto error;
#endif
        if ((!udev_device_get_property_value(device, "ID_INPUT_KEYBOARD")) &&
            (!udev_device_get_property_value(device, "ID_INPUT_KEY")))
          goto error;

        break;

      case EEZE_UDEV_TYPE_MOUSE:
#ifdef OLD_UDEV_RRRRRRRRRRRRRR
        if ((!(test = udev_device_get_subsystem(device)))
            || (strcmp(test, "input")))
          goto error;

        test = udev_device_get_property_value(device, "ID_CLASS");

        if ((_walk_parents_test_attr(device, "bInterfaceProtocol", "02"))
            || ((test) && (!strcmp(test, "mouse"))))
          break;

        goto error;
#endif

        if (!udev_device_get_property_value(device, "ID_INPUT_MOUSE"))
          goto error;

        break;

      case EEZE_UDEV_TYPE_TOUCHPAD:
#ifdef OLD_UDEV_RRRRRRRRRRRRRR
        if ((!(test = udev_device_get_subsystem(device)))
            || (strcmp(test, "input")))
          goto error;

        if (_walk_parents_test_attr(device, "resolution", NULL))
          break;

        goto error;
#endif
        if (!udev_device_get_property_value(device, "ID_INPUT_TOUCHPAD"))
          goto error;

        break;

      case EEZE_UDEV_TYPE_DRIVE_MOUNTABLE:
#ifdef OLD_UDEV_RRRRRRRRRRRRRR
        if ((!(test = udev_device_get_subsystem(device)))
            || (strcmp(test, "block")))
          goto error;
#endif
        if (!(test = (udev_device_get_property_value(device, "ID_FS_USAGE"))) ||
            (strcmp("filesystem", test)))
          goto error;
        {
           int devcheck;

           devcheck = open(udev_device_get_devnode(device), O_RDONLY);
           if (devcheck < 0) goto error;
           close(devcheck);
        }

        break;

      case EEZE_UDEV_TYPE_DRIVE_INTERNAL:
        if (udev_device_get_property_value(device, "ID_FS_USAGE")) goto error;
        test = udev_device_get_sysattr_value(device, "removable");
        if (test && test[0] == '1') goto error;
        test = udev_device_get_property_value(device, "ID_BUS");
        if ((!test) || strcmp(test, "ata")) goto error;
        test = udev_device_get_property_value(device, "ID_TYPE");
        if ((!test) || strcmp(test, "disk")) goto error;
        break;

      case EEZE_UDEV_TYPE_DRIVE_REMOVABLE:
        if (udev_device_get_sysattr_value(device, "partition")) goto error;
        test = udev_device_get_sysattr_value(device, "removable");
        if ((!test) || (test[0] == '0')) goto error;
        test = udev_device_get_property_value(device, "ID_TYPE");
        if ((!test) || strcmp(test, "disk")) goto error;

        break;

      case EEZE_UDEV_TYPE_DRIVE_CDROM:
        if (!udev_device_get_property_value(device, "ID_CDROM"))
          goto error;

        break;

      case EEZE_UDEV_TYPE_POWER_AC:
#ifdef OLD_UDEV_RRRRRRRRRRRRRR
        if ((!(test = udev_device_get_subsystem(device)))
            || (strcmp(test, "power_supply")))
          goto error;
#endif
        test = udev_device_get_property_value(device, "POWER_SUPPLY_ONLINE");
        if (!test) goto error;
        break;

      case EEZE_UDEV_TYPE_POWER_BAT:
#ifdef OLD_UDEV_RRRRRRRRRRRRRR
        if ((!(test = udev_device_get_subsystem(device)))
            || (strcmp(test, "power_supply")))
          goto error;
#endif
        test = udev_device_get_property_value(device, "POWER_SUPPLY_PRESENT");
        if (!test) goto error;
        break;

      case EEZE_UDEV_TYPE_IS_IT_HOT_OR_IS_IT_COLD_SENSOR:
#ifdef OLD_UDEV_RRRRRRRRRRRRRR
        if ((!(test = udev_device_get_subsystem(device)))
            || (strcmp(test, "hwmon")))
          goto error;
#endif /* have to do stuff up here since we need info from the parent */
        if (!_walk_parents_test_attr(device, "temp1_input", NULL))
          goto error;

        /* if device is not the one which has the temp input, we must go up the chain */
        if (!udev_device_get_sysattr_value(device, "temp1_input"))
          {
             for (parent = udev_device_get_parent(device); parent; parent = udev_device_get_parent(parent)) /*check for parent */
               if (udev_device_get_sysattr_value(parent, "temp1_input"))
                 {
                    tmpdev = device;

                    if (!(device = _copy_device(parent)))
                      goto error;

                    udev_device_unref(tmpdev);
                    break;
                 }
          }

        break;

      default:
        break;
     }
out:
   (*func)(eina_stringshare_add(ret), event, sdata, watch);
error:
   if (device)
     udev_device_unref(device);
   return EINA_TRUE;
}
Exemple #9
0
static struct udev_device *handle_scsi_default(struct udev_device *parent, char **path)
{
	struct udev_device *hostdev;
	int host, bus, target, lun;
	const char *name;
	char *base;
	char *pos;
	DIR *dir;
	struct dirent *dent;
	int basenum;

	hostdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host");
	if (hostdev == NULL)
		return NULL;

	name = udev_device_get_sysname(parent);
	if (sscanf(name, "%d:%d:%d:%d", &host, &bus, &target, &lun) != 4)
		return NULL;

	/* rebase host offset to get the local relative number */
	basenum = -1;
	base = strdup(udev_device_get_syspath(hostdev));
	if (base == NULL)
		return NULL;
	pos = strrchr(base, '/');
	if (pos == NULL) {
		parent = NULL;
		goto out;
	}
	pos[0] = '\0';
	dir = opendir(base);
	if (dir == NULL) {
		parent = NULL;
		goto out;
	}
	for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
		char *rest;
		int i;

		if (dent->d_name[0] == '.')
			continue;
		if (dent->d_type != DT_DIR && dent->d_type != DT_LNK)
			continue;
		if (strncmp(dent->d_name, "host", 4) != 0)
			continue;
		i = strtoul(&dent->d_name[4], &rest, 10);
		if (rest[0] != '\0')
			continue;
		if (basenum == -1 || i < basenum)
			basenum = i;
	}
	closedir(dir);
	if (basenum == -1) {
		parent = NULL;
		goto out;
	}
	host -= basenum;

	path_prepend(path, "scsi-%u:%u:%u:%u", host, bus, target, lun);
out:
	free(base);
	return hostdev;
}
int main(int argc, char **argv)
{
	struct udev *udev = udev_new();
	if (udev == NULL) {
		fprintf(stderr, "Unable to initialize udev context");
		return -1;
	}

#ifdef DEBUG
	struct udev_enumerate *enumerate = udev_enumerate_new(udev);
	if (enumerate == NULL) {
		fprintf(stderr, "Unable to enumerate devices");
		return -1;
	}

	udev_enumerate_add_match_subsystem(enumerate, "drm");
	udev_enumerate_scan_devices(enumerate);
	struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
	if (devices == NULL) {
		fprintf(stderr, "Unable to enumerate devices");
		return -1;
	}

	// List devices
	struct udev_list_entry *dev_entry;
	udev_list_entry_foreach(dev_entry, devices) {
		const char *path = udev_list_entry_get_name(dev_entry);
		struct udev_device *dev = udev_device_new_from_syspath(udev, path);
		printf("%s [devtype=%s]\n", path, udev_device_get_devtype(dev));
	}
	udev_enumerate_unref(enumerate);
#endif

	// Setup monitor
	struct udev_monitor *monitor = udev_monitor_new_from_netlink(udev, "udev");
	if (monitor == NULL) {
		fprintf(stderr, "Unable to initialize udev monitor");
		return -1;
	}

	if (udev_monitor_filter_add_match_subsystem_devtype(monitor, "drm", "drm_minor") < 0) {
		fprintf(stderr, "Unable to setup udev monitor");
		return -1;
	}
	if (udev_monitor_filter_update(monitor) < 0) {
		fprintf(stderr, "Unable to setup udev monitor");
		return -1;
	}

	if (udev_monitor_enable_receiving(monitor) < 0) {
		fprintf(stderr, "Unable to listen in udev monitor");
		return -1;
	}

	// The same issue as in SO, receive_device does not block, use select
	// http://stackoverflow.com/questions/15687784/libudev-monitoring-returns-null-pointer-on-raspbian
	int fd = udev_monitor_get_fd(monitor);
	while(1) {
		fd_set fds;
		FD_ZERO(&fds);
		FD_SET(fd, &fds);
		int ret = select(fd+1, &fds, NULL, NULL, NULL);
		if (ret > 0 && FD_ISSET(fd, &fds)) {
			struct udev_device *dev = udev_monitor_receive_device(monitor);
			if (dev == NULL) {
				continue;
			}

			printf("%s\n", udev_device_get_syspath(dev));
			for (int i=1; i<argc; i++) {
				system(argv[i]);
			}
			udev_device_unref(dev);
		}
	}

	udev_monitor_unref(monitor);
	udev_unref(udev);
	return 0;
}
Exemple #11
0
int dev_create(struct wiimote_dev *dev) {
	int ret = 0;
	struct udev *udev;
	struct udev_device *d, *p;
	struct stat st;
	const char *root, *snum, *driver, *subs;
	int num;

	if (!dev->device) {
		ret = EINVAL;
		goto exit;
	}

	if (stat(dev->device, &st)) {
		ret = errno;
		goto exit;
	}

	udev = udev_new();
	if (!udev) {
		fputs("could not connect to udev\n", stderr);
		ret = errno;
		goto exit;
	}

	d = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
	if (!d) {
		fputs("could not find udev device\n", stderr);
		ret = errno;
		goto exit_udev;
	}

	p = udev_device_get_parent_with_subsystem_devtype(d, "hid", NULL);
	if (!p) {
		fputs("could not find parent HID device\n", stderr);
		ret = errno;
		goto exit_dev;
	}

	driver = udev_device_get_driver(p);
	subs = udev_device_get_subsystem(p);
	if (!driver || strcmp(driver, "wiimote") || !subs || strcmp(subs, "hid")) {
		fputs("parent is not a HID Wiimote\n", stderr);
		ret = errno;
		goto exit_dev;
	}

	root = udev_device_get_syspath(p);
	snum = udev_device_get_sysname(p);
	snum = snum ? strchr(snum, '.') : NULL;
	if (!root || !snum) {
		fputs("Could not get root path\n", stderr);
		ret = errno;
		goto exit_dev;
	}

	num = strtol(&snum[1], NULL, 16);
	if (num < 0) {
		fputs("Negative device number!\n", stderr);
		ret = errno;
		goto exit_dev;
	}
	dev->dev_id = num;

	dev->root = strdup(root);
	if (!dev->root) {
		fputs("Could not set device root\n", stderr);
		ret = errno;
		goto exit_dev;
	}

	printf("using device %d from root %s for %s\n",
		dev->dev_id, dev->root, dev->device);

	dev->ifs = XWII_IFACE_CORE | XWII_IFACE_ACCEL;
	ret = xwii_iface_new(&dev->iface, dev->root);
	if (ret) {
		fputs("Could not create xwiimote interface\n", stderr);
		ret = errno;
		goto exit_wii;
	}

	ret = xwii_iface_open(dev->iface, dev->ifs);
	if (ret) {
		fputs("Could not open xwiimote interface\n", stderr);
		ret = errno;
		goto exit_wii;
	}
	if (xwii_iface_opened(dev->iface) != dev->ifs) {
		fputs("Some interfaces failed to open\n", stderr);
		ret = errno;
		goto exit_wii;
	}

	dev->fd = xwii_iface_get_fd(dev->iface);

	goto exit_dev;

exit_wii:
	free(dev->root);
	dev->root = NULL;

exit_dev:
	udev_device_unref(d);
exit_udev:
	udev_unref(udev);
exit:
	return ret;
}
Exemple #12
0
void
UdevSubsystem::print_info(udev_device* device)
{
  log_debug("/---------------------------------------------");
  log_debug("devpath: " << udev_device_get_devpath(device));

  if (udev_device_get_action(device))
    log_debug("action: " << udev_device_get_action(device));
  //log_debug("init: " << udev_device_get_is_initialized(device));

  if (udev_device_get_subsystem(device))
    log_debug("subsystem: " << udev_device_get_subsystem(device));

  if (udev_device_get_devtype(device))
    log_debug("devtype:   " << udev_device_get_devtype(device));

  if (udev_device_get_syspath(device))
    log_debug("syspath:   " << udev_device_get_syspath(device));

  if (udev_device_get_sysname(device))
    log_debug("sysname:   " << udev_device_get_sysname(device));

  if (udev_device_get_sysnum(device))
    log_debug("sysnum:    " << udev_device_get_sysnum(device));

  if (udev_device_get_devnode(device))
    log_debug("devnode:   " << udev_device_get_devnode(device));

  if (udev_device_get_driver(device))
    log_debug("driver:    " << udev_device_get_driver(device));

  if (udev_device_get_action(device))
    log_debug("action:    " << udev_device_get_action(device));

  //udev_device_get_sysattr_value(device, "busnum");
  //udev_device_get_sysattr_value(device, "devnum");

#if 0
  // FIXME: only works with newer versions of libudev
  {
    log_debug("list: ");
    struct udev_list_entry* it = udev_device_get_tags_list_entry(device);
    while((it = udev_list_entry_get_next(it)) != 0)
    {
      log_debug("  "
                << udev_list_entry_get_name(it) << " = "
                << udev_list_entry_get_value(it)
        );
    }
  }

  {
    log_debug("properties: ");
    struct udev_list_entry* it = udev_device_get_properties_list_entry(device);
    while((it = udev_list_entry_get_next(it)) != 0)
    {
      log_debug("  "
                << udev_list_entry_get_name(it) << " = "
                << udev_list_entry_get_value(it)
        );
    }
  }

  {
    log_debug("devlist: ");
    struct udev_list_entry* it = udev_device_get_tags_list_entry(device);
    while((it = udev_list_entry_get_next(it)) != 0)
    {
      log_debug("  "
                << udev_list_entry_get_name(it) << " = "
                << udev_list_entry_get_value(it)
        );
    }
  }
#endif

  log_debug("\\----------------------------------------------");
}
Exemple #13
0
void* udevmain(void* context){
    // Enumerate all currently connected devices
    udevenum();
    if(connectstatus & 2)
        // If a device failed to connect, enumerate again to make sure we reconnect it (if possible)
        udevenum();

    // Done scanning. Enter a loop to poll for device updates
    struct udev_monitor* monitor = udev_monitor_new_from_netlink(udev, "udev");
    udev_monitor_filter_add_match_subsystem_devtype(monitor, "usb", 0);
    udev_monitor_enable_receiving(monitor);
    // Get an fd for the monitor
    int fd = udev_monitor_get_fd(monitor);
    fd_set fds;
    while(udev){
        FD_ZERO(&fds);
        FD_SET(fd, &fds);
        // Block until an event is read
        if(select(fd + 1, &fds, 0, 0, 0) > 0 && FD_ISSET(fd, &fds)){
            struct udev_device* dev = udev_monitor_receive_device(monitor);
            if(dev){
                const char* action = udev_device_get_action(dev);
                if(action && !strcmp(action, "add")){
                    // Device added. Check vendor and product ID and add the device if it matches.
                    const char* vendor = udev_device_get_sysattr_value(dev, "idVendor");
                    if(vendor && !strcmp(vendor, V_CORSAIR_STR)){
                        const char* product = udev_device_get_sysattr_value(dev, "idProduct");
                        if(product && !strcmp(product, P_K70_STR)){
                            pthread_mutex_lock(&kblistmutex);
                            openusb(dev, 70);
                            pthread_mutex_unlock(&kblistmutex);
                        } else if(product && !strcmp(product, P_K95_STR)){
                            pthread_mutex_lock(&kblistmutex);
                            openusb(dev, 95);
                            pthread_mutex_unlock(&kblistmutex);
                        } else
                            // Free the device if it wasn't used
                            udev_device_unref(dev);
                    } else
                        udev_device_unref(dev);
                    // Wait a little bit and then re-enumerate devices. Sometimes the keyboard doesn't get picked up right away.
                    usleep(100000);
                    connectstatus = 0;
                    udevenum();
                    if(connectstatus & 2)
                        udevenum();
                } else if(!strcmp(action, "remove")){
                    // Device removed. Look for it in our list of keyboards
                    pthread_mutex_lock(&kblistmutex);
                    const char* path = udev_device_get_syspath(dev);
                    for(int i = 1; i < DEV_MAX; i++){
                        if(keyboard[i].udev && !strcmp(path, udev_device_get_syspath(keyboard[i].udev))){
                            pthread_mutex_lock(&keyboard[i].mutex);
                            closeusb(i);
                            break;
                        }
                    }
                    pthread_mutex_unlock(&kblistmutex);
                }
            }
        }
    }
    udev_monitor_unref(monitor);
    return 0;
}
Exemple #14
0
static void
device_added(struct udev_device *udev_device)
{
    const char *path, *name = NULL;
    char *config_info = NULL;
    const char *syspath;
    const char *tags_prop;
    const char *key, *value, *tmp;
    InputOption *options = NULL, *tmpo;
    InputAttributes attrs = {};
    DeviceIntPtr dev = NULL;
    struct udev_list_entry *set, *entry;
    struct udev_device *parent;
    int rc;

    path = udev_device_get_devnode(udev_device);

    syspath = udev_device_get_syspath(udev_device);

    if (!path || !syspath)
        return;

    if (!udev_device_get_property_value(udev_device, "ID_INPUT")) {
        LogMessageVerb(X_INFO, 10,
                       "config/udev: ignoring device %s without "
                       "property ID_INPUT set\n",
                       path);
        return;
    }

    options = calloc(sizeof(*options), 1);
    if (!options)
        return;

    options->key = strdup("_source");
    options->value = strdup("server/udev");
    if (!options->key || !options->value)
        goto unwind;

    parent = udev_device_get_parent(udev_device);
    if (parent) {
        const char *ppath = udev_device_get_devnode(parent);
        const char *product = udev_device_get_property_value(parent, "PRODUCT");
        const char *pnp_id = udev_device_get_sysattr_value(parent, "id");
        unsigned int usb_vendor, usb_model;

        name = udev_device_get_sysattr_value(parent, "name");
        LOG_SYSATTR(ppath, "name", name);
        if (!name) {
            name = udev_device_get_property_value(parent, "NAME");
            LOG_PROPERTY(ppath, "NAME", name);
        }

        if (pnp_id)
            attrs.pnp_id = strdup(pnp_id);
        LOG_SYSATTR(ppath, "id", pnp_id);

        /* construct USB ID in lowercase hex - "0000:ffff" */
        if (product && sscanf(product, "%*x/%4x/%4x/%*x", &usb_vendor, &usb_model) == 2) {
            if (asprintf(&attrs.usb_id, "%04x:%04x", usb_vendor, usb_model)
                == -1)
                attrs.usb_id = NULL;
            else
                LOG_PROPERTY(path, "PRODUCT", product);
        }
    }
    if (!name)
        name = "(unnamed)";
    else
        attrs.product = strdup(name);
    add_option(&options, "name", name);

    add_option(&options, "path", path);
    add_option(&options, "device", path);
    if (path)
        attrs.device = strdup(path);

    tags_prop = udev_device_get_property_value(udev_device, "ID_INPUT.tags");
    LOG_PROPERTY(path, "ID_INPUT.tags", tags_prop);
    attrs.tags = xstrtokenize(tags_prop, ",");

    if (asprintf(&config_info, "udev:%s", syspath) == -1) {
        config_info = NULL;
        goto unwind;
    }

    if (device_is_duplicate(config_info)) {
        LogMessage(X_WARNING, "config/udev: device %s already added. "
                              "Ignoring.\n", name);
        goto unwind;
    }

    set = udev_device_get_properties_list_entry(udev_device);
    udev_list_entry_foreach(entry, set) {
        key = udev_list_entry_get_name(entry);
        if (!key)
            continue;
        value = udev_list_entry_get_value(entry);
        if (!strncasecmp(key, UDEV_XKB_PROP_KEY,
                                sizeof(UDEV_XKB_PROP_KEY) - 1)) {
            LOG_PROPERTY(path, key, value);
            tmp = key + sizeof(UDEV_XKB_PROP_KEY) - 1;
            if (!strcasecmp(tmp, "rules"))
                add_option(&options, "xkb_rules", value);
            else if (!strcasecmp(tmp, "layout"))
                add_option(&options, "xkb_layout", value);
            else if (!strcasecmp(tmp, "variant"))
                add_option(&options, "xkb_variant", value);
            else if (!strcasecmp(tmp, "model"))
                add_option(&options, "xkb_model", value);
            else if (!strcasecmp(tmp, "options"))
                add_option(&options, "xkb_options", value);
        } else if (!strcmp(key, "ID_VENDOR")) {
            LOG_PROPERTY(path, key, value);
            attrs.vendor = strdup(value);
        } else if (!strcmp(key, "ID_INPUT_KEY")) {
            LOG_PROPERTY(path, key, value);
            attrs.flags |= ATTR_KEYBOARD;
        } else if (!strcmp(key, "ID_INPUT_MOUSE")) {
            LOG_PROPERTY(path, key, value);
            attrs.flags |= ATTR_POINTER;
        } else if (!strcmp(key, "ID_INPUT_JOYSTICK")) {
            LOG_PROPERTY(path, key, value);
            attrs.flags |= ATTR_JOYSTICK;
        } else if (!strcmp(key, "ID_INPUT_TABLET")) {
            LOG_PROPERTY(path, key, value);
            attrs.flags |= ATTR_TABLET;
        } else if (!strcmp(key, "ID_INPUT_TOUCHPAD")) {
            LOG_PROPERTY(path, key, value);
            attrs.flags |= ATTR_TOUCHPAD;
        } else if (!strcmp(key, "ID_INPUT_TOUCHSCREEN")) {
            LOG_PROPERTY(path, key, value);
            attrs.flags |= ATTR_TOUCHSCREEN;
        }
    }
static int dev_if_packed_info(struct udev_device *dev, char *ifs_str, size_t len) {
        _cleanup_free_ char *filename = NULL;
        _cleanup_close_ int fd = -1;
        ssize_t size;
        unsigned char buf[18 + 65535];
        int pos = 0;
        unsigned strpos = 0;
        struct usb_interface_descriptor {
                u_int8_t        bLength;
                u_int8_t        bDescriptorType;
                u_int8_t        bInterfaceNumber;
                u_int8_t        bAlternateSetting;
                u_int8_t        bNumEndpoints;
                u_int8_t        bInterfaceClass;
                u_int8_t        bInterfaceSubClass;
                u_int8_t        bInterfaceProtocol;
                u_int8_t        iInterface;
        } __attribute__((packed));

        if (asprintf(&filename, "%s/descriptors", udev_device_get_syspath(dev)) < 0)
                return log_oom();

        fd = open(filename, O_RDONLY|O_CLOEXEC);
        if (fd < 0) {
                fprintf(stderr, "error opening USB device 'descriptors' file\n");
                return -errno;
        }

        size = read(fd, buf, sizeof(buf));
        if (size < 18 || size == sizeof(buf))
                return -EIO;

        ifs_str[0] = '\0';
        while (pos < size && strpos+7 < len-2) {
                struct usb_interface_descriptor *desc;
                char if_str[8];

                desc = (struct usb_interface_descriptor *) &buf[pos];
                if (desc->bLength < 3)
                        break;
                pos += desc->bLength;

                if (desc->bDescriptorType != USB_DT_INTERFACE)
                        continue;

                if (snprintf(if_str, 8, ":%02x%02x%02x",
                             desc->bInterfaceClass,
                             desc->bInterfaceSubClass,
                             desc->bInterfaceProtocol) != 7)
                        continue;

                if (strstr(ifs_str, if_str) != NULL)
                        continue;

                memcpy(&ifs_str[strpos], if_str, 8),
                strpos += 7;
        }

        if (strpos > 0) {
                ifs_str[strpos++] = ':';
                ifs_str[strpos++] = '\0';
        }

        return 0;
}
//-----------------------------------------------------------------------------
void HIDDeviceManager::OnEvent(int i, int fd)
{
    OVR_UNUSED(i);
    OVR_UNUSED(fd);

    // There is a device status change
    udev_device* hid = udev_monitor_receive_device(HIDMonitor);
    if (hid)
    {
        const char* dev_path = udev_device_get_devnode(hid);
        const char* action = udev_device_get_action(hid);

        HIDDeviceDesc device_info;
        device_info.Path = dev_path;

        MessageType notify_type;
        if (OVR_strcmp(action, "add") == 0)
        {
            notify_type = Message_DeviceAdded;

            // Retrieve the device info.  This can only be done on a connected
            // device and is invalid for a disconnected device

            // Get the USB device
            hid = udev_device_get_parent_with_subsystem_devtype(hid, "usb", "usb_device");
            if (!hid)
            {
                return;
            }

            const char* path = udev_device_get_syspath(hid);

            GetDescriptorFromPath(path, &device_info);
        }
        else if (OVR_strcmp(action, "remove") == 0)
        {
            notify_type = Message_DeviceRemoved;
        }
        else
        {
            return;
        }

        bool error = false;
        bool deviceFound = false;
        for (UPInt i = 0; i < NotificationDevices.GetSize(); i++)
        {
            if (NotificationDevices[i] &&
                NotificationDevices[i]->OnDeviceNotification(notify_type, &device_info, &error))
            {
                // The notification was for an existing device
                deviceFound = true;
                break;
            }
        }

        if (notify_type == Message_DeviceAdded && !deviceFound)
        {
            DevManager->DetectHIDDevice(device_info);
        }

        udev_device_unref(hid);
    }
}
Exemple #17
0
static int enumerate_partitions(dev_t devnum) {

        _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
        _cleanup_udev_device_unref_ struct udev_device *d = NULL;
        _cleanup_blkid_free_probe_ blkid_probe b = NULL;
        _cleanup_udev_unref_ struct udev *udev = NULL;
        _cleanup_free_ char *boot = NULL, *home = NULL, *srv = NULL;
        struct udev_list_entry *first, *item;
        struct udev_device *parent = NULL;
        const char *name, *node, *pttype, *devtype;
        int boot_nr = -1, home_nr = -1, srv_nr = -1;
        bool home_rw = true, srv_rw = true;
        blkid_partlist pl;
        int r, k;
        dev_t pn;

        udev = udev_new();
        if (!udev)
                return log_oom();

        d = udev_device_new_from_devnum(udev, 'b', devnum);
        if (!d)
                return log_oom();

        name = udev_device_get_devnode(d);
        if (!name)
                name = udev_device_get_syspath(d);
        if (!name) {
                log_debug("Device %u:%u does not have a name, ignoring.",
                          major(devnum), minor(devnum));
                return 0;
        }

        parent = udev_device_get_parent(d);
        if (!parent) {
                log_debug("%s: not a partitioned device, ignoring.", name);
                return 0;
        }

        /* Does it have a devtype? */
        devtype = udev_device_get_devtype(parent);
        if (!devtype) {
                log_debug("%s: parent doesn't have a device type, ignoring.", name);
                return 0;
        }

        /* Is this a disk or a partition? We only care for disks... */
        if (!streq(devtype, "disk")) {
                log_debug("%s: parent isn't a raw disk, ignoring.", name);
                return 0;
        }

        /* Does it have a device node? */
        node = udev_device_get_devnode(parent);
        if (!node) {
                log_debug("%s: parent device does not have device node, ignoring.", name);
                return 0;
        }

        log_debug("%s: root device %s.", name, node);

        pn = udev_device_get_devnum(parent);
        if (major(pn) == 0)
                return 0;

        errno = 0;
        b = blkid_new_probe_from_filename(node);
        if (!b) {
                if (errno == 0)
                        return log_oom();

                return log_error_errno(errno, "%s: failed to allocate prober: %m", node);
        }

        blkid_probe_enable_partitions(b, 1);
        blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);

        errno = 0;
        r = blkid_do_safeprobe(b);
        if (r == 1)
                return 0; /* no results */
        else if (r == -2) {
                log_warning("%s: probe gave ambiguous results, ignoring", node);
                return 0;
        } else if (r != 0)
                return log_error_errno(errno ?: EIO, "%s: failed to probe: %m", node);

        errno = 0;
        r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
        if (r != 0)
                return log_error_errno(errno ?: EIO,
                                       "%s: failed to determine partition table type: %m", node);

        /* We only do this all for GPT... */
        if (!streq_ptr(pttype, "gpt")) {
                log_debug("%s: not a GPT partition table, ignoring.", node);
                return 0;
        }

        errno = 0;
        pl = blkid_probe_get_partitions(b);
        if (!pl) {
                if (errno == 0)
                        return log_oom();

                return log_error_errno(errno, "%s: failed to list partitions: %m", node);
        }

        e = udev_enumerate_new(udev);
        if (!e)
                return log_oom();

        r = udev_enumerate_add_match_parent(e, parent);
        if (r < 0)
                return log_oom();

        r = udev_enumerate_add_match_subsystem(e, "block");
        if (r < 0)
                return log_oom();

        r = udev_enumerate_scan_devices(e);
        if (r < 0)
                return log_error_errno(r, "%s: failed to enumerate partitions: %m", node);

        first = udev_enumerate_get_list_entry(e);
        udev_list_entry_foreach(item, first) {
                _cleanup_udev_device_unref_ struct udev_device *q;
                unsigned long long flags;
                const char *stype, *subnode;
                sd_id128_t type_id;
                blkid_partition pp;
                dev_t qn;
                int nr;

                q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
                if (!q)
                        continue;

                qn = udev_device_get_devnum(q);
                if (major(qn) == 0)
                        continue;

                if (qn == devnum)
                        continue;

                if (qn == pn)
                        continue;

                subnode = udev_device_get_devnode(q);
                if (!subnode)
                        continue;

                pp = blkid_partlist_devno_to_partition(pl, qn);
                if (!pp)
                        continue;

                nr = blkid_partition_get_partno(pp);
                if (nr < 0)
                        continue;

                stype = blkid_partition_get_type_string(pp);
                if (!stype)
                        continue;

                if (sd_id128_from_string(stype, &type_id) < 0)
                        continue;

                flags = blkid_partition_get_flags(pp);

                if (sd_id128_equal(type_id, GPT_SWAP)) {

                        if (flags & GPT_FLAG_NO_AUTO)
                                continue;

                        if (flags & GPT_FLAG_READ_ONLY) {
                                log_debug("%s marked as read-only swap partition, which is bogus. Ignoring.", subnode);
                                continue;
                        }

                        k = add_swap(subnode);
                        if (k < 0)
                                r = k;

                } else if (sd_id128_equal(type_id, GPT_ESP)) {

                        /* We only care for the first /boot partition */
                        if (boot && nr >= boot_nr)
                                continue;

                        /* Note that we do not honour the "no-auto"
                         * flag for the ESP, as it is often unset, to
                         * hide it from Windows. */

                        boot_nr = nr;

                        r = free_and_strdup(&boot, subnode);
                        if (r < 0)
                                return log_oom();

                } else if (sd_id128_equal(type_id, GPT_HOME)) {

                        if (flags & GPT_FLAG_NO_AUTO)
                                continue;

                        /* We only care for the first /home partition */
                        if (home && nr >= home_nr)
                                continue;

                        home_nr = nr;
                        home_rw = !(flags & GPT_FLAG_READ_ONLY),

                        r = free_and_strdup(&home, subnode);
                        if (r < 0)
                                return log_oom();

                } else if (sd_id128_equal(type_id, GPT_SRV)) {

                        if (flags & GPT_FLAG_NO_AUTO)
                                continue;

                        /* We only care for the first /srv partition */
                        if (srv && nr >= srv_nr)
                                continue;

                        srv_nr = nr;
                        srv_rw = !(flags & GPT_FLAG_READ_ONLY),

                        r = free_and_strdup(&srv, subnode);
                        if (r < 0)
                                return log_oom();
                }
        }
Exemple #18
0
static int builtin_firmware(struct udev_device *dev, int argc, char *argv[], bool test)
{
        struct udev *udev = udev_device_get_udev(dev);
        static const char *searchpath[] = { FIRMWARE_PATH };
        char fwencpath[UTIL_PATH_SIZE];
        char misspath[UTIL_PATH_SIZE];
        char loadpath[UTIL_PATH_SIZE];
        char datapath[UTIL_PATH_SIZE];
        char fwpath[UTIL_PATH_SIZE];
        const char *firmware;
        FILE *fwfile = NULL;
        struct utsname kernel;
        struct stat statbuf;
        unsigned int i;
        int rc = EXIT_SUCCESS;

        firmware = udev_device_get_property_value(dev, "FIRMWARE");
        if (firmware == NULL) {
                log_error("firmware parameter missing\n\n");
                rc = EXIT_FAILURE;
                goto exit;
        }

        /* lookup firmware file */
        uname(&kernel);
        for (i = 0; i < ELEMENTSOF(searchpath); i++) {
                util_strscpyl(fwpath, sizeof(fwpath), searchpath[i], kernel.release, "/", firmware, NULL);
                fwfile = fopen(fwpath, "re");
                if (fwfile != NULL)
                        break;

                util_strscpyl(fwpath, sizeof(fwpath), searchpath[i], firmware, NULL);
                fwfile = fopen(fwpath, "re");
                if (fwfile != NULL)
                        break;
        }

        util_path_encode(firmware, fwencpath, sizeof(fwencpath));
        util_strscpyl(misspath, sizeof(misspath), "/run/udev/firmware-missing/", fwencpath, NULL);
        util_strscpyl(loadpath, sizeof(loadpath), udev_device_get_syspath(dev), "/loading", NULL);

        if (fwfile == NULL) {
                int err;

                /* This link indicates the missing firmware file and the associated device */
                log_debug("did not find firmware file '%s'\n", firmware);
                do {
                        err = mkdir_parents(misspath, 0755);
                        if (err != 0 && err != -ENOENT)
                                break;
                        err = symlink(udev_device_get_devpath(dev), misspath);
                        if (err != 0)
                                err = -errno;
                } while (err == -ENOENT);
                rc = EXIT_FAILURE;
                /*
                 * Do not cancel the request in the initrd, the real root might have
                 * the firmware file and the 'coldplug' run in the real root will find
                 * this pending request and fulfill or cancel it.
                 * */
                if (!in_initrd())
                        set_loading(udev, loadpath, "-1");
                goto exit;
        }

        if (stat(fwpath, &statbuf) < 0 || statbuf.st_size == 0) {
                if (!in_initrd())
                        set_loading(udev, loadpath, "-1");
                rc = EXIT_FAILURE;
                goto exit;
        }

        if (unlink(misspath) == 0)
                util_delete_path(udev, misspath);

        if (!set_loading(udev, loadpath, "1"))
                goto exit;

        util_strscpyl(datapath, sizeof(datapath), udev_device_get_syspath(dev), "/data", NULL);
        if (!copy_firmware(udev, fwpath, datapath, statbuf.st_size)) {
                log_error("error sending firmware '%s' to device\n", firmware);
                set_loading(udev, loadpath, "-1");
                rc = EXIT_FAILURE;
                goto exit;
        };

        set_loading(udev, loadpath, "0");
exit:
        if (fwfile)
                fclose(fwfile);
        return rc;
}
static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], bool test) {
        struct udev_list_entry *entry;
        unsigned release[1024];
        unsigned release_count = 0;
        _cleanup_close_ int fd = -1;
        const char *node;

        node = udev_device_get_devnode(dev);
        if (!node) {
                log_error("No device node for \"%s\"", udev_device_get_syspath(dev));
                return EXIT_FAILURE;
        }

        udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev)) {
                const char *key;
                char *endptr;

                key = udev_list_entry_get_name(entry);
                if (startswith(key, "KEYBOARD_KEY_")) {
                        const char *keycode;
                        unsigned scancode;

                        /* KEYBOARD_KEY_<hex scan code>=<key identifier string> */
                        scancode = strtoul(key + 13, &endptr, 16);
                        if (endptr[0] != '\0') {
                                log_warning("Unable to parse scan code from \"%s\"", key);
                                continue;
                        }

                        keycode = udev_list_entry_get_value(entry);

                        /* a leading '!' needs a force-release entry */
                        if (keycode[0] == '!') {
                                keycode++;

                                release[release_count] = scancode;
                                if (release_count <  ELEMENTSOF(release)-1)
                                        release_count++;

                                if (keycode[0] == '\0')
                                        continue;
                        }

                        if (fd == -1) {
                                fd = open_device(node);
                                if (fd < 0)
                                        return EXIT_FAILURE;
                        }

                        map_keycode(fd, node, scancode, keycode);
                } else if (startswith(key, "EVDEV_ABS_")) {
                        unsigned evcode;

                        /* EVDEV_ABS_<EV_ABS code>=<min>:<max>:<res>:<fuzz>:<flat> */
                        evcode = strtoul(key + 10, &endptr, 16);
                        if (endptr[0] != '\0') {
                                log_warning("Unable to parse EV_ABS code from \"%s\"", key);
                                continue;
                        }

                        if (fd == -1) {
                                fd = open_device(node);
                                if (fd < 0)
                                        return EXIT_FAILURE;
                        }

                        override_abs(fd, node, evcode, udev_list_entry_get_value(entry));
                } else if (streq(key, "POINTINGSTICK_SENSITIVITY"))
                        set_trackpoint_sensitivity(dev, udev_list_entry_get_value(entry));
        }

        /* install list of force-release codes */
        if (release_count > 0)
                install_force_release(dev, release, release_count);

        return EXIT_SUCCESS;
}
Exemple #20
0
static int update_link(struct udev_device *dev, const char *slink, int test)
{
	struct udev *udev = udev_device_get_udev(dev);
	struct udev_list_node dev_list;
	struct udev_list_entry *dev_entry;
	char target[UTIL_PATH_SIZE];
	int count;
	int priority = 0;
	int rc = 0;

	dbg(udev, "update symlink '%s' of '%s'\n", slink, udev_device_get_syspath(dev));

	udev_list_init(&dev_list);
	count = name_index_get_devices(udev, slink, &dev_list);
	if (count > 1)
		info(udev, "found %i devices with name '%s'\n", count, slink);

	/* if we don't have a reference, delete it */
	if (count <= 0) {
		info(udev, "no reference left, remove '%s'\n", slink);
		if (!test) {
			unlink(slink);
			util_delete_path(udev, slink);
		}
		goto out;
	}

	/* find the device with the highest priority */
	target[0] = '\0';
	udev_list_entry_foreach(dev_entry, udev_list_get_entry(&dev_list)) {
		const char *syspath;
		struct udev_device *dev_db;
		const char *devnode;

		syspath = udev_list_entry_get_name(dev_entry);
		dbg(udev, "found '%s' for '%s'\n", syspath, slink);

		/* did we find ourself? we win, if we have the same priority */
		if (strcmp(udev_device_get_syspath(dev), syspath) == 0) {
			dbg(udev, "compare (our own) priority of '%s' %i >= %i\n",
			    udev_device_get_devpath(dev), udev_device_get_devlink_priority(dev), priority);
			if (strcmp(udev_device_get_devnode(dev), slink) == 0) {
				info(udev, "'%s' is our device node, database inconsistent, skip link update\n",
				     udev_device_get_devnode(dev));
			} else if (target[0] == '\0' || udev_device_get_devlink_priority(dev) >= priority) {
				priority = udev_device_get_devlink_priority(dev);
				util_strlcpy(target, udev_device_get_devnode(dev), sizeof(target));
			}
			continue;
		}

		/* another device, read priority from database */
		dev_db = udev_device_new_from_syspath(udev, syspath);
		if (dev_db == NULL)
			continue;
		devnode = udev_device_get_devnode(dev_db);
		if (devnode != NULL) {
			if (strcmp(devnode, slink) == 0) {
				info(udev, "'%s' is a device node of '%s', skip link update\n",
				     devnode, syspath);
			} else {
				dbg(udev, "compare priority of '%s' %i > %i\n",
				    udev_device_get_devpath(dev_db),
				    udev_device_get_devlink_priority(dev_db),
				    priority);
				if (target[0] == '\0' || udev_device_get_devlink_priority(dev_db) > priority) {
					priority = udev_device_get_devlink_priority(dev_db);
					util_strlcpy(target, devnode, sizeof(target));
				}
			}
		}
		udev_device_unref(dev_db);
	}
	udev_list_cleanup_entries(udev, &dev_list);

	if (target[0] == '\0') {
		info(udev, "no current target for '%s' found\n", slink);
		rc = 1;
		goto out;
	}

	/* create symlink to the target with the highest priority */
	info(udev, "'%s' with target '%s' has the highest priority %i, create it\n", slink, target, priority);
	if (!test) {
		util_create_path(udev, slink);
		node_symlink(udev, target, slink);
	}
out:
	return rc;
}
/* handle "[<SUBSYSTEM>/<KERNEL>]<attribute>" format */
int util_resolve_subsys_kernel(struct udev *udev, const char *string,
                               char *result, size_t maxsize, int read_value)
{
        char temp[UTIL_PATH_SIZE];
        char *subsys;
        char *sysname;
        struct udev_device *dev;
        char *attr;

        if (string[0] != '[')
                return -1;

        util_strscpy(temp, sizeof(temp), string);

        subsys = &temp[1];

        sysname = strchr(subsys, '/');
        if (sysname == NULL)
                return -1;
        sysname[0] = '\0';
        sysname = &sysname[1];

        attr = strchr(sysname, ']');
        if (attr == NULL)
                return -1;
        attr[0] = '\0';
        attr = &attr[1];
        if (attr[0] == '/')
                attr = &attr[1];
        if (attr[0] == '\0')
                attr = NULL;

        if (read_value && attr == NULL)
                return -1;

        dev = udev_device_new_from_subsystem_sysname(udev, subsys, sysname);
        if (dev == NULL)
                return -1;

        if (read_value) {
                const char *val;

                val = udev_device_get_sysattr_value(dev, attr);
                if (val != NULL)
                        util_strscpy(result, maxsize, val);
                else
                        result[0] = '\0';
                info(udev, "value '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
        } else {
                size_t l;
                char *s;

                s = result;
                l = util_strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL);
                if (attr != NULL)
                        util_strpcpyl(&s, l, "/", attr, NULL);
                info(udev, "path '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
        }
        udev_device_unref(dev);
        return 0;
}
ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK
udevGetIfaceDefBond(struct udev *udev,
                    struct udev_device *dev,
                    const char *name,
                    virInterfaceDef *ifacedef)
{
    struct dirent **slave_list = NULL;
    int slave_count = 0;
    size_t i;
    const char *tmp_str;
    int tmp_int;

    /* Initial defaults */
    ifacedef->data.bond.target = NULL;
    ifacedef->data.bond.nbItf = 0;
    ifacedef->data.bond.itf = NULL;

    /* Set the bond specifics */
    tmp_str = udev_device_get_sysattr_value(dev, "bonding/downdelay");
    if (!tmp_str) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not retrieve 'bonding/downdelay' for '%s'"), name);
        goto error;
    }
    if (virStrToLong_i(tmp_str, NULL, 10, &tmp_int) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not parse 'bonding/downdelay' '%s' for '%s'"),
                tmp_str, name);
        goto error;
    }
    ifacedef->data.bond.downdelay = tmp_int;

    tmp_str = udev_device_get_sysattr_value(dev, "bonding/updelay");
    if (!tmp_str) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not retrieve 'bonding/updelay' for '%s'"), name);
        goto error;
    }
    if (virStrToLong_i(tmp_str, NULL, 10, &tmp_int) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not parse 'bonding/updelay' '%s' for '%s'"),
                tmp_str, name);
        goto error;
    }
    ifacedef->data.bond.updelay = tmp_int;

    tmp_str = udev_device_get_sysattr_value(dev, "bonding/miimon");
    if (!tmp_str) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not retrieve 'bonding/miimon' for '%s'"), name);
        goto error;
    }
    if (virStrToLong_i(tmp_str, NULL, 10, &tmp_int) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not parse 'bonding/miimon' '%s' for '%s'"),
                tmp_str, name);
        goto error;
    }
    ifacedef->data.bond.frequency = tmp_int;

    tmp_str = udev_device_get_sysattr_value(dev, "bonding/arp_interval");
    if (!tmp_str) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not retrieve 'bonding/arp_interval' for '%s'"), name);
        goto error;
    }
    if (virStrToLong_i(tmp_str, NULL, 10, &tmp_int) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not parse 'bonding/arp_interval' '%s' for '%s'"),
                tmp_str, name);
        goto error;
    }
    ifacedef->data.bond.interval = tmp_int;

    /* bonding/mode is in the format: "balance-rr 0" so we find the
     * space and increment the pointer to get the number and convert
     * it to an interger. libvirt uses 1 through 7 while the raw
     * number is 0 through 6 so increment it by 1.
     */
    tmp_str = udev_device_get_sysattr_value(dev, "bonding/mode");
    if (!tmp_str) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not retrieve 'bonding/mode' for '%s'"), name);
        goto error;
    }
    tmp_str = strchr(tmp_str, ' ');
    if (!tmp_str) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Invalid format for 'bonding/mode' for '%s'"), name);
        goto error;
    }
    if (strlen(tmp_str) < 2) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Unable to find correct value in 'bonding/mode' for '%s'"),
                name);
        goto error;
    }
    if (virStrToLong_i(tmp_str + 1, NULL, 10, &tmp_int) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not parse 'bonding/mode' '%s' for '%s'"),
                tmp_str, name);
        goto error;
    }
    ifacedef->data.bond.mode = tmp_int + 1;

    /* bonding/arp_validate is in the format: "none 0" so we find the
     * space and increment the pointer to get the number and convert
     * it to an interger.
     */
    tmp_str = udev_device_get_sysattr_value(dev, "bonding/arp_validate");
    if (!tmp_str) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not retrieve 'bonding/arp_validate' for '%s'"), name);
        goto error;
    }
    tmp_str = strchr(tmp_str, ' ');
    if (!tmp_str) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Invalid format for 'bonding/arp_validate' for '%s'"), name);
        goto error;
    }
    if (strlen(tmp_str) < 2) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Unable to find correct value in 'bonding/arp_validate' "
                "for '%s'"), name);
        goto error;
    }
    if (virStrToLong_i(tmp_str + 1, NULL, 10, &tmp_int) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not parse 'bonding/arp_validate' '%s' for '%s'"),
                tmp_str, name);
        goto error;
    }
    ifacedef->data.bond.validate = tmp_int;

    /* bonding/use_carrier is 0 or 1 and libvirt stores it as 1 or 2. */
    tmp_str = udev_device_get_sysattr_value(dev, "bonding/use_carrier");
    if (!tmp_str) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not retrieve 'bonding/use_carrier' for '%s'"), name);
        goto error;
    }
    if (virStrToLong_i(tmp_str, NULL, 10, &tmp_int) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not parse 'bonding/use_carrier' '%s' for '%s'"),
                tmp_str, name);
        goto error;
    }
    ifacedef->data.bond.carrier = tmp_int + 1;

    /* MII or ARP Monitoring is based on arp_interval and miimon.
     * if arp_interval > 0 then ARP monitoring is in play, if
     * miimon > 0 then MII monitoring is in play.
     */
    if (ifacedef->data.bond.interval > 0)
        ifacedef->data.bond.monit = VIR_INTERFACE_BOND_MONIT_ARP;
    else if (ifacedef->data.bond.frequency > 0)
        ifacedef->data.bond.monit = VIR_INTERFACE_BOND_MONIT_MII;
    else
        ifacedef->data.bond.monit = VIR_INTERFACE_BOND_MONIT_NONE;

    tmp_str = udev_device_get_sysattr_value(dev, "bonding/arp_ip_target");
    if (!tmp_str) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not retrieve 'bonding/arp_ip_target' for '%s'"), name);
        goto error;
    }
    if (VIR_STRDUP(ifacedef->data.bond.target, tmp_str) < 0)
        goto error;

    /* Slaves of the bond */
    /* Get each slave in the bond */
    slave_count = scandir(udev_device_get_syspath(dev), &slave_list,
            udevBondScanDirFilter, alphasort);

    if (slave_count < 0) {
        virReportSystemError(errno,
                _("Could not get slaves of bond '%s'"), name);
        goto error;
    }

    /* Allocate our list of slave devices */
    if (VIR_ALLOC_N(ifacedef->data.bond.itf, slave_count) < 0)
        goto error;
    ifacedef->data.bond.nbItf = slave_count;

    for (i = 0; i < slave_count; i++) {
        /* Names are slave_interface. e.g. slave_eth0
         * so we use the part after the _
         */
        tmp_str = strchr(slave_list[i]->d_name, '_');
        if (!tmp_str || strlen(tmp_str) < 2) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid enslaved interface name '%s' seen for "
                             "bond '%s'"), slave_list[i]->d_name, name);
            goto error;
        }
        /* go past the _ */
        tmp_str++;

        ifacedef->data.bond.itf[i] =
            udevGetIfaceDef(udev, tmp_str);
        if (!ifacedef->data.bond.itf[i]) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not get interface information for '%s', which is "
                  "a enslaved in bond '%s'"), slave_list[i]->d_name, name);
            goto error;
        }
        VIR_FREE(slave_list[i]);
    }

    VIR_FREE(slave_list);

    return 0;

 error:
    for (i = 0; slave_count != -1 && i < slave_count; i++) {
        VIR_FREE(slave_list[i]);
    }
    VIR_FREE(slave_list);

    return -1;
}
static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], bool test) {
        struct udev_list_entry *entry;
        struct {
                unsigned int scan;
                unsigned int key;
        } map[1024];
        unsigned int map_count = 0;
        unsigned int release[1024];
        unsigned int release_count = 0;

        udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev)) {
                const char *key;
                unsigned int scancode;
                char *endptr;
                const char *keycode;
                const struct key *k;

                key = udev_list_entry_get_name(entry);
                if (!startswith(key, "KEYBOARD_KEY_"))
                        continue;

                /* KEYBOARD_KEY_<hex scan code>=<key identifier string> */
                scancode = strtoul(key + 13, &endptr, 16);
                if (endptr[0] != '\0') {
                        log_error("Error, unable to parse scan code from '%s'", key);
                        continue;
                }

                keycode = udev_list_entry_get_value(entry);

                /* a leading '!' needs a force-release entry */
                if (keycode[0] == '!') {
                        keycode++;

                        release[release_count] = scancode;
                        if (release_count <  ELEMENTSOF(release)-1)
                                release_count++;

                        if (keycode[0] == '\0')
                                continue;
                }

                /* translate identifier to key code */
                k = keyboard_lookup_key(keycode, strlen(keycode));
                if (!k) {
                        log_error("Error, unknown key identifier '%s'", keycode);
                        continue;
                }

                map[map_count].scan = scancode;
                map[map_count].key = k->id;
                if (map_count < ELEMENTSOF(map)-1)
                        map_count++;
        }

        if (map_count > 0 || release_count > 0) {
                const char *node;
                int fd;
                unsigned int i;

                node = udev_device_get_devnode(dev);
                if (!node) {
                        log_error("Error, no device node for '%s'", udev_device_get_syspath(dev));
                        return EXIT_FAILURE;
                }

                fd = open(udev_device_get_devnode(dev), O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
                if (fd < 0) {
                        log_error("Error, opening device '%s': %m", node);
                        return EXIT_FAILURE;
                }

                /* install list of map codes */
                for (i = 0; i < map_count; i++) {
                        log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)",
                                  map[i].scan, map[i].scan, map[i].key, map[i].key);
                        if (ioctl(fd, EVIOCSKEYCODE, &map[i]) < 0)
                                log_error("Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", node, map[i].scan, map[i].key);
                }

                /* install list of force-release codes */
                if (release_count > 0)
                        install_force_release(dev, release, release_count);

                close(fd);
        }

        return EXIT_SUCCESS;
}
int open_wii_device(struct wiimoteglue_state *state, struct wii_device* dev) {
  if (dev->xwii != NULL) {
    return 0; //Already open.
  }
  
  if (dev->udev == NULL) {
    return -1; //Not even connected.
  }
  
  int i;
  struct xwii_iface *wiidev;
  char* syspath = udev_device_get_syspath(dev->udev);
  if (syspath == NULL)
    return -1;
  xwii_iface_new(&wiidev,syspath);
  xwii_iface_watch(wiidev,true);
  xwii_iface_open(wiidev,  XWII_IFACE_WRITABLE | (XWII_IFACE_ALL ^ XWII_IFACE_ACCEL ^ XWII_IFACE_IR ^ XWII_IFACE_MOTION_PLUS));
  if (!(xwii_iface_available(wiidev) & (XWII_IFACE_CORE | XWII_IFACE_PRO_CONTROLLER | XWII_IFACE_BALANCE_BOARD))) {
    printf("Tried to open a non-wiimote device...\n");
    printf("Or we didn't have permission on the event devices?\n");
    printf("You might need to add a udev rule to give permission.\n");
    xwii_iface_unref(wiidev);
    return -1;
  }

  dev->xwii = wiidev;
  dev->ifaces = xwii_iface_opened(wiidev);

  if (state->ignore_pro && (dev->ifaces & XWII_IFACE_PRO_CONTROLLER)) {
    xwii_iface_unref(wiidev);
    dev->xwii = NULL;
    return 0;
  }



  dev->type = REMOTE;
  if (dev->ifaces & XWII_IFACE_BALANCE_BOARD) {
    dev->type = BALANCE;
  }
  if (dev->ifaces & XWII_IFACE_PRO_CONTROLLER) {
    dev->type = PRO;
  }

  dev->fd = xwii_iface_get_fd(wiidev);
  wiimoteglue_epoll_watch_wiimote(state->epfd, dev);



  compute_device_map(state,dev);

  if (dev->map->accel_active) {
    xwii_iface_open(wiidev,XWII_IFACE_ACCEL);
  } else {
    xwii_iface_close(wiidev,XWII_IFACE_ACCEL);
  }

  if (dev->map->IR_count) {
    xwii_iface_open(wiidev,XWII_IFACE_IR);
  } else {
    xwii_iface_close(wiidev,XWII_IFACE_IR);
  }
  
  /*LEDs only checked after opening,
   *and we want to store the state
   *only on the very initial opening.*/
  if (dev->original_leds[0] == -2)
    store_led_state(state,dev);

  return 0;

}
/*
 * A unique USB identification is generated like this:
 *
 * 1.) Get the USB device type from InterfaceClass and InterfaceSubClass
 * 2.) If the device type is 'Mass-Storage/SPC-2' or 'Mass-Storage/RBC',
 *     use the SCSI vendor and model as USB-Vendor and USB-model.
 * 3.) Otherwise, use the USB manufacturer and product as
 *     USB-Vendor and USB-model. Any non-printable characters
 *     in those strings will be skipped; a slash '/' will be converted
 *     into a full stop '.'.
 * 4.) If that fails, too, we will use idVendor and idProduct
 *     as USB-Vendor and USB-model.
 * 5.) The USB identification is the USB-vendor and USB-model
 *     string concatenated with an underscore '_'.
 * 6.) If the device supplies a serial number, this number
 *     is concatenated with the identification with an underscore '_'.
 */
static int builtin_usb_id(struct udev_device *dev, int argc, char *argv[], bool test) {
        char vendor_str[64];
        char vendor_str_enc[256];
        const char *vendor_id;
        char model_str[64];
        char model_str_enc[256];
        const char *product_id;
        char serial_str[UTIL_NAME_SIZE];
        char packed_if_str[UTIL_NAME_SIZE];
        char revision_str[64];
        char type_str[64];
        char instance_str[64];
        const char *ifnum = NULL;
        const char *driver = NULL;
        char serial[256];

        struct udev_device *dev_interface = NULL;
        struct udev_device *dev_usb = NULL;
        const char *if_class, *if_subclass;
        int if_class_num;
        int protocol = 0;
        size_t l;
        char *s;

        vendor_str[0] = '\0';
        model_str[0] = '\0';
        serial_str[0] = '\0';
        packed_if_str[0] = '\0';
        revision_str[0] = '\0';
        type_str[0] = '\0';
        instance_str[0] = '\0';

        /* shortcut, if we are called directly for a "usb_device" type */
        if (udev_device_get_devtype(dev) != NULL && streq(udev_device_get_devtype(dev), "usb_device")) {
                dev_if_packed_info(dev, packed_if_str, sizeof(packed_if_str));
                dev_usb = dev;
                goto fallback;
        }

        /* usb interface directory */
        dev_interface = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
        if (dev_interface == NULL) {
                log_debug("unable to access usb_interface device of '%s'",
                     udev_device_get_syspath(dev));
                return EXIT_FAILURE;
        }

        ifnum = udev_device_get_sysattr_value(dev_interface, "bInterfaceNumber");
        driver = udev_device_get_sysattr_value(dev_interface, "driver");

        if_class = udev_device_get_sysattr_value(dev_interface, "bInterfaceClass");
        if (!if_class) {
                log_debug("%s: cannot get bInterfaceClass attribute",
                     udev_device_get_sysname(dev));
                return EXIT_FAILURE;
        }

        if_class_num = strtoul(if_class, NULL, 16);
        if (if_class_num == 8) {
                /* mass storage */
                if_subclass = udev_device_get_sysattr_value(dev_interface, "bInterfaceSubClass");
                if (if_subclass != NULL)
                        protocol = set_usb_mass_storage_ifsubtype(type_str, if_subclass, sizeof(type_str)-1);
        } else {
                set_usb_iftype(type_str, if_class_num, sizeof(type_str)-1);
        }

        log_debug("%s: if_class %d protocol %d",
             udev_device_get_syspath(dev_interface), if_class_num, protocol);

        /* usb device directory */
        dev_usb = udev_device_get_parent_with_subsystem_devtype(dev_interface, "usb", "usb_device");
        if (!dev_usb) {
                log_debug("unable to find parent 'usb' device of '%s'",
                     udev_device_get_syspath(dev));
                return EXIT_FAILURE;
        }

        /* all interfaces of the device in a single string */
        dev_if_packed_info(dev_usb, packed_if_str, sizeof(packed_if_str));

        /* mass storage : SCSI or ATAPI */
        if ((protocol == 6 || protocol == 2)) {
                struct udev_device *dev_scsi;
                const char *scsi_model, *scsi_vendor, *scsi_type, *scsi_rev;
                int host, bus, target, lun;

                /* get scsi device */
                dev_scsi = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device");
                if (dev_scsi == NULL) {
                        log_debug("unable to find parent 'scsi' device of '%s'",
                             udev_device_get_syspath(dev));
                        goto fallback;
                }
                if (sscanf(udev_device_get_sysname(dev_scsi), "%d:%d:%d:%d", &host, &bus, &target, &lun) != 4) {
                        log_debug("invalid scsi device '%s'", udev_device_get_sysname(dev_scsi));
                        goto fallback;
                }

                /* Generic SPC-2 device */
                scsi_vendor = udev_device_get_sysattr_value(dev_scsi, "vendor");
                if (!scsi_vendor) {
                        log_debug("%s: cannot get SCSI vendor attribute",
                             udev_device_get_sysname(dev_scsi));
                        goto fallback;
                }
                udev_util_encode_string(scsi_vendor, vendor_str_enc, sizeof(vendor_str_enc));
                util_replace_whitespace(scsi_vendor, vendor_str, sizeof(vendor_str)-1);
                util_replace_chars(vendor_str, NULL);

                scsi_model = udev_device_get_sysattr_value(dev_scsi, "model");
                if (!scsi_model) {
                        log_debug("%s: cannot get SCSI model attribute",
                             udev_device_get_sysname(dev_scsi));
                        goto fallback;
                }
                udev_util_encode_string(scsi_model, model_str_enc, sizeof(model_str_enc));
                util_replace_whitespace(scsi_model, model_str, sizeof(model_str)-1);
                util_replace_chars(model_str, NULL);

                scsi_type = udev_device_get_sysattr_value(dev_scsi, "type");
                if (!scsi_type) {
                        log_debug("%s: cannot get SCSI type attribute",
                             udev_device_get_sysname(dev_scsi));
                        goto fallback;
                }
                set_scsi_type(type_str, scsi_type, sizeof(type_str)-1);

                scsi_rev = udev_device_get_sysattr_value(dev_scsi, "rev");
                if (!scsi_rev) {
                        log_debug("%s: cannot get SCSI revision attribute",
                             udev_device_get_sysname(dev_scsi));
                        goto fallback;
                }
                util_replace_whitespace(scsi_rev, revision_str, sizeof(revision_str)-1);
                util_replace_chars(revision_str, NULL);

                /*
                 * some broken devices have the same identifiers
                 * for all luns, export the target:lun number
                 */
                sprintf(instance_str, "%d:%d", target, lun);
        }

fallback:
        vendor_id = udev_device_get_sysattr_value(dev_usb, "idVendor");
        product_id = udev_device_get_sysattr_value(dev_usb, "idProduct");

        /* fallback to USB vendor & device */
        if (vendor_str[0] == '\0') {
                const char *usb_vendor = NULL;

                usb_vendor = udev_device_get_sysattr_value(dev_usb, "manufacturer");
                if (!usb_vendor)
                        usb_vendor = vendor_id;
                if (!usb_vendor) {
                        log_debug("No USB vendor information available");
                        return EXIT_FAILURE;
                }
                udev_util_encode_string(usb_vendor, vendor_str_enc, sizeof(vendor_str_enc));
                util_replace_whitespace(usb_vendor, vendor_str, sizeof(vendor_str)-1);
                util_replace_chars(vendor_str, NULL);
        }

        if (model_str[0] == '\0') {
                const char *usb_model = NULL;

                usb_model = udev_device_get_sysattr_value(dev_usb, "product");
                if (!usb_model)
                        usb_model = product_id;
                if (!usb_model)
                        return EXIT_FAILURE;
                udev_util_encode_string(usb_model, model_str_enc, sizeof(model_str_enc));
                util_replace_whitespace(usb_model, model_str, sizeof(model_str)-1);
                util_replace_chars(model_str, NULL);
        }

        if (revision_str[0] == '\0') {
                const char *usb_rev;

                usb_rev = udev_device_get_sysattr_value(dev_usb, "bcdDevice");
                if (usb_rev) {
                        util_replace_whitespace(usb_rev, revision_str, sizeof(revision_str)-1);
                        util_replace_chars(revision_str, NULL);
                }
        }

        if (serial_str[0] == '\0') {
                const char *usb_serial;

                usb_serial = udev_device_get_sysattr_value(dev_usb, "serial");
                if (usb_serial) {
                        const unsigned char *p;

                        /* http://msdn.microsoft.com/en-us/library/windows/hardware/gg487321.aspx */
                        for (p = (unsigned char *)usb_serial; *p != '\0'; p++)
                                if (*p < 0x20 || *p > 0x7f || *p == ',') {
                                        usb_serial = NULL;
                                        break;
                                }
                }

                if (usb_serial) {
                        util_replace_whitespace(usb_serial, serial_str, sizeof(serial_str)-1);
                        util_replace_chars(serial_str, NULL);
                }
        }

        s = serial;
        l = strpcpyl(&s, sizeof(serial), vendor_str, "_", model_str, NULL);
        if (serial_str[0] != '\0')
                l = strpcpyl(&s, l, "_", serial_str, NULL);

        if (instance_str[0] != '\0')
                strpcpyl(&s, l, "-", instance_str, NULL);

        udev_builtin_add_property(dev, test, "ID_VENDOR", vendor_str);
        udev_builtin_add_property(dev, test, "ID_VENDOR_ENC", vendor_str_enc);
        udev_builtin_add_property(dev, test, "ID_VENDOR_ID", vendor_id);
        udev_builtin_add_property(dev, test, "ID_MODEL", model_str);
        udev_builtin_add_property(dev, test, "ID_MODEL_ENC", model_str_enc);
        udev_builtin_add_property(dev, test, "ID_MODEL_ID", product_id);
        udev_builtin_add_property(dev, test, "ID_REVISION", revision_str);
        udev_builtin_add_property(dev, test, "ID_SERIAL", serial);
        if (serial_str[0] != '\0')
                udev_builtin_add_property(dev, test, "ID_SERIAL_SHORT", serial_str);
        if (type_str[0] != '\0')
                udev_builtin_add_property(dev, test, "ID_TYPE", type_str);
        if (instance_str[0] != '\0')
                udev_builtin_add_property(dev, test, "ID_INSTANCE", instance_str);
        udev_builtin_add_property(dev, test, "ID_BUS", "usb");
        if (packed_if_str[0] != '\0')
                udev_builtin_add_property(dev, test, "ID_USB_INTERFACES", packed_if_str);
        if (ifnum != NULL)
                udev_builtin_add_property(dev, test, "ID_USB_INTERFACE_NUM", ifnum);
        if (driver != NULL)
                udev_builtin_add_property(dev, test, "ID_USB_DRIVER", driver);
        return EXIT_SUCCESS;
}
static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
        struct udev *udev = udev_device_get_udev(names->pcidev);
        unsigned domain, bus, slot, func, dev_port = 0;
        size_t l;
        char *s;
        const char *attr;
        struct udev_device *pci = NULL;
        char slots[256], str[256];
        _cleanup_closedir_ DIR *dir = NULL;
        struct dirent *dent;
        int hotplug_slot = 0, err = 0;

        if (sscanf(udev_device_get_sysname(names->pcidev), "%x:%x:%x.%u", &domain, &bus, &slot, &func) != 4)
                return -ENOENT;

        /* kernel provided port index for multiple ports on a single PCI function */
        attr = udev_device_get_sysattr_value(dev, "dev_port");
        if (attr)
                dev_port = strtol(attr, NULL, 10);

        /* compose a name based on the raw kernel's PCI bus, slot numbers */
        s = names->pci_path;
        l = sizeof(names->pci_path);
        if (domain > 0)
                l = strpcpyf(&s, l, "P%u", domain);
        l = strpcpyf(&s, l, "p%us%u", bus, slot);
        if (func > 0 || is_pci_multifunction(names->pcidev))
                l = strpcpyf(&s, l, "f%u", func);
        if (dev_port > 0)
                l = strpcpyf(&s, l, "d%u", dev_port);
        if (l == 0)
                names->pci_path[0] = '\0';

        /* ACPI _SUN  — slot user number */
        pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
        if (!pci) {
                err = -ENOENT;
                goto out;
        }
        xsprintf(slots, "%s/slots", udev_device_get_syspath(pci));
        dir = opendir(slots);
        if (!dir) {
                err = -errno;
                goto out;
        }

        for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
                int i;
                char *rest;
                char *address;

                if (dent->d_name[0] == '.')
                        continue;
                i = strtol(dent->d_name, &rest, 10);
                if (rest[0] != '\0')
                        continue;
                if (i < 1)
                        continue;
                xsprintf(str, "%s/%s/address", slots, dent->d_name);
                if (read_one_line_file(str, &address) >= 0) {
                        /* match slot address with device by stripping the function */
                        if (strneq(address, udev_device_get_sysname(names->pcidev), strlen(address)))
                                hotplug_slot = i;
                        free(address);
                }

                if (hotplug_slot > 0)
                        break;
        }

        if (hotplug_slot > 0) {
                s = names->pci_slot;
                l = sizeof(names->pci_slot);
                if (domain > 0)
                        l = strpcpyf(&s, l, "P%d", domain);
                l = strpcpyf(&s, l, "s%d", hotplug_slot);
                if (func > 0 || is_pci_multifunction(names->pcidev))
                        l = strpcpyf(&s, l, "f%d", func);
                if (dev_port > 0)
                        l = strpcpyf(&s, l, "d%d", dev_port);
                if (l == 0)
                        names->pci_slot[0] = '\0';
        }
out:
        udev_device_unref(pci);
        return err;
}
Exemple #27
0
static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
        struct udev *udev = udev_device_get_udev(names->pcidev);
        unsigned int bus;
        unsigned int slot;
        unsigned int func;
        unsigned int dev_id = 0;
        size_t l;
        char *s;
        const char *attr;
        struct udev_device *pci = NULL;
        char slots[256];
        DIR *dir;
        struct dirent *dent;
        char str[256];
        int hotplug_slot = 0;
        int err = 0;

        if (sscanf(udev_device_get_sysname(names->pcidev), "0000:%x:%x.%d", &bus, &slot, &func) != 3)
                return -ENOENT;

        /* kernel provided multi-device index */
        attr = udev_device_get_sysattr_value(dev, "dev_id");
        if (attr)
                dev_id = strtol(attr, NULL, 16);

        /* compose a name based on the raw kernel's PCI bus, slot numbers */
        s = names->pci_path;
        l = util_strpcpyf(&s, sizeof(names->pci_path), "p%ds%d", bus, slot);
        if (func > 0 || is_pci_multifunction(names->pcidev))
                l = util_strpcpyf(&s, l, "f%d", func);
        if (dev_id > 0)
                l = util_strpcpyf(&s, l, "d%d", dev_id);
        if (l == 0)
                names->pci_path[0] = '\0';

        /* ACPI _SUN  -- slot user number */
        pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
        if (!pci) {
                err = -ENOENT;
                goto out;
        }
        snprintf(slots, sizeof(slots), "%s/slots", udev_device_get_syspath(pci));
        dir = opendir(slots);
        if (!dir) {
                err = -errno;
                goto out;
        }

        for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
                int i;
                char *rest;
                char *address;

                if (dent->d_name[0] == '.')
                        continue;
                i = strtol(dent->d_name, &rest, 10);
                if (rest[0] != '\0')
                        continue;
                if (i < 1)
                        continue;
                snprintf(str, sizeof(str), "%s/%s/address", slots, dent->d_name);
                if (read_one_line_file(str, &address) >= 0) {
                        /* match slot address with device by stripping the function */
                        if (strncmp(address, udev_device_get_sysname(names->pcidev), strlen(address)) == 0)
                                hotplug_slot = i;
                        free(address);
                }

                if (hotplug_slot > 0)
                        break;
        }
        closedir(dir);

        if (hotplug_slot > 0) {
                s = names->pci_slot;
                l = util_strpcpyf(&s, sizeof(names->pci_slot), "s%d", hotplug_slot);
                if (func > 0 || is_pci_multifunction(names->pcidev))
                        l = util_strpcpyf(&s, l, "f%d", func);
                if (dev_id > 0)
                        l = util_strpcpyf(&s, l, "d%d", dev_id);
                if (l == 0)
                        names->pci_path[0] = '\0';
        }
out:
        udev_device_unref(pci);
        return err;
}
Exemple #28
0
static int builtin_firmware(struct udev_device *dev, int argc, char *argv[], bool test) {
        struct udev *udev = udev_device_get_udev(dev);
        static const char *searchpath[] = { FIRMWARE_PATH };
        char loadpath[UTIL_PATH_SIZE];
        char datapath[UTIL_PATH_SIZE];
        char fwpath[UTIL_PATH_SIZE];
        const char *firmware;
        FILE *fwfile = NULL;
        struct utsname kernel;
        struct stat statbuf;
        unsigned int i;
        int rc = EXIT_SUCCESS;

        firmware = udev_device_get_property_value(dev, "FIRMWARE");
        if (firmware == NULL) {
                log_error("firmware parameter missing");
                rc = EXIT_FAILURE;
                goto exit;
        }

        /* lookup firmware file */
        uname(&kernel);
        for (i = 0; i < ELEMENTSOF(searchpath); i++) {
                strscpyl(fwpath, sizeof(fwpath), searchpath[i], kernel.release, "/", firmware, NULL);
                fwfile = fopen(fwpath, "re");
                if (fwfile != NULL)
                        break;

                strscpyl(fwpath, sizeof(fwpath), searchpath[i], firmware, NULL);
                fwfile = fopen(fwpath, "re");
                if (fwfile != NULL)
                        break;
        }

        strscpyl(loadpath, sizeof(loadpath), udev_device_get_syspath(dev), "/loading", NULL);

        if (fwfile == NULL) {
                log_debug("did not find firmware file '%s'", firmware);
                rc = EXIT_FAILURE;
                /*
                 * Do not cancel the request in the initrd, the real root might have
                 * the firmware file and the 'coldplug' run in the real root will find
                 * this pending request and fulfill or cancel it.
                 * */
                if (!in_initrd())
                        set_loading(udev, loadpath, "-1");
                goto exit;
        }

        if (stat(fwpath, &statbuf) < 0 || statbuf.st_size == 0) {
                if (!in_initrd())
                        set_loading(udev, loadpath, "-1");
                rc = EXIT_FAILURE;
                goto exit;
        }

        if (!set_loading(udev, loadpath, "1"))
                goto exit;

        strscpyl(datapath, sizeof(datapath), udev_device_get_syspath(dev), "/data", NULL);
        if (!copy_firmware(udev, fwpath, datapath, statbuf.st_size)) {
                log_error("error sending firmware '%s' to device", firmware);
                set_loading(udev, loadpath, "-1");
                rc = EXIT_FAILURE;
                goto exit;
        };

        set_loading(udev, loadpath, "0");
exit:
        if (fwfile)
                fclose(fwfile);
        return rc;
}
Exemple #29
0
int main(int argc, char *argv[])
{
	static const struct option options[] = {
		{ "help", no_argument, NULL, 'h' },
		{ "mode", required_argument, NULL, 'm' },
		{ "devpath", required_argument, NULL, 'p' },
		{ "method", required_argument, NULL, 'M' },
		{ }
	};
	enum method {
		METHOD_UNDEF,
		METHOD_CSR,
		METHOD_LOGITECH_HID,
		METHOD_DELL,
	} method = METHOD_UNDEF;
	struct udev *udev;
	struct udev_device *udev_dev = NULL;
	char syspath[PATH_MAX];
	int (*usb_switch)(int fd, enum mode mode) = NULL;
	enum mode mode = HCI;
	const char *devpath = NULL;
	int err = -1;
	int rc = 1;

	for (;;) {
		int option;

		option = getopt_long(argc, argv, "m:p:M:h", options, NULL);
		if (option == -1)
			break;

		switch (option) {
		case 'm':
			if (!strcmp(optarg, "hid")) {
				mode = HID;
			} else if (!strcmp(optarg, "hci")) {
				mode = HCI;
			} else {
				usage("error: undefined radio mode\n");
				exit(1);
			}
			break;
		case 'p':
			devpath = optarg;
			break;
		case 'M':
			if (!strcmp(optarg, "csr")) {
				method = METHOD_CSR;
				usb_switch = usb_switch_csr;
			} else if (!strcmp(optarg, "logitech-hid")) {
				method = METHOD_LOGITECH_HID;
			} else if (!strcmp(optarg, "dell")) {
				method = METHOD_DELL;
				usb_switch = usb_switch_dell;
			} else {
				usage("error: undefined switching method\n");
				exit(1);
			}
			break;
		case 'h':
			usage(NULL);
		}
	}

	if (!devpath || method == METHOD_UNDEF) {
		usage("error: --devpath= and --method= must be defined\n");
		exit(1);
	}

	udev = udev_new();
	if (udev == NULL)
		goto exit;

	snprintf(syspath, sizeof(syspath), "/sys/%s", devpath);
	udev_dev = udev_device_new_from_syspath(udev, syspath);
	if (udev_dev == NULL) {
		fprintf(stderr, "error: could not find '%s'\n", devpath);
		goto exit;
	}

	switch (method) {
	case METHOD_CSR:
	case METHOD_DELL: {
		struct udev_device *dev;
		int handle;
		const char *type;

		/* get the parent usb_device if needed */
		dev = udev_dev;
		type = udev_device_get_devtype(dev);
		if (type == NULL || strcmp(type, "usb_device") != 0) {
			dev = udev_device_get_parent_with_subsystem_devtype(dev,
							"usb", "usb_device");
			if (dev == NULL) {
				fprintf(stderr, "error: could not find usb_device for '%s'\n", devpath);
				goto exit;
			}
		}

		handle = find_device(dev);
		if (handle < 0) {
			fprintf(stderr, "error: unable to handle '%s'\n",
				udev_device_get_syspath(dev));
			goto exit;
		}
		err = usb_switch(handle, mode);
		close(handle);
		break;
	}
	case METHOD_LOGITECH_HID: {
		const char *device;

		device = udev_device_get_devnode(udev_dev);
		if (device == NULL) {
			fprintf(stderr, "error: could not find hiddev device node\n");
			goto exit;
		}
		err = hid_switch_logitech(device);
		break;
	}
	default:
		break;
	}

	if (err < 0)
		fprintf(stderr, "error: switching device '%s' failed.\n",
			udev_device_get_syspath(udev_dev));
exit:
	udev_device_unref(udev_dev);
	udev_unref(udev);
	return rc;
}
ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK
udevGetIfaceDefBridge(struct udev *udev,
                      struct udev_device *dev,
                      const char *name,
                      virInterfaceDef *ifacedef)
{
    struct dirent **member_list = NULL;
    int member_count = 0;
    char *member_path;
    const char *tmp_str;
    int stp;
    size_t i;

    /* Set our type to Bridge  */
    ifacedef->type = VIR_INTERFACE_TYPE_BRIDGE;

    /* Retrieve the forward delay */
    tmp_str = udev_device_get_sysattr_value(dev, "bridge/forward_delay");
    if (!tmp_str) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not retrieve 'bridge/forward_delay' for '%s'"), name);
        goto error;
    }

    if (VIR_STRDUP(ifacedef->data.bridge.delay, tmp_str) < 0)
        goto error;

    /* Retrieve Spanning Tree State. Valid values = -1, 0, 1 */
    tmp_str = udev_device_get_sysattr_value(dev, "bridge/stp_state");
    if (!tmp_str) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
            _("Could not retrieve 'bridge/stp_state' for '%s'"), name);
        goto error;
    }

    if (virStrToLong_i(tmp_str, NULL, 10, &stp) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not parse 'bridge/stp_state' '%s' for '%s'"),
                tmp_str, name);
        goto error;
    }

    switch (stp) {
    case -1:
    case 0:
    case 1:
        ifacedef->data.bridge.stp = stp;
        break;
    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
            _("Invalid STP state value %d received for '%s'. Must be "
              "-1, 0, or 1."), stp, name);
        goto error;
    }

    /* Members of the bridge */
    if (virAsprintf(&member_path, "%s/%s",
                udev_device_get_syspath(dev), "brif") < 0)
        goto error;

    /* Get each member of the bridge */
    member_count = scandir(member_path, &member_list,
            udevBridgeScanDirFilter, alphasort);

    /* Don't need the path anymore */
    VIR_FREE(member_path);

    if (member_count < 0) {
        virReportSystemError(errno,
                _("Could not get members of bridge '%s'"),
                name);
        goto error;
    }

    /* Allocate our list of member devices */
    if (VIR_ALLOC_N(ifacedef->data.bridge.itf, member_count) < 0)
        goto error;
    ifacedef->data.bridge.nbItf = member_count;

    /* Get the interface defintions for each member of the bridge */
    for (i = 0; i < member_count; i++) {
        ifacedef->data.bridge.itf[i] =
            udevGetIfaceDef(udev, member_list[i]->d_name);
        if (!ifacedef->data.bridge.itf[i]) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                _("Could not get interface information for '%s', which is "
                  "a member of bridge '%s'"), member_list[i]->d_name, name);
            goto error;
        }
        VIR_FREE(member_list[i]);
    }

    VIR_FREE(member_list);

    return 0;

 error:
    for (i = 0; member_count != -1 && i < member_count; i++) {
        VIR_FREE(member_list[i]);
    }
    VIR_FREE(member_list);

    return -1;
}