mirror of
https://github.com/systemd/systemd.git
synced 2024-11-15 07:24:00 +03:00
253 lines
5.3 KiB
C
253 lines
5.3 KiB
C
/*
|
|
* 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/>.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <inttypes.h>
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "udev.h"
|
|
|
|
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,
|
|
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 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(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 (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, subsys, devtype);
|
|
}
|
|
|
|
|
|
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)
|
|
{
|
|
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);
|
|
return 0;
|
|
}
|
|
|
|
static int builtin_usb_db(struct udev_device *dev, int argc, char *argv[], bool test)
|
|
{
|
|
return builtin_db(dev, test, USB_DATABASE, "idVendor", "idProduct", "usb", "usb_device");
|
|
}
|
|
|
|
static int builtin_pci_db(struct udev_device *dev, int argc, char *argv[], bool test)
|
|
{
|
|
return builtin_db(dev, test, PCI_DATABASE, "vendor", "device", "pci", NULL);
|
|
}
|
|
|
|
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,
|
|
};
|