1 /* 2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> 3 * 2005-2007 Takahiro Hirofuchi 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include <ctype.h> 20 #include <limits.h> 21 #include <stdint.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 26 #include <getopt.h> 27 #include <unistd.h> 28 29 #include "vhci_driver.h" 30 #include "usbip_common.h" 31 #include "usbip_network.h" 32 #include "usbip.h" 33 34 static const char usbip_detach_usage_string[] = 35 "usbip detach <args>\n" 36 " -p, --port=<port> " USBIP_VHCI_DRV_NAME 37 " port the device is on\n"; 38 39 void usbip_detach_usage(void) 40 { 41 printf("usage: %s", usbip_detach_usage_string); 42 } 43 44 static int detach_port(char *port) 45 { 46 int ret = 0; 47 uint8_t portnum; 48 char path[PATH_MAX+1]; 49 int i; 50 struct usbip_imported_device *idev; 51 int found = 0; 52 53 unsigned int port_len = strlen(port); 54 55 for (unsigned int i = 0; i < port_len; i++) 56 if (!isdigit(port[i])) { 57 err("invalid port %s", port); 58 return -1; 59 } 60 61 portnum = atoi(port); 62 63 ret = usbip_vhci_driver_open(); 64 if (ret < 0) { 65 err("open vhci_driver"); 66 return -1; 67 } 68 69 /* check for invalid port */ 70 for (i = 0; i < vhci_driver->nports; i++) { 71 idev = &vhci_driver->idev[i]; 72 73 if (idev->port == portnum) { 74 found = 1; 75 if (idev->status != VDEV_ST_NULL) 76 break; 77 info("Port %d is already detached!\n", idev->port); 78 goto call_driver_close; 79 } 80 } 81 82 if (!found) { 83 err("Invalid port %s > maxports %d", 84 port, vhci_driver->nports); 85 goto call_driver_close; 86 } 87 88 /* remove the port state file */ 89 snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", portnum); 90 91 remove(path); 92 rmdir(VHCI_STATE_PATH); 93 94 ret = usbip_vhci_detach_device(portnum); 95 if (ret < 0) { 96 ret = -1; 97 err("Port %d detach request failed!\n", portnum); 98 goto call_driver_close; 99 } 100 info("Port %d is now detached!\n", portnum); 101 102 call_driver_close: 103 usbip_vhci_driver_close(); 104 105 return ret; 106 } 107 108 int usbip_detach(int argc, char *argv[]) 109 { 110 static const struct option opts[] = { 111 { "port", required_argument, NULL, 'p' }, 112 { NULL, 0, NULL, 0 } 113 }; 114 int opt; 115 int ret = -1; 116 117 for (;;) { 118 opt = getopt_long(argc, argv, "p:", opts, NULL); 119 120 if (opt == -1) 121 break; 122 123 switch (opt) { 124 case 'p': 125 ret = detach_port(optarg); 126 goto out; 127 default: 128 goto err_out; 129 } 130 } 131 132 err_out: 133 usbip_detach_usage(); 134 out: 135 return ret; 136 } 137