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
20static int usbip_help(int argc, char *argv[]);
21static int usbip_version(int argc, char *argv[]);
22
23static const char usbip_version_string[] = PACKAGE_STRING;
24
25static const char usbip_usage_string[] =
26	"usbip [--debug] [--log] [--tcp-port PORT] [version]\n"
27	"             [help] <command> <args>\n";
28
29static void usbip_usage(void)
30{
31	printf("usage: %s", usbip_usage_string);
32}
33
34struct command {
35	const char *name;
36	int (*fn)(int argc, char *argv[]);
37	const char *help;
38	void (*usage)(void);
39};
40
41static 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
93static 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");
114done:
115	return ret;
116}
117
118static 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
127static 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
133int 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);
189out:
190	return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
191}
192