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 ret = -1; 72 err("Invalid port %s > maxports %d", 73 port, vhci_driver->nports); 74 goto call_driver_close; 75 } 76 77 /* remove the port state file */ 78 snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", portnum); 79 80 remove(path); 81 rmdir(VHCI_STATE_PATH); 82 83 ret = usbip_vhci_detach_device(portnum); 84 if (ret < 0) { 85 ret = -1; 86 err("Port %d detach request failed!\n", portnum); 87 goto call_driver_close; 88 } 89 info("Port %d is now detached!\n", portnum); 90 91 call_driver_close: 92 usbip_vhci_driver_close(); 93 94 return ret; 95 } 96 97 int usbip_detach(int argc, char *argv[]) 98 { 99 static const struct option opts[] = { 100 { "port", required_argument, NULL, 'p' }, 101 { NULL, 0, NULL, 0 } 102 }; 103 int opt; 104 int ret = -1; 105 106 for (;;) { 107 opt = getopt_long(argc, argv, "p:", opts, NULL); 108 109 if (opt == -1) 110 break; 111 112 switch (opt) { 113 case 'p': 114 ret = detach_port(optarg); 115 goto out; 116 default: 117 goto err_out; 118 } 119 } 120 121 err_out: 122 usbip_detach_usage(); 123 out: 124 return ret; 125 } 126