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