From: Salvador Fandiño <salva@xxxxxxxxxx> Now every vhci_hcd device is controlled by its own sysfs attributes (before all of them were controlled by vhci_hcd.0 attributes). This patch addapts the usbip tools to use the new interface through libusbip. The user visible changes are as follows: - The files containing port information are named as "port$ix-$port" (they were "port$port" before), as port numbers are local to the vhci_hcd device now. - Command "usbip port" by default only list ports attached to "vhci_hcd.0", the new flag "--vhci-ix" can be used to list other device. The flag "--all" is also available for listing all the devices (it has not been made the default because it inserts per vhci_hcd device headers, changing the output format). Signed-off-by: Salvador Fandiño <salva@xxxxxxxxxx> --- tools/usb/usbip/src/Makefile.am | 3 +- tools/usb/usbip/src/usbip_attach.c | 101 ++++++++++++++++-------- tools/usb/usbip/src/usbip_detach.c | 57 ++++++++------ tools/usb/usbip/src/usbip_enumerate.c | 55 +++++++++++++ tools/usb/usbip/src/usbip_enumerate.h | 25 ++++++ tools/usb/usbip/src/usbip_port.c | 143 +++++++++++++++++++++++++++++----- tools/usb/usbip/src/utils.c | 16 ++++ tools/usb/usbip/src/utils.h | 1 + 8 files changed, 322 insertions(+), 79 deletions(-) create mode 100644 tools/usb/usbip/src/usbip_enumerate.c create mode 100644 tools/usb/usbip/src/usbip_enumerate.h diff --git a/tools/usb/usbip/src/Makefile.am b/tools/usb/usbip/src/Makefile.am index e26f39e0579d..50436aaa3900 100644 --- a/tools/usb/usbip/src/Makefile.am +++ b/tools/usb/usbip/src/Makefile.am @@ -7,6 +7,7 @@ sbin_PROGRAMS := usbip usbipd usbip_SOURCES := usbip.h utils.h usbip.c utils.c usbip_network.c \ usbip_attach.c usbip_detach.c usbip_list.c \ - usbip_bind.c usbip_unbind.c usbip_port.c + usbip_bind.c usbip_unbind.c usbip_port.c \ + usbip_enumerate.c usbipd_SOURCES := usbip_network.h usbipd.c usbip_network.c diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c index 7f07b2d50f59..3901dd507451 100644 --- a/tools/usb/usbip/src/usbip_attach.c +++ b/tools/usb/usbip/src/usbip_attach.c @@ -35,6 +35,7 @@ #include "usbip_common.h" #include "usbip_network.h" #include "usbip.h" +#include "usbip_enumerate.h" static const char usbip_attach_usage_string[] = "usbip attach <args>\n" @@ -48,7 +49,8 @@ void usbip_attach_usage(void) } #define MAX_BUFF 100 -static int record_connection(char *host, char *port, char *busid, int rhport) +static int record_connection(char *host, char *port, + char *busid, int vhci_ix, int rhport) { int fd; char path[PATH_MAX+1]; @@ -70,7 +72,7 @@ static int record_connection(char *host, char *port, char *busid, int rhport) return -1; } - snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport); + snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d-%d", vhci_ix, rhport); fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU); if (fd < 0) @@ -90,46 +92,78 @@ static int record_connection(char *host, char *port, char *busid, int rhport) return 0; } -static int import_device(int sockfd, struct usbip_usb_device *udev) +static int import_device(int sockfd, struct usbip_usb_device *udev, + int *pvhci_ix, int *pport) { - int rc; - int port; uint32_t speed = udev->speed; + int rc = -1; - rc = usbip_vhci_driver_open(); - if (rc < 0) { - err("open vhci_driver"); - goto err_out; + struct udev_enumerate *enumerate; + struct udev_list_entry *list, *entry; + + enumerate = vhci_enumerate(); + if (!enumerate) { + err("unable to list vhci_hcd drivers"); + return -1; + } + + list = udev_enumerate_get_list_entry(enumerate); + if (!list) { + err("unable to list vhci_hcd drivers"); + return -1; } - do { - port = usbip_vhci_get_free_port(speed); - if (port < 0) { - err("no free port"); - goto err_driver_close; + udev_list_entry_foreach(entry, list) { + const char *path = udev_list_entry_get_name(entry); + int port, vhci_ix; + + if (usbip_vhci_driver_open_path(path) < 0) + continue; + + vhci_ix = usbip_vhci_driver_ix(); + + /* Between the moment we read and parse the status + * files and the one we try to attach a socket to the + * port, the later one may become occupied from some + * other process. In order to avoid that race + * condition, we retry on EBUSY errors. On any other + * error we just jump to the next vhci_hcd device + */ + while (1) { + port = usbip_vhci_get_free_port(speed); + if (port < 0) + break; + + dbg("got free port %d at %s", port, path); + rc = usbip_vhci_attach_device(port, sockfd, + udev->busnum, + udev->devnum, + speed); + + if (rc >= 0 || errno != EBUSY) + break; + + usbip_vhci_refresh_device_list(); } - dbg("got free port %d", port); + usbip_vhci_driver_close(); - rc = usbip_vhci_attach_device(port, sockfd, udev->busnum, - udev->devnum, udev->speed); - if (rc < 0 && errno != EBUSY) { - err("import device"); - goto err_driver_close; + if (rc >= 0) { + *pport = port; + *pvhci_ix = vhci_ix; + goto done; } - } while (rc < 0); - - usbip_vhci_driver_close(); + } + err("import device failed"); - return port; +done: + udev_enumerate_unref(enumerate); -err_driver_close: - usbip_vhci_driver_close(); -err_out: - return -1; + return rc; } -static int query_import_device(int sockfd, char *busid) +static int query_import_device(int sockfd, char *busid, + int *pvhci_ix, int *pport) { int rc; struct op_import_request request; @@ -178,7 +212,7 @@ static int query_import_device(int sockfd, char *busid) } /* import a device */ - return import_device(sockfd, &reply.udev); + return import_device(sockfd, &reply.udev, pvhci_ix, pport); } static int attach_device(char *host, char *busid) @@ -186,6 +220,7 @@ static int attach_device(char *host, char *busid) int sockfd; int rc; int rhport; + int vhci_ix; sockfd = usbip_net_tcp_connect(host, usbip_port_string); if (sockfd < 0) { @@ -193,15 +228,15 @@ static int attach_device(char *host, char *busid) return -1; } - rhport = query_import_device(sockfd, busid); - if (rhport < 0) { + rc = query_import_device(sockfd, busid, &vhci_ix, &rhport); + if (rc < 0) { err("query"); return -1; } close(sockfd); - rc = record_connection(host, usbip_port_string, busid, rhport); + rc = record_connection(host, usbip_port_string, busid, vhci_ix, rhport); if (rc < 0) { err("record connection"); return -1; diff --git a/tools/usb/usbip/src/usbip_detach.c b/tools/usb/usbip/src/usbip_detach.c index 9db9d21bb2ec..06ad88d9959b 100644 --- a/tools/usb/usbip/src/usbip_detach.c +++ b/tools/usb/usbip/src/usbip_detach.c @@ -30,49 +30,39 @@ #include "usbip_common.h" #include "usbip_network.h" #include "usbip.h" +#include "utils.h" static const char usbip_detach_usage_string[] = "usbip detach <args>\n" - " -p, --port=<port> " USBIP_VHCI_DRV_NAME - " port the device is on\n"; + " -i, --vhci-ix=<ix> index of the " + USBIP_VHCI_DRV_NAME + " the device is on (defaults to 0)\n" + " -p, --port=<port> port the device is on\n"; void usbip_detach_usage(void) { printf("usage: %s", usbip_detach_usage_string); } -static int detach_port(char *port) +static int detach_port(int vhci_ix, int port) { int ret; - uint8_t portnum; char path[PATH_MAX+1]; - unsigned int port_len = strlen(port); - - for (unsigned int i = 0; i < port_len; i++) - if (!isdigit(port[i])) { - err("invalid port %s", port); - return -1; - } - - /* check max port */ - - portnum = atoi(port); - /* remove the port state file */ - snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", portnum); + snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d-%d", vhci_ix, port); remove(path); rmdir(VHCI_STATE_PATH); - ret = usbip_vhci_driver_open(); + ret = usbip_vhci_driver_open_ix(vhci_ix); if (ret < 0) { err("open vhci_driver"); return -1; } - ret = usbip_vhci_detach_device(portnum); + ret = usbip_vhci_detach_device(port); if (ret < 0) return -1; @@ -85,28 +75,45 @@ int usbip_detach(int argc, char *argv[]) { static const struct option opts[] = { { "port", required_argument, NULL, 'p' }, + { "vhci-ix", 0, NULL, 'i' }, { NULL, 0, NULL, 0 } }; int opt; - int ret = -1; + int port = -1; + int vhci_ix = 0; for (;;) { - opt = getopt_long(argc, argv, "p:", opts, NULL); + opt = getopt_long(argc, argv, "p:i:", opts, NULL); if (opt == -1) break; switch (opt) { case 'p': - ret = detach_port(optarg); - goto out; + if (atoi_with_check(optarg, &port) < 0) { + err("bad port number"); + return -1; + } + break; + case 'i': + if (atoi_with_check(optarg, &vhci_ix) < 0) { + err("bad vhci index"); + return -1; + } + break; default: goto err_out; } } + if (optind < argc) + goto err_out; + + if (port < 0) + goto err_out; + + return detach_port(vhci_ix, port); err_out: usbip_detach_usage(); -out: - return ret; + return -1; } diff --git a/tools/usb/usbip/src/usbip_enumerate.c b/tools/usb/usbip/src/usbip_enumerate.c new file mode 100644 index 000000000000..b6197435b476 --- /dev/null +++ b/tools/usb/usbip/src/usbip_enumerate.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 Qindel Formación y Servicios SL + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <libudev.h> + +#include "usbip_enumerate.h" +#include "vhci_driver.h" + +struct udev_enumerate *vhci_enumerate(void) +{ + struct udev *udev_context = NULL; + struct udev_enumerate *enumerate = NULL; + int rc; + + udev_context = udev_new(); + if (!udev_context) { + err("udev_new failed"); + return NULL; + } + + enumerate = udev_enumerate_new(udev_context); + if (!enumerate) { + err("udev_enumerate_new failed"); + goto err; + } + + udev_enumerate_add_match_subsystem(enumerate, USBIP_VHCI_BUS_TYPE); + udev_enumerate_add_match_sysname(enumerate, + USBIP_VHCI_DEVICE_NAME_PATTERN); + rc = udev_enumerate_scan_devices(enumerate); + if (rc < 0) { + err("udev_enumerate_scan_devices failed: %d", rc); + udev_enumerate_unref(enumerate); + enumerate = NULL; + } + +err: + udev_unref(udev_context); + + return enumerate; +} diff --git a/tools/usb/usbip/src/usbip_enumerate.h b/tools/usb/usbip/src/usbip_enumerate.h new file mode 100644 index 000000000000..ce1f4e6941d0 --- /dev/null +++ b/tools/usb/usbip/src/usbip_enumerate.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2018 Qindel Formacion y Servicios SL + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef __USBIP_ENUMERATE_H +#define __USBIP_ENUMERATE_H + +#include <libudev.h> + +struct udev_enumerate *vhci_enumerate(void); + +#endif /* __USBIP_ENUMERATE_H */ diff --git a/tools/usb/usbip/src/usbip_port.c b/tools/usb/usbip/src/usbip_port.c index 7bd74fb3a9cd..a981a73b7dfb 100644 --- a/tools/usb/usbip/src/usbip_port.c +++ b/tools/usb/usbip/src/usbip_port.c @@ -13,54 +13,157 @@ * GNU General Public License for more details. */ +#include <getopt.h> + #include "vhci_driver.h" #include "usbip_common.h" +#include "usbip_enumerate.h" +#include "utils.h" + +static const char usbip_port_usage_string[] = + "usbip port <args>\n" + " -i, --vhci-ix=<ix> index of the " + USBIP_VHCI_DRV_NAME + " the device is on (defaults to 0)\n" + " -a, --all list the ports from all the available " + USBIP_VHCI_DRV_NAME "'s\n"; + +void usbip_port_usage(void) +{ + printf("usage: %s", usbip_port_usage_string); +} static int list_imported_devices(void) { int i; struct usbip_imported_device *idev; - int ret; + int ret = 0; + + for (i = 0; i < vhci_driver->nports; i++) { + idev = &vhci_driver->idev[i]; + if (usbip_vhci_imported_device_dump(idev) < 0) { + err("unable to list device %d", i); + ret = -1; + } + } + return ret; +} + +static void list_imported_devices_header(void) +{ + printf("Imported USB devices\n"); + printf("====================\n"); +} + +static int list_imported_devices_ix(int vhci_ix) +{ + int ret; if (usbip_names_init(USBIDS_FILE)) err("failed to open %s", USBIDS_FILE); - ret = usbip_vhci_driver_open(); + ret = usbip_vhci_driver_open_ix(vhci_ix); if (ret < 0) { err("open vhci_driver"); goto err_names_free; } - printf("Imported USB devices\n"); - printf("====================\n"); + list_imported_devices_header(); + ret = list_imported_devices(); + usbip_vhci_driver_close(); +err_names_free: + usbip_names_free(); + return ret; +} - for (i = 0; i < vhci_driver->nports; i++) { - idev = &vhci_driver->idev[i]; +static int list_imported_devices_all(void) +{ + struct udev_enumerate *enumerate = NULL; + struct udev_list_entry *list, *entry; + int rc = 0; + + if (usbip_names_init(USBIDS_FILE)) + err("failed to open %s", USBIDS_FILE); - if (usbip_vhci_imported_device_dump(idev) < 0) - goto err_driver_close; + enumerate = vhci_enumerate(); + if (!enumerate) { + err("Unable to list vhci_hcd drivers"); + return -1; } - usbip_vhci_driver_close(); - usbip_names_free(); + list = udev_enumerate_get_list_entry(enumerate); + if (!list) { + err("Unable to list vhci_hcd drivers"); + return -1; + } - return ret; + list_imported_devices_header(); -err_driver_close: - usbip_vhci_driver_close(); -err_names_free: + udev_list_entry_foreach(entry, list) { + const char *path = udev_list_entry_get_name(entry); + int i; + int len = printf("VHCI: %s\n", path); + + /* write a line of dashes */ + for (i = 1; i < len; i++) + putchar('-'); + putchar('\n'); + + if (usbip_vhci_driver_open_path(path) < 0) { + err("usbip_vhci_driver_open_path"); + rc = -1; + continue; + } + if (list_imported_devices() < 0) + rc = -1; + usbip_vhci_driver_close(); + } usbip_names_free(); - return -1; + udev_enumerate_unref(enumerate); + + return rc; } int usbip_port_show(__attribute__((unused)) int argc, __attribute__((unused)) char *argv[]) { - int ret; + int vhci_ix = 0; + int all = 0; + static const struct option opts[] = { + { "vhci-ix", 0, NULL, 'i' }, + { "all", 0, NULL, 'a' }, + { NULL, 0, NULL, 0 } + }; - ret = list_imported_devices(); - if (ret < 0) - err("list imported devices"); + for (;;) { + int opt = getopt_long(argc, argv, "i:a", opts, NULL); - return ret; + if (opt == -1) + break; + switch (opt) { + case 'i': + if (atoi_with_check(optarg, &vhci_ix) < 0) { + err("Bad vhci index"); + return -1; + } + break; + case 'a': + all = 1; + break; + default: + goto err_out; + } + } + + if (optind < argc) + goto err_out; + + if (all) + return list_imported_devices_all(); + else + return list_imported_devices_ix(vhci_ix); + +err_out: + usbip_port_usage(); + return -1; } diff --git a/tools/usb/usbip/src/utils.c b/tools/usb/usbip/src/utils.c index 3d7b42e77299..0c55ab4f3d98 100644 --- a/tools/usb/usbip/src/utils.c +++ b/tools/usb/usbip/src/utils.c @@ -19,6 +19,8 @@ #include <errno.h> #include <stdio.h> #include <string.h> +#include <stdlib.h> +#include <ctype.h> #include "usbip_common.h" #include "utils.h" @@ -53,3 +55,17 @@ int modify_match_busid(char *busid, int add) return 0; } + +int atoi_with_check(const char *str, int *pi) +{ + ssize_t len = strlen(str); + + for (ssize_t i = 0; i < len; i++) { + if (!isdigit(str[i])) { + err("%s is not a number", str); + return -1; + } + } + *pi = atoi(str); + return 0; +} diff --git a/tools/usb/usbip/src/utils.h b/tools/usb/usbip/src/utils.h index 5916fd3e02a6..a07d03c9bb12 100644 --- a/tools/usb/usbip/src/utils.h +++ b/tools/usb/usbip/src/utils.h @@ -20,6 +20,7 @@ #define __UTILS_H int modify_match_busid(char *busid, int add); +int atoi_with_check(const char *str, int *pi); #endif /* __UTILS_H */ -- 2.14.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html