130 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>4 * 2005-2007 Takahiro Hirofuchi5 */6 7#include <libudev.h>8 9#include <errno.h>10#include <stdio.h>11#include <string.h>12 13#include <getopt.h>14 15#include "usbip_common.h"16#include "utils.h"17#include "usbip.h"18#include "sysfs_utils.h"19 20static const char usbip_unbind_usage_string[] =21 "usbip unbind <args>\n"22 " -b, --busid=<busid> Unbind " USBIP_HOST_DRV_NAME ".ko from "23 "device on <busid>\n";24 25void usbip_unbind_usage(void)26{27 printf("usage: %s", usbip_unbind_usage_string);28}29 30static int unbind_device(char *busid)31{32 char bus_type[] = "usb";33 int rc, ret = -1;34 35 char unbind_attr_name[] = "unbind";36 char unbind_attr_path[SYSFS_PATH_MAX];37 char rebind_attr_name[] = "rebind";38 char rebind_attr_path[SYSFS_PATH_MAX];39 40 struct udev *udev;41 struct udev_device *dev;42 const char *driver;43 44 /* Create libudev context. */45 udev = udev_new();46 47 /* Check whether the device with this bus ID exists. */48 dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);49 if (!dev) {50 err("device with the specified bus ID does not exist");51 goto err_close_udev;52 }53 54 /* Check whether the device is using usbip-host driver. */55 driver = udev_device_get_driver(dev);56 if (!driver || strcmp(driver, "usbip-host")) {57 err("device is not bound to usbip-host driver");58 goto err_close_udev;59 }60 61 /* Unbind device from driver. */62 snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",63 SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,64 USBIP_HOST_DRV_NAME, unbind_attr_name);65 66 rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid));67 if (rc < 0) {68 err("error unbinding device %s from driver", busid);69 goto err_close_udev;70 }71 72 /* Notify driver of unbind. */73 rc = modify_match_busid(busid, 0);74 if (rc < 0) {75 err("unable to unbind device on %s", busid);76 goto err_close_udev;77 }78 79 /* Trigger new probing. */80 snprintf(rebind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",81 SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,82 USBIP_HOST_DRV_NAME, rebind_attr_name);83 84 rc = write_sysfs_attribute(rebind_attr_path, busid, strlen(busid));85 if (rc < 0) {86 err("error rebinding");87 goto err_close_udev;88 }89 90 ret = 0;91 info("unbind device on busid %s: complete", busid);92 93err_close_udev:94 udev_device_unref(dev);95 udev_unref(udev);96 97 return ret;98}99 100int usbip_unbind(int argc, char *argv[])101{102 static const struct option opts[] = {103 { "busid", required_argument, NULL, 'b' },104 { NULL, 0, NULL, 0 }105 };106 107 int opt;108 int ret = -1;109 110 for (;;) {111 opt = getopt_long(argc, argv, "b:", opts, NULL);112 113 if (opt == -1)114 break;115 116 switch (opt) {117 case 'b':118 ret = unbind_device(optarg);119 goto out;120 default:121 goto err_out;122 }123 }124 125err_out:126 usbip_unbind_usage();127out:128 return ret;129}130