Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
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
+6 −5
Original line number Diff line number Diff line
@@ -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
+0 −652
Original line number Diff line number Diff line
/*
 *
 * Copyright (C) 2005-2007 Takahiro Hirofuchi
 */

#define _GNU_SOURCE
#include <getopt.h>
#include <glib.h>

#include "usbip.h"
#include "utils.h"

static const struct option longopts[] = {
	{"usbip",	required_argument,	NULL, 'u'},
	{"other",	required_argument,	NULL, 'o'},
	{"list",	no_argument,		NULL, 'l'},
	{"list2",	no_argument,		NULL, 'L'},
	{"help",	no_argument,		NULL, 'h'},
#if 0
	{"allusbip",	no_argument,		NULL, 'a'},
	{"export-to",   required_argument,	NULL, 'e'},
	{"unexport",    required_argument,	NULL, 'x'},
	{"busid",	required_argument,	NULL, 'b'},
#endif

	{NULL,		0,			NULL,  0}
};

static void show_help(void)
{
	printf("Usage: usbip_bind_driver [OPTION]\n");
	printf("Change driver binding for USB/IP.\n");
	printf("  --usbip busid        make a device exportable\n");
	printf("  --other busid        use a device by a local driver\n");
	printf("  --list               print usb devices and their drivers\n");
	printf("  --list2              print usb devices and their drivers in parseable mode\n");
#if 0
	printf("  --allusbip           make all devices exportable\n");
	printf("  --export-to host     export the device to 'host'\n");
	printf("  --unexport host      unexport a device previously exported to 'host'\n");
	printf("  --busid busid        the busid used for --export-to\n");
#endif
}

static 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) {
		g_warning("too long busid");
		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);

	g_debug("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;
}

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[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) {
		g_warning("opening unbind_path failed: %d", fd);
		return -1;
	}

	ret = write(fd, busid, strnlen(busid, BUS_ID_SIZE));
	if (ret < 0) {
		g_warning("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];
	g_debug("unbinding interface");

	snprintf(inf_busid, BUS_ID_SIZE, "%s:%d.%d", busid, configvalue, interface);

	return unbind_interface_busid(inf_busid);
}


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);
}

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) {
		g_warning("read config and ninf value, removed?");
		return -1;
	}

	if (devclass == 0x09) {
		g_message("skip unbinding of hub");
		return -1;
	}

	for (i = 0; i < ninterface; i++) {
		char driver[PATH_MAX];
		int ret;

		bzero(&driver, sizeof(driver));

		getdriver(busid, configvalue, i, driver, PATH_MAX-1);

		g_debug(" %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) {
			g_warning("unbind driver at %s:%d.%d failed",
					busid, configvalue, i);
			failed = 1;
		}
	}

	if (failed)
		return -1;
	else
		return 0;
}

/* 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) {
		g_warning("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) {
			g_warning("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) {
		g_warning("unbind drivers of %s, failed", busid);
		return -1;
	}

	ret = modify_match_busid(busid, 1);
	if (ret < 0) {
		g_warning("add %s to match_busid, failed", busid);
		return -1;
	}

	ret = bind_to_usbip(busid);
	if (ret < 0) {
		g_warning("bind usbip to %s, failed", busid);
		modify_match_busid(busid, 0);
		return -1;
	}

	g_message("bind %s to usbip, complete!", busid);

	return 0;
}



static int use_device_by_other(char *busid)
{
	int ret;
	int config;

	/* read and write the same config value to kick probing */
	config = read_bConfigurationValue(busid);
	if (config < 0) {
		g_warning("read bConfigurationValue of %s, failed", busid);
		return -1;
	}

	ret = modify_match_busid(busid, 0);
	if (ret < 0) {
		g_warning("del %s to match_busid, failed", busid);
		return -1;
	}

	ret = write_bConfigurationValue(busid, config);
	if (ret < 0) {
		g_warning("read bConfigurationValue of %s, failed", busid);
		return -1;
	}

	g_message("bind %s to other drivers than usbip, complete!", busid);

	return 0;
}


#include <sys/types.h>
#include <regex.h>

#include <errno.h>
#include <string.h>
#include <stdio.h>



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)
		g_error("regcomp: %s\n", strerror(errno));

	ret = regexec(&regex, busid, 0, pmatch, 0);
	if (ret)
		return 0;	/* not matched */

	return 1;
}


#include <dirent.h>
static int show_devices(void)
{
	DIR *dir;

	dir = opendir("/sys/bus/usb/devices/");
	if (!dir)
		g_error("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)
		g_error("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;
}


#if 0
static int export_to(char *host, char *busid) {

	int ret;

	if( host == NULL ) {
		printf( "no host given\n\n");
		show_help();
		return -1;
	}
	if( busid == NULL ) {
		/* XXX print device list and ask for busnumber, if none is
		 * given */
		printf( "no busid given, use --busid switch\n\n");
		show_help();
		return -1;
	}


	ret = use_device_by_usbip(busid);
	if( ret != 0 ) {
		printf( "could not bind driver to usbip\n");
		return -1;
	}

	printf( "DEBUG: exporting device '%s' to '%s'\n", busid, host );
	ret = export_busid_to_host(host, busid); /* usbip_export.[ch] */
	if( ret != 0 ) {
		printf( "could not export device to host\n" );
		printf( "   host: %s, device: %s\n", host, busid );
		use_device_by_other(busid);
		return -1;
	}

	return 0;
}

static int unexport_from(char *host, char *busid) {

	int ret;

	if (!host || !busid)
		g_error("no host or no busid\n");

	g_message("unexport_from: host: '%s', busid: '%s'", host, busid);

	ret = unexport_busid_from_host(host, busid); /* usbip_export.[ch] */
	if( ret != 0 ) {
		err( "could not unexport device from host\n" );
		err( "   host: %s, device: %s\n", host, busid );
	}

	ret = use_device_by_other(busid);
	if (ret < 0)
		g_error("could not unbind device from usbip\n");

	return 0;
}


static int allusbip(void)
{
	DIR *dir;

	dir = opendir("/sys/bus/usb/devices/");
	if (!dir)
		g_error("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))
			continue;

		{
			char name[PATH_MAX];
			int conf, ninf = 0;
			int i;
			int be_local = 0;

			conf = read_bConfigurationValue(busid);
			ninf = read_bNumInterfaces(busid);

			getdevicename(busid, name, sizeof(name));

			for (i = 0; i < ninf; i++) {
				char driver[PATH_MAX];

				getdriver(busid, conf, i, driver, sizeof(driver));
#if 0
				if (strncmp(driver, "usbhid", 6) == 0 || strncmp(driver, "usb-storage", 11) == 0) {
					be_local = 1;
					break;
				}
#endif
			}

			if (be_local == 0)
				use_device_by_usbip(busid);
		}
	}

	closedir(dir);

	return 0;
}
#endif

int main(int argc, char **argv)
{
	char *busid = NULL;
	char *remote_host __attribute__((unused)) = NULL;

	enum {
		cmd_unknown = 0,
		cmd_use_by_usbip,
		cmd_use_by_other,
		cmd_list,
		cmd_list2,
		cmd_allusbip,
		cmd_export_to,
		cmd_unexport,
		cmd_help,
	} cmd = cmd_unknown;

	if (geteuid() != 0)
		g_warning("running non-root?");

	for (;;) {
		int c;
		int index = 0;

		c = getopt_long(argc, argv, "u:o:hlLae:x:b:", longopts, &index);
		if (c == -1)
			break;

		switch (c) {
			case 'u':
				cmd = cmd_use_by_usbip;
				busid = optarg;
				break;
			case 'o' :
				cmd = cmd_use_by_other;
				busid = optarg;
				break;
			case 'l' :
				cmd = cmd_list;
				break;
			case 'L' :
				cmd = cmd_list2;
				break;
			case 'a' :
				cmd = cmd_allusbip;
				break;
			case 'b':
				busid = optarg;
				break;
			case 'e':
				cmd = cmd_export_to;
				remote_host = optarg;
				break;
			case 'x':
				cmd = cmd_unexport;
				remote_host = optarg;
				break;
			case 'h': /* fallthrough */
			case '?':
				cmd = cmd_help;
				break;
			default:
				g_error("getopt");
		}

		//if (cmd)
		//	break;
	}

	switch (cmd) {
		case cmd_use_by_usbip:
			use_device_by_usbip(busid);
			break;
		case cmd_use_by_other:
			use_device_by_other(busid);
			break;
		case cmd_list:
			show_devices();
			break;
		case cmd_list2:
			show_devices2();
			break;
#if 0
		case cmd_allusbip:
			allusbip();
			break;
		case cmd_export_to:
			export_to(remote_host, busid);
			break;
		case cmd_unexport:
			unexport_from(remote_host, busid);
			break;
#endif
		case cmd_help: /* fallthrough */
		case cmd_unknown:
			show_help();
			break;
		default:
			g_error("NOT REACHED");
	}

	return 0;
}
+135 −679

File changed.

Preview size limit exceeded, changes collapsed.

+39 −0
Original line number Diff line number Diff line
/*
 * 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 */
Loading