1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * command structure borrowed from udev
4  * (git://git.kernel.org/pub/scm/linux/hotplug/udev.git)
5  *
6  * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
7  *               2005-2007 Takahiro Hirofuchi
8  */
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 
13 #include <getopt.h>
14 #include <syslog.h>
15 
16 #include "usbip_common.h"
17 #include "usbip_network.h"
18 #include "usbip.h"
19 
20 static int usbip_help(int argc, char *argv[]);
21 static int usbip_version(int argc, char *argv[]);
22 
23 static const char usbip_version_string[] = PACKAGE_STRING;
24 
25 static const char usbip_usage_string[] =
26 	"usbip [--debug] [--log] [--tcp-port PORT] [version]\n"
27 	"             [help] <command> <args>\n";
28 
usbip_usage(void)29 static void usbip_usage(void)
30 {
31 	printf("usage: %s", usbip_usage_string);
32 }
33 
34 struct command {
35 	const char *name;
36 	int (*fn)(int argc, char *argv[]);
37 	const char *help;
38 	void (*usage)(void);
39 };
40 
41 static const struct command cmds[] = {
42 	{
43 		.name  = "help",
44 		.fn    = usbip_help,
45 		.help  = NULL,
46 		.usage = NULL
47 	},
48 	{
49 		.name  = "version",
50 		.fn    = usbip_version,
51 		.help  = NULL,
52 		.usage = NULL
53 	},
54 	{
55 		.name  = "attach",
56 		.fn    = usbip_attach,
57 		.help  = "Attach a remote USB device",
58 		.usage = usbip_attach_usage
59 	},
60 	{
61 		.name  = "detach",
62 		.fn    = usbip_detach,
63 		.help  = "Detach a remote USB device",
64 		.usage = usbip_detach_usage
65 	},
66 	{
67 		.name  = "list",
68 		.fn    = usbip_list,
69 		.help  = "List exportable or local USB devices",
70 		.usage = usbip_list_usage
71 	},
72 	{
73 		.name  = "bind",
74 		.fn    = usbip_bind,
75 		.help  = "Bind device to " USBIP_HOST_DRV_NAME ".ko",
76 		.usage = usbip_bind_usage
77 	},
78 	{
79 		.name  = "unbind",
80 		.fn    = usbip_unbind,
81 		.help  = "Unbind device from " USBIP_HOST_DRV_NAME ".ko",
82 		.usage = usbip_unbind_usage
83 	},
84 	{
85 		.name  = "port",
86 		.fn    = usbip_port_show,
87 		.help  = "Show imported USB devices",
88 		.usage = NULL
89 	},
90 	{ NULL, NULL, NULL, NULL }
91 };
92 
usbip_help(int argc,char * argv[])93 static int usbip_help(int argc, char *argv[])
94 {
95 	const struct command *cmd;
96 	int i;
97 	int ret = 0;
98 
99 	if (argc > 1 && argv++) {
100 		for (i = 0; cmds[i].name != NULL; i++)
101 			if (!strcmp(cmds[i].name, argv[0]) && cmds[i].usage) {
102 				cmds[i].usage();
103 				goto done;
104 			}
105 		ret = -1;
106 	}
107 
108 	usbip_usage();
109 	printf("\n");
110 	for (cmd = cmds; cmd->name != NULL; cmd++)
111 		if (cmd->help != NULL)
112 			printf("  %-10s %s\n", cmd->name, cmd->help);
113 	printf("\n");
114 done:
115 	return ret;
116 }
117 
usbip_version(int argc,char * argv[])118 static int usbip_version(int argc, char *argv[])
119 {
120 	(void) argc;
121 	(void) argv;
122 
123 	printf(PROGNAME " (%s)\n", usbip_version_string);
124 	return 0;
125 }
126 
run_command(const struct command * cmd,int argc,char * argv[])127 static int run_command(const struct command *cmd, int argc, char *argv[])
128 {
129 	dbg("running command: `%s'", cmd->name);
130 	return cmd->fn(argc, argv);
131 }
132 
main(int argc,char * argv[])133 int main(int argc, char *argv[])
134 {
135 	static const struct option opts[] = {
136 		{ "debug",    no_argument,       NULL, 'd' },
137 		{ "log",      no_argument,       NULL, 'l' },
138 		{ "tcp-port", required_argument, NULL, 't' },
139 		{ NULL,       0,                 NULL,  0  }
140 	};
141 
142 	char *cmd;
143 	int opt;
144 	int i, rc = -1;
145 
146 	usbip_use_stderr = 1;
147 	opterr = 0;
148 	for (;;) {
149 		opt = getopt_long(argc, argv, "+dlt:", opts, NULL);
150 
151 		if (opt == -1)
152 			break;
153 
154 		switch (opt) {
155 		case 'd':
156 			usbip_use_debug = 1;
157 			break;
158 		case 'l':
159 			usbip_use_syslog = 1;
160 			openlog("", LOG_PID, LOG_USER);
161 			break;
162 		case 't':
163 			usbip_setup_port_number(optarg);
164 			break;
165 		case '?':
166 			printf("usbip: invalid option\n");
167 			/* Terminate after printing error */
168 			/* FALLTHRU */
169 		default:
170 			usbip_usage();
171 			goto out;
172 		}
173 	}
174 
175 	cmd = argv[optind];
176 	if (cmd) {
177 		for (i = 0; cmds[i].name != NULL; i++)
178 			if (!strcmp(cmds[i].name, cmd)) {
179 				argc -= optind;
180 				argv += optind;
181 				optind = 0;
182 				rc = run_command(&cmds[i], argc, argv);
183 				goto out;
184 			}
185 	}
186 
187 	/* invalid command */
188 	usbip_help(0, NULL);
189 out:
190 	return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
191 }
192