/* * Copyright (C) 2011 matt mooney * 2005-2007 Takahiro Hirofuchi * * 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include "usbip_common.h" #include "usbip_network.h" #include "usbip.h" static const char usbip_list_usage_string[] = "usbip list [-p|--parsable] \n" " -p, --parsable Parsable list format\n" " -r, --remote= List the exportable USB devices on \n" " -l, --local List the local USB devices\n"; void usbip_list_usage(void) { printf("usage: %s", usbip_list_usage_string); } static int get_exported_devices(char *host, int sockfd) { char product_name[100]; char class_name[100]; struct op_devlist_reply reply; uint16_t code = OP_REP_DEVLIST; struct usbip_usb_device udev; struct usbip_usb_interface uintf; unsigned int i; int j, rc; rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0); if (rc < 0) { dbg("usbip_net_send_op_common failed"); return -1; } rc = usbip_net_recv_op_common(sockfd, &code); if (rc < 0) { dbg("usbip_net_recv_op_common failed"); return -1; } memset(&reply, 0, sizeof(reply)); rc = usbip_net_recv(sockfd, &reply, sizeof(reply)); if (rc < 0) { dbg("usbip_net_recv_op_devlist failed"); return -1; } PACK_OP_DEVLIST_REPLY(0, &reply); dbg("exportable devices: %d\n", reply.ndev); if (reply.ndev == 0) { info("no exportable devices found on %s", host); return 0; } printf("Exportable USB devices\n"); printf("======================\n"); printf(" - %s\n", host); for (i = 0; i < reply.ndev; i++) { memset(&udev, 0, sizeof(udev)); rc = usbip_net_recv(sockfd, &udev, sizeof(udev)); if (rc < 0) { dbg("usbip_net_recv failed: usbip_usb_device[%d]", i); return -1; } usbip_net_pack_usb_device(0, &udev); usbip_names_get_product(product_name, sizeof(product_name), udev.idVendor, udev.idProduct); usbip_names_get_class(class_name, sizeof(class_name), udev.bDeviceClass, udev.bDeviceSubClass, udev.bDeviceProtocol); printf("%11s: %s\n", udev.busid, product_name); printf("%11s: %s\n", "", udev.path); printf("%11s: %s\n", "", class_name); for (j = 0; j < udev.bNumInterfaces; j++) { rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf)); if (rc < 0) { dbg("usbip_net_recv failed: usbip_usb_intf[%d]", j); return -1; } usbip_net_pack_usb_interface(0, &uintf); usbip_names_get_class(class_name, sizeof(class_name), uintf.bInterfaceClass, uintf.bInterfaceSubClass, uintf.bInterfaceProtocol); printf("%11s: %2d - %s\n", "", j, class_name); } printf("\n"); } return 0; } static int list_exported_devices(char *host) { int rc; int sockfd; sockfd = usbip_net_tcp_connect(host, USBIP_PORT_STRING); if (sockfd < 0) { err("could not connect to %s:%s: %s", host, USBIP_PORT_STRING, gai_strerror(sockfd)); return -1; } dbg("connected to %s:%s", host, USBIP_PORT_STRING); rc = get_exported_devices(host, sockfd); if (rc < 0) { err("failed to get device list from %s", host); return -1; } close(sockfd); return 0; } static void print_device(char *busid, char *vendor, char *product, bool parsable) { if (parsable) printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product); else printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product); } static void print_product_name(char *product_name, bool parsable) { if (!parsable) printf(" %s\n", product_name); } static void print_interface(char *busid, char *driver, bool parsable) { if (parsable) printf("%s=%s#", busid, driver); else printf("%9s%s -> %s\n", "", busid, driver); } static int is_device(void *x) { struct sysfs_attribute *devpath; struct sysfs_device *dev = x; int ret = 0; devpath = sysfs_get_device_attr(dev, "devpath"); if (devpath && *devpath->value != '0') ret = 1; return ret; } static int devcmp(void *a, void *b) { return strcmp(a, b); } static int list_devices(bool parsable) { char bus_type[] = "usb"; char busid[SYSFS_BUS_ID_SIZE]; char product_name[128]; struct sysfs_bus *ubus; struct sysfs_device *dev; struct sysfs_device *intf; struct sysfs_attribute *idVendor; struct sysfs_attribute *idProduct; struct sysfs_attribute *bConfValue; struct sysfs_attribute *bNumIntfs; struct dlist *devlist; int i; int ret = -1; ubus = sysfs_open_bus(bus_type); if (!ubus) { err("could not open %s bus: %s", bus_type, strerror(errno)); return -1; } devlist = sysfs_get_bus_devices(ubus); if (!devlist) { err("could not get %s bus devices: %s", bus_type, strerror(errno)); goto err_out; } /* remove interfaces and root hubs from device list */ dlist_filter_sort(devlist, is_device, devcmp); if (!parsable) { printf("Local USB devices\n"); printf("=================\n"); } dlist_for_each_data(devlist, dev, struct sysfs_device) { idVendor = sysfs_get_device_attr(dev, "idVendor"); idProduct = sysfs_get_device_attr(dev, "idProduct"); bConfValue = sysfs_get_device_attr(dev, "bConfigurationValue"); bNumIntfs = sysfs_get_device_attr(dev, "bNumInterfaces"); if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) { err("problem getting device attributes: %s", strerror(errno)); goto err_out; } /* get product name */ usbip_names_get_product(product_name, sizeof(product_name), strtol(idVendor->value, NULL, 16), strtol(idProduct->value, NULL, 16)); print_device(dev->bus_id, idVendor->value, idProduct->value, parsable); print_product_name(product_name, parsable); for (i = 0; i < atoi(bNumIntfs->value); i++) { snprintf(busid, sizeof(busid), "%s:%.1s.%d", dev->bus_id, bConfValue->value, i); intf = sysfs_open_device(bus_type, busid); if (!intf) { err("could not open device interface: %s", strerror(errno)); goto err_out; } print_interface(busid, intf->driver_name, parsable); sysfs_close_device(intf); } printf("\n"); } ret = 0; err_out: sysfs_close_bus(ubus); return ret; } int usbip_list(int argc, char *argv[]) { static const struct option opts[] = { { "parsable", no_argument, NULL, 'p' }, { "remote", required_argument, NULL, 'r' }, { "local", no_argument, NULL, 'l' }, { NULL, 0, NULL, 0 } }; bool parsable = false; int opt; int ret = -1; if (usbip_names_init(USBIDS_FILE)) err("failed to open %s", USBIDS_FILE); for (;;) { opt = getopt_long(argc, argv, "pr:l", opts, NULL); if (opt == -1) break; switch (opt) { case 'p': parsable = true; break; case 'r': ret = list_exported_devices(optarg); goto out; case 'l': ret = list_devices(parsable); goto out; default: goto err_out; } } err_out: usbip_list_usage(); out: usbip_names_free(); return ret; }