1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> 4 * 2005-2007 Takahiro Hirofuchi 5 */ 6 7 #include <ctype.h> 8 #include <limits.h> 9 #include <stdint.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 14 #include <getopt.h> 15 #include <unistd.h> 16 17 #include "vhci_driver.h" 18 #include "usbip_common.h" 19 #include "usbip_network.h" 20 #include "usbip.h" 21 22 static const char usbip_detach_usage_string[] = 23 "usbip detach <args>\n" 24 " -p, --port=<port> " USBIP_VHCI_DRV_NAME 25 " port the device is on\n"; 26 27 void usbip_detach_usage(void) 28 { 29 printf("usage: %s", usbip_detach_usage_string); 30 } 31 32 static int detach_port(char *port) 33 { 34 int ret = 0; 35 uint8_t portnum; 36 char path[PATH_MAX+1]; 37 int i; 38 struct usbip_imported_device *idev; 39 int found = 0; 40 41 unsigned int port_len = strlen(port); 42 43 for (unsigned int i = 0; i < port_len; i++) 44 if (!isdigit(port[i])) { 45 err("invalid port %s", port); 46 return -1; 47 } 48 49 portnum = atoi(port); 50 51 ret = usbip_vhci_driver_open(); 52 if (ret < 0) { 53 err("open vhci_driver (is vhci_hcd loaded?)"); 54 return -1; 55 } 56 57 /* check for invalid port */ 58 for (i = 0; i < vhci_driver->nports; i++) { 59 idev = &vhci_driver->idev[i]; 60 61 if (idev->port == portnum) { 62 found = 1; 63 if (idev->status != VDEV_ST_NULL) 64 break; 65 info("Port %d is already detached!\n", idev->port); 66 goto call_driver_close; 67 } 68 } 69 70 if (!found) { 71 err("Invalid port %s > maxports %d", 72 port, vhci_driver->nports); 73 goto call_driver_close; 74 } 75 76 /* remove the port state file */ 77 snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", portnum); 78 79 remove(path); 80 rmdir(VHCI_STATE_PATH); 81 82 ret = usbip_vhci_detach_device(portnum); 83 if (ret < 0) { 84 ret = -1; 85 err("Port %d detach request failed!\n", portnum); 86 goto call_driver_close; 87 } 88 info("Port %d is now detached!\n", portnum); 89 90 call_driver_close: 91 usbip_vhci_driver_close(); 92 93 return ret; 94 } 95 96 int usbip_detach(int argc, char *argv[]) 97 { 98 static const struct option opts[] = { 99 { "port", required_argument, NULL, 'p' }, 100 { NULL, 0, NULL, 0 } 101 }; 102 int opt; 103 int ret = -1; 104 105 for (;;) { 106 opt = getopt_long(argc, argv, "p:", opts, NULL); 107 108 if (opt == -1) 109 break; 110 111 switch (opt) { 112 case 'p': 113 ret = detach_port(optarg); 114 goto out; 115 default: 116 goto err_out; 117 } 118 } 119 120 err_out: 121 usbip_detach_usage(); 122 out: 123 return ret; 124 } 125