libimcv: Fixed processing of PTS Simple Component Evidence
[strongswan.git] / src / pki / command.c
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 #include "pki.h"
18
19 #define _GNU_SOURCE
20 #include <getopt.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdio.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 static int argc;
50
51 static char **argv;
52
53 static options_t *options;
54
55 /**
56 * Global options used by all subcommands
57 */
58 static struct option command_opts[MAX_COMMANDS > MAX_OPTIONS ? MAX_COMMANDS : MAX_OPTIONS];
59
60 /**
61 * Global optstring used by all subcommands
62 */
63 static char command_optstring[(MAX_COMMANDS > MAX_OPTIONS ? MAX_COMMANDS : MAX_OPTIONS) * 3];
64
65 /**
66 * Build command_opts/command_optstr for the active command
67 */
68 static void build_opts()
69 {
70 int i, pos = 0;
71
72 memset(command_opts, 0, sizeof(command_opts));
73 memset(command_optstring, 0, sizeof(command_optstring));
74 if (active == help_idx)
75 {
76 for (i = 0; i < MAX_COMMANDS && cmds[i].cmd; i++)
77 {
78 command_opts[i].name = cmds[i].cmd;
79 command_opts[i].val = cmds[i].op;
80 command_optstring[i] = cmds[i].op;
81 }
82 }
83 else
84 {
85 for (i = 0; cmds[active].options[i].name; i++)
86 {
87 command_opts[i].name = cmds[active].options[i].name;
88 command_opts[i].has_arg = cmds[active].options[i].arg;
89 command_opts[i].val = cmds[active].options[i].op;
90 command_optstring[pos++] = cmds[active].options[i].op;
91 switch (cmds[active].options[i].arg)
92 {
93 case optional_argument:
94 command_optstring[pos++] = ':';
95 /* FALL */
96 case required_argument:
97 command_optstring[pos++] = ':';
98 /* FALL */
99 case no_argument:
100 default:
101 break;
102 }
103 }
104 }
105 }
106
107 /**
108 * getopt_long wrapper
109 */
110 int command_getopt(char **arg)
111 {
112 int op;
113
114 while (TRUE)
115 {
116 op = getopt_long(argc, argv, command_optstring, command_opts, NULL);
117 switch (op)
118 {
119 case '+':
120 if (!options->from(options, optarg, &argc, &argv, optind))
121 {
122 /* a error value */
123 return 255;
124 }
125 continue;
126 case 'v':
127 dbg_default_set_level(atoi(optarg));
128 continue;
129 default:
130 *arg = optarg;
131 return op;
132 }
133 }
134 }
135
136 /**
137 * Register a command
138 */
139 void command_register(command_t command)
140 {
141 int i;
142
143 if (registered == MAX_COMMANDS)
144 {
145 fprintf(stderr, "unable to register command, please increase "
146 "MAX_COMMANDS\n");
147 return;
148 }
149
150 cmds[registered] = command;
151 /* append default options, but not to --help */
152 if (!active)
153 {
154 for (i = 0; i < countof(cmds[registered].options) - 1; i++)
155 {
156 if (!cmds[registered].options[i].name)
157 {
158 break;
159 }
160 }
161 if (i > countof(cmds[registered].options) - 3)
162 {
163 fprintf(stderr, "command '%s' registered too many options, please "
164 "increase MAX_OPTIONS\n", command.cmd);
165 }
166 else
167 {
168 cmds[registered].options[i++] = (command_option_t) {
169 "debug", 'v', 1, "set debug level, default: 1"
170 };
171 cmds[registered].options[i++] = (command_option_t) {
172 "options", '+', 1, "read command line options from file"
173 };
174 }
175 for (i = 0; cmds[registered].line[i]; i++)
176 {
177 if (i == MAX_LINES - 1)
178 {
179 fprintf(stderr, "command '%s' specifies too many usage summary "
180 "lines, please increase MAX_LINES\n", command.cmd);
181 break;
182 }
183 }
184 }
185 registered++;
186 }
187
188 /**
189 * Print usage text, with an optional error
190 */
191 int command_usage(char *error)
192 {
193 FILE *out = stdout;
194 int i, indent = 0;
195
196 if (error)
197 {
198 out = stderr;
199 fprintf(out, "Error: %s\n", error);
200 }
201 fprintf(out, "strongSwan %s PKI tool\n", VERSION);
202
203 if (active == help_idx)
204 {
205 fprintf(out, "loaded plugins: %s\n",
206 lib->plugins->loaded_plugins(lib->plugins));
207 }
208
209 fprintf(out, "usage:\n");
210 if (active == help_idx)
211 {
212 for (i = 0; i < MAX_COMMANDS && cmds[i].cmd; i++)
213 {
214 fprintf(out, " pki --%-7s (-%c) %s\n",
215 cmds[i].cmd, cmds[i].op, cmds[i].description);
216 }
217 }
218 else
219 {
220 for (i = 0; i < MAX_LINES && cmds[active].line[i]; i++)
221 {
222 if (i == 0)
223 {
224 indent = fprintf(out, " pki --%s ", cmds[active].cmd);
225 fprintf(out, "%s\n", cmds[active].line[i]);
226 }
227 else
228 {
229 fprintf(out, "%*s%s\n", indent, "", cmds[active].line[i]);
230 }
231 }
232 for (i = 0; cmds[active].options[i].name; i++)
233 {
234 fprintf(out, " --%-15s (-%c) %s\n",
235 cmds[active].options[i].name, cmds[active].options[i].op,
236 cmds[active].options[i].desc);
237 }
238 }
239 return error != NULL;
240 }
241
242
243 /**
244 * Show usage information
245 */
246 static int help(int argc, char *argv[])
247 {
248 return command_usage(NULL);
249 }
250
251 /**
252 * Dispatch cleanup hook
253 */
254 static void cleanup()
255 {
256 options->destroy(options);
257 }
258
259 /**
260 * Dispatch commands.
261 */
262 int command_dispatch(int c, char *v[])
263 {
264 int op, i;
265
266 options = options_create();
267 atexit(cleanup);
268 active = help_idx = registered;
269 argc = c;
270 argv = v;
271 command_register((command_t){help, 'h', "help", "show usage information"});
272
273 build_opts();
274 op = getopt_long(c, v, command_optstring, command_opts, NULL);
275 for (i = 0; i < MAX_COMMANDS && cmds[i].cmd; i++)
276 {
277 if (cmds[i].op == op)
278 {
279 active = i;
280 build_opts();
281 return cmds[i].call();
282 }
283 }
284 return command_usage(c > 1 ? "invalid operation" : NULL);
285 }