vtysh_main.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /* Virtual terminal interface shell.
  2. * Copyright (C) 2000 Kunihiro Ishiguro
  3. *
  4. * This file is part of GNU Zebra.
  5. *
  6. * GNU Zebra is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation; either version 2, or (at your option) any
  9. * later version.
  10. *
  11. * GNU Zebra is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GNU Zebra; see the file COPYING. If not, write to the Free
  18. * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  19. * 02111-1307, USA.
  20. */
  21. #include <zebra.h>
  22. #include <sys/un.h>
  23. #include <setjmp.h>
  24. #include <sys/wait.h>
  25. #include <pwd.h>
  26. #include <readline/readline.h>
  27. #include <readline/history.h>
  28. #include <lib/version.h>
  29. #include "getopt.h"
  30. #include "command.h"
  31. #include "memory.h"
  32. #include "vtysh/vtysh.h"
  33. #include "vtysh/vtysh_user.h"
  34. /* VTY shell program name. */
  35. char *progname;
  36. /* Configuration file name and directory. */
  37. char config_default[] = SYSCONFDIR VTYSH_DEFAULT_CONFIG;
  38. /* Flag for indicate executing child command. */
  39. int execute_flag = 0;
  40. /* For sigsetjmp() & siglongjmp(). */
  41. static sigjmp_buf jmpbuf;
  42. /* Flag for avoid recursive siglongjmp() call. */
  43. static int jmpflag = 0;
  44. /* A static variable for holding the line. */
  45. static char *line_read;
  46. /* Master of threads. */
  47. struct thread_master *master;
  48. /* SIGTSTP handler. This function care user's ^Z input. */
  49. void
  50. sigtstp (int sig)
  51. {
  52. /* Execute "end" command. */
  53. vtysh_execute ("end");
  54. /* Initialize readline. */
  55. rl_initialize ();
  56. printf ("\n");
  57. /* Check jmpflag for duplicate siglongjmp(). */
  58. if (! jmpflag)
  59. return;
  60. jmpflag = 0;
  61. /* Back to main command loop. */
  62. siglongjmp (jmpbuf, 1);
  63. }
  64. /* SIGINT handler. This function care user's ^Z input. */
  65. void
  66. sigint (int sig)
  67. {
  68. /* Check this process is not child process. */
  69. if (! execute_flag)
  70. {
  71. rl_initialize ();
  72. printf ("\n");
  73. rl_forced_update_display ();
  74. }
  75. }
  76. /* Signale wrapper for vtysh. We don't use sigevent because
  77. * vtysh doesn't use threads. TODO */
  78. RETSIGTYPE *
  79. vtysh_signal_set (int signo, void (*func)(int))
  80. {
  81. int ret;
  82. struct sigaction sig;
  83. struct sigaction osig;
  84. sig.sa_handler = func;
  85. sigemptyset (&sig.sa_mask);
  86. sig.sa_flags = 0;
  87. #ifdef SA_RESTART
  88. sig.sa_flags |= SA_RESTART;
  89. #endif /* SA_RESTART */
  90. ret = sigaction (signo, &sig, &osig);
  91. if (ret < 0)
  92. return (SIG_ERR);
  93. else
  94. return (osig.sa_handler);
  95. }
  96. /* Initialization of signal handles. */
  97. void
  98. vtysh_signal_init ()
  99. {
  100. vtysh_signal_set (SIGINT, sigint);
  101. vtysh_signal_set (SIGTSTP, sigtstp);
  102. vtysh_signal_set (SIGPIPE, SIG_IGN);
  103. }
  104. /* Help information display. */
  105. static void
  106. usage (int status)
  107. {
  108. if (status != 0)
  109. fprintf (stderr, "Try `%s --help' for more information.\n", progname);
  110. else
  111. printf ("Usage : %s [OPTION...]\n\n" \
  112. "Integrated shell for Quagga routing software suite. \n\n" \
  113. "-b, --boot Execute boot startup configuration\n" \
  114. "-c, --command Execute argument as command\n" \
  115. "-d, --daemon Connect only to the specified daemon\n" \
  116. "-E, --echo Echo prompt and command in -c mode\n" \
  117. "-C, --dryrun Check configuration for validity and exit\n" \
  118. "-h, --help Display this help and exit\n\n" \
  119. "Note that multiple commands may be executed from the command\n" \
  120. "line by passing multiple -c args, or by embedding linefeed\n" \
  121. "characters in one or more of the commands.\n\n" \
  122. "Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
  123. exit (status);
  124. }
  125. /* VTY shell options, we use GNU getopt library. */
  126. struct option longopts[] =
  127. {
  128. { "boot", no_argument, NULL, 'b'},
  129. /* For compatibility with older zebra/quagga versions */
  130. { "eval", required_argument, NULL, 'e'},
  131. { "command", required_argument, NULL, 'c'},
  132. { "daemon", required_argument, NULL, 'd'},
  133. { "echo", no_argument, NULL, 'E'},
  134. { "dryrun", no_argument, NULL, 'C'},
  135. { "help", no_argument, NULL, 'h'},
  136. { 0 }
  137. };
  138. /* Read a string, and return a pointer to it. Returns NULL on EOF. */
  139. char *
  140. vtysh_rl_gets ()
  141. {
  142. HIST_ENTRY *last;
  143. /* If the buffer has already been allocated, return the memory
  144. * to the free pool. */
  145. if (line_read)
  146. {
  147. free (line_read);
  148. line_read = NULL;
  149. }
  150. /* Get a line from the user. Change prompt according to node. XXX. */
  151. line_read = readline (vtysh_prompt ());
  152. /* If the line has any text in it, save it on the history. But only if
  153. * last command in history isn't the same one. */
  154. if (line_read && *line_read)
  155. {
  156. using_history();
  157. last = previous_history();
  158. if (!last || strcmp (last->line, line_read) != 0)
  159. add_history (line_read);
  160. }
  161. return (line_read);
  162. }
  163. /* VTY shell main routine. */
  164. int
  165. main (int argc, char **argv, char **env)
  166. {
  167. char *p;
  168. int opt;
  169. int dryrun = 0;
  170. int boot_flag = 0;
  171. const char *daemon_name = NULL;
  172. struct cmd_rec {
  173. const char *line;
  174. struct cmd_rec *next;
  175. } *cmd = NULL;
  176. struct cmd_rec *tail = NULL;
  177. int echo_command = 0;
  178. /* Preserve name of myself. */
  179. progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
  180. /* Option handling. */
  181. while (1)
  182. {
  183. opt = getopt_long (argc, argv, "be:c:d:EhC", longopts, 0);
  184. if (opt == EOF)
  185. break;
  186. switch (opt)
  187. {
  188. case 0:
  189. break;
  190. case 'b':
  191. boot_flag = 1;
  192. break;
  193. case 'e':
  194. case 'c':
  195. {
  196. struct cmd_rec *cr;
  197. cr = XMALLOC(0, sizeof(*cr));
  198. cr->line = optarg;
  199. cr->next = NULL;
  200. if (tail)
  201. tail->next = cr;
  202. else
  203. cmd = cr;
  204. tail = cr;
  205. }
  206. break;
  207. case 'd':
  208. daemon_name = optarg;
  209. break;
  210. case 'E':
  211. echo_command = 1;
  212. break;
  213. case 'C':
  214. dryrun = 1;
  215. break;
  216. case 'h':
  217. usage (0);
  218. break;
  219. default:
  220. usage (1);
  221. break;
  222. }
  223. }
  224. /* Initialize user input buffer. */
  225. line_read = NULL;
  226. /* Signal and others. */
  227. vtysh_signal_init ();
  228. /* Make vty structure and register commands. */
  229. vtysh_init_vty ();
  230. vtysh_init_cmd ();
  231. vtysh_user_init ();
  232. vtysh_config_init ();
  233. vty_init_vtysh ();
  234. sort_node ();
  235. /* Read vtysh configuration file before connecting to daemons. */
  236. vtysh_read_config (config_default);
  237. /* Start execution only if not in dry-run mode */
  238. if(dryrun)
  239. return(0);
  240. /* Make sure we pass authentication before proceeding. */
  241. vtysh_auth ();
  242. /* Do not connect until we have passed authentication. */
  243. if (vtysh_connect_all (daemon_name) <= 0)
  244. {
  245. fprintf(stderr, "Exiting: failed to connect to any daemons.\n");
  246. exit(1);
  247. }
  248. /* If eval mode. */
  249. if (cmd)
  250. {
  251. /* Enter into enable node. */
  252. vtysh_execute ("enable");
  253. while (cmd != NULL)
  254. {
  255. char *eol;
  256. while ((eol = strchr(cmd->line, '\n')) != NULL)
  257. {
  258. *eol = '\0';
  259. if (echo_command)
  260. printf("%s%s\n", vtysh_prompt(), cmd->line);
  261. vtysh_execute_no_pager(cmd->line);
  262. cmd->line = eol+1;
  263. }
  264. if (echo_command)
  265. printf("%s%s\n", vtysh_prompt(), cmd->line);
  266. vtysh_execute_no_pager (cmd->line);
  267. {
  268. struct cmd_rec *cr;
  269. cr = cmd;
  270. cmd = cmd->next;
  271. XFREE(0, cr);
  272. }
  273. }
  274. exit (0);
  275. }
  276. /* Boot startup configuration file. */
  277. if (boot_flag)
  278. {
  279. if (vtysh_read_config (integrate_default))
  280. {
  281. fprintf (stderr, "Can't open configuration file [%s]\n",
  282. integrate_default);
  283. exit (1);
  284. }
  285. else
  286. exit (0);
  287. }
  288. vtysh_pager_init ();
  289. vtysh_readline_init ();
  290. vty_hello (vty);
  291. /* Enter into enable node. */
  292. vtysh_execute ("enable");
  293. /* Preparation for longjmp() in sigtstp(). */
  294. sigsetjmp (jmpbuf, 1);
  295. jmpflag = 1;
  296. /* Main command loop. */
  297. while (vtysh_rl_gets ())
  298. vtysh_execute (line_read);
  299. printf ("\n");
  300. /* Rest in peace. */
  301. exit (0);
  302. }