linux/drivers/staging/usbip/userspace/src/usbip_list.c
<<
>>
Prefs
   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_product_name(char *product_name, bool parsable)
 163{
 164        if (!parsable)
 165                printf("   %s\n", product_name);
 166}
 167
 168static void print_interface(char *busid, char *driver, bool parsable)
 169{
 170        if (parsable)
 171                printf("%s=%s#", busid, driver);
 172        else
 173                printf("%9s%s -> %s\n", "", busid, driver);
 174}
 175
 176static int is_device(void *x)
 177{
 178        struct sysfs_attribute *devpath;
 179        struct sysfs_device *dev = x;
 180        int ret = 0;
 181
 182        devpath = sysfs_get_device_attr(dev, "devpath");
 183        if (devpath && *devpath->value != '0')
 184                ret = 1;
 185
 186        return ret;
 187}
 188
 189static int devcmp(void *a, void *b)
 190{
 191        return strcmp(a, b);
 192}
 193
 194static int list_devices(bool parsable)
 195{
 196        char bus_type[] = "usb";
 197        char busid[SYSFS_BUS_ID_SIZE];
 198        char product_name[128];
 199        struct sysfs_bus *ubus;
 200        struct sysfs_device *dev;
 201        struct sysfs_device *intf;
 202        struct sysfs_attribute *idVendor;
 203        struct sysfs_attribute *idProduct;
 204        struct sysfs_attribute *bConfValue;
 205        struct sysfs_attribute *bNumIntfs;
 206        struct dlist *devlist;
 207        int i;
 208        int ret = -1;
 209
 210        ubus = sysfs_open_bus(bus_type);
 211        if (!ubus) {
 212                err("could not open %s bus: %s", bus_type, strerror(errno));
 213                return -1;
 214        }
 215
 216        devlist = sysfs_get_bus_devices(ubus);
 217        if (!devlist) {
 218                err("could not get %s bus devices: %s", bus_type,
 219                    strerror(errno));
 220                goto err_out;
 221        }
 222
 223        /* remove interfaces and root hubs from device list */
 224        dlist_filter_sort(devlist, is_device, devcmp);
 225
 226        if (!parsable) {
 227                printf("Local USB devices\n");
 228                printf("=================\n");
 229        }
 230        dlist_for_each_data(devlist, dev, struct sysfs_device) {
 231                idVendor   = sysfs_get_device_attr(dev, "idVendor");
 232                idProduct  = sysfs_get_device_attr(dev, "idProduct");
 233                bConfValue = sysfs_get_device_attr(dev, "bConfigurationValue");
 234                bNumIntfs  = sysfs_get_device_attr(dev, "bNumInterfaces");
 235                if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) {
 236                        err("problem getting device attributes: %s",
 237                            strerror(errno));
 238                        goto err_out;
 239                }
 240
 241                /* get product name */
 242                usbip_names_get_product(product_name, sizeof(product_name),
 243                                        strtol(idVendor->value, NULL, 16),
 244                                        strtol(idProduct->value, NULL, 16));
 245                print_device(dev->bus_id, idVendor->value, idProduct->value,
 246                             parsable);
 247                print_product_name(product_name, parsable);
 248
 249                for (i = 0; i < atoi(bNumIntfs->value); i++) {
 250                        snprintf(busid, sizeof(busid), "%s:%.1s.%d",
 251                                 dev->bus_id, bConfValue->value, i);
 252                        intf = sysfs_open_device(bus_type, busid);
 253                        if (!intf) {
 254                                err("could not open device interface: %s",
 255                                    strerror(errno));
 256                                goto err_out;
 257                        }
 258                        print_interface(busid, intf->driver_name, parsable);
 259                        sysfs_close_device(intf);
 260                }
 261                printf("\n");
 262        }
 263
 264        ret = 0;
 265
 266err_out:
 267        sysfs_close_bus(ubus);
 268
 269        return ret;
 270}
 271
 272int usbip_list(int argc, char *argv[])
 273{
 274        static const struct option opts[] = {
 275                { "parsable", no_argument,       NULL, 'p' },
 276                { "remote",   required_argument, NULL, 'r' },
 277                { "local",    no_argument,       NULL, 'l' },
 278                { NULL,       0,                 NULL,  0  }
 279        };
 280
 281        bool parsable = false;
 282        int opt;
 283        int ret = -1;
 284
 285        if (usbip_names_init(USBIDS_FILE))
 286                err("failed to open %s", USBIDS_FILE);
 287
 288        for (;;) {
 289                opt = getopt_long(argc, argv, "pr:l", opts, NULL);
 290
 291                if (opt == -1)
 292                        break;
 293
 294                switch (opt) {
 295                case 'p':
 296                        parsable = true;
 297                        break;
 298                case 'r':
 299                        ret = list_exported_devices(optarg);
 300                        goto out;
 301                case 'l':
 302                        ret = list_devices(parsable);
 303                        goto out;
 304                default:
 305                        goto err_out;
 306                }
 307        }
 308
 309err_out:
 310        usbip_list_usage();
 311out:
 312        usbip_names_free();
 313
 314        return ret;
 315}
 316