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
34static 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
39void usbip_detach_usage(void)
40{
41	printf("usage: %s", usbip_detach_usage_string);
42}
43
44static int detach_port(char *port)
45{
46	int ret;
47	uint8_t portnum;
48	char path[PATH_MAX+1];
49
50	for (unsigned int i = 0; i < strlen(port); i++)
51		if (!isdigit(port[i])) {
52			err("invalid port %s", port);
53			return -1;
54		}
55
56	/* check max port */
57
58	portnum = atoi(port);
59
60	/* remove the port state file */
61
62	snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", portnum);
63
64	remove(path);
65	rmdir(VHCI_STATE_PATH);
66
67	ret = usbip_vhci_driver_open();
68	if (ret < 0) {
69		err("open vhci_driver");
70		return -1;
71	}
72
73	ret = usbip_vhci_detach_device(portnum);
74	if (ret < 0)
75		return -1;
76
77	usbip_vhci_driver_close();
78
79	return ret;
80}
81
82int usbip_detach(int argc, char *argv[])
83{
84	static const struct option opts[] = {
85		{ "port", required_argument, NULL, 'p' },
86		{ NULL, 0, NULL, 0 }
87	};
88	int opt;
89	int ret = -1;
90
91	for (;;) {
92		opt = getopt_long(argc, argv, "p:", opts, NULL);
93
94		if (opt == -1)
95			break;
96
97		switch (opt) {
98		case 'p':
99			ret = detach_port(optarg);
100			goto out;
101		default:
102			goto err_out;
103		}
104	}
105
106err_out:
107	usbip_detach_usage();
108out:
109	return ret;
110}
111