root/tools/usb/usbip/src/usbip.c
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * command structure borrowed from udev
 * (git://git.kernel.org/pub/scm/linux/hotplug/udev.git)
 *
 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
 *               2005-2007 Takahiro Hirofuchi
 */

#include <stdio.h>
#include <stdlib.h>

#include <getopt.h>
#include <syslog.h>

#include "usbip_common.h"
#include "usbip_network.h"
#include "usbip.h"

static int usbip_help(int argc, char *argv[]);
static int usbip_version(int argc, char *argv[]);

static const char usbip_version_string[] = PACKAGE_STRING;

static const char usbip_usage_string[] =
        "usbip [--debug] [--log] [--tcp-port PORT] [version]\n"
        "             [help] <command> <args>\n";

static void usbip_usage(void)
{
        printf("usage: %s", usbip_usage_string);
}

struct command {
        const char *name;
        int (*fn)(int argc, char *argv[]);
        const char *help;
        void (*usage)(void);
};

static const struct command cmds[] = {
        {
                .name  = "help",
                .fn    = usbip_help,
                .help  = NULL,
                .usage = NULL
        },
        {
                .name  = "version",
                .fn    = usbip_version,
                .help  = NULL,
                .usage = NULL
        },
        {
                .name  = "attach",
                .fn    = usbip_attach,
                .help  = "Attach a remote USB device",
                .usage = usbip_attach_usage
        },
        {
                .name  = "detach",
                .fn    = usbip_detach,
                .help  = "Detach a remote USB device",
                .usage = usbip_detach_usage
        },
        {
                .name  = "list",
                .fn    = usbip_list,
                .help  = "List exportable or local USB devices",
                .usage = usbip_list_usage
        },
        {
                .name  = "bind",
                .fn    = usbip_bind,
                .help  = "Bind device to " USBIP_HOST_DRV_NAME ".ko",
                .usage = usbip_bind_usage
        },
        {
                .name  = "unbind",
                .fn    = usbip_unbind,
                .help  = "Unbind device from " USBIP_HOST_DRV_NAME ".ko",
                .usage = usbip_unbind_usage
        },
        {
                .name  = "port",
                .fn    = usbip_port_show,
                .help  = "Show imported USB devices",
                .usage = NULL
        },
        { NULL, NULL, NULL, NULL }
};

static int usbip_help(int argc, char *argv[])
{
        const struct command *cmd;
        int i;
        int ret = 0;

        if (argc > 1 && argv++) {
                for (i = 0; cmds[i].name != NULL; i++)
                        if (!strcmp(cmds[i].name, argv[0]) && cmds[i].usage) {
                                cmds[i].usage();
                                goto done;
                        }
                ret = -1;
        }

        usbip_usage();
        printf("\n");
        for (cmd = cmds; cmd->name != NULL; cmd++)
                if (cmd->help != NULL)
                        printf("  %-10s %s\n", cmd->name, cmd->help);
        printf("\n");
done:
        return ret;
}

static int usbip_version(int argc, char *argv[])
{
        (void) argc;
        (void) argv;

        printf(PROGNAME " (%s)\n", usbip_version_string);
        return 0;
}

static int run_command(const struct command *cmd, int argc, char *argv[])
{
        dbg("running command: `%s'", cmd->name);
        return cmd->fn(argc, argv);
}

int main(int argc, char *argv[])
{
        static const struct option opts[] = {
                { "debug",    no_argument,       NULL, 'd' },
                { "log",      no_argument,       NULL, 'l' },
                { "tcp-port", required_argument, NULL, 't' },
                { NULL,       0,                 NULL,  0  }
        };

        char *cmd;
        int opt;
        int i, rc = -1;

        usbip_use_stderr = 1;
        opterr = 0;
        for (;;) {
                opt = getopt_long(argc, argv, "+dlt:", opts, NULL);

                if (opt == -1)
                        break;

                switch (opt) {
                case 'd':
                        usbip_use_debug = 1;
                        break;
                case 'l':
                        usbip_use_syslog = 1;
                        openlog("", LOG_PID, LOG_USER);
                        break;
                case 't':
                        usbip_setup_port_number(optarg);
                        break;
                case '?':
                        printf("usbip: invalid option\n");
                        /* Terminate after printing error */
                        /* FALLTHRU */
                default:
                        usbip_usage();
                        goto out;
                }
        }

        cmd = argv[optind];
        if (cmd) {
                for (i = 0; cmds[i].name != NULL; i++)
                        if (!strcmp(cmds[i].name, cmd)) {
                                argc -= optind;
                                argv += optind;
                                optind = 0;
                                rc = run_command(&cmds[i], argc, argv);
                                goto out;
                        }
        }

        /* invalid command */
        usbip_help(0, NULL);
out:
        return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
}