GNU Linux-libre 4.19.264-gnu1
[releases.git] / tools / usb / usbip / src / usbip_list.c
1 /*
2  * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3  *               2005-2007 Takahiro Hirofuchi
4  * Copyright (C) 2015-2016 Samsung Electronics
5  *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
6  *               Krzysztof Opasiak <k.opasiak@samsung.com>
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <sys/types.h>
23 #include <libudev.h>
24
25 #include <errno.h>
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include <getopt.h>
33 #include <netdb.h>
34 #include <unistd.h>
35
36 #include <dirent.h>
37
38 #include <linux/usb/ch9.h>
39
40 #include "usbip_common.h"
41 #include "usbip_network.h"
42 #include "usbip.h"
43
44 static const char usbip_list_usage_string[] =
45         "usbip list [-p|--parsable] <args>\n"
46         "    -p, --parsable         Parsable list format\n"
47         "    -r, --remote=<host>    List the exportable USB devices on <host>\n"
48         "    -l, --local            List the local USB devices\n";
49
50 void usbip_list_usage(void)
51 {
52         printf("usage: %s", usbip_list_usage_string);
53 }
54
55 static int get_exported_devices(char *host, int sockfd)
56 {
57         char product_name[100];
58         char class_name[100];
59         struct op_devlist_reply reply;
60         uint16_t code = OP_REP_DEVLIST;
61         struct usbip_usb_device udev;
62         struct usbip_usb_interface uintf;
63         unsigned int i;
64         int rc, j;
65         int status;
66
67         rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
68         if (rc < 0) {
69                 dbg("usbip_net_send_op_common failed");
70                 return -1;
71         }
72
73         rc = usbip_net_recv_op_common(sockfd, &code, &status);
74         if (rc < 0) {
75                 err("Exported Device List Request failed - %s\n",
76                     usbip_op_common_status_string(status));
77                 return -1;
78         }
79
80         memset(&reply, 0, sizeof(reply));
81         rc = usbip_net_recv(sockfd, &reply, sizeof(reply));
82         if (rc < 0) {
83                 dbg("usbip_net_recv_op_devlist failed");
84                 return -1;
85         }
86         PACK_OP_DEVLIST_REPLY(0, &reply);
87         dbg("exportable devices: %d\n", reply.ndev);
88
89         if (reply.ndev == 0) {
90                 info("no exportable devices found on %s", host);
91                 return 0;
92         }
93
94         printf("Exportable USB devices\n");
95         printf("======================\n");
96         printf(" - %s\n", host);
97
98         for (i = 0; i < reply.ndev; i++) {
99                 memset(&udev, 0, sizeof(udev));
100                 rc = usbip_net_recv(sockfd, &udev, sizeof(udev));
101                 if (rc < 0) {
102                         dbg("usbip_net_recv failed: usbip_usb_device[%d]", i);
103                         return -1;
104                 }
105                 usbip_net_pack_usb_device(0, &udev);
106
107                 usbip_names_get_product(product_name, sizeof(product_name),
108                                         udev.idVendor, udev.idProduct);
109                 usbip_names_get_class(class_name, sizeof(class_name),
110                                       udev.bDeviceClass, udev.bDeviceSubClass,
111                                       udev.bDeviceProtocol);
112                 printf("%11s: %s\n", udev.busid, product_name);
113                 printf("%11s: %s\n", "", udev.path);
114                 printf("%11s: %s\n", "", class_name);
115
116                 for (j = 0; j < udev.bNumInterfaces; j++) {
117                         rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf));
118                         if (rc < 0) {
119                                 err("usbip_net_recv failed: usbip_usb_intf[%d]",
120                                                 j);
121
122                                 return -1;
123                         }
124                         usbip_net_pack_usb_interface(0, &uintf);
125
126                         usbip_names_get_class(class_name, sizeof(class_name),
127                                         uintf.bInterfaceClass,
128                                         uintf.bInterfaceSubClass,
129                                         uintf.bInterfaceProtocol);
130                         printf("%11s: %2d - %s\n", "", j, class_name);
131                 }
132
133                 printf("\n");
134         }
135
136         return 0;
137 }
138
139 static int list_exported_devices(char *host)
140 {
141         int rc;
142         int sockfd;
143
144         sockfd = usbip_net_tcp_connect(host, usbip_port_string);
145         if (sockfd < 0) {
146                 err("could not connect to %s:%s: %s", host,
147                     usbip_port_string, gai_strerror(sockfd));
148                 return -1;
149         }
150         dbg("connected to %s:%s", host, usbip_port_string);
151
152         rc = get_exported_devices(host, sockfd);
153         if (rc < 0) {
154                 err("failed to get device list from %s", host);
155                 return -1;
156         }
157
158         close(sockfd);
159
160         return 0;
161 }
162
163 static void print_device(const char *busid, const char *vendor,
164                          const char *product, bool parsable)
165 {
166         if (parsable)
167                 printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product);
168         else
169                 printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product);
170 }
171
172 static void print_product_name(char *product_name, bool parsable)
173 {
174         if (!parsable)
175                 printf("   %s\n", product_name);
176 }
177
178 static int list_devices(bool parsable)
179 {
180         struct udev *udev;
181         struct udev_enumerate *enumerate;
182         struct udev_list_entry *devices, *dev_list_entry;
183         struct udev_device *dev;
184         const char *path;
185         const char *idVendor;
186         const char *idProduct;
187         const char *bConfValue;
188         const char *bNumIntfs;
189         const char *busid;
190         char product_name[128];
191         int ret = -1;
192         const char *devpath;
193
194         /* Create libudev context. */
195         udev = udev_new();
196
197         /* Create libudev device enumeration. */
198         enumerate = udev_enumerate_new(udev);
199
200         /* Take only USB devices that are not hubs and do not have
201          * the bInterfaceNumber attribute, i.e. are not interfaces.
202          */
203         udev_enumerate_add_match_subsystem(enumerate, "usb");
204         udev_enumerate_add_nomatch_sysattr(enumerate, "bDeviceClass", "09");
205         udev_enumerate_add_nomatch_sysattr(enumerate, "bInterfaceNumber", NULL);
206         udev_enumerate_scan_devices(enumerate);
207
208         devices = udev_enumerate_get_list_entry(enumerate);
209
210         /* Show information about each device. */
211         udev_list_entry_foreach(dev_list_entry, devices) {
212                 path = udev_list_entry_get_name(dev_list_entry);
213                 dev = udev_device_new_from_syspath(udev, path);
214
215                 /* Ignore devices attached to vhci_hcd */
216                 devpath = udev_device_get_devpath(dev);
217                 if (strstr(devpath, USBIP_VHCI_DRV_NAME)) {
218                         dbg("Skip the device %s already attached to %s\n",
219                             devpath, USBIP_VHCI_DRV_NAME);
220                         continue;
221                 }
222
223                 /* Get device information. */
224                 idVendor = udev_device_get_sysattr_value(dev, "idVendor");
225                 idProduct = udev_device_get_sysattr_value(dev, "idProduct");
226                 bConfValue = udev_device_get_sysattr_value(dev,
227                                 "bConfigurationValue");
228                 bNumIntfs = udev_device_get_sysattr_value(dev,
229                                 "bNumInterfaces");
230                 busid = udev_device_get_sysname(dev);
231                 if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) {
232                         err("problem getting device attributes: %s",
233                             strerror(errno));
234                         goto err_out;
235                 }
236
237                 /* Get product name. */
238                 usbip_names_get_product(product_name, sizeof(product_name),
239                                         strtol(idVendor, NULL, 16),
240                                         strtol(idProduct, NULL, 16));
241
242                 /* Print information. */
243                 print_device(busid, idVendor, idProduct, parsable);
244                 print_product_name(product_name, parsable);
245
246                 printf("\n");
247
248                 udev_device_unref(dev);
249         }
250
251         ret = 0;
252
253 err_out:
254         udev_enumerate_unref(enumerate);
255         udev_unref(udev);
256
257         return ret;
258 }
259
260 static int list_gadget_devices(bool parsable)
261 {
262         int ret = -1;
263         struct udev *udev;
264         struct udev_enumerate *enumerate;
265         struct udev_list_entry *devices, *dev_list_entry;
266         struct udev_device *dev;
267         const char *path;
268         const char *driver;
269
270         const struct usb_device_descriptor *d_desc;
271         const char *descriptors;
272         char product_name[128];
273
274         uint16_t idVendor;
275         char idVendor_buf[8];
276         uint16_t idProduct;
277         char idProduct_buf[8];
278         const char *busid;
279
280         udev = udev_new();
281         enumerate = udev_enumerate_new(udev);
282
283         udev_enumerate_add_match_subsystem(enumerate, "platform");
284
285         udev_enumerate_scan_devices(enumerate);
286         devices = udev_enumerate_get_list_entry(enumerate);
287
288         udev_list_entry_foreach(dev_list_entry, devices) {
289                 path = udev_list_entry_get_name(dev_list_entry);
290                 dev = udev_device_new_from_syspath(udev, path);
291
292                 driver = udev_device_get_driver(dev);
293                 /* We only have mechanism to enumerate gadgets bound to vudc */
294                 if (driver == NULL || strcmp(driver, USBIP_DEVICE_DRV_NAME))
295                         continue;
296
297                 /* Get device information. */
298                 descriptors = udev_device_get_sysattr_value(dev,
299                                 VUDC_DEVICE_DESCR_FILE);
300
301                 if (!descriptors) {
302                         err("problem getting device attributes: %s",
303                             strerror(errno));
304                         goto err_out;
305                 }
306
307                 d_desc = (const struct usb_device_descriptor *) descriptors;
308
309                 idVendor = le16toh(d_desc->idVendor);
310                 sprintf(idVendor_buf, "0x%4x", idVendor);
311                 idProduct = le16toh(d_desc->idProduct);
312                 sprintf(idProduct_buf, "0x%4x", idVendor);
313                 busid = udev_device_get_sysname(dev);
314
315                 /* Get product name. */
316                 usbip_names_get_product(product_name, sizeof(product_name),
317                                         le16toh(idVendor),
318                                         le16toh(idProduct));
319
320                 /* Print information. */
321                 print_device(busid, idVendor_buf, idProduct_buf, parsable);
322                 print_product_name(product_name, parsable);
323
324                 printf("\n");
325
326                 udev_device_unref(dev);
327         }
328         ret = 0;
329
330 err_out:
331         udev_enumerate_unref(enumerate);
332         udev_unref(udev);
333
334         return ret;
335 }
336
337 int usbip_list(int argc, char *argv[])
338 {
339         static const struct option opts[] = {
340                 { "parsable", no_argument,       NULL, 'p' },
341                 { "remote",   required_argument, NULL, 'r' },
342                 { "local",    no_argument,       NULL, 'l' },
343                 { "device",    no_argument,       NULL, 'd' },
344                 { NULL,       0,                 NULL,  0  }
345         };
346
347         bool parsable = false;
348         int opt;
349         int ret = -1;
350
351         if (usbip_names_init(USBIDS_FILE))
352                 err("failed to open %s", USBIDS_FILE);
353
354         for (;;) {
355                 opt = getopt_long(argc, argv, "pr:ld", opts, NULL);
356
357                 if (opt == -1)
358                         break;
359
360                 switch (opt) {
361                 case 'p':
362                         parsable = true;
363                         break;
364                 case 'r':
365                         ret = list_exported_devices(optarg);
366                         goto out;
367                 case 'l':
368                         ret = list_devices(parsable);
369                         goto out;
370                 case 'd':
371                         ret = list_gadget_devices(parsable);
372                         goto out;
373                 default:
374                         goto err_out;
375                 }
376         }
377
378 err_out:
379         usbip_list_usage();
380 out:
381         usbip_names_free();
382
383         return ret;
384 }