chiark / gitweb /
usb-db: move from udev-extras
authorLennart Poettering <lennart@poettering.net>
Tue, 16 Jun 2009 18:57:28 +0000 (20:57 +0200)
committerKay Sievers <kay.sievers@vrfy.org>
Tue, 16 Jun 2009 18:57:28 +0000 (20:57 +0200)
configure.ac
extras/Makefile.am
extras/usb-db/.gitignore [new file with mode: 0644]
extras/usb-db/Makefile.am [new file with mode: 0644]
extras/usb-db/usb-db.c [new file with mode: 0644]

index 2fae2cc..947ab80 100644 (file)
@@ -72,6 +72,22 @@ if test "x$enable_extras" = xyes; then
        PKG_CHECK_MODULES(LIBUSB, libusb >= 0.1.12)
        AC_SUBST(LIBUSB_CFLAGS)
        AC_SUBST(LIBUSB_LIBS)
+
+       PKG_CHECK_MODULES(USBUTILS, usbutils >= 0.82)
+       AC_SUBST([USB_DATABASE], [$($PKG_CONFIG --variable=usbids usbutils)])
+
+       AC_CHECK_FILES([/usr/share/pci.ids], [pciids=/usr/share/pci.ids])
+       AC_CHECK_FILES([/usr/share/hwdata/pci.ids], [pciids=/usr/share/hwdata/pci.ids])
+       AC_CHECK_FILES([/usr/share/misc/pci.ids], [pciids=/usr/share/misc/pci.ids])
+       AC_ARG_WITH(pci-ids-path,
+               AS_HELP_STRING([--pci-ids-path=DIR], [Path to pci.ids file]),
+               [PCI_DATABASE=${withval}],
+               [if test -n "$pciids" ; then
+                       PCI_DATABASE="$pciids"
+               else
+                       AC_MSG_ERROR([pci.ids not found, try --with-pci-ids-path=])
+               fi])
+       AC_SUBST(PCI_DATABASE)
 fi
 AM_CONDITIONAL([ENABLE_EXTRAS], [test "x$enable_extras" = xyes])
 
@@ -113,6 +129,7 @@ AC_CONFIG_FILES([
        extras/v4l_id/Makefile
        extras/hid2hci/Makefile
        extras/udev-acl/Makefile
+       extras/usb-db/Makefile
        extras/gudev/Makefile
        extras/gudev/gudev-1.0.pc
        extras/gudev/docs/Makefile
@@ -144,5 +161,8 @@ AC_MSG_RESULT([
        extras:                 ${enable_extras}
        gintrospection:         ${enable_introspection}
 
+       usb.ids:                ${USB_DATABASE}
+       pci.ids:                ${PCI_DATABASE}
+
        xsltproc:               ${XSLTPROC}
 ])
index e4136ad..07bf48e 100644 (file)
@@ -17,6 +17,7 @@ SUBDIRS = \
 if ENABLE_EXTRAS
 SUBDIRS += \
        udev-acl \
+       usb-db \
        hid2hci \
        gudev
 endif
diff --git a/extras/usb-db/.gitignore b/extras/usb-db/.gitignore
new file mode 100644 (file)
index 0000000..861a838
--- /dev/null
@@ -0,0 +1,2 @@
+usb-db
+pci-db
diff --git a/extras/usb-db/Makefile.am b/extras/usb-db/Makefile.am
new file mode 100644 (file)
index 0000000..58fd2c9
--- /dev/null
@@ -0,0 +1,12 @@
+include $(top_srcdir)/Makefile.am.inc
+
+udevhomedir = $(udev_prefix)/lib/udev
+udevhome_PROGRAMS = usb-db pci-db
+
+usb_db_SOURCES = usb-db.c
+usb_db_CPPFLAGS = $(AM_CPPFLAGS) -DUSB_DATABASE=\"$(USB_DATABASE)\" -DBUILD_FOR_USB
+usb_db_LDADD = $(top_builddir)/libudev/libudev.la
+
+pci_db_SOURCES = $(usb_db_SOURCES)
+pci_db_CPPFLAGS = $(AM_CPPFLAGS) -DPCI_DATABASE=\"$(PCI_DATABASE)\" -DBUILD_FOR_PCI
+pci_db_LDADD = $(top_builddir)/libudev/libudev.la
diff --git a/extras/usb-db/usb-db.c b/extras/usb-db/usb-db.c
new file mode 100644 (file)
index 0000000..db1f843
--- /dev/null
@@ -0,0 +1,266 @@
+/*-*- linux-c -*-*/
+
+/*
+ * Copyright (C) 2009 Lennart Poettering <lennart@poettering.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details:
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include <libudev.h>
+
+#if defined(BUILD_FOR_USB)
+# define DATABASE USB_DATABASE
+# define SUBSYSTEM "usb"
+# define DEVTYPE "usb_device"
+# define VENDOR_ATTR "idVendor"
+# define PRODUCT_ATTR "idProduct"
+#elif defined(BUILD_FOR_PCI)
+# define DATABASE PCI_DATABASE
+# define SUBSYSTEM "pci"
+# define DEVTYPE NULL
+# define VENDOR_ATTR "vendor"
+# define PRODUCT_ATTR "device"
+#else
+# error "Are you havin' a laugh?"
+#endif
+
+static int get_id_attr(
+       struct udev_device *parent,
+       const char *name,
+       uint16_t *value) {
+
+       const char *t;
+       unsigned u;
+
+       if (!(t = udev_device_get_sysattr_value(parent, name))) {
+               fprintf(stderr, "%s lacks %s.\n", udev_device_get_syspath(parent), name);
+               return -1;
+       }
+
+       if (!strncmp(t, "0x", 2))
+               t += 2;
+
+       if (sscanf(t, "%04x", &u) != 1 || u > 0xFFFFU) {
+               fprintf(stderr, "Failed to parse %s on %s.\n", name, udev_device_get_syspath(parent));
+               return -1;
+       }
+
+       *value = (uint16_t) u;
+       return 0;
+}
+
+static int get_vid_pid(
+       struct udev_device *parent,
+       uint16_t *vid,
+       uint16_t *pid) {
+
+       if (get_id_attr(parent, VENDOR_ATTR, vid) < 0)
+               return -1;
+       else if (*vid <= 0) {
+               fprintf(stderr, "Invalid vendor id.\n");
+               return -1;
+       }
+
+       if (get_id_attr(parent, PRODUCT_ATTR, pid) < 0)
+               return -1;
+
+       return 0;
+}
+
+static void rstrip(char *n) {
+       size_t i;
+
+       for (i = strlen(n); i > 0 && isspace(n[i-1]); i--)
+               n[i-1] = 0;
+}
+
+#define HEXCHARS "0123456789abcdefABCDEF"
+#define WHITESPACE " \t\n\r"
+
+static int lookup_vid_pid(
+       uint16_t vid,
+       uint16_t pid,
+       char **vendor,
+       char **product) {
+
+       FILE *f;
+       int ret = -1;
+       int found_vendor = 0;
+       char *line = NULL;
+
+       *vendor = *product = NULL;
+
+       if (!(f = fopen(DATABASE, "r"))) {
+               fprintf(stderr, "Failed to open database file "DATABASE": %s\n", strerror(errno));
+               return -1;
+       }
+
+       for (;;) {
+               size_t n;
+
+               if (line) {
+                       free(line);
+                       line = NULL;
+               }
+
+               if (getline(&line, &n, f) < 0)
+                       break;
+
+               rstrip(line);
+
+               if (line[0] == '#' || line[0] == 0)
+                       continue;
+
+               if (strspn(line, HEXCHARS) == 4) {
+                       unsigned u;
+
+                       if (found_vendor)
+                               break;
+
+                       if (sscanf(line, "%04x", &u) == 1 && u == vid) {
+                               char *t;
+
+                               t = line+4;
+                               t += strspn(t, WHITESPACE);
+
+                               if (!(*vendor = strdup(t))) {
+                                       fprintf(stderr, "Out of memory.\n");
+                                       goto finish;
+                               }
+
+                               found_vendor = 1;
+                       }
+
+                       continue;
+               }
+
+               if (found_vendor && line[0] == '\t' && strspn(line+1, HEXCHARS) == 4) {
+                       unsigned u;
+
+                       if (sscanf(line+1, "%04x", &u) == 1 && u == pid) {
+                               char *t;
+
+                               t = line+5;
+                               t += strspn(t, WHITESPACE);
+
+                               if (!(*product = strdup(t))) {
+                                       fprintf(stderr, "Out of memory.\n");
+                                       goto finish;
+                               }
+
+                               break;
+                       }
+               }
+       }
+
+       ret = 0;
+
+finish:
+       free(line);
+       fclose(f);
+
+       if (ret < 0) {
+               free(*product);
+               free(*vendor);
+
+               *product = *vendor = NULL;
+       }
+
+       return ret;
+}
+
+static struct udev_device *find_device(struct udev_device *dev, const char *subsys, const char *devtype)
+{
+       const char *str;
+
+       str = udev_device_get_subsystem(dev);
+       if (str == NULL)
+               goto try_parent;
+       if (strcmp(str, subsys) != 0)
+               goto try_parent;
+
+       if (devtype != NULL) {
+               str = udev_device_get_devtype(dev);
+               if (str == NULL)
+                       goto try_parent;
+               if (strcmp(str, devtype) != 0)
+                       goto try_parent;
+       }
+       return dev;
+try_parent:
+       return udev_device_get_parent_with_subsystem_devtype(dev, SUBSYSTEM, DEVTYPE);
+}
+
+int main(int argc, char*argv[]) {
+
+       struct udev *udev = NULL;
+       int ret = 1;
+       char *sp;
+       struct udev_device *dev = NULL, *parent = NULL;
+       uint16_t vid = 0, pid = 0;
+       char *vendor = NULL, *product = NULL;
+
+       if (argc < 2) {
+               fprintf(stderr, "Need to pass sysfs path.\n");
+               goto finish;
+       }
+
+       if (!(udev = udev_new()))
+               goto finish;
+
+       if (asprintf(&sp, "%s/%s", udev_get_sys_path(udev), argv[1]) < 0) {
+               fprintf(stderr, "Failed to allocate sysfs path.\n");
+               goto finish;
+       }
+
+       dev = udev_device_new_from_syspath(udev, sp);
+       free(sp);
+
+       if (!dev) {
+               fprintf(stderr, "Failed to access %s.\n", argv[1]);
+               goto finish;
+       }
+
+       parent = find_device(dev, SUBSYSTEM, DEVTYPE);
+       if (!parent) {
+               fprintf(stderr, "Failed to find device.\n");
+               goto finish;
+       }
+
+       if (get_vid_pid(parent, &vid, &pid) < 0)
+               goto finish;
+
+       if (lookup_vid_pid(vid, pid, &vendor, &product) < 0)
+               goto finish;
+
+       if (vendor)
+               printf("ID_VENDOR_FROM_DATABASE=%s\n", vendor);
+
+       if (product)
+               printf("ID_MODEL_FROM_DATABASE=%s\n", product);
+
+       ret = 0;
+
+finish:
+       udev_device_unref(dev);
+       udev_unref(udev);
+       free(vendor);
+       free(product);
+
+       return ret;
+}