|
@@ -1,724 +1,180 @@
|
|
|
/*
|
|
|
+ * command structure borrowed from udev
|
|
|
+ * (git://git.kernel.org/pub/scm/linux/hotplug/udev.git)
|
|
|
*
|
|
|
- * Copyright (C) 2005-2007 Takahiro Hirofuchi
|
|
|
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
|
|
|
+ * 2005-2007 Takahiro Hirofuchi
|
|
|
+ *
|
|
|
+ * 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/>.
|
|
|
*/
|
|
|
|
|
|
-#ifdef HAVE_CONFIG_H
|
|
|
-#include "../config.h"
|
|
|
-#endif
|
|
|
-
|
|
|
-#include "usbip.h"
|
|
|
-#include "usbip_network.h"
|
|
|
-#include <ctype.h>
|
|
|
-#include <sys/types.h>
|
|
|
-#include <sys/stat.h>
|
|
|
+#include <stdio.h>
|
|
|
#include <stdlib.h>
|
|
|
-#include <fcntl.h>
|
|
|
-#include <glib.h>
|
|
|
-
|
|
|
-static const char version[] = PACKAGE_STRING;
|
|
|
-
|
|
|
-
|
|
|
-/* /sys/devices/platform/vhci_hcd/usb6/6-1/6-1:1.1 -> 1 */
|
|
|
-static int get_interface_number(char *path)
|
|
|
-{
|
|
|
- char *c;
|
|
|
-
|
|
|
- c = strstr(path, vhci_driver->hc_device->bus_id);
|
|
|
- if (!c)
|
|
|
- return -1; /* hc exist? */
|
|
|
- c++;
|
|
|
- /* -> usb6/6-1/6-1:1.1 */
|
|
|
-
|
|
|
- c = strchr(c, '/');
|
|
|
- if (!c)
|
|
|
- return -1; /* hc exist? */
|
|
|
- c++;
|
|
|
- /* -> 6-1/6-1:1.1 */
|
|
|
-
|
|
|
- c = strchr(c, '/');
|
|
|
- if (!c)
|
|
|
- return -1; /* no interface path */
|
|
|
- c++;
|
|
|
- /* -> 6-1:1.1 */
|
|
|
-
|
|
|
- c = strchr(c, ':');
|
|
|
- if (!c)
|
|
|
- return -1; /* no configuration? */
|
|
|
- c++;
|
|
|
- /* -> 1.1 */
|
|
|
-
|
|
|
- c = strchr(c, '.');
|
|
|
- if (!c)
|
|
|
- return -1; /* no interface? */
|
|
|
- c++;
|
|
|
- /* -> 1 */
|
|
|
-
|
|
|
-
|
|
|
- return atoi(c);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static struct sysfs_device *open_usb_interface(struct usb_device *udev, int i)
|
|
|
-{
|
|
|
- struct sysfs_device *suinf;
|
|
|
- char busid[SYSFS_BUS_ID_SIZE];
|
|
|
-
|
|
|
- snprintf(busid, SYSFS_BUS_ID_SIZE, "%s:%d.%d",
|
|
|
- udev->busid, udev->bConfigurationValue, i);
|
|
|
-
|
|
|
- suinf = sysfs_open_device("usb", busid);
|
|
|
- if (!suinf)
|
|
|
- err("sysfs_open_device %s", busid);
|
|
|
-
|
|
|
- return suinf;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-#define MAX_BUFF 100
|
|
|
-static int record_connection(char *host, char *port, char *busid, int rhport)
|
|
|
-{
|
|
|
- int fd;
|
|
|
- char path[PATH_MAX+1];
|
|
|
- char buff[MAX_BUFF+1];
|
|
|
- int ret;
|
|
|
-
|
|
|
- mkdir(VHCI_STATE_PATH, 0700);
|
|
|
|
|
|
- snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
|
|
|
-
|
|
|
- fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
|
|
|
- if (fd < 0)
|
|
|
- return -1;
|
|
|
-
|
|
|
- snprintf(buff, MAX_BUFF, "%s %s %s\n",
|
|
|
- host, port, busid);
|
|
|
-
|
|
|
- ret = write(fd, buff, strlen(buff));
|
|
|
- if (ret != (ssize_t) strlen(buff)) {
|
|
|
- close(fd);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- close(fd);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int read_record(int rhport, char *host, char *port, char *busid)
|
|
|
-{
|
|
|
- FILE *file;
|
|
|
- char path[PATH_MAX+1];
|
|
|
-
|
|
|
- snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
|
|
|
-
|
|
|
- file = fopen(path, "r");
|
|
|
- if (!file) {
|
|
|
- err("fopen");
|
|
|
- return -1;
|
|
|
- }
|
|
|
+#include <getopt.h>
|
|
|
|
|
|
- if (fscanf(file, "%s %s %s\n", host, port, busid) != 3) {
|
|
|
- err("fscanf");
|
|
|
- fclose(file);
|
|
|
- return -1;
|
|
|
- }
|
|
|
+#include "usbip_common.h"
|
|
|
+#include "usbip.h"
|
|
|
|
|
|
- fclose(file);
|
|
|
+static int usbip_help(int argc, char *argv[]);
|
|
|
+static int usbip_version(int argc, char *argv[]);
|
|
|
|
|
|
- return 0;
|
|
|
-}
|
|
|
+static const char usbip_version_string[] = PACKAGE_STRING;
|
|
|
|
|
|
+static const char usbip_usage_string[] =
|
|
|
+ "usbip [--debug] [version]\n"
|
|
|
+ " [help] <command> <args>\n";
|
|
|
|
|
|
-int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev)
|
|
|
+static void usbip_usage(void)
|
|
|
{
|
|
|
- char product_name[100];
|
|
|
- char host[NI_MAXHOST] = "unknown host";
|
|
|
- char serv[NI_MAXSERV] = "unknown port";
|
|
|
- char remote_busid[SYSFS_BUS_ID_SIZE];
|
|
|
- int ret;
|
|
|
-
|
|
|
- if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED) {
|
|
|
- info("Port %02d: <%s>", idev->port, usbip_status_string(idev->status));
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- ret = read_record(idev->port, host, serv, remote_busid);
|
|
|
- if (ret) {
|
|
|
- err("read_record");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- info("Port %02d: <%s> at %s", idev->port,
|
|
|
- usbip_status_string(idev->status), usbip_speed_string(idev->udev.speed));
|
|
|
-
|
|
|
- usbip_names_get_product(product_name, sizeof(product_name),
|
|
|
- idev->udev.idVendor, idev->udev.idProduct);
|
|
|
-
|
|
|
- info(" %s", product_name);
|
|
|
-
|
|
|
- info("%10s -> usbip://%s:%s/%s (remote devid %08x (bus/dev %03d/%03d))",
|
|
|
- idev->udev.busid, host, serv, remote_busid,
|
|
|
- idev->devid,
|
|
|
- idev->busnum, idev->devnum);
|
|
|
-
|
|
|
- for (int i=0; i < idev->udev.bNumInterfaces; i++) {
|
|
|
- /* show interface information */
|
|
|
- struct sysfs_device *suinf;
|
|
|
-
|
|
|
- suinf = open_usb_interface(&idev->udev, i);
|
|
|
- if (!suinf)
|
|
|
- continue;
|
|
|
-
|
|
|
- info(" %6s used by %-17s", suinf->bus_id, suinf->driver_name);
|
|
|
- sysfs_close_device(suinf);
|
|
|
-
|
|
|
- /* show class device information */
|
|
|
- struct usbip_class_device *cdev;
|
|
|
-
|
|
|
- dlist_for_each_data(idev->cdev_list, cdev,
|
|
|
- struct usbip_class_device) {
|
|
|
- int ifnum = get_interface_number(cdev->dev_path);
|
|
|
- if (ifnum == i) {
|
|
|
- info(" %s", cdev->class_path);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
+ printf("usage: %s", usbip_usage_string);
|
|
|
}
|
|
|
|
|
|
+struct command {
|
|
|
+ const char *name;
|
|
|
+ int (*fn)(int argc, char *argv[]);
|
|
|
+ const char *help;
|
|
|
+ void (*usage)(void);
|
|
|
+};
|
|
|
|
|
|
+static const struct command cmds[] = {
|
|
|
+ {
|
|
|
+ .name = "help",
|
|
|
+ .fn = usbip_help,
|
|
|
+ .help = NULL,
|
|
|
+ .usage = NULL
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .name = "version",
|
|
|
+ .fn = usbip_version,
|
|
|
+ .help = NULL,
|
|
|
+ .usage = NULL
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .name = "attach",
|
|
|
+ .fn = usbip_attach,
|
|
|
+ .help = "Attach a remote USB device",
|
|
|
+ .usage = usbip_attach_usage
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .name = "detach",
|
|
|
+ .fn = usbip_detach,
|
|
|
+ .help = "Detach a remote USB device",
|
|
|
+ .usage = usbip_detach_usage
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .name = "list",
|
|
|
+ .fn = usbip_list,
|
|
|
+ .help = "List exported or local USB devices",
|
|
|
+ .usage = usbip_list_usage
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .name = "bind",
|
|
|
+ .fn = usbip_bind,
|
|
|
+ .help = "Bind device to " USBIP_HOST_DRV_NAME ".ko",
|
|
|
+ .usage = usbip_bind_usage
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .name = "unbind",
|
|
|
+ .fn = usbip_unbind,
|
|
|
+ .help = "Unbind device from " USBIP_HOST_DRV_NAME ".ko",
|
|
|
+ .usage = usbip_unbind_usage
|
|
|
+ },
|
|
|
+ { NULL, NULL, NULL, NULL }
|
|
|
+};
|
|
|
|
|
|
-
|
|
|
-static int query_exported_devices(int sockfd)
|
|
|
+static int usbip_help(int argc, char *argv[])
|
|
|
{
|
|
|
- int ret;
|
|
|
- struct op_devlist_reply rep;
|
|
|
- uint16_t code = OP_REP_DEVLIST;
|
|
|
-
|
|
|
- bzero(&rep, sizeof(rep));
|
|
|
-
|
|
|
- ret = usbip_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
|
|
|
- if (ret < 0) {
|
|
|
- err("send op_common");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- ret = usbip_recv_op_common(sockfd, &code);
|
|
|
- if (ret < 0) {
|
|
|
- err("recv op_common");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- ret = usbip_recv(sockfd, (void *) &rep, sizeof(rep));
|
|
|
- if (ret < 0) {
|
|
|
- err("recv op_devlist");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- PACK_OP_DEVLIST_REPLY(0, &rep);
|
|
|
- dbg("exportable %d devices", rep.ndev);
|
|
|
-
|
|
|
- for (unsigned int i=0; i < rep.ndev; i++) {
|
|
|
- char product_name[100];
|
|
|
- char class_name[100];
|
|
|
- struct usb_device udev;
|
|
|
+ const struct command *cmd;
|
|
|
+ int i;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
- bzero(&udev, sizeof(udev));
|
|
|
-
|
|
|
- ret = usbip_recv(sockfd, (void *) &udev, sizeof(udev));
|
|
|
- if (ret < 0) {
|
|
|
- err("recv usb_device[%d]", i);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- pack_usb_device(0, &udev);
|
|
|
-
|
|
|
- usbip_names_get_product(product_name, sizeof(product_name),
|
|
|
- udev.idVendor, udev.idProduct);
|
|
|
- usbip_names_get_class(class_name, sizeof(class_name), udev.bDeviceClass,
|
|
|
- udev.bDeviceSubClass, udev.bDeviceProtocol);
|
|
|
-
|
|
|
- info("%8s: %s", udev.busid, product_name);
|
|
|
- info("%8s: %s", " ", udev.path);
|
|
|
- info("%8s: %s", " ", class_name);
|
|
|
-
|
|
|
- for (int j=0; j < udev.bNumInterfaces; j++) {
|
|
|
- struct usb_interface uinf;
|
|
|
-
|
|
|
- ret = usbip_recv(sockfd, (void *) &uinf, sizeof(uinf));
|
|
|
- if (ret < 0) {
|
|
|
- err("recv usb_interface[%d]", j);
|
|
|
- return -1;
|
|
|
+ if (argc > 1 && argv++) {
|
|
|
+ for (i = 0; cmds[i].name != NULL; i++)
|
|
|
+ if (!strcmp(cmds[i].name, argv[0]) && cmds[i].usage) {
|
|
|
+ cmds[i].usage();
|
|
|
+ goto done;
|
|
|
}
|
|
|
-
|
|
|
- pack_usb_interface(0, &uinf);
|
|
|
- usbip_names_get_class(class_name, sizeof(class_name), uinf.bInterfaceClass,
|
|
|
- uinf.bInterfaceSubClass, uinf.bInterfaceProtocol);
|
|
|
-
|
|
|
- info("%8s: %2d - %s", " ", j, class_name);
|
|
|
- }
|
|
|
-
|
|
|
- info(" ");
|
|
|
- }
|
|
|
-
|
|
|
- return rep.ndev;
|
|
|
-}
|
|
|
-
|
|
|
-static int import_device(int sockfd, struct usb_device *udev)
|
|
|
-{
|
|
|
- int ret;
|
|
|
- int port;
|
|
|
-
|
|
|
- ret = usbip_vhci_driver_open();
|
|
|
- if (ret < 0) {
|
|
|
- err("open vhci_driver");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- port = usbip_vhci_get_free_port();
|
|
|
- if (port < 0) {
|
|
|
- err("no free port");
|
|
|
- usbip_vhci_driver_close();
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- ret = usbip_vhci_attach_device(port, sockfd, udev->busnum,
|
|
|
- udev->devnum, udev->speed);
|
|
|
- if (ret < 0) {
|
|
|
- err("import device");
|
|
|
- usbip_vhci_driver_close();
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- usbip_vhci_driver_close();
|
|
|
-
|
|
|
- return port;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static int query_import_device(int sockfd, char *busid)
|
|
|
-{
|
|
|
- int ret;
|
|
|
- struct op_import_request request;
|
|
|
- struct op_import_reply reply;
|
|
|
- uint16_t code = OP_REP_IMPORT;
|
|
|
-
|
|
|
- bzero(&request, sizeof(request));
|
|
|
- bzero(&reply, sizeof(reply));
|
|
|
-
|
|
|
-
|
|
|
- /* send a request */
|
|
|
- ret = usbip_send_op_common(sockfd, OP_REQ_IMPORT, 0);
|
|
|
- if (ret < 0) {
|
|
|
- err("send op_common");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1);
|
|
|
-
|
|
|
- PACK_OP_IMPORT_REQUEST(0, &request);
|
|
|
-
|
|
|
- ret = usbip_send(sockfd, (void *) &request, sizeof(request));
|
|
|
- if (ret < 0) {
|
|
|
- err("send op_import_request");
|
|
|
- return -1;
|
|
|
+ ret = -1;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- /* recieve a reply */
|
|
|
- ret = usbip_recv_op_common(sockfd, &code);
|
|
|
- if (ret < 0) {
|
|
|
- err("recv op_common");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- ret = usbip_recv(sockfd, (void *) &reply, sizeof(reply));
|
|
|
- if (ret < 0) {
|
|
|
- err("recv op_import_reply");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- PACK_OP_IMPORT_REPLY(0, &reply);
|
|
|
-
|
|
|
-
|
|
|
- /* check the reply */
|
|
|
- if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) {
|
|
|
- err("recv different busid %s", reply.udev.busid);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /* import a device */
|
|
|
- return import_device(sockfd, &reply.udev);
|
|
|
-}
|
|
|
-
|
|
|
-static int attach_device(char *host, char *busid)
|
|
|
-{
|
|
|
- int sockfd;
|
|
|
- int ret;
|
|
|
- int rhport;
|
|
|
-
|
|
|
- sockfd = tcp_connect(host, USBIP_PORT_STRING);
|
|
|
- if (sockfd < 0) {
|
|
|
- err("tcp connect");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- rhport = query_import_device(sockfd, busid);
|
|
|
- if (rhport < 0) {
|
|
|
- err("query");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- close(sockfd);
|
|
|
-
|
|
|
- ret = record_connection(host, USBIP_PORT_STRING,
|
|
|
- busid, rhport);
|
|
|
- if (ret < 0) {
|
|
|
- err("record connection");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int detach_port(char *port)
|
|
|
-{
|
|
|
- int ret;
|
|
|
- uint8_t portnum;
|
|
|
-
|
|
|
- for (unsigned int i=0; i < strlen(port); i++)
|
|
|
- if (!isdigit(port[i])) {
|
|
|
- err("invalid port %s", port);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- /* check max port */
|
|
|
-
|
|
|
- portnum = atoi(port);
|
|
|
-
|
|
|
- ret = usbip_vhci_driver_open();
|
|
|
- if (ret < 0) {
|
|
|
- err("open vhci_driver");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- ret = usbip_vhci_detach_device(portnum);
|
|
|
- if (ret < 0)
|
|
|
- return -1;
|
|
|
-
|
|
|
- usbip_vhci_driver_close();
|
|
|
-
|
|
|
+ usbip_usage();
|
|
|
+ printf("\n");
|
|
|
+ for (cmd = cmds; cmd->name != NULL; cmd++)
|
|
|
+ if (cmd->help != NULL)
|
|
|
+ printf(" %-10s %s\n", cmd->name, cmd->help);
|
|
|
+ printf("\n");
|
|
|
+done:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int show_exported_devices(char *host)
|
|
|
+static int usbip_version(int argc, char *argv[])
|
|
|
{
|
|
|
- int ret;
|
|
|
- int sockfd;
|
|
|
-
|
|
|
- sockfd = tcp_connect(host, USBIP_PORT_STRING);
|
|
|
- if (sockfd < 0) {
|
|
|
- err("- %s failed", host);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- info("- %s", host);
|
|
|
-
|
|
|
- ret = query_exported_devices(sockfd);
|
|
|
- if (ret < 0) {
|
|
|
- err("query");
|
|
|
- return -1;
|
|
|
- }
|
|
|
+ (void) argc;
|
|
|
+ (void) argv;
|
|
|
|
|
|
- close(sockfd);
|
|
|
+ printf("%s\n", usbip_version_string);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int attach_exported_devices(char *host, int sockfd)
|
|
|
+static int run_command(const struct command *cmd, int argc, char *argv[])
|
|
|
{
|
|
|
- int ret;
|
|
|
- struct op_devlist_reply rep;
|
|
|
- uint16_t code = OP_REP_DEVLIST;
|
|
|
-
|
|
|
- bzero(&rep, sizeof(rep));
|
|
|
-
|
|
|
- ret = usbip_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
|
|
|
- if(ret < 0) {
|
|
|
- err("send op_common");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- ret = usbip_recv_op_common(sockfd, &code);
|
|
|
- if(ret < 0) {
|
|
|
- err("recv op_common");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- ret = usbip_recv(sockfd, (void *) &rep, sizeof(rep));
|
|
|
- if(ret < 0) {
|
|
|
- err("recv op_devlist");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- PACK_OP_DEVLIST_REPLY(0, &rep);
|
|
|
- dbg("exportable %d devices", rep.ndev);
|
|
|
-
|
|
|
- for(unsigned int i=0; i < rep.ndev; i++) {
|
|
|
- char product_name[100];
|
|
|
- char class_name[100];
|
|
|
- struct usb_device udev;
|
|
|
-
|
|
|
- bzero(&udev, sizeof(udev));
|
|
|
-
|
|
|
- ret = usbip_recv(sockfd, (void *) &udev, sizeof(udev));
|
|
|
- if(ret < 0) {
|
|
|
- err("recv usb_device[%d]", i);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- pack_usb_device(0, &udev);
|
|
|
-
|
|
|
- usbip_names_get_product(product_name, sizeof(product_name),
|
|
|
- udev.idVendor, udev.idProduct);
|
|
|
- usbip_names_get_class(class_name, sizeof(class_name), udev.bDeviceClass,
|
|
|
- udev.bDeviceSubClass, udev.bDeviceProtocol);
|
|
|
-
|
|
|
- dbg("Attaching usb port %s from host %s on usbip, with deviceid: %s", udev.busid, host, product_name);
|
|
|
-
|
|
|
- for (int j=0; j < udev.bNumInterfaces; j++) {
|
|
|
- struct usb_interface uinf;
|
|
|
-
|
|
|
- ret = usbip_recv(sockfd, (void *) &uinf, sizeof(uinf));
|
|
|
- if (ret < 0) {
|
|
|
- err("recv usb_interface[%d]", j);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- pack_usb_interface(0, &uinf);
|
|
|
- usbip_names_get_class(class_name, sizeof(class_name), uinf.bInterfaceClass,
|
|
|
- uinf.bInterfaceSubClass, uinf.bInterfaceProtocol);
|
|
|
-
|
|
|
- dbg("interface %2d - %s", j, class_name);
|
|
|
- }
|
|
|
-
|
|
|
- attach_device(host, udev.busid);
|
|
|
- }
|
|
|
-
|
|
|
- return rep.ndev;
|
|
|
-}
|
|
|
-
|
|
|
-static int attach_devices_all(char *host)
|
|
|
-{
|
|
|
- int ret;
|
|
|
- int sockfd;
|
|
|
-
|
|
|
- sockfd = tcp_connect(host, USBIP_PORT_STRING);
|
|
|
- if(sockfd < 0) {
|
|
|
- err("- %s failed", host);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- info("- %s", host);
|
|
|
-
|
|
|
- ret = attach_exported_devices(host, sockfd);
|
|
|
- if(ret < 0) {
|
|
|
- err("query");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- close(sockfd);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-const char help_message[] = "\
|
|
|
-Usage: usbip [options] \n\
|
|
|
- -a, --attach [host] [bus_id] \n\
|
|
|
- Attach a remote USB device. \n\
|
|
|
- \n\
|
|
|
- -x, --attachall [host] \n\
|
|
|
- Attach all remote USB devices on the specific host. \n\
|
|
|
- \n\
|
|
|
- -d, --detach [ports] \n\
|
|
|
- Detach an imported USB device. \n\
|
|
|
- \n\
|
|
|
- -l, --list [hosts] \n\
|
|
|
- List exported USB devices. \n\
|
|
|
- \n\
|
|
|
- -p, --port \n\
|
|
|
- List virtual USB port status. \n\
|
|
|
- \n\
|
|
|
- -D, --debug \n\
|
|
|
- Print debugging information. \n\
|
|
|
- \n\
|
|
|
- -v, --version \n\
|
|
|
- Show version. \n\
|
|
|
- \n\
|
|
|
- -h, --help \n\
|
|
|
- Print this help. \n";
|
|
|
-
|
|
|
-static void show_help(void)
|
|
|
-{
|
|
|
- printf("%s", help_message);
|
|
|
-}
|
|
|
-
|
|
|
-static int show_port_status(void)
|
|
|
-{
|
|
|
- int ret;
|
|
|
- struct usbip_imported_device *idev;
|
|
|
-
|
|
|
- ret = usbip_vhci_driver_open();
|
|
|
- if (ret < 0)
|
|
|
- return ret;
|
|
|
-
|
|
|
- for (int i = 0; i < vhci_driver->nports; i++) {
|
|
|
- idev = &vhci_driver->idev[i];
|
|
|
-
|
|
|
- if (usbip_vhci_imported_device_dump(idev) < 0)
|
|
|
- ret = -1;
|
|
|
- }
|
|
|
-
|
|
|
- usbip_vhci_driver_close();
|
|
|
-
|
|
|
- return ret;
|
|
|
+ dbg("running command: `%s'\n", cmd->name);
|
|
|
+ return cmd->fn(argc, argv);
|
|
|
}
|
|
|
|
|
|
-#define _GNU_SOURCE
|
|
|
-#include <getopt.h>
|
|
|
-static const struct option longopts[] = {
|
|
|
- {"attach", no_argument, NULL, 'a'},
|
|
|
- {"attachall", no_argument, NULL, 'x'},
|
|
|
- {"detach", no_argument, NULL, 'd'},
|
|
|
- {"port", no_argument, NULL, 'p'},
|
|
|
- {"list", no_argument, NULL, 'l'},
|
|
|
- {"version", no_argument, NULL, 'v'},
|
|
|
- {"help", no_argument, NULL, 'h'},
|
|
|
- {"debug", no_argument, NULL, 'D'},
|
|
|
- {"syslog", no_argument, NULL, 'S'},
|
|
|
- {NULL, 0, NULL, 0}
|
|
|
-};
|
|
|
-
|
|
|
int main(int argc, char *argv[])
|
|
|
{
|
|
|
- int ret;
|
|
|
-
|
|
|
- enum {
|
|
|
- cmd_attach = 1,
|
|
|
- cmd_attachall,
|
|
|
- cmd_detach,
|
|
|
- cmd_port,
|
|
|
- cmd_list,
|
|
|
- cmd_help,
|
|
|
- cmd_version
|
|
|
- } cmd = 0;
|
|
|
-
|
|
|
- usbip_use_stderr = 1;
|
|
|
-
|
|
|
- if (geteuid() != 0)
|
|
|
- g_warning("running non-root?");
|
|
|
-
|
|
|
- ret = usbip_names_init(USBIDS_FILE);
|
|
|
- if (ret)
|
|
|
- notice("failed to open %s", USBIDS_FILE);
|
|
|
+ static const struct option opts[] = {
|
|
|
+ { "debug", no_argument, NULL, 'd' },
|
|
|
+ { NULL, 0, NULL, 0 }
|
|
|
+ };
|
|
|
+ char *cmd;
|
|
|
+ int opt;
|
|
|
+ int i, rc = -1;
|
|
|
|
|
|
+ opterr = 0;
|
|
|
for (;;) {
|
|
|
- int c;
|
|
|
- int index = 0;
|
|
|
-
|
|
|
- c = getopt_long(argc, argv, "adplvhDSx", longopts, &index);
|
|
|
+ opt = getopt_long(argc, argv, "+d", opts, NULL);
|
|
|
|
|
|
- if (c == -1)
|
|
|
+ if (opt == -1)
|
|
|
break;
|
|
|
|
|
|
- switch(c) {
|
|
|
- case 'a':
|
|
|
- if (!cmd)
|
|
|
- cmd = cmd_attach;
|
|
|
- else
|
|
|
- cmd = cmd_help;
|
|
|
- break;
|
|
|
- case 'd':
|
|
|
- if (!cmd)
|
|
|
- cmd = cmd_detach;
|
|
|
- else
|
|
|
- cmd = cmd_help;
|
|
|
- break;
|
|
|
- case 'p':
|
|
|
- if (!cmd)
|
|
|
- cmd = cmd_port;
|
|
|
- else cmd = cmd_help;
|
|
|
- break;
|
|
|
- case 'l':
|
|
|
- if (!cmd)
|
|
|
- cmd = cmd_list;
|
|
|
- else
|
|
|
- cmd = cmd_help;
|
|
|
- break;
|
|
|
- case 'v':
|
|
|
- if (!cmd)
|
|
|
- cmd = cmd_version;
|
|
|
- else
|
|
|
- cmd = cmd_help;
|
|
|
- break;
|
|
|
- case 'x':
|
|
|
- if(!cmd)
|
|
|
- cmd = cmd_attachall;
|
|
|
- else
|
|
|
- cmd = cmd_help;
|
|
|
- break;
|
|
|
- case 'h':
|
|
|
- cmd = cmd_help;
|
|
|
- break;
|
|
|
- case 'D':
|
|
|
- usbip_use_debug = 1;
|
|
|
- break;
|
|
|
- case 'S':
|
|
|
- usbip_use_syslog = 1;
|
|
|
- break;
|
|
|
- case '?':
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- err("getopt");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- ret = 0;
|
|
|
- switch(cmd) {
|
|
|
- case cmd_attach:
|
|
|
- if (optind == argc - 2)
|
|
|
- ret = attach_device(argv[optind], argv[optind+1]);
|
|
|
- else
|
|
|
- show_help();
|
|
|
- break;
|
|
|
- case cmd_detach:
|
|
|
- while (optind < argc)
|
|
|
- ret = detach_port(argv[optind++]);
|
|
|
- break;
|
|
|
- case cmd_port:
|
|
|
- ret = show_port_status();
|
|
|
- break;
|
|
|
- case cmd_list:
|
|
|
- while (optind < argc)
|
|
|
- ret = show_exported_devices(argv[optind++]);
|
|
|
- break;
|
|
|
- case cmd_attachall:
|
|
|
- while(optind < argc)
|
|
|
- ret = attach_devices_all(argv[optind++]);
|
|
|
- break;
|
|
|
- case cmd_version:
|
|
|
- printf("%s\n", version);
|
|
|
- break;
|
|
|
- case cmd_help:
|
|
|
- show_help();
|
|
|
+ switch (opt) {
|
|
|
+ case 'd':
|
|
|
+ usbip_use_debug = 1;
|
|
|
+ usbip_use_stderr = 1;
|
|
|
break;
|
|
|
default:
|
|
|
- show_help();
|
|
|
+ goto err_out;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+ cmd = argv[optind];
|
|
|
+ if (cmd) {
|
|
|
+ for (i = 0; cmds[i].name != NULL; i++)
|
|
|
+ if (!strcmp(cmds[i].name, cmd)) {
|
|
|
+ argc -= optind;
|
|
|
+ argv += optind;
|
|
|
+ optind = 0;
|
|
|
+ rc = run_command(&cmds[i], argc, argv);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- usbip_names_free();
|
|
|
-
|
|
|
- exit((ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
|
|
|
+err_out:
|
|
|
+ usbip_usage();
|
|
|
+out:
|
|
|
+ return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
|
|
|
}
|