[PATCH 3/4] usbip tools: use per vhci_hcd controller attributes

From: Salvador Fandino
Date: Tue Jan 30 2018 - 03:45:20 EST


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