1/* 2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> 3 * 2005-2007 Takahiro Hirofuchi 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19#include <sys/types.h> 20#include <sysfs/libsysfs.h> 21 22#include <errno.h> 23#include <stdbool.h> 24#include <stdint.h> 25#include <stdio.h> 26#include <stdlib.h> 27#include <string.h> 28 29#include <getopt.h> 30#include <netdb.h> 31#include <unistd.h> 32 33#include "usbip_common.h" 34#include "usbip_network.h" 35#include "usbip.h" 36 37static const char usbip_list_usage_string[] = 38 "usbip list [-p|--parsable] <args>\n" 39 " -p, --parsable Parsable list format\n" 40 " -r, --remote=<host> List the exportable USB devices on <host>\n" 41 " -l, --local List the local USB devices\n"; 42 43void usbip_list_usage(void) 44{ 45 printf("usage: %s", usbip_list_usage_string); 46} 47 48static int get_exported_devices(char *host, int sockfd) 49{ 50 char product_name[100]; 51 char class_name[100]; 52 struct op_devlist_reply reply; 53 uint16_t code = OP_REP_DEVLIST; 54 struct usbip_usb_device udev; 55 struct usbip_usb_interface uintf; 56 unsigned int i; 57 int j, rc; 58 59 rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0); 60 if (rc < 0) { 61 dbg("usbip_net_send_op_common failed"); 62 return -1; 63 } 64 65 rc = usbip_net_recv_op_common(sockfd, &code); 66 if (rc < 0) { 67 dbg("usbip_net_recv_op_common failed"); 68 return -1; 69 } 70 71 memset(&reply, 0, sizeof(reply)); 72 rc = usbip_net_recv(sockfd, &reply, sizeof(reply)); 73 if (rc < 0) { 74 dbg("usbip_net_recv_op_devlist failed"); 75 return -1; 76 } 77 PACK_OP_DEVLIST_REPLY(0, &reply); 78 dbg("exportable devices: %d\n", reply.ndev); 79 80 if (reply.ndev == 0) { 81 info("no exportable devices found on %s", host); 82 return 0; 83 } 84 85 printf("Exportable USB devices\n"); 86 printf("======================\n"); 87 printf(" - %s\n", host); 88 89 for (i = 0; i < reply.ndev; i++) { 90 memset(&udev, 0, sizeof(udev)); 91 rc = usbip_net_recv(sockfd, &udev, sizeof(udev)); 92 if (rc < 0) { 93 dbg("usbip_net_recv failed: usbip_usb_device[%d]", i); 94 return -1; 95 } 96 usbip_net_pack_usb_device(0, &udev); 97 98 usbip_names_get_product(product_name, sizeof(product_name), 99 udev.idVendor, udev.idProduct); 100 usbip_names_get_class(class_name, sizeof(class_name), 101 udev.bDeviceClass, udev.bDeviceSubClass, 102 udev.bDeviceProtocol); 103 printf("%11s: %s\n", udev.busid, product_name); 104 printf("%11s: %s\n", "", udev.path); 105 printf("%11s: %s\n", "", class_name); 106 107 for (j = 0; j < udev.bNumInterfaces; j++) { 108 rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf)); 109 if (rc < 0) { 110 dbg("usbip_net_recv failed: usbip_usb_intf[%d]", 111 j); 112 113 return -1; 114 } 115 usbip_net_pack_usb_interface(0, &uintf); 116 117 usbip_names_get_class(class_name, sizeof(class_name), 118 uintf.bInterfaceClass, 119 uintf.bInterfaceSubClass, 120 uintf.bInterfaceProtocol); 121 printf("%11s: %2d - %s\n", "", j, class_name); 122 } 123 printf("\n"); 124 } 125 126 return 0; 127} 128 129static int list_exported_devices(char *host) 130{ 131 int rc; 132 int sockfd; 133 134 sockfd = usbip_net_tcp_connect(host, USBIP_PORT_STRING); 135 if (sockfd < 0) { 136 err("could not connect to %s:%s: %s", host, 137 USBIP_PORT_STRING, gai_strerror(sockfd)); 138 return -1; 139 } 140 dbg("connected to %s:%s", host, USBIP_PORT_STRING); 141 142 rc = get_exported_devices(host, sockfd); 143 if (rc < 0) { 144 err("failed to get device list from %s", host); 145 return -1; 146 } 147 148 close(sockfd); 149 150 return 0; 151} 152 153static void print_device(char *busid, char *vendor, char *product, 154 bool parsable) 155{ 156 if (parsable) 157 printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product); 158 else 159 printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product); 160} 161 162static void print_interface(char *busid, char *driver, bool parsable) 163{ 164 if (parsable) 165 printf("%s=%s#", busid, driver); 166 else 167 printf("%9s%s -> %s\n", "", busid, driver); 168} 169 170static int is_device(void *x) 171{ 172 struct sysfs_attribute *devpath; 173 struct sysfs_device *dev = x; 174 int ret = 0; 175 176 devpath = sysfs_get_device_attr(dev, "devpath"); 177 if (devpath && *devpath->value != '0') 178 ret = 1; 179 180 return ret; 181} 182 183static int devcmp(void *a, void *b) 184{ 185 return strcmp(a, b); 186} 187 188static int list_devices(bool parsable) 189{ 190 char bus_type[] = "usb"; 191 char busid[SYSFS_BUS_ID_SIZE]; 192 struct sysfs_bus *ubus; 193 struct sysfs_device *dev; 194 struct sysfs_device *intf; 195 struct sysfs_attribute *idVendor; 196 struct sysfs_attribute *idProduct; 197 struct sysfs_attribute *bConfValue; 198 struct sysfs_attribute *bNumIntfs; 199 struct dlist *devlist; 200 int i; 201 int ret = -1; 202 203 ubus = sysfs_open_bus(bus_type); 204 if (!ubus) { 205 err("could not open %s bus: %s", bus_type, strerror(errno)); 206 return -1; 207 } 208 209 devlist = sysfs_get_bus_devices(ubus); 210 if (!devlist) { 211 err("could not get %s bus devices: %s", bus_type, 212 strerror(errno)); 213 goto err_out; 214 } 215 216 /* remove interfaces and root hubs from device list */ 217 dlist_filter_sort(devlist, is_device, devcmp); 218 219 if (!parsable) { 220 printf("Local USB devices\n"); 221 printf("=================\n"); 222 } 223 dlist_for_each_data(devlist, dev, struct sysfs_device) { 224 idVendor = sysfs_get_device_attr(dev, "idVendor"); 225 idProduct = sysfs_get_device_attr(dev, "idProduct"); 226 bConfValue = sysfs_get_device_attr(dev, "bConfigurationValue"); 227 bNumIntfs = sysfs_get_device_attr(dev, "bNumInterfaces"); 228 if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) { 229 err("problem getting device attributes: %s", 230 strerror(errno)); 231 goto err_out; 232 } 233 234 print_device(dev->bus_id, idVendor->value, idProduct->value, 235 parsable); 236 237 for (i = 0; i < atoi(bNumIntfs->value); i++) { 238 snprintf(busid, sizeof(busid), "%s:%.1s.%d", 239 dev->bus_id, bConfValue->value, i); 240 intf = sysfs_open_device(bus_type, busid); 241 if (!intf) { 242 err("could not open device interface: %s", 243 strerror(errno)); 244 goto err_out; 245 } 246 print_interface(busid, intf->driver_name, parsable); 247 sysfs_close_device(intf); 248 } 249 printf("\n"); 250 } 251 252 ret = 0; 253 254err_out: 255 sysfs_close_bus(ubus); 256 257 return ret; 258} 259 260int usbip_list(int argc, char *argv[]) 261{ 262 static const struct option opts[] = { 263 { "parsable", no_argument, NULL, 'p' }, 264 { "remote", required_argument, NULL, 'r' }, 265 { "local", no_argument, NULL, 'l' }, 266 { NULL, 0, NULL, 0 } 267 }; 268 269 bool parsable = false; 270 int opt; 271 int ret = -1; 272 273 if (usbip_names_init(USBIDS_FILE)) 274 err("failed to open %s", USBIDS_FILE); 275 276 for (;;) { 277 opt = getopt_long(argc, argv, "pr:l", opts, NULL); 278 279 if (opt == -1) 280 break; 281 282 switch (opt) { 283 case 'p': 284 parsable = true; 285 break; 286 case 'r': 287 ret = list_exported_devices(optarg); 288 goto out; 289 case 'l': 290 ret = list_devices(parsable); 291 goto out; 292 default: 293 goto err_out; 294 } 295 } 296 297err_out: 298 usbip_list_usage(); 299out: 300 usbip_names_free(); 301 302 return ret; 303} 304