You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

541 lines
12 KiB

  1. /***************************************************************************
  2. * Copyright (C) 2005 by Dominic Rath *
  3. * Dominic.Rath@gmx.de *
  4. * *
  5. * part of this file is taken from libcli (libcli.sourceforge.net) *
  6. * Copyright (C) David Parrish (david@dparrish.com) *
  7. * *
  8. * This program is free software; you can redistribute it and/or modify *
  9. * it under the terms of the GNU General Public License as published by *
  10. * the Free Software Foundation; either version 2 of the License, or *
  11. * (at your option) any later version. *
  12. * *
  13. * This program is distributed in the hope that it will be useful, *
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  16. * GNU General Public License for more details. *
  17. * *
  18. * You should have received a copy of the GNU General Public License *
  19. * along with this program; if not, write to the *
  20. * Free Software Foundation, Inc., *
  21. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  22. ***************************************************************************/
  23. #ifdef HAVE_CONFIG_H
  24. #include "config.h"
  25. #endif
  26. #include "replacements.h"
  27. #include "command.h"
  28. #include "log.h"
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <ctype.h>
  32. #include <stdarg.h>
  33. #include <stdio.h>
  34. #include <unistd.h>
  35. int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
  36. int build_unique_lengths(command_context_t *context, command_t *commands)
  37. {
  38. command_t *c, *p;
  39. /* iterate through all commands */
  40. for (c = commands; c; c = c->next)
  41. {
  42. /* find out how many characters are required to uniquely identify a command */
  43. for (c->unique_len = 1; c->unique_len <= strlen(c->name); c->unique_len++)
  44. {
  45. int foundmatch = 0;
  46. /* for every command, see if the current length is enough */
  47. for (p = commands; p; p = p->next)
  48. {
  49. /* ignore the command itself */
  50. if (c == p)
  51. continue;
  52. /* compare commands up to the current length */
  53. if (strncmp(p->name, c->name, c->unique_len) == 0)
  54. foundmatch++;
  55. }
  56. /* when none of the commands matched, we've found the minimum length required */
  57. if (!foundmatch)
  58. break;
  59. }
  60. /* if the current command has children, build the unique lengths for them */
  61. if (c->children)
  62. build_unique_lengths(context, c->children);
  63. }
  64. return ERROR_OK;
  65. }
  66. command_t* register_command(command_context_t *context, command_t *parent, char *name, int (*handler)(struct command_context_s *context, char* name, char** args, int argc), enum command_mode mode, char *help)
  67. {
  68. command_t *c, *p;
  69. if (!context || !name)
  70. return NULL;
  71. c = malloc(sizeof(command_t));
  72. c->name = strdup(name);
  73. c->parent = parent;
  74. c->children = NULL;
  75. c->handler = handler;
  76. c->mode = mode;
  77. if (help)
  78. c->help = strdup(help);
  79. else
  80. c->help = NULL;
  81. c->unique_len = 0;
  82. c->next = NULL;
  83. /* place command in tree */
  84. if (parent)
  85. {
  86. if (parent->children)
  87. {
  88. /* find last child */
  89. for (p = parent->children; p && p->next; p = p->next);
  90. if (p)
  91. p->next = c;
  92. }
  93. else
  94. {
  95. parent->children = c;
  96. }
  97. }
  98. else
  99. {
  100. if (context->commands)
  101. {
  102. /* find last command */
  103. for (p = context->commands; p && p->next; p = p->next);
  104. if (p)
  105. p->next = c;
  106. }
  107. else
  108. {
  109. context->commands = c;
  110. }
  111. }
  112. /* update unique lengths */
  113. build_unique_lengths(context, (parent) ? parent : context->commands);
  114. return c;
  115. }
  116. int unregister_command(command_context_t *context, char *name)
  117. {
  118. command_t *c, *p = NULL, *c2;
  119. if ((!context) || (!name))
  120. return ERROR_INVALID_ARGUMENTS;
  121. /* find command */
  122. for (c = context->commands; c; c = c->next)
  123. {
  124. if (strcmp(name, c->name) == 0)
  125. {
  126. /* unlink command */
  127. if (p)
  128. {
  129. p->next = c->next;
  130. }
  131. else
  132. {
  133. context->commands = c->next;
  134. }
  135. /* unregister children */
  136. if (c->children)
  137. {
  138. for (c2 = c->children; c2; c2 = c2->next)
  139. {
  140. free(c2->name);
  141. if (c2->help)
  142. free(c2->help);
  143. free(c2);
  144. }
  145. }
  146. /* delete command */
  147. free(c->name);
  148. if (c->help)
  149. free(c->help);
  150. free(c);
  151. }
  152. /* remember the last command for unlinking */
  153. p = c;
  154. }
  155. return ERROR_OK;
  156. }
  157. int parse_line(char *line, char *words[], int max_words)
  158. {
  159. int nwords = 0;
  160. char *p = line;
  161. char *word_start = line;
  162. int inquote = 0;
  163. while (nwords < max_words - 1)
  164. {
  165. /* check if we reached
  166. * a terminating NUL
  167. * a matching closing quote character " or '
  168. * we're inside a word but not a quote, and the current character is whitespace
  169. */
  170. if (!*p || *p == inquote || (word_start && !inquote && isspace(*p)))
  171. {
  172. /* we're inside a word or quote, and reached its end*/
  173. if (word_start)
  174. {
  175. int len;
  176. char *word_end=p;
  177. /* This will handle extra whitespace within quotes */
  178. while (isspace(*word_start)&&(word_start<word_end))
  179. word_start++;
  180. while (isspace(*(word_end-1))&&(word_start<word_end))
  181. word_end--;
  182. len = word_end - word_start;
  183. if (len>0)
  184. {
  185. /* copy the word */
  186. memcpy(words[nwords] = malloc(len + 1), word_start, len);
  187. /* add terminating NUL */
  188. words[nwords++][len] = 0;
  189. }
  190. }
  191. /* we're done parsing the line */
  192. if (!*p)
  193. break;
  194. /* skip over trailing quote or whitespace*/
  195. if (inquote || isspace(*p))
  196. p++;
  197. while (isspace(*p))
  198. p++;
  199. inquote = 0;
  200. word_start = 0;
  201. }
  202. else if (*p == '"' || *p == '\'')
  203. {
  204. /* we've reached the beginning of a quote */
  205. inquote = *p++;
  206. word_start = p;
  207. }
  208. else
  209. {
  210. /* we've reached the beginning of a new word */
  211. if (!word_start)
  212. word_start = p;
  213. /* normal character, skip */
  214. p++;
  215. }
  216. }
  217. return nwords;
  218. }
  219. void command_print(command_context_t *context, char *format, ...)
  220. {
  221. va_list ap;
  222. char *buffer = NULL;
  223. int n, size = 0;
  224. char *p;
  225. va_start(ap, format);
  226. /* process format string */
  227. /* TODO: possible bug. va_list is undefined after the first call to vsnprintf */
  228. while (!buffer || (n = vsnprintf(buffer, size, format, ap)) >= size)
  229. {
  230. /* increase buffer until it fits the whole string */
  231. if (!(p = realloc(buffer, size += 4096)))
  232. return;
  233. buffer = p;
  234. }
  235. /* vsnprintf failed */
  236. if (n < 0)
  237. return;
  238. p = buffer;
  239. /* process lines in buffer */
  240. do {
  241. char *next = strchr(p, '\n');
  242. if (next)
  243. *next++ = 0;
  244. if (context->output_handler)
  245. context->output_handler(context, p);
  246. p = next;
  247. } while (p);
  248. if (buffer)
  249. free(buffer);
  250. va_end(ap);
  251. }
  252. int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word)
  253. {
  254. command_t *c;
  255. for (c = commands; c; c = c->next)
  256. {
  257. if (strncasecmp(c->name, words[start_word], c->unique_len))
  258. continue;
  259. if (strncasecmp(c->name, words[start_word], strlen(words[start_word])))
  260. continue;
  261. if ((c->mode == context->mode) || (c->mode == COMMAND_ANY))
  262. {
  263. if (!c->children)
  264. {
  265. if (!c->handler)
  266. {
  267. command_print(context, "No handler for command");
  268. break;
  269. }
  270. else
  271. {
  272. return c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);
  273. }
  274. }
  275. else
  276. {
  277. if (start_word == num_words - 1)
  278. {
  279. command_print(context, "Incomplete command");
  280. break;
  281. }
  282. return find_and_run_command(context, c->children, words, num_words, start_word + 1);
  283. }
  284. }
  285. }
  286. command_print(context, "Command %s not found", words[start_word]);
  287. return ERROR_OK;
  288. }
  289. int command_run_line(command_context_t *context, char *line)
  290. {
  291. int nwords;
  292. char *words[128] = {0};
  293. int retval;
  294. int i;
  295. if ((!context) || (!line))
  296. return ERROR_INVALID_ARGUMENTS;
  297. /* skip preceding whitespace */
  298. while (isspace(*line))
  299. line++;
  300. /* empty line, ignore */
  301. if (!*line)
  302. return ERROR_OK;
  303. /* ignore comments */
  304. if (*line && (line[0] == '#'))
  305. return ERROR_OK;
  306. if (context->echo)
  307. {
  308. command_print(context, "%s", line);
  309. }
  310. nwords = parse_line(line, words, sizeof(words) / sizeof(words[0]));
  311. if (nwords > 0)
  312. retval = find_and_run_command(context, context->commands, words, nwords, 0);
  313. else
  314. return ERROR_INVALID_ARGUMENTS;
  315. for (i = 0; i < nwords; i++)
  316. free(words[i]);
  317. return retval;
  318. }
  319. int command_run_file(command_context_t *context, FILE *file, enum command_mode mode)
  320. {
  321. int retval = ERROR_OK;
  322. int old_command_mode;
  323. char buffer[4096];
  324. old_command_mode = context->mode;
  325. context->mode = mode;
  326. while (fgets(buffer, 4096, file))
  327. {
  328. char *p;
  329. char *cmd, *end;
  330. /* stop processing line after a comment (#, !) or a LF, CR were encountered */
  331. if ((p = strpbrk(buffer, "#!\r\n")))
  332. *p = 0;
  333. /* skip over leading whitespace */
  334. cmd = buffer;
  335. while (isspace(*cmd))
  336. cmd++;
  337. /* empty (all whitespace) line? */
  338. if (!*cmd)
  339. continue;
  340. /* search the end of the current line, ignore trailing whitespace */
  341. for (p = end = cmd; *p; p++)
  342. if (!isspace(*p))
  343. end = p;
  344. /* terminate end */
  345. *++end = 0;
  346. if (strcasecmp(cmd, "quit") == 0)
  347. break;
  348. /* run line */
  349. if ((retval = command_run_line(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION)
  350. break;
  351. }
  352. context->mode = old_command_mode;
  353. return retval;
  354. }
  355. void command_print_help_line(command_context_t* context, struct command_s *command, int indent)
  356. {
  357. command_t *c;
  358. char indents[32] = {0};
  359. char *help = "no help available";
  360. char name_buf[64];
  361. int i;
  362. for (i = 0; i < indent; i+=2)
  363. {
  364. indents[i*2] = ' ';
  365. indents[i*2+1] = '-';
  366. }
  367. indents[i*2] = 0;
  368. if ((command->mode == COMMAND_EXEC) || (command->mode == COMMAND_ANY))
  369. {
  370. if (command->help)
  371. help = command->help;
  372. snprintf(name_buf, 64, command->name);
  373. strncat(name_buf, indents, 64);
  374. command_print(context, "%20s\t%s", name_buf, help);
  375. }
  376. if (command->children)
  377. {
  378. for (c = command->children; c; c = c->next)
  379. {
  380. command_print_help_line(context, c, indent + 1);
  381. }
  382. }
  383. }
  384. int command_print_help(command_context_t* context, char* name, char** args, int argc)
  385. {
  386. command_t *c;
  387. for (c = context->commands; c; c = c->next)
  388. {
  389. if (argc == 1)
  390. {
  391. if (strncasecmp(c->name, args[0], c->unique_len))
  392. continue;
  393. if (strncasecmp(c->name, args[0], strlen(args[0])))
  394. continue;
  395. }
  396. command_print_help_line(context, c, 0);
  397. }
  398. return ERROR_OK;
  399. }
  400. void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, char* line), void *priv)
  401. {
  402. context->output_handler = output_handler;
  403. context->output_handler_priv = priv;
  404. }
  405. command_context_t* copy_command_context(command_context_t* context)
  406. {
  407. command_context_t* copy_context = malloc(sizeof(command_context_t));
  408. *copy_context = *context;
  409. return copy_context;
  410. }
  411. int command_done(command_context_t *context)
  412. {
  413. free(context);
  414. return ERROR_OK;
  415. }
  416. command_context_t* command_init()
  417. {
  418. command_context_t* context = malloc(sizeof(command_context_t));
  419. context->mode = COMMAND_EXEC;
  420. context->commands = NULL;
  421. context->current_target = 0;
  422. context->echo = 0;
  423. context->output_handler = NULL;
  424. context->output_handler_priv = NULL;
  425. register_command(context, NULL, "help", command_print_help,
  426. COMMAND_EXEC, "display this help");
  427. register_command(context, NULL, "sleep", handle_sleep_command,
  428. COMMAND_ANY, "sleep for <n> milliseconds");
  429. return context;
  430. }
  431. /* sleep command sleeps for <n> miliseconds
  432. * this is useful in target startup scripts
  433. */
  434. int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
  435. {
  436. unsigned long duration = 0;
  437. if (argc == 1)
  438. {
  439. duration = strtoul(args[0], NULL, 0);
  440. usleep(duration * 1000);
  441. }
  442. return ERROR_OK;
  443. }