/*-*- linux-c -*-*/ /* * Copyright (C) 2009 Lennart Poettering * * 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 #include #include #include #include #include #include static int get_vid_pid( struct udev_device *usb, uint16_t *vid, uint16_t *pid) { const char *t; if ((t = udev_device_get_sysattr_value(usb, "idVendor"))) { unsigned u; if (sscanf(t, "%04x", &u) != 1 || u <= 0 || u > 0xFFFFU) { fprintf(stderr, "Failed to parse idVendor on %s.\n", udev_device_get_syspath(usb)); return -1; } *vid = (uint16_t) u; } if ((t = udev_device_get_sysattr_value(usb, "idProduct"))) { unsigned u; if (sscanf(t, "%04x", &u) != 1 || u > 0xFFFFU) { fprintf(stderr, "Failed to parse idProduct on %s.\n", udev_device_get_syspath(usb)); return -1; } *pid = (uint16_t) u; } 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(USB_DATABASE, "r"))) { fprintf(stderr, "Failed to open database file "USB_DATABASE": %s", 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; } int main(int argc, char*argv[]) { struct udev *udev = NULL; int ret = 1; char *sp; struct udev_device *dev = NULL, *usb = 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; } if (!(usb = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device"))) { fprintf(stderr, "Failed to find usb_device.\n"); goto finish; } if (get_vid_pid(usb, &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: if (dev) udev_device_unref(dev); if (udev) udev_unref(udev); free(vendor); free(product); return ret; }