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 <libudev.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 rc, j; 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 err("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 124 printf("\n"); 125 } 126 127 return 0; 128} 129 130static int list_exported_devices(char *host) 131{ 132 int rc; 133 int sockfd; 134 135 sockfd = usbip_net_tcp_connect(host, usbip_port_string); 136 if (sockfd < 0) { 137 err("could not connect to %s:%s: %s", host, 138 usbip_port_string, gai_strerror(sockfd)); 139 return -1; 140 } 141 dbg("connected to %s:%s", host, usbip_port_string); 142 143 rc = get_exported_devices(host, sockfd); 144 if (rc < 0) { 145 err("failed to get device list from %s", host); 146 return -1; 147 } 148 149 close(sockfd); 150 151 return 0; 152} 153 154static void print_device(const char *busid, const char *vendor, 155 const char *product, bool parsable) 156{ 157 if (parsable) 158 printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product); 159 else 160 printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product); 161} 162 163static void print_product_name(char *product_name, bool parsable) 164{ 165 if (!parsable) 166 printf(" %s\n", product_name); 167} 168 169static int list_devices(bool parsable) 170{ 171 struct udev *udev; 172 struct udev_enumerate *enumerate; 173 struct udev_list_entry *devices, *dev_list_entry; 174 struct udev_device *dev; 175 const char *path; 176 const char *idVendor; 177 const char *idProduct; 178 const char *bConfValue; 179 const char *bNumIntfs; 180 const char *busid; 181 char product_name[128]; 182 int ret = -1; 183 184 /* Create libudev context. */ 185 udev = udev_new(); 186 187 /* Create libudev device enumeration. */ 188 enumerate = udev_enumerate_new(udev); 189 190 /* Take only USB devices that are not hubs and do not have 191 * the bInterfaceNumber attribute, i.e. are not interfaces. 192 */ 193 udev_enumerate_add_match_subsystem(enumerate, "usb"); 194 udev_enumerate_add_nomatch_sysattr(enumerate, "bDeviceClass", "09"); 195 udev_enumerate_add_nomatch_sysattr(enumerate, "bInterfaceNumber", NULL); 196 udev_enumerate_scan_devices(enumerate); 197 198 devices = udev_enumerate_get_list_entry(enumerate); 199 200 /* Show information about each device. */ 201 udev_list_entry_foreach(dev_list_entry, devices) { 202 path = udev_list_entry_get_name(dev_list_entry); 203 dev = udev_device_new_from_syspath(udev, path); 204 205 /* Get device information. */ 206 idVendor = udev_device_get_sysattr_value(dev, "idVendor"); 207 idProduct = udev_device_get_sysattr_value(dev, "idProduct"); 208 bConfValue = udev_device_get_sysattr_value(dev, "bConfigurationValue"); 209 bNumIntfs = udev_device_get_sysattr_value(dev, "bNumInterfaces"); 210 busid = udev_device_get_sysname(dev); 211 if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) { 212 err("problem getting device attributes: %s", 213 strerror(errno)); 214 goto err_out; 215 } 216 217 /* Get product name. */ 218 usbip_names_get_product(product_name, sizeof(product_name), 219 strtol(idVendor, NULL, 16), 220 strtol(idProduct, NULL, 16)); 221 222 /* Print information. */ 223 print_device(busid, idVendor, idProduct, parsable); 224 print_product_name(product_name, parsable); 225 226 printf("\n"); 227 228 udev_device_unref(dev); 229 } 230 231 ret = 0; 232 233err_out: 234 udev_enumerate_unref(enumerate); 235 udev_unref(udev); 236 237 return ret; 238} 239 240int usbip_list(int argc, char *argv[]) 241{ 242 static const struct option opts[] = { 243 { "parsable", no_argument, NULL, 'p' }, 244 { "remote", required_argument, NULL, 'r' }, 245 { "local", no_argument, NULL, 'l' }, 246 { NULL, 0, NULL, 0 } 247 }; 248 249 bool parsable = false; 250 int opt; 251 int ret = -1; 252 253 if (usbip_names_init(USBIDS_FILE)) 254 err("failed to open %s", USBIDS_FILE); 255 256 for (;;) { 257 opt = getopt_long(argc, argv, "pr:l", opts, NULL); 258 259 if (opt == -1) 260 break; 261 262 switch (opt) { 263 case 'p': 264 parsable = true; 265 break; 266 case 'r': 267 ret = list_exported_devices(optarg); 268 goto out; 269 case 'l': 270 ret = list_devices(parsable); 271 goto out; 272 default: 273 goto err_out; 274 } 275 } 276 277err_out: 278 usbip_list_usage(); 279out: 280 usbip_names_free(); 281 282 return ret; 283} 284