From fc1ad9fffd0817f6b8842eabc8dc2b0da611b768 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Sun, 10 Apr 2011 09:51:30 -0300 Subject: [PATCH] tools/lib: atusb can now be selected by bus/device or by bus-port path Examples: usb:1/6 select logical device 6 on bus 1 usb:1-3.1.4 starting at bus 1, choose ports 3, 1, and 4 - usbopen.c (initialize, open_usb): moved libusb initialization to separate function, to allow for sharing - usbopen.h (restrict_usb_path), usbopen.c (restricted_path, open_usb, restrict_usb_dev, restrict_usb_by_dev, read_num, restrict_usb_by_port, restrict_usb_path): added mechanism to restrict USB path - atusb.c (atusb_open): if an argument is given, call restrict_usb_path with it --- tools/lib/atusb.c | 2 + tools/lib/usbopen.c | 139 ++++++++++++++++++++++++++++++++++++++++++-- tools/lib/usbopen.h | 5 +- 3 files changed, 139 insertions(+), 7 deletions(-) diff --git a/tools/lib/atusb.c b/tools/lib/atusb.c index 5f7dc49..5efe1fb 100644 --- a/tools/lib/atusb.c +++ b/tools/lib/atusb.c @@ -54,6 +54,8 @@ static void *atusb_open(const char *arg) { usb_dev_handle *dev; + if (arg) + restrict_usb_path(arg); dev = open_usb(USB_VENDOR, USB_PRODUCT); if (dev) { error = 0; diff --git a/tools/lib/usbopen.c b/tools/lib/usbopen.c index 8561ebf..830cda9 100644 --- a/tools/lib/usbopen.c +++ b/tools/lib/usbopen.c @@ -1,8 +1,8 @@ /* * lib/usbopen.c - Common USB device lookup and open code * - * Written 2008-2010 by Werner Almesberger - * Copyright 2008-2010 Werner Almesberger + * Written 2008-2011 by Werner Almesberger + * Copyright 2008-2011 Werner Almesberger * * 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 @@ -12,16 +12,37 @@ +#include #include #include #include +#include #include #include "usbopen.h" +#define USB_PATH_ROOT "/sys/bus/usb/devices/" +#define USB_BUS_LEAF "/busnum" +#define USB_DEV_LEAF "/devnum" + static uint16_t vendor = 0; static uint16_t product = 0; +static const struct usb_device *restricted_path = NULL; + + +static void initialize(void) +{ + static int initialized = 0; + + if (initialized) + return; + initialized = 1; + + usb_init(); + usb_find_busses(); + usb_find_devices(); +} usb_dev_handle *open_usb(uint16_t default_vendor, uint16_t default_product) @@ -33,12 +54,12 @@ usb_dev_handle *open_usb(uint16_t default_vendor, uint16_t default_product) int res; #endif - usb_init(); - usb_find_busses(); - usb_find_devices(); + initialize(); for (bus = usb_get_busses(); bus; bus = bus->next) for (dev = bus->devices; dev; dev = dev->next) { + if (restricted_path && restricted_path != dev) + continue; if (dev->descriptor.idVendor != (vendor ? vendor : default_vendor)) continue; @@ -99,3 +120,111 @@ void parse_usb_id(const char *id) bad_id(id); product = tmp; } + + +static void restrict_usb_dev(int bus_num, int dev_num) +{ + const struct usb_bus *bus; + const struct usb_device *dev; + + initialize(); + + for (bus = usb_busses; bus; bus = bus->next) { + if (atoi(bus->dirname) != bus_num) + continue; + for (dev = bus->devices; dev; dev = dev->next) + if (dev->devnum == dev_num) { + restricted_path = dev; + return; + } + } + fprintf(stderr, "no device %d/%d\n", bus_num, dev_num); + exit(1); +} + + +static void restrict_usb_by_dev(const char *path) +{ + int bus_num, dev_num; + + if (sscanf(path, "%d/%d", &bus_num, &dev_num) != 2) { + fprintf(stderr, "invalid device syntax \"%s\"\n", path); + exit(1); + } + restrict_usb_dev(bus_num, dev_num); +} + + +static int read_num(const char *fmt, ...) +{ + va_list ap; + FILE *file; + char *buf; + int n, num; + + va_start(ap, fmt); + n = vsnprintf(NULL, 0, fmt, ap); + va_end(ap); + + buf = malloc(n+1); + if (!buf) { + perror("malloc"); + exit(1); + } + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + va_end(ap); + + file = fopen(buf, "r"); + if (!file) { + perror(buf); + exit(1); + } + + n = fscanf(file, "%d", &num); + if (n <0) { + perror(buf); + exit(1); + } + if (n != 1) { + fprintf(stderr, "%s: can't read number\n", buf); + exit(1); + } + + fclose(file); + free(buf); + + return num; +} + + +static void restrict_usb_by_port(const char *path) +{ + const char *p; + int bus_num, dev_num; + + /* + * We sanitize the path, in case we're part of a program running with + * suid. + */ + for (p = path; *p; p++) + if (!strchr("0123456789-.", *p)) { + fprintf(stderr, + "invalid character \'%c\' in USB path\n", *p); + exit(1); + } + + bus_num = read_num("%s%s%s", USB_PATH_ROOT, path, USB_BUS_LEAF); + dev_num = read_num("%s%s%s", USB_PATH_ROOT, path, USB_DEV_LEAF); + restrict_usb_dev(bus_num, dev_num); +} + + +void restrict_usb_path(const char *path) +{ + if (strchr(path, '/')) + restrict_usb_by_dev(path); + else + restrict_usb_by_port(path); +} diff --git a/tools/lib/usbopen.h b/tools/lib/usbopen.h index f784229..53a5e31 100644 --- a/tools/lib/usbopen.h +++ b/tools/lib/usbopen.h @@ -1,8 +1,8 @@ /* * lib/usbopen.h - Common USB device lookup and open code * - * Written 2008-2010 by Werner Almesberger - * Copyright 2008-2010 Werner Almesberger + * Written 2008-2011 by Werner Almesberger + * Copyright 2008-2011 Werner Almesberger * * 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 @@ -20,5 +20,6 @@ usb_dev_handle *open_usb(uint16_t default_vendor, uint16_t default_product); void parse_usb_id(const char *id); +void restrict_usb_path(const char *path); #endif /* !USB_OPEN_H */