command.c 7.1 KB

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