Commit e9837bbb authored by matt mooney's avatar matt mooney Committed by Greg Kroah-Hartman

staging: usbip: userspace tools v1.0.0

The new and improved (well somewhat, with a ways to go) userspace utility.

    mfm:pts/8[~/tmp/userspace]
    May26 05:18:31 % ./src/usbip help
    usage: usbip [--debug] [version]
                 [help] <command> <args>

      attach     Attach a remote USB device
      detach     Detach a remote USB device
      list       List exported or local USB devices
      bind       Bind device to usbip-host.ko
      unbind     Unbind device from usbip-host.ko

This first commit of the userspace `usbip' utility uses to same
implementation as the old tools, `usbip' and  `usbip_bind_driver'.
Nothing significant has changed so compatibility with windows has
_not_ been broken. However, the tools remain broken in many ways
due to the old implementation.
Signed-off-by: default avatarmatt mooney <mfm@muteddisk.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 58058422
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT([usbip], [0.1.8], [usbip-devel@lists.sourceforge.net])
AC_DEFINE([USBIP_VERSION], [0x000106], [numeric version number])
AC_INIT([usbip], [1.0.0], [usbip-devel@lists.sourceforge.net])
AC_DEFINE([USBIP_VERSION], [0x00000100], [binary-coded decimal version number])
CURRENT=0
REVISION=1
......
......@@ -2,9 +2,10 @@ AM_CPPFLAGS := -I$(top_srcdir)/libsrc -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"'
AM_CFLAGS := @EXTRA_CFLAGS@ @PACKAGE_CFLAGS@
LDADD := $(top_srcdir)/libsrc/libusbip.la @PACKAGE_LIBS@
sbin_PROGRAMS := usbip usbipd usbip_bind_driver
sbin_PROGRAMS := usbip usbipd
usbip_SOURCES := usbip.c usbip_network.c usbip_network.h
usbipd_SOURCES := usbipd.c usbip_network.c usbip_network.h
usbip_bind_driver_SOURCES := bind-driver.c utils.c utils.h \
usbip_network.h usbip_network.c
usbip_SOURCES := usbip.c utils.c usbip_network.c \
usbip_attach.c usbip_detach.c usbip_list.c \
usbip_bind.c usbip_unbind.c
usbipd_SOURCES := usbipd.c usbip_network.c
This diff is collapsed.
This diff is collapsed.
/*
* 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/>.
*/
#ifndef __USBIP_H
#define __USBIP_H
#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
/* usbip commands */
int usbip_attach(int argc, char *argv[]);
int usbip_detach(int argc, char *argv[]);
int usbip_list(int argc, char *argv[]);
int usbip_bind(int argc, char *argv[]);
int usbip_unbind(int argc, char *argv[]);
void usbip_attach_usage(void);
void usbip_detach_usage(void);
void usbip_list_usage(void);
void usbip_bind_usage(void);
void usbip_unbind_usage(void);
#endif /* __USBIP_H */
/*
* 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/>.
*/
#include <sys/stat.h>
#include <sysfs/libsysfs.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <getopt.h>
#include <unistd.h>
#include "vhci_driver.h"
#include "usbip_common.h"
#include "usbip_network.h"
#include "usbip.h"
static const char usbip_attach_usage_string[] =
"usbip attach <args>\n"
" -h, --host=<host> The machine with exported USB devices\n"
" -b, --busid=<busid> Busid of the device on <host>\n";
void usbip_attach_usage(void)
{
printf("usage: %s", usbip_attach_usage_string);
}
#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 import_device(int sockfd, struct usb_device *udev)
{
int rc;
int port;
rc = usbip_vhci_driver_open();
if (rc < 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;
}
rc = usbip_vhci_attach_device(port, sockfd, udev->busnum,
udev->devnum, udev->speed);
if (rc < 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 rc;
struct op_import_request request;
struct op_import_reply reply;
uint16_t code = OP_REP_IMPORT;
memset(&request, 0, sizeof(request));
memset(&reply, 0, sizeof(reply));
/* send a request */
rc = usbip_send_op_common(sockfd, OP_REQ_IMPORT, 0);
if (rc < 0) {
err("send op_common");
return -1;
}
strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1);
PACK_OP_IMPORT_REQUEST(0, &request);
rc = usbip_send(sockfd, (void *) &request, sizeof(request));
if (rc < 0) {
err("send op_import_request");
return -1;
}
/* recieve a reply */
rc = usbip_recv_op_common(sockfd, &code);
if (rc < 0) {
err("recv op_common");
return -1;
}
rc = usbip_recv(sockfd, (void *) &reply, sizeof(reply));
if (rc < 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 rc;
int rhport;
sockfd = usbip_net_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);
rc = record_connection(host, USBIP_PORT_STRING, busid, rhport);
if (rc < 0) {
err("record connection");
return -1;
}
return 0;
}
int usbip_attach(int argc, char *argv[])
{
static const struct option opts[] = {
{ "host", required_argument, NULL, 'h' },
{ "busid", required_argument, NULL, 'b' },
{ NULL, 0, NULL, 0 }
};
char *host = NULL;
char *busid = NULL;
int opt;
int ret = -1;
for (;;) {
opt = getopt_long(argc, argv, "h:b:", opts, NULL);
if (opt == -1)
break;
switch (opt) {
case 'h':
host = optarg;
break;
case 'b':
busid = optarg;
break;
default:
goto err_out;
}
}
if (!host || !busid)
goto err_out;
ret = attach_device(host, busid);
goto out;
err_out:
usbip_attach_usage();
out:
return ret;
}
/*
* 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/>.
*/
#include <sysfs/libsysfs.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <unistd.h>
#include "usbip_common.h"
#include "utils.h"
#include "usbip.h"
static const char usbip_bind_usage_string[] =
"usbip bind <args>\n"
" -b, --busid=<busid> Bind " USBIP_HOST_DRV_NAME ".ko to device "
"on <busid>\n";
void usbip_bind_usage(void)
{
printf("usage: %s", usbip_bind_usage_string);
}
static const char unbind_path_format[] = "/sys/bus/usb/devices/%s/driver/unbind";
/* buggy driver may cause dead lock */
static int unbind_interface_busid(char *busid)
{
char unbind_path[SYSFS_PATH_MAX];
int fd;
int ret;
snprintf(unbind_path, sizeof(unbind_path), unbind_path_format, busid);
fd = open(unbind_path, O_WRONLY);
if (fd < 0) {
dbg("opening unbind_path failed: %d", fd);
return -1;
}
ret = write(fd, busid, strnlen(busid, BUS_ID_SIZE));
if (ret < 0) {
dbg("write to unbind_path failed: %d", ret);
close(fd);
return -1;
}
close(fd);
return 0;
}
static int unbind_interface(char *busid, int configvalue, int interface)
{
char inf_busid[BUS_ID_SIZE];
dbg("unbinding interface");
snprintf(inf_busid, BUS_ID_SIZE, "%s:%d.%d", busid, configvalue, interface);
return unbind_interface_busid(inf_busid);
}
static int unbind(char *busid)
{
int configvalue = 0;
int ninterface = 0;
int devclass = 0;
int i;
int failed = 0;
configvalue = read_bConfigurationValue(busid);
ninterface = read_bNumInterfaces(busid);
devclass = read_bDeviceClass(busid);
if (configvalue < 0 || ninterface < 0 || devclass < 0) {
dbg("read config and ninf value, removed?");
return -1;
}
if (devclass == 0x09) {
dbg("skip unbinding of hub");
return -1;
}
for (i = 0; i < ninterface; i++) {
char driver[PATH_MAX];
int ret;
memset(&driver, 0, sizeof(driver));
getdriver(busid, configvalue, i, driver, PATH_MAX-1);
dbg(" %s:%d.%d -> %s ", busid, configvalue, i, driver);
if (!strncmp("none", driver, PATH_MAX))
continue; /* unbound interface */
#if 0
if (!strncmp("usbip", driver, PATH_MAX))
continue; /* already bound to usbip */
#endif
/* unbinding */
ret = unbind_interface(busid, configvalue, i);
if (ret < 0) {
dbg("unbind driver at %s:%d.%d failed",
busid, configvalue, i);
failed = 1;
}
}
if (failed)
return -1;
else
return 0;
}
static const char bind_path_format[] = "/sys/bus/usb/drivers/%s/bind";
static int bind_interface_busid(char *busid, char *driver)
{
char bind_path[PATH_MAX];
int fd;
int ret;
snprintf(bind_path, sizeof(bind_path), bind_path_format, driver);
fd = open(bind_path, O_WRONLY);
if (fd < 0)
return -1;
ret = write(fd, busid, strnlen(busid, BUS_ID_SIZE));
if (ret < 0) {
close(fd);
return -1;
}
close(fd);
return 0;
}
static int bind_interface(char *busid, int configvalue, int interface, char *driver)
{
char inf_busid[BUS_ID_SIZE];
snprintf(inf_busid, BUS_ID_SIZE, "%s:%d.%d", busid, configvalue, interface);
return bind_interface_busid(inf_busid, driver);
}
/* call at unbound state */
static int bind_to_usbip(char *busid)
{
int configvalue = 0;
int ninterface = 0;
int i;
int failed = 0;
configvalue = read_bConfigurationValue(busid);
ninterface = read_bNumInterfaces(busid);
if (configvalue < 0 || ninterface < 0) {
dbg("read config and ninf value, removed?");
return -1;
}
for (i = 0; i < ninterface; i++) {
int ret;
ret = bind_interface(busid, configvalue, i,
USBIP_HOST_DRV_NAME);
if (ret < 0) {
dbg("bind usbip at %s:%d.%d, failed",
busid, configvalue, i);
failed = 1;
/* need to contine binding at other interfaces */
}
}
if (failed)
return -1;
else
return 0;
}
static int use_device_by_usbip(char *busid)
{
int ret;
ret = unbind(busid);
if (ret < 0) {
dbg("unbind drivers of %s, failed", busid);
return -1;
}
ret = modify_match_busid(busid, 1);
if (ret < 0) {
dbg("add %s to match_busid, failed", busid);
return -1;
}
ret = bind_to_usbip(busid);
if (ret < 0) {
dbg("bind usbip to %s, failed", busid);
modify_match_busid(busid, 0);
return -1;
}
dbg("bind %s complete!", busid);
return 0;
}
int usbip_bind(int argc, char *argv[])
{
static const struct option opts[] = {
{ "busid", required_argument, NULL, 'b' },
{ NULL, 0, NULL, 0 }
};
int opt;
int ret = -1;
for (;;) {
opt = getopt_long(argc, argv, "b:", opts, NULL);
if (opt == -1)
break;
switch (opt) {
case 'b':
ret = use_device_by_usbip(optarg);
goto out;
default:
goto err_out;
}
}
err_out:
usbip_bind_usage();
out:
return ret;
}
/*
* 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/>.
*/
#include <sysfs/libsysfs.h>
#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <unistd.h>
#include "vhci_driver.h"
#include "usbip_common.h"
#include "usbip_network.h"
#include "usbip.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";
void usbip_detach_usage(void)
{
printf("usage: %s", usbip_detach_usage_string);
}
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();
return ret;
}
int usbip_detach(int argc, char *argv[])
{
static const struct option opts[] = {
{ "port", required_argument, NULL, 'p' },
{ NULL, 0, NULL, 0 }
};
int opt;
int ret = -1;
for (;;) {
opt = getopt_long(argc, argv, "p:", opts, NULL);
if (opt == -1)
break;
switch (opt) {
case 'p':
ret = detach_port(optarg);
goto out;
default:
goto err_out;
}
}
err_out:
usbip_detach_usage();
out:
return ret;
}
/*
* 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/>.
*/
#include <sys/types.h>
#include <sysfs/libsysfs.h>
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <getopt.h>
#include <netdb.h>
#include <regex.h>
#include <unistd.h>
#include "usbip_common.h"
#include "usbip_network.h"
#include "utils.h"
#include "usbip.h"
static const char usbip_list_usage_string[] =
"usbip list [-p|--parsable] <args>\n"
" -p, --parsable Parsable list format\n"
" -r, --remote=<host> List the exported USB devices on <host>\n"
" -l, --local List the local USB devices\n";
void usbip_list_usage(void)
{
printf("usage: %s", usbip_list_usage_string);
}
static int query_exported_devices(int sockfd)
{
int ret;
struct op_devlist_reply rep;
uint16_t code = OP_REP_DEVLIST;
memset(&rep, 0, 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;
memset(&udev, 0, 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);
printf("%8s: %s\n", udev.busid, product_name);
printf("%8s: %s\n", " ", udev.path);
printf("%8s: %s\n", " ", 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;
}
pack_usb_interface(0, &uinf);
usbip_names_get_class(class_name, sizeof(class_name),
uinf.bInterfaceClass,
uinf.bInterfaceSubClass,
uinf.bInterfaceProtocol);
printf("%8s: %2d - %s\n", " ", j, class_name);
}
printf("\n");
}
return rep.ndev;
}
static int show_exported_devices(char *host)
{
int ret;
int sockfd;
sockfd = usbip_net_tcp_connect(host, USBIP_PORT_STRING);
if (sockfd < 0) {
err("unable to connect to %s port %s: %s\n", host,
USBIP_PORT_STRING, gai_strerror(sockfd));
return -1;
}
dbg("connected to %s port %s\n", host, USBIP_PORT_STRING);
printf("- %s\n", host);
ret = query_exported_devices(sockfd);
if (ret < 0) {
err("query");
return -1;
}
close(sockfd);
return 0;
}
static int is_usb_device(char *busid)
{
int ret;
regex_t regex;
regmatch_t pmatch[1];
ret = regcomp(&regex, "^[0-9]+-[0-9]+(\\.[0-9]+)*$", REG_NOSUB|REG_EXTENDED);
if (ret < 0)
err("regcomp: %s\n", strerror(errno));
ret = regexec(&regex, busid, 0, pmatch, 0);
if (ret)
return 0; /* not matched */
return 1;
}
static int show_devices(void)
{
DIR *dir;
dir = opendir("/sys/bus/usb/devices/");
if (!dir)
err("opendir: %s", strerror(errno));
printf("List USB devices\n");
for (;;) {
struct dirent *dirent;
char *busid;
dirent = readdir(dir);
if (!dirent)
break;
busid = dirent->d_name;
if (is_usb_device(busid)) {
char name[100] = {'\0'};
char driver[100] = {'\0'};
int conf, ninf = 0;
int i;
conf = read_bConfigurationValue(busid);
ninf = read_bNumInterfaces(busid);
getdevicename(busid, name, sizeof(name));
printf(" - busid %s (%s)\n", busid, name);
for (i = 0; i < ninf; i++) {
getdriver(busid, conf, i, driver,
sizeof(driver));
printf(" %s:%d.%d -> %s\n", busid, conf,
i, driver);
}
printf("\n");
}
}
closedir(dir);
return 0;
}
static int show_devices2(void)
{
DIR *dir;
dir = opendir("/sys/bus/usb/devices/");
if (!dir)
err("opendir: %s", strerror(errno));
for (;;) {
struct dirent *dirent;
char *busid;
dirent = readdir(dir);
if (!dirent)
break;
busid = dirent->d_name;
if (is_usb_device(busid)) {
char name[100] = {'\0'};
char driver[100] = {'\0'};
int conf, ninf = 0;
int i;
conf = read_bConfigurationValue(busid);
ninf = read_bNumInterfaces(busid);
getdevicename(busid, name, sizeof(name));
printf("busid=%s#usbid=%s#", busid, name);
for (i = 0; i < ninf; i++) {
getdriver(busid, conf, i, driver, sizeof(driver));
printf("%s:%d.%d=%s#", busid, conf, i, driver);
}
printf("\n");
}
}
closedir(dir);
return 0;
}
int usbip_list(int argc, char *argv[])
{
static const struct option opts[] = {
{ "parsable", no_argument, NULL, 'p' },
{ "remote", required_argument, NULL, 'r' },
{ "local", no_argument, NULL, 'l' },
{ NULL, 0, NULL, 0 }
};
bool is_parsable = false;
int opt;
int ret = -1;
if (usbip_names_init(USBIDS_FILE))
err("failed to open %s\n", USBIDS_FILE);
for (;;) {
opt = getopt_long(argc, argv, "pr:l", opts, NULL);
if (opt == -1)
break;
switch (opt) {
case 'p':
is_parsable = true;
break;
case 'r':
ret = show_exported_devices(optarg);
goto out;
case 'l':
if (is_parsable)
ret = show_devices2();
else
ret = show_devices();
goto out;
default:
goto err_out;
}
}
err_out:
usbip_list_usage();
out:
usbip_names_free();
return ret;
}
/*
* 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/>.
*/
#include <stdio.h>
#include <getopt.h>
#include <unistd.h>
#include "usbip_common.h"
#include "utils.h"
#include "usbip.h"
static const char usbip_unbind_usage_string[] =
"usbip unbind <args>\n"
" -b, --busid=<busid> Unbind " USBIP_HOST_DRV_NAME ".ko from "
"device on <busid>\n";
void usbip_unbind_usage(void)
{
printf("usage: %s", usbip_unbind_usage_string);
}
static int use_device_by_other(char *busid)
{
int rc;
int config;
/* read and write the same config value to kick probing */
config = read_bConfigurationValue(busid);
if (config < 0) {
dbg("read bConfigurationValue of %s, failed", busid);
return -1;
}
rc = modify_match_busid(busid, 0);
if (rc < 0) {
dbg("del %s to match_busid, failed", busid);
return -1;
}
rc = write_bConfigurationValue(busid, config);
if (rc < 0) {
dbg("read bConfigurationValue of %s, failed", busid);
return -1;
}
info("bind %s to other drivers than usbip, complete!", busid);
return 0;
}
int usbip_unbind(int argc, char *argv[])
{
static const struct option opts[] = {
{ "busid", required_argument, NULL, 'b' },
{ NULL, 0, NULL, 0 }
};
int opt;
int ret = -1;
for (;;) {
opt = getopt_long(argc, argv, "b:", opts, NULL);
if (opt == -1)
break;
switch (opt) {
case 'b':
ret = use_device_by_other(optarg);
goto out;
default:
goto err_out;
}
}
err_out:
usbip_unbind_usage();
out:
return ret;
}
......@@ -3,8 +3,61 @@
* Copyright (C) 2005-2007 Takahiro Hirofuchi
*/
#include <sysfs/libsysfs.h>
#include <fcntl.h>
#include <libgen.h>
#include <string.h>
#include <unistd.h>
#include "usbip_common.h"
#include "utils.h"
int modify_match_busid(char *busid, int add)
{
int fd;
int ret;
char buff[BUS_ID_SIZE + 4];
char sysfs_mntpath[SYSFS_PATH_MAX];
char match_busid_path[SYSFS_PATH_MAX];
ret = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX);
if (ret < 0) {
err("sysfs must be mounted");
return -1;
}
snprintf(match_busid_path, sizeof(match_busid_path),
"%s/%s/usb/%s/%s/match_busid", sysfs_mntpath, SYSFS_BUS_NAME,
SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME);
/* BUS_IS_SIZE includes NULL termination? */
if (strnlen(busid, BUS_ID_SIZE) > BUS_ID_SIZE - 1) {
dbg("busid is too long");
return -1;
}
fd = open(match_busid_path, O_WRONLY);
if (fd < 0)
return -1;
if (add)
snprintf(buff, BUS_ID_SIZE + 4, "add %s", busid);
else
snprintf(buff, BUS_ID_SIZE + 4, "del %s", busid);
dbg("write \"%s\" to %s", buff, match_busid_path);
ret = write(fd, buff, sizeof(buff));
if (ret < 0) {
close(fd);
return -1;
}
close(fd);
return 0;
}
int read_integer(char *path)
{
char buff[100];
......@@ -36,7 +89,7 @@ int read_string(char *path, char *string, size_t len)
int ret = 0;
char *p;
bzero(string, len);
memset(string, 0, len);
fd = open(path, O_RDONLY);
if (fd < 0) {
......@@ -122,15 +175,16 @@ int getdriver(char *busid, int conf, int infnum, char *driver, size_t len)
{
char path[PATH_MAX];
char linkto[PATH_MAX];
const char none[] = "none";
int ret;
snprintf(path, PATH_MAX, "/sys/bus/usb/devices/%s:%d.%d/driver", busid, conf, infnum);
/* readlink does not add NULL */
bzero(linkto, sizeof(linkto));
memset(linkto, 0, sizeof(linkto));
ret = readlink(path, linkto, sizeof(linkto)-1);
if (ret < 0) {
strncpy(driver, "none", len);
strncpy(driver, none, len);
return -1;
} else {
strncpy(driver, basename(linkto), len);
......
......@@ -25,6 +25,7 @@
/* Be sync to kernel header */
#define BUS_ID_SIZE 20
int modify_match_busid(char *busid, int add);
int read_string(char *path, char *, size_t len);
int read_integer(char *path);
int getdevicename(char *busid, char *name, size_t len);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment