File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / swanctl / command.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 09:46:45 2020 UTC (4 years, 4 months ago) by misho
Branches: strongswan, MAIN
CVS tags: v5_9_2p0, v5_8_4p7, HEAD
Strongswan

    1: /*
    2:  * Copyright (C) 2009 Martin Willi
    3:  * HSR Hochschule fuer Technik Rapperswil
    4:  *
    5:  * This program is free software; you can redistribute it and/or modify it
    6:  * under the terms of the GNU General Public License as published by the
    7:  * Free Software Foundation; either version 2 of the License, or (at your
    8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
    9:  *
   10:  * This program is distributed in the hope that it will be useful, but
   11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   13:  * for more details.
   14:  */
   15: 
   16: #include "command.h"
   17: 
   18: #define _GNU_SOURCE
   19: #include <getopt.h>
   20: #include <stdlib.h>
   21: #include <string.h>
   22: #include <stdio.h>
   23: #include <errno.h>
   24: 
   25: #include <library.h>
   26: #include <utils/debug.h>
   27: #include <utils/optionsfrom.h>
   28: 
   29: /**
   30:  * Registered commands.
   31:  */
   32: static command_t cmds[MAX_COMMANDS];
   33: 
   34: /**
   35:  * active command.
   36:  */
   37: static int active = 0;
   38: 
   39: /**
   40:  * number of registered commands
   41:  */
   42: static int registered = 0;
   43: 
   44: /**
   45:  * help command index
   46:  */
   47: static int help_idx;
   48: 
   49: /**
   50:  * Uri to connect to
   51:  */
   52: static char *uri = NULL;
   53: 
   54: static int argc;
   55: 
   56: static char **argv;
   57: 
   58: static options_t *options;
   59: 
   60: /**
   61:  * Global options used by all subcommands
   62:  */
   63: static struct option command_opts[MAX_COMMANDS > MAX_OPTIONS ?
   64: 									MAX_COMMANDS : MAX_OPTIONS];
   65: 
   66: /**
   67:  * Global optstring used by all subcommands
   68:  */
   69: static char command_optstring[(MAX_COMMANDS > MAX_OPTIONS ?
   70: 								MAX_COMMANDS : MAX_OPTIONS) * 3];
   71: 
   72: /**
   73:  * Build command_opts/command_optstr for the active command
   74:  */
   75: static void build_opts()
   76: {
   77: 	int i, pos = 0;
   78: 
   79: 	memset(command_opts, 0, sizeof(command_opts));
   80: 	memset(command_optstring, 0, sizeof(command_optstring));
   81: 	if (active == help_idx)
   82: 	{
   83: 		for (i = 0; i < MAX_COMMANDS && cmds[i].cmd; i++)
   84: 		{
   85: 			command_opts[i].name = cmds[i].cmd;
   86: 			command_opts[i].val = cmds[i].op;
   87: 			command_optstring[i] = cmds[i].op;
   88: 		}
   89: 	}
   90: 	else
   91: 	{
   92: 		for (i = 0; cmds[active].options[i].name; i++)
   93: 		{
   94: 			command_opts[i].name = cmds[active].options[i].name;
   95: 			command_opts[i].has_arg = cmds[active].options[i].arg;
   96: 			command_opts[i].val = cmds[active].options[i].op;
   97: 			command_optstring[pos++] = cmds[active].options[i].op;
   98: 			switch (cmds[active].options[i].arg)
   99: 			{
  100: 				case optional_argument:
  101: 					command_optstring[pos++] = ':';
  102: 					/* FALL */
  103: 				case required_argument:
  104: 					command_optstring[pos++] = ':';
  105: 					/* FALL */
  106: 				case no_argument:
  107: 				default:
  108: 					break;
  109: 			}
  110: 		}
  111: 	}
  112: }
  113: 
  114: /**
  115:  * getopt_long wrapper
  116:  */
  117: int command_getopt(char **arg)
  118: {
  119: 	int op;
  120: 
  121: 	while (TRUE)
  122: 	{
  123: 		op = getopt_long(argc, argv, command_optstring, command_opts, NULL);
  124: 		switch (op)
  125: 		{
  126: 			case '+':
  127: 			case 'v':
  128: 			case 'u':
  129: 				continue;
  130: 			default:
  131: 				*arg = optarg;
  132: 				return op;
  133: 		}
  134: 	}
  135: }
  136: 
  137: /**
  138:  * Register a command
  139:  */
  140: void command_register(command_t command)
  141: {
  142: 	int i;
  143: 
  144: 	if (registered == MAX_COMMANDS)
  145: 	{
  146: 		fprintf(stderr, "unable to register command, please increase "
  147: 				"MAX_COMMANDS\n");
  148: 		return;
  149: 	}
  150: 	for (i = 0; i < MAX_COMMANDS && cmds[i].cmd; i++)
  151: 	{
  152: 		if (cmds[i].op == command.op)
  153: 		{
  154: 			fprintf(stderr, "unable to register command --%s, short option "
  155: 					"conflicts with --%s\n", command.cmd, cmds[i].cmd);
  156: 			return;
  157: 		}
  158: 	}
  159: 
  160: 	cmds[registered] = command;
  161: 	/* append default options, but not to --help */
  162: 	if (!active)
  163: 	{
  164: 		for (i = 0; i < countof(cmds[registered].options) - 1; i++)
  165: 		{
  166: 			if (!cmds[registered].options[i].name)
  167: 			{
  168: 				break;
  169: 			}
  170: 		}
  171: 		if (i > countof(cmds[registered].options) - 3)
  172: 		{
  173: 			fprintf(stderr, "command '%s' registered too many options, please "
  174: 					"increase MAX_OPTIONS\n", command.cmd);
  175: 		}
  176: 		else
  177: 		{
  178: 			cmds[registered].options[i++] = (command_option_t) {
  179: 				"debug",	'v', 1, "set debug level, default: 1"
  180: 			};
  181: 			cmds[registered].options[i++] = (command_option_t) {
  182: 				"options",	'+', 1, "read command line options from file"
  183: 			};
  184: 			cmds[registered].options[i++] = (command_option_t) {
  185: 				"uri",		'u', 1, "service URI to connect to"
  186: 			};
  187: 		}
  188: 		for (i = 0; cmds[registered].line[i]; i++)
  189: 		{
  190: 			if (i == MAX_LINES - 1)
  191: 			{
  192: 				fprintf(stderr, "command '%s' specifies too many usage summary "
  193: 						"lines, please increase MAX_LINES\n", command.cmd);
  194: 				break;
  195: 			}
  196: 		}
  197: 	}
  198: 	registered++;
  199: }
  200: 
  201: /**
  202:  * Print usage text, with an optional error
  203:  */
  204: int command_usage(char *error, ...)
  205: {
  206: 	va_list args;
  207: 	FILE *out = stdout;
  208: 	int i;
  209: 
  210: 	if (error)
  211: 	{
  212: 		out = stderr;
  213: 		fprintf(out, "Error: ");
  214: 		va_start(args, error);
  215: 		vfprintf(out, error, args);
  216: 		va_end(args);
  217: 		fprintf(out, "\n");
  218: 	}
  219: 	fprintf(out, "strongSwan %s swanctl\n", VERSION);
  220: 
  221: 	if (active == help_idx)
  222: 	{
  223: 		fprintf(out, "loaded plugins: %s\n",
  224: 				lib->plugins->loaded_plugins(lib->plugins));
  225: 	}
  226: 
  227: 	fprintf(out, "usage:\n");
  228: 	if (active == help_idx)
  229: 	{
  230: 		for (i = 0; i < MAX_COMMANDS && cmds[i].cmd; i++)
  231: 		{
  232: 			fprintf(out, "  swanctl --%-16s (-%c)  %s\n",
  233: 					cmds[i].cmd, cmds[i].op, cmds[i].description);
  234: 		}
  235: 	}
  236: 	else
  237: 	{
  238: 		for (i = 0; i < MAX_LINES && cmds[active].line[i]; i++)
  239: 		{
  240: 			if (i == 0)
  241: 			{
  242: 				fprintf(out, "  swanctl --%s %s\n",
  243: 						cmds[active].cmd, cmds[active].line[i]);
  244: 			}
  245: 			else
  246: 			{
  247: 				fprintf(out, "                 %s\n", cmds[active].line[i]);
  248: 			}
  249: 		}
  250: 		for (i = 0; cmds[active].options[i].name; i++)
  251: 		{
  252: 			fprintf(out, "           --%-15s (-%c)  %s\n",
  253: 					cmds[active].options[i].name, cmds[active].options[i].op,
  254: 					cmds[active].options[i].desc);
  255: 		}
  256: 	}
  257: 	return error != NULL;
  258: }
  259: 
  260: /**
  261:  * Dispatch cleanup hook
  262:  */
  263: static void cleanup()
  264: {
  265: 	options->destroy(options);
  266: }
  267: 
  268: /**
  269:  * Process options common for all commands
  270:  */
  271: static bool process_common_opts()
  272: {
  273: 	while (TRUE)
  274: 	{
  275: 		switch (getopt_long(argc, argv, command_optstring, command_opts, NULL))
  276: 		{
  277: 			case '+':
  278: 				if (!options->from(options, optarg, &argc, &argv, optind))
  279: 				{
  280: 					return FALSE;
  281: 				}
  282: 				continue;
  283: 			case 'v':
  284: 				dbg_default_set_level(atoi(optarg));
  285: 				continue;
  286: 			case 'u':
  287: 				uri = optarg;
  288: 				continue;
  289: 			default:
  290: 				continue;
  291: 			case '?':
  292: 				return FALSE;
  293: 			case EOF:
  294: 				return TRUE;
  295: 		}
  296: 	}
  297: }
  298: 
  299: /**
  300:  * Open vici connection, call a command
  301:  */
  302: static int call_command(command_t *cmd)
  303: {
  304: 	vici_conn_t *conn;
  305: 	int ret;
  306: 
  307: 	conn = vici_connect(uri);
  308: 	if (!conn)
  309: 	{
  310: 		ret = errno;
  311: 		command_usage("connecting to '%s' URI failed: %s",
  312: 					  uri ?: "default", strerror(errno));
  313: 		return ret;
  314: 	}
  315: 	ret = cmd->call(conn);
  316: 	vici_disconnect(conn);
  317: 	return ret;
  318: }
  319: 
  320: /**
  321:  * Dispatch commands.
  322:  */
  323: int command_dispatch(int c, char *v[])
  324: {
  325: 	int op, i;
  326: 
  327: 	uri = lib->settings->get_str(lib->settings, "%s.socket",
  328: 			lib->settings->get_str(lib->settings, "%s.plugins.vici.socket",
  329: 								   NULL, lib->ns), lib->ns);
  330: 
  331: 	options = options_create();
  332: 	atexit(cleanup);
  333: 	active = help_idx = registered;
  334: 	argc = c;
  335: 	argv = v;
  336: 	command_register((command_t){NULL, 'h', "help", "show usage information"});
  337: 
  338: 	build_opts();
  339: 	op = getopt_long(c, v, command_optstring, command_opts, NULL);
  340: 	for (i = 0; i < MAX_COMMANDS && cmds[i].cmd; i++)
  341: 	{
  342: 		if (cmds[i].op == op)
  343: 		{
  344: 			active = i;
  345: 			build_opts();
  346: 			if (help_idx == i)
  347: 			{
  348: 				return command_usage(NULL);
  349: 			}
  350: 			if (!process_common_opts())
  351: 			{
  352: 				return command_usage("invalid options");
  353: 			}
  354: 			optind = 2;
  355: 			return call_command(&cmds[i]);
  356: 		}
  357: 	}
  358: 	return command_usage(c > 1 ? "invalid operation" : NULL);
  359: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>