summaryrefslogtreecommitdiff
path: root/src/udev/udev-builtin-hwdb.c
diff options
context:
space:
mode:
authorPaul Sherwood <paul.sherwood@codethink.co.uk>2013-02-12 13:36:23 +0000
committerPaul Sherwood <paul.sherwood@codethink.co.uk>2013-02-12 13:36:23 +0000
commit6204a046f3d3c610925afe8bba404bbb2f0f0c4d (patch)
treec95fa62c57ae2f8bc7abc56a535d8fa027243860 /src/udev/udev-builtin-hwdb.c
parent8fee3eb8a8550892d0dcf4431b861aacd49e57ec (diff)
parentdee4c244254bb49d1ffa8bd7171ae9cce596d2d0 (diff)
downloadsystemd-6204a046f3d3c610925afe8bba404bbb2f0f0c4d.tar.gz
Merge tag 'v197' into pauls-trove/sd-update
systemd 197
Diffstat (limited to 'src/udev/udev-builtin-hwdb.c')
-rw-r--r--src/udev/udev-builtin-hwdb.c315
1 files changed, 115 insertions, 200 deletions
diff --git a/src/udev/udev-builtin-hwdb.c b/src/udev/udev-builtin-hwdb.c
index 0db21641b1..0b35d799fe 100644
--- a/src/udev/udev-builtin-hwdb.c
+++ b/src/udev/udev-builtin-hwdb.c
@@ -1,22 +1,21 @@
-/*
- * usb-db, pci-db - lookup vendor/product database
- *
- * Copyright (C) 2009 Lennart Poettering <lennart@poettering.net>
- * Copyright (C) 2011 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+/***
+ This file is part of systemd.
+
+ Copyright 2012 Kay Sievers <kay@vrfy.org>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
#include <stdio.h>
#include <errno.h>
@@ -24,224 +23,140 @@
#include <inttypes.h>
#include <ctype.h>
#include <stdlib.h>
+#include <getopt.h>
#include "udev.h"
-static int get_id_attr(
- struct udev_device *parent,
- const char *name,
- uint16_t *value) {
+static struct udev_hwdb *hwdb;
- const char *t;
- unsigned u;
+int udev_builtin_hwdb_lookup(struct udev_device *dev, const char *modalias, bool test) {
+ struct udev_list_entry *entry;
+ int n = 0;
- if (!(t = udev_device_get_sysattr_value(parent, name))) {
- fprintf(stderr, "%s lacks %s.\n", udev_device_get_syspath(parent), name);
- return -1;
- }
-
- if (startswith(t, "0x"))
- t += 2;
+ if (!hwdb)
+ return -ENOENT;
- 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;
+ udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0)) {
+ if (udev_builtin_add_property(dev, test,
+ udev_list_entry_get_name(entry),
+ udev_list_entry_get_value(entry)) < 0)
+ return -ENOMEM;
+ n++;
}
-
- *value = (uint16_t) u;
- return 0;
+ return n;
}
-static int get_vid_pid(
- struct udev_device *parent,
- const char *vendor_attr,
- const char *product_attr,
- 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 const char *modalias_usb(struct udev_device *dev, char *s, size_t size) {
+ const char *v, *p;
+ int vn, pn;
+
+ v = udev_device_get_sysattr_value(dev, "idVendor");
+ if (!v)
+ return NULL;
+ p = udev_device_get_sysattr_value(dev, "idProduct");
+ if (!p)
+ return NULL;
+ vn = strtol(v, NULL, 16);
+ if (vn <= 0)
+ return NULL;
+ pn = strtol(p, NULL, 16);
+ if (pn <= 0)
+ return NULL;
+ snprintf(s, size, "usb:v%04Xp%04X*", vn, pn);
+ return s;
}
-static void rstrip(char *n) {
- size_t i;
+static int udev_builtin_hwdb_search(struct udev_device *dev, const char *subsystem, bool test) {
+ struct udev_device *d;
+ char s[16];
+ int n = 0;
- for (i = strlen(n); i > 0 && isspace(n[i-1]); i--)
- n[i-1] = 0;
-}
+ for (d = dev; d; d = udev_device_get_parent(d)) {
+ const char *dsubsys;
+ const char *modalias = NULL;
-#define HEXCHARS "0123456789abcdefABCDEF"
-#define WHITESPACE " \t\n\r"
-static int lookup_vid_pid(const char *database,
- 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, "rme"))) {
- fprintf(stderr, "Failed to open database file '%s': %s\n", database, strerror(errno));
- return -1;
- }
-
- for (;;) {
- size_t n;
-
- if (getline(&line, &n, f) < 0)
- break;
-
- rstrip(line);
-
- if (line[0] == '#' || line[0] == 0)
+ dsubsys = udev_device_get_subsystem(d);
+ if (!dsubsys)
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;
- }
-
+ /* look only at devices of a specific subsystem */
+ if (subsystem && !streq(dsubsys, subsystem))
continue;
- }
- if (found_vendor && line[0] == '\t' && strspn(line+1, HEXCHARS) == 4) {
- unsigned u;
+ /* the usb_device does not have a modalias, compose one */
+ if (streq(dsubsys, "usb"))
+ modalias = modalias_usb(dev, s, sizeof(s));
- if (sscanf(line+1, "%04x", &u) == 1 && u == pid) {
- char *t;
+ if (!modalias)
+ modalias = udev_device_get_property_value(d, "MODALIAS");
- t = line+5;
- t += strspn(t, WHITESPACE);
-
- if (!(*product = strdup(t))) {
- fprintf(stderr, "Out of memory.\n");
- goto finish;
- }
-
- break;
- }
- }
+ if (!modalias)
+ continue;
+ n = udev_builtin_hwdb_lookup(dev, modalias, test);
+ if (n > 0)
+ break;
}
- ret = 0;
+ return n;
+}
-finish:
- free(line);
- fclose(f);
+static int builtin_hwdb(struct udev_device *dev, int argc, char *argv[], bool test) {
+ static const struct option options[] = {
+ { "subsystem", required_argument, NULL, 's' },
+ {}
+ };
+ const char *subsystem = NULL;
- if (ret < 0) {
- free(*product);
- free(*vendor);
+ if (!hwdb)
+ return EXIT_FAILURE;
- *product = *vendor = NULL;
- }
+ for (;;) {
+ int option;
- return ret;
-}
+ option = getopt_long(argc, argv, "s", options, NULL);
+ if (option == -1)
+ break;
-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;
+ switch (option) {
+ case 's':
+ subsystem = optarg;
+ break;
+ }
}
- return dev;
-try_parent:
- return udev_device_get_parent_with_subsystem_devtype(dev, subsys, devtype);
-}
+ if (udev_builtin_hwdb_search(dev, subsystem, test) < 0)
+ return EXIT_FAILURE;
+ return EXIT_SUCCESS;
+}
-static int builtin_db(struct udev_device *dev, bool test,
- const char *database,
- const char *vendor_attr, const char *product_attr,
- const char *subsys, const char *devtype)
+/* called at udev startup and reload */
+static int builtin_hwdb_init(struct udev *udev)
{
- struct udev_device *parent;
- uint16_t vid = 0, pid = 0;
- char *vendor = NULL, *product = NULL;
-
- parent = find_device(dev, subsys, devtype);
- if (!parent) {
- fprintf(stderr, "Failed to find device.\n");
- goto finish;
- }
-
- if (get_vid_pid(parent, vendor_attr, product_attr, &vid, &pid) < 0)
- goto finish;
-
- if (lookup_vid_pid(database, vid, pid, &vendor, &product) < 0)
- goto finish;
-
- if (vendor)
- udev_builtin_add_property(dev, test, "ID_VENDOR_FROM_DATABASE", vendor);
- if (product)
- udev_builtin_add_property(dev, test, "ID_MODEL_FROM_DATABASE", product);
-
-finish:
- free(vendor);
- free(product);
+ if (hwdb)
+ return 0;
+ hwdb = udev_hwdb_new(udev);
+ if (!hwdb)
+ return -ENOMEM;
return 0;
}
-static int builtin_usb_db(struct udev_device *dev, int argc, char *argv[], bool test)
+/* called on udev shutdown and reload request */
+static void builtin_hwdb_exit(struct udev *udev)
{
- return builtin_db(dev, test, USB_DATABASE, "idVendor", "idProduct", "usb", "usb_device");
+ hwdb = udev_hwdb_unref(hwdb);
}
-static int builtin_pci_db(struct udev_device *dev, int argc, char *argv[], bool test)
+/* called every couple of seconds during event activity; 'true' if config has changed */
+static bool builtin_hwdb_validate(struct udev *udev)
{
- return builtin_db(dev, test, PCI_DATABASE, "vendor", "device", "pci", NULL);
+ return udev_hwdb_validate(hwdb);
}
-const struct udev_builtin udev_builtin_usb_db = {
- .name = "usb-db",
- .cmd = builtin_usb_db,
- .help = "USB vendor/product database",
- .run_once = true,
-};
-
-const struct udev_builtin udev_builtin_pci_db = {
- .name = "pci-db",
- .cmd = builtin_pci_db,
- .help = "PCI vendor/product database",
- .run_once = true,
+const struct udev_builtin udev_builtin_hwdb = {
+ .name = "hwdb",
+ .cmd = builtin_hwdb,
+ .init = builtin_hwdb_init,
+ .exit = builtin_hwdb_exit,
+ .validate = builtin_hwdb_validate,
+ .help = "hardware database",
};