/* Compile: gcc -o vnet -lvserver vnet.c */

#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>

typedef uint32_t nid_t;

/* exit, silent exit, perror exit
 *
 * exit code conventions:
 * 
 * 0 = OK
 * 1 = Wrong usage
 * 2 = A command failed
 * 3 = An opts specific function failed
 */
#define EXIT_USAGE   1
#define EXIT_COMMAND 2
#define EXIT_OPTS    3

#define EXIT(MSG,RC) { \
	printf(MSG"; try '%s --help' for more information\n", argv[0]); \
	exit(RC); \
}

#define SEXIT(MSG,RC) { \
	printf(MSG"\n"); \
	exit(RC); \
}

#define PEXIT(MSG,RC) { \
	perror(MSG); \
	exit(RC); \
}


#define NAME  "vnet"
#define DESCR "Network Context Manager"

#define SHORT_OPTS "hCMn:"

static const
struct option LONG_OPTS[] = {
	{ "help",      no_argument,       0, 'h' },
	{ "create",    no_argument,       0, 'C' },
	{ "migrate",   no_argument,       0, 'M' },
	{ "nid",       required_argument, 0, 'x' },
	{ 0,0,0,0 }
};

struct commands {
	bool create;
	bool migrate;
};

struct options {
	nid_t nid;
};

static inline
void cmd_help()
{
	printf("Usage: %s <command> <opts>* -- <program> <args>*\n"
	       "\n"
	       "Available commands:\n"
	       "    -h,--help               Show this help message\n"
	       "    -C,--create             Create a new security context\n"
	       "    -M,--migrate            Migrate to an existing context\n"
	       "\n"
	       "Available options:\n"
	       "    -n,--nid <nid>          The Network Context ID\n"
	       "\n",
	       NAME);
	exit(EXIT_SUCCESS);
}

int main(int argc, char *argv[])
{
	struct commands cmds = {
		.create   = false,
		.migrate  = false,
	};

	struct options opts = {
		.nid   = -1,
	};

	int c;

	while (1) {
		c = getopt_long(argc, argv, SHORT_OPTS, LONG_OPTS, 0);
		if (c == -1) break;

		switch (c) {
			case 'h':
				cmd_help();
				break;

			case 'C':
				cmds.create = true;
				break;

			case 'M':
				cmds.migrate = true;
				break;

			case 'n':
				opts.nid = (nid_t) atoi(optarg);
				break;
			default:
				printf("Try '%s --help' for more information\n", argv[0]);
				exit(EXIT_USAGE);
				break;
		}
	}

	if (cmds.create && cmds.migrate)
		EXIT("Can't create and migrate at the same time", EXIT_USAGE);

	if (cmds.create)
		if (vc_net_create(opts.nid) < 0)
			PEXIT("Failed to create network context", EXIT_COMMAND);

	if (cmds.migrate)
		if (vc_net_migrate(opts.nid) < 0)
			PEXIT("Failed to migrate to network context", EXIT_COMMAND);

	if (argc > optind)
		execvp(argv[optind], argv+optind);

	exit(EXIT_SUCCESS);
}