18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * command structure borrowed from udev
48c2ecf20Sopenharmony_ci * (git://git.kernel.org/pub/scm/linux/hotplug/udev.git)
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
78c2ecf20Sopenharmony_ci *               2005-2007 Takahiro Hirofuchi
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <stdio.h>
118c2ecf20Sopenharmony_ci#include <stdlib.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <getopt.h>
148c2ecf20Sopenharmony_ci#include <syslog.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include "usbip_common.h"
178c2ecf20Sopenharmony_ci#include "usbip_network.h"
188c2ecf20Sopenharmony_ci#include "usbip.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic int usbip_help(int argc, char *argv[]);
218c2ecf20Sopenharmony_cistatic int usbip_version(int argc, char *argv[]);
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic const char usbip_version_string[] = PACKAGE_STRING;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic const char usbip_usage_string[] =
268c2ecf20Sopenharmony_ci	"usbip [--debug] [--log] [--tcp-port PORT] [version]\n"
278c2ecf20Sopenharmony_ci	"             [help] <command> <args>\n";
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic void usbip_usage(void)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	printf("usage: %s", usbip_usage_string);
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistruct command {
358c2ecf20Sopenharmony_ci	const char *name;
368c2ecf20Sopenharmony_ci	int (*fn)(int argc, char *argv[]);
378c2ecf20Sopenharmony_ci	const char *help;
388c2ecf20Sopenharmony_ci	void (*usage)(void);
398c2ecf20Sopenharmony_ci};
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic const struct command cmds[] = {
428c2ecf20Sopenharmony_ci	{
438c2ecf20Sopenharmony_ci		.name  = "help",
448c2ecf20Sopenharmony_ci		.fn    = usbip_help,
458c2ecf20Sopenharmony_ci		.help  = NULL,
468c2ecf20Sopenharmony_ci		.usage = NULL
478c2ecf20Sopenharmony_ci	},
488c2ecf20Sopenharmony_ci	{
498c2ecf20Sopenharmony_ci		.name  = "version",
508c2ecf20Sopenharmony_ci		.fn    = usbip_version,
518c2ecf20Sopenharmony_ci		.help  = NULL,
528c2ecf20Sopenharmony_ci		.usage = NULL
538c2ecf20Sopenharmony_ci	},
548c2ecf20Sopenharmony_ci	{
558c2ecf20Sopenharmony_ci		.name  = "attach",
568c2ecf20Sopenharmony_ci		.fn    = usbip_attach,
578c2ecf20Sopenharmony_ci		.help  = "Attach a remote USB device",
588c2ecf20Sopenharmony_ci		.usage = usbip_attach_usage
598c2ecf20Sopenharmony_ci	},
608c2ecf20Sopenharmony_ci	{
618c2ecf20Sopenharmony_ci		.name  = "detach",
628c2ecf20Sopenharmony_ci		.fn    = usbip_detach,
638c2ecf20Sopenharmony_ci		.help  = "Detach a remote USB device",
648c2ecf20Sopenharmony_ci		.usage = usbip_detach_usage
658c2ecf20Sopenharmony_ci	},
668c2ecf20Sopenharmony_ci	{
678c2ecf20Sopenharmony_ci		.name  = "list",
688c2ecf20Sopenharmony_ci		.fn    = usbip_list,
698c2ecf20Sopenharmony_ci		.help  = "List exportable or local USB devices",
708c2ecf20Sopenharmony_ci		.usage = usbip_list_usage
718c2ecf20Sopenharmony_ci	},
728c2ecf20Sopenharmony_ci	{
738c2ecf20Sopenharmony_ci		.name  = "bind",
748c2ecf20Sopenharmony_ci		.fn    = usbip_bind,
758c2ecf20Sopenharmony_ci		.help  = "Bind device to " USBIP_HOST_DRV_NAME ".ko",
768c2ecf20Sopenharmony_ci		.usage = usbip_bind_usage
778c2ecf20Sopenharmony_ci	},
788c2ecf20Sopenharmony_ci	{
798c2ecf20Sopenharmony_ci		.name  = "unbind",
808c2ecf20Sopenharmony_ci		.fn    = usbip_unbind,
818c2ecf20Sopenharmony_ci		.help  = "Unbind device from " USBIP_HOST_DRV_NAME ".ko",
828c2ecf20Sopenharmony_ci		.usage = usbip_unbind_usage
838c2ecf20Sopenharmony_ci	},
848c2ecf20Sopenharmony_ci	{
858c2ecf20Sopenharmony_ci		.name  = "port",
868c2ecf20Sopenharmony_ci		.fn    = usbip_port_show,
878c2ecf20Sopenharmony_ci		.help  = "Show imported USB devices",
888c2ecf20Sopenharmony_ci		.usage = NULL
898c2ecf20Sopenharmony_ci	},
908c2ecf20Sopenharmony_ci	{ NULL, NULL, NULL, NULL }
918c2ecf20Sopenharmony_ci};
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic int usbip_help(int argc, char *argv[])
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	const struct command *cmd;
968c2ecf20Sopenharmony_ci	int i;
978c2ecf20Sopenharmony_ci	int ret = 0;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (argc > 1 && argv++) {
1008c2ecf20Sopenharmony_ci		for (i = 0; cmds[i].name != NULL; i++)
1018c2ecf20Sopenharmony_ci			if (!strcmp(cmds[i].name, argv[0]) && cmds[i].usage) {
1028c2ecf20Sopenharmony_ci				cmds[i].usage();
1038c2ecf20Sopenharmony_ci				goto done;
1048c2ecf20Sopenharmony_ci			}
1058c2ecf20Sopenharmony_ci		ret = -1;
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	usbip_usage();
1098c2ecf20Sopenharmony_ci	printf("\n");
1108c2ecf20Sopenharmony_ci	for (cmd = cmds; cmd->name != NULL; cmd++)
1118c2ecf20Sopenharmony_ci		if (cmd->help != NULL)
1128c2ecf20Sopenharmony_ci			printf("  %-10s %s\n", cmd->name, cmd->help);
1138c2ecf20Sopenharmony_ci	printf("\n");
1148c2ecf20Sopenharmony_cidone:
1158c2ecf20Sopenharmony_ci	return ret;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic int usbip_version(int argc, char *argv[])
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	(void) argc;
1218c2ecf20Sopenharmony_ci	(void) argv;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	printf(PROGNAME " (%s)\n", usbip_version_string);
1248c2ecf20Sopenharmony_ci	return 0;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic int run_command(const struct command *cmd, int argc, char *argv[])
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	dbg("running command: `%s'", cmd->name);
1308c2ecf20Sopenharmony_ci	return cmd->fn(argc, argv);
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ciint main(int argc, char *argv[])
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	static const struct option opts[] = {
1368c2ecf20Sopenharmony_ci		{ "debug",    no_argument,       NULL, 'd' },
1378c2ecf20Sopenharmony_ci		{ "log",      no_argument,       NULL, 'l' },
1388c2ecf20Sopenharmony_ci		{ "tcp-port", required_argument, NULL, 't' },
1398c2ecf20Sopenharmony_ci		{ NULL,       0,                 NULL,  0  }
1408c2ecf20Sopenharmony_ci	};
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	char *cmd;
1438c2ecf20Sopenharmony_ci	int opt;
1448c2ecf20Sopenharmony_ci	int i, rc = -1;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	usbip_use_stderr = 1;
1478c2ecf20Sopenharmony_ci	opterr = 0;
1488c2ecf20Sopenharmony_ci	for (;;) {
1498c2ecf20Sopenharmony_ci		opt = getopt_long(argc, argv, "+dlt:", opts, NULL);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci		if (opt == -1)
1528c2ecf20Sopenharmony_ci			break;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci		switch (opt) {
1558c2ecf20Sopenharmony_ci		case 'd':
1568c2ecf20Sopenharmony_ci			usbip_use_debug = 1;
1578c2ecf20Sopenharmony_ci			break;
1588c2ecf20Sopenharmony_ci		case 'l':
1598c2ecf20Sopenharmony_ci			usbip_use_syslog = 1;
1608c2ecf20Sopenharmony_ci			openlog("", LOG_PID, LOG_USER);
1618c2ecf20Sopenharmony_ci			break;
1628c2ecf20Sopenharmony_ci		case 't':
1638c2ecf20Sopenharmony_ci			usbip_setup_port_number(optarg);
1648c2ecf20Sopenharmony_ci			break;
1658c2ecf20Sopenharmony_ci		case '?':
1668c2ecf20Sopenharmony_ci			printf("usbip: invalid option\n");
1678c2ecf20Sopenharmony_ci			/* Terminate after printing error */
1688c2ecf20Sopenharmony_ci			/* FALLTHRU */
1698c2ecf20Sopenharmony_ci		default:
1708c2ecf20Sopenharmony_ci			usbip_usage();
1718c2ecf20Sopenharmony_ci			goto out;
1728c2ecf20Sopenharmony_ci		}
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	cmd = argv[optind];
1768c2ecf20Sopenharmony_ci	if (cmd) {
1778c2ecf20Sopenharmony_ci		for (i = 0; cmds[i].name != NULL; i++)
1788c2ecf20Sopenharmony_ci			if (!strcmp(cmds[i].name, cmd)) {
1798c2ecf20Sopenharmony_ci				argc -= optind;
1808c2ecf20Sopenharmony_ci				argv += optind;
1818c2ecf20Sopenharmony_ci				optind = 0;
1828c2ecf20Sopenharmony_ci				rc = run_command(&cmds[i], argc, argv);
1838c2ecf20Sopenharmony_ci				goto out;
1848c2ecf20Sopenharmony_ci			}
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	/* invalid command */
1888c2ecf20Sopenharmony_ci	usbip_help(0, NULL);
1898c2ecf20Sopenharmony_ciout:
1908c2ecf20Sopenharmony_ci	return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
1918c2ecf20Sopenharmony_ci}
192