Annotation of embedaddon/strongswan/src/swanctl/command.c, revision 1.1.1.1

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: }

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