Return to command.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / swanctl |
1.1 ! misho 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: }