123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- /*
- * 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 <libudev.h>
- #include <errno.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <getopt.h>
- #include "usbip_common.h"
- #include "utils.h"
- #include "usbip.h"
- #include "sysfs_utils.h"
- enum unbind_status {
- UNBIND_ST_OK,
- UNBIND_ST_USBIP_HOST,
- UNBIND_ST_FAILED
- };
- 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);
- }
- /* call at unbound state */
- static int bind_usbip(char *busid)
- {
- char attr_name[] = "bind";
- char bind_attr_path[SYSFS_PATH_MAX];
- int rc = -1;
- snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s",
- SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
- SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name);
- rc = write_sysfs_attribute(bind_attr_path, busid, strlen(busid));
- if (rc < 0) {
- err("error binding device %s to driver: %s", busid,
- strerror(errno));
- return -1;
- }
- return 0;
- }
- /* buggy driver may cause dead lock */
- static int unbind_other(char *busid)
- {
- enum unbind_status status = UNBIND_ST_OK;
- char attr_name[] = "unbind";
- char unbind_attr_path[SYSFS_PATH_MAX];
- int rc = -1;
- struct udev *udev;
- struct udev_device *dev;
- const char *driver;
- const char *bDevClass;
- /* Create libudev context. */
- udev = udev_new();
- /* Get the device. */
- dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
- if (!dev) {
- dbg("unable to find device with bus ID %s", busid);
- goto err_close_busid_dev;
- }
- /* Check what kind of device it is. */
- bDevClass = udev_device_get_sysattr_value(dev, "bDeviceClass");
- if (!bDevClass) {
- dbg("unable to get bDevClass device attribute");
- goto err_close_busid_dev;
- }
- if (!strncmp(bDevClass, "09", strlen(bDevClass))) {
- dbg("skip unbinding of hub");
- goto err_close_busid_dev;
- }
- /* Get the device driver. */
- driver = udev_device_get_driver(dev);
- if (!driver) {
- /* No driver bound to this device. */
- goto out;
- }
- if (!strncmp(USBIP_HOST_DRV_NAME, driver,
- strlen(USBIP_HOST_DRV_NAME))) {
- /* Already bound to usbip-host. */
- status = UNBIND_ST_USBIP_HOST;
- goto out;
- }
- /* Unbind device from driver. */
- snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
- SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
- SYSFS_DRIVERS_NAME, driver, attr_name);
- rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid));
- if (rc < 0) {
- err("error unbinding device %s from driver", busid);
- goto err_close_busid_dev;
- }
- goto out;
- err_close_busid_dev:
- status = UNBIND_ST_FAILED;
- out:
- udev_device_unref(dev);
- udev_unref(udev);
- return status;
- }
- static int bind_device(char *busid)
- {
- int rc;
- struct udev *udev;
- struct udev_device *dev;
- /* Check whether the device with this bus ID exists. */
- udev = udev_new();
- dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
- if (!dev) {
- err("device with the specified bus ID does not exist");
- return -1;
- }
- udev_unref(udev);
- rc = unbind_other(busid);
- if (rc == UNBIND_ST_FAILED) {
- err("could not unbind driver from device on busid %s", busid);
- return -1;
- } else if (rc == UNBIND_ST_USBIP_HOST) {
- err("device on busid %s is already bound to %s", busid,
- USBIP_HOST_DRV_NAME);
- return -1;
- }
- rc = modify_match_busid(busid, 1);
- if (rc < 0) {
- err("unable to bind device on %s", busid);
- return -1;
- }
- rc = bind_usbip(busid);
- if (rc < 0) {
- err("could not bind device to %s", USBIP_HOST_DRV_NAME);
- modify_match_busid(busid, 0);
- return -1;
- }
- info("bind device on busid %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 = bind_device(optarg);
- goto out;
- default:
- goto err_out;
- }
- }
- err_out:
- usbip_bind_usage();
- out:
- return ret;
- }
|