162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * command structure borrowed from udev
462306a36Sopenharmony_ci * (git://git.kernel.org/pub/scm/linux/hotplug/udev.git)
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
762306a36Sopenharmony_ci *               2005-2007 Takahiro Hirofuchi
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <stdio.h>
1162306a36Sopenharmony_ci#include <stdlib.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <getopt.h>
1462306a36Sopenharmony_ci#include <syslog.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "usbip_common.h"
1762306a36Sopenharmony_ci#include "usbip_network.h"
1862306a36Sopenharmony_ci#include "usbip.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic int usbip_help(int argc, char *argv[]);
2162306a36Sopenharmony_cistatic int usbip_version(int argc, char *argv[]);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic const char usbip_version_string[] = PACKAGE_STRING;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic const char usbip_usage_string[] =
2662306a36Sopenharmony_ci	"usbip [--debug] [--log] [--tcp-port PORT] [version]\n"
2762306a36Sopenharmony_ci	"             [help] <command> <args>\n";
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic void usbip_usage(void)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	printf("usage: %s", usbip_usage_string);
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistruct command {
3562306a36Sopenharmony_ci	const char *name;
3662306a36Sopenharmony_ci	int (*fn)(int argc, char *argv[]);
3762306a36Sopenharmony_ci	const char *help;
3862306a36Sopenharmony_ci	void (*usage)(void);
3962306a36Sopenharmony_ci};
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic const struct command cmds[] = {
4262306a36Sopenharmony_ci	{
4362306a36Sopenharmony_ci		.name  = "help",
4462306a36Sopenharmony_ci		.fn    = usbip_help,
4562306a36Sopenharmony_ci		.help  = NULL,
4662306a36Sopenharmony_ci		.usage = NULL
4762306a36Sopenharmony_ci	},
4862306a36Sopenharmony_ci	{
4962306a36Sopenharmony_ci		.name  = "version",
5062306a36Sopenharmony_ci		.fn    = usbip_version,
5162306a36Sopenharmony_ci		.help  = NULL,
5262306a36Sopenharmony_ci		.usage = NULL
5362306a36Sopenharmony_ci	},
5462306a36Sopenharmony_ci	{
5562306a36Sopenharmony_ci		.name  = "attach",
5662306a36Sopenharmony_ci		.fn    = usbip_attach,
5762306a36Sopenharmony_ci		.help  = "Attach a remote USB device",
5862306a36Sopenharmony_ci		.usage = usbip_attach_usage
5962306a36Sopenharmony_ci	},
6062306a36Sopenharmony_ci	{
6162306a36Sopenharmony_ci		.name  = "detach",
6262306a36Sopenharmony_ci		.fn    = usbip_detach,
6362306a36Sopenharmony_ci		.help  = "Detach a remote USB device",
6462306a36Sopenharmony_ci		.usage = usbip_detach_usage
6562306a36Sopenharmony_ci	},
6662306a36Sopenharmony_ci	{
6762306a36Sopenharmony_ci		.name  = "list",
6862306a36Sopenharmony_ci		.fn    = usbip_list,
6962306a36Sopenharmony_ci		.help  = "List exportable or local USB devices",
7062306a36Sopenharmony_ci		.usage = usbip_list_usage
7162306a36Sopenharmony_ci	},
7262306a36Sopenharmony_ci	{
7362306a36Sopenharmony_ci		.name  = "bind",
7462306a36Sopenharmony_ci		.fn    = usbip_bind,
7562306a36Sopenharmony_ci		.help  = "Bind device to " USBIP_HOST_DRV_NAME ".ko",
7662306a36Sopenharmony_ci		.usage = usbip_bind_usage
7762306a36Sopenharmony_ci	},
7862306a36Sopenharmony_ci	{
7962306a36Sopenharmony_ci		.name  = "unbind",
8062306a36Sopenharmony_ci		.fn    = usbip_unbind,
8162306a36Sopenharmony_ci		.help  = "Unbind device from " USBIP_HOST_DRV_NAME ".ko",
8262306a36Sopenharmony_ci		.usage = usbip_unbind_usage
8362306a36Sopenharmony_ci	},
8462306a36Sopenharmony_ci	{
8562306a36Sopenharmony_ci		.name  = "port",
8662306a36Sopenharmony_ci		.fn    = usbip_port_show,
8762306a36Sopenharmony_ci		.help  = "Show imported USB devices",
8862306a36Sopenharmony_ci		.usage = NULL
8962306a36Sopenharmony_ci	},
9062306a36Sopenharmony_ci	{ NULL, NULL, NULL, NULL }
9162306a36Sopenharmony_ci};
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic int usbip_help(int argc, char *argv[])
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	const struct command *cmd;
9662306a36Sopenharmony_ci	int i;
9762306a36Sopenharmony_ci	int ret = 0;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	if (argc > 1 && argv++) {
10062306a36Sopenharmony_ci		for (i = 0; cmds[i].name != NULL; i++)
10162306a36Sopenharmony_ci			if (!strcmp(cmds[i].name, argv[0]) && cmds[i].usage) {
10262306a36Sopenharmony_ci				cmds[i].usage();
10362306a36Sopenharmony_ci				goto done;
10462306a36Sopenharmony_ci			}
10562306a36Sopenharmony_ci		ret = -1;
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	usbip_usage();
10962306a36Sopenharmony_ci	printf("\n");
11062306a36Sopenharmony_ci	for (cmd = cmds; cmd->name != NULL; cmd++)
11162306a36Sopenharmony_ci		if (cmd->help != NULL)
11262306a36Sopenharmony_ci			printf("  %-10s %s\n", cmd->name, cmd->help);
11362306a36Sopenharmony_ci	printf("\n");
11462306a36Sopenharmony_cidone:
11562306a36Sopenharmony_ci	return ret;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic int usbip_version(int argc, char *argv[])
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	(void) argc;
12162306a36Sopenharmony_ci	(void) argv;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	printf(PROGNAME " (%s)\n", usbip_version_string);
12462306a36Sopenharmony_ci	return 0;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic int run_command(const struct command *cmd, int argc, char *argv[])
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	dbg("running command: `%s'", cmd->name);
13062306a36Sopenharmony_ci	return cmd->fn(argc, argv);
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ciint main(int argc, char *argv[])
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	static const struct option opts[] = {
13662306a36Sopenharmony_ci		{ "debug",    no_argument,       NULL, 'd' },
13762306a36Sopenharmony_ci		{ "log",      no_argument,       NULL, 'l' },
13862306a36Sopenharmony_ci		{ "tcp-port", required_argument, NULL, 't' },
13962306a36Sopenharmony_ci		{ NULL,       0,                 NULL,  0  }
14062306a36Sopenharmony_ci	};
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	char *cmd;
14362306a36Sopenharmony_ci	int opt;
14462306a36Sopenharmony_ci	int i, rc = -1;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	usbip_use_stderr = 1;
14762306a36Sopenharmony_ci	opterr = 0;
14862306a36Sopenharmony_ci	for (;;) {
14962306a36Sopenharmony_ci		opt = getopt_long(argc, argv, "+dlt:", opts, NULL);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci		if (opt == -1)
15262306a36Sopenharmony_ci			break;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci		switch (opt) {
15562306a36Sopenharmony_ci		case 'd':
15662306a36Sopenharmony_ci			usbip_use_debug = 1;
15762306a36Sopenharmony_ci			break;
15862306a36Sopenharmony_ci		case 'l':
15962306a36Sopenharmony_ci			usbip_use_syslog = 1;
16062306a36Sopenharmony_ci			openlog("", LOG_PID, LOG_USER);
16162306a36Sopenharmony_ci			break;
16262306a36Sopenharmony_ci		case 't':
16362306a36Sopenharmony_ci			usbip_setup_port_number(optarg);
16462306a36Sopenharmony_ci			break;
16562306a36Sopenharmony_ci		case '?':
16662306a36Sopenharmony_ci			printf("usbip: invalid option\n");
16762306a36Sopenharmony_ci			/* Terminate after printing error */
16862306a36Sopenharmony_ci			/* FALLTHRU */
16962306a36Sopenharmony_ci		default:
17062306a36Sopenharmony_ci			usbip_usage();
17162306a36Sopenharmony_ci			goto out;
17262306a36Sopenharmony_ci		}
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	cmd = argv[optind];
17662306a36Sopenharmony_ci	if (cmd) {
17762306a36Sopenharmony_ci		for (i = 0; cmds[i].name != NULL; i++)
17862306a36Sopenharmony_ci			if (!strcmp(cmds[i].name, cmd)) {
17962306a36Sopenharmony_ci				argc -= optind;
18062306a36Sopenharmony_ci				argv += optind;
18162306a36Sopenharmony_ci				optind = 0;
18262306a36Sopenharmony_ci				rc = run_command(&cmds[i], argc, argv);
18362306a36Sopenharmony_ci				goto out;
18462306a36Sopenharmony_ci			}
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	/* invalid command */
18862306a36Sopenharmony_ci	usbip_help(0, NULL);
18962306a36Sopenharmony_ciout:
19062306a36Sopenharmony_ci	return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
19162306a36Sopenharmony_ci}
192