vtysh_main.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  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. char history_file[MAXPATHLEN];
  39. /* Flag for indicate executing child command. */
  40. int execute_flag = 0;
  41. /* For sigsetjmp() & siglongjmp(). */
  42. static sigjmp_buf jmpbuf;
  43. /* Flag for avoid recursive siglongjmp() call. */
  44. static int jmpflag = 0;
  45. /* A static variable for holding the line. */
  46. static char *line_read;
  47. /* Master of threads. */
  48. struct thread_master *master;
  49. /* Command logging */
  50. FILE *logfile;
  51. /* SIGTSTP handler. This function care user's ^Z input. */
  52. static void
  53. sigtstp (int sig)
  54. {
  55. /* Execute "end" command. */
  56. vtysh_execute ("end");
  57. /* Initialize readline. */
  58. rl_initialize ();
  59. printf ("\n");
  60. /* Check jmpflag for duplicate siglongjmp(). */
  61. if (! jmpflag)
  62. return;
  63. jmpflag = 0;
  64. /* Back to main command loop. */
  65. siglongjmp (jmpbuf, 1);
  66. }
  67. /* SIGINT handler. This function care user's ^Z input. */
  68. static void
  69. sigint (int sig)
  70. {
  71. /* Check this process is not child process. */
  72. if (! execute_flag)
  73. {
  74. rl_initialize ();
  75. printf ("\n");
  76. rl_forced_update_display ();
  77. }
  78. }
  79. /* Signale wrapper for vtysh. We don't use sigevent because
  80. * vtysh doesn't use threads. TODO */
  81. static void
  82. vtysh_signal_set (int signo, void (*func)(int))
  83. {
  84. struct sigaction sig;
  85. struct sigaction osig;
  86. sig.sa_handler = func;
  87. sigemptyset (&sig.sa_mask);
  88. sig.sa_flags = 0;
  89. #ifdef SA_RESTART
  90. sig.sa_flags |= SA_RESTART;
  91. #endif /* SA_RESTART */
  92. sigaction (signo, &sig, &osig);
  93. }
  94. /* Initialization of signal handles. */
  95. static void
  96. vtysh_signal_init ()
  97. {
  98. vtysh_signal_set (SIGINT, sigint);
  99. vtysh_signal_set (SIGTSTP, sigtstp);
  100. vtysh_signal_set (SIGPIPE, SIG_IGN);
  101. }
  102. /* Help information display. */
  103. static void
  104. usage (int status)
  105. {
  106. if (status != 0)
  107. fprintf (stderr, "Try `%s --help' for more information.\n", progname);
  108. else
  109. printf ("Usage : %s [OPTION...]\n\n" \
  110. "Integrated shell for Quagga routing software suite. \n\n" \
  111. "-b, --boot Execute boot startup configuration\n" \
  112. "-c, --command Execute argument as command\n" \
  113. "-d, --daemon Connect only to the specified daemon\n" \
  114. "-E, --echo Echo prompt and command in -c mode\n" \
  115. "-C, --dryrun Check configuration for validity and exit\n" \
  116. "-h, --help Display this help and exit\n\n" \
  117. "Note that multiple commands may be executed from the command\n" \
  118. "line by passing multiple -c args, or by embedding linefeed\n" \
  119. "characters in one or more of the commands.\n\n" \
  120. "Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
  121. exit (status);
  122. }
  123. /* VTY shell options, we use GNU getopt library. */
  124. struct option longopts[] =
  125. {
  126. { "boot", no_argument, NULL, 'b'},
  127. /* For compatibility with older zebra/quagga versions */
  128. { "eval", required_argument, NULL, 'e'},
  129. { "command", required_argument, NULL, 'c'},
  130. { "daemon", required_argument, NULL, 'd'},
  131. { "echo", no_argument, NULL, 'E'},
  132. { "dryrun", no_argument, NULL, 'C'},
  133. { "help", no_argument, NULL, 'h'},
  134. { "noerror", no_argument, NULL, 'n'},
  135. { 0 }
  136. };
  137. /* Read a string, and return a pointer to it. Returns NULL on EOF. */
  138. static char *
  139. vtysh_rl_gets ()
  140. {
  141. HIST_ENTRY *last;
  142. /* If the buffer has already been allocated, return the memory
  143. * to the free pool. */
  144. if (line_read)
  145. {
  146. free (line_read);
  147. line_read = NULL;
  148. }
  149. /* Get a line from the user. Change prompt according to node. XXX. */
  150. line_read = readline (vtysh_prompt ());
  151. /* If the line has any text in it, save it on the history. But only if
  152. * last command in history isn't the same one. */
  153. if (line_read && *line_read)
  154. {
  155. using_history();
  156. last = previous_history();
  157. if (!last || strcmp (last->line, line_read) != 0) {
  158. add_history (line_read);
  159. append_history(1,history_file);
  160. }
  161. }
  162. return (line_read);
  163. }
  164. static void log_it(const char *line)
  165. {
  166. time_t t = time(NULL);
  167. struct tm *tmp = localtime(&t);
  168. const char *user = getenv("USER");
  169. char tod[64];
  170. if (!user)
  171. user = "boot";
  172. strftime(tod, sizeof tod, "%Y%m%d-%H:%M.%S", tmp);
  173. fprintf(logfile, "%s:%s %s\n", tod, user, line);
  174. }
  175. /* VTY shell main routine. */
  176. int
  177. main (int argc, char **argv, char **env)
  178. {
  179. char *p;
  180. int opt;
  181. int dryrun = 0;
  182. int boot_flag = 0;
  183. const char *daemon_name = NULL;
  184. struct cmd_rec {
  185. const char *line;
  186. struct cmd_rec *next;
  187. } *cmd = NULL;
  188. struct cmd_rec *tail = NULL;
  189. int echo_command = 0;
  190. int no_error = 0;
  191. char *homedir = NULL;
  192. /* Preserve name of myself. */
  193. progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
  194. /* if logging open now */
  195. if ((p = getenv("VTYSH_LOG")) != NULL)
  196. logfile = fopen(p, "a");
  197. /* Option handling. */
  198. while (1)
  199. {
  200. opt = getopt_long (argc, argv, "be:c:d:nEhC", longopts, 0);
  201. if (opt == EOF)
  202. break;
  203. switch (opt)
  204. {
  205. case 0:
  206. break;
  207. case 'b':
  208. boot_flag = 1;
  209. break;
  210. case 'e':
  211. case 'c':
  212. {
  213. struct cmd_rec *cr;
  214. cr = XMALLOC(MTYPE_TMP, sizeof(*cr));
  215. cr->line = optarg;
  216. cr->next = NULL;
  217. if (tail)
  218. tail->next = cr;
  219. else
  220. cmd = cr;
  221. tail = cr;
  222. }
  223. break;
  224. case 'd':
  225. daemon_name = optarg;
  226. break;
  227. case 'n':
  228. no_error = 1;
  229. break;
  230. case 'E':
  231. echo_command = 1;
  232. break;
  233. case 'C':
  234. dryrun = 1;
  235. break;
  236. case 'h':
  237. usage (0);
  238. break;
  239. default:
  240. usage (1);
  241. break;
  242. }
  243. }
  244. /* Initialize user input buffer. */
  245. line_read = NULL;
  246. setlinebuf(stdout);
  247. /* Signal and others. */
  248. vtysh_signal_init ();
  249. /* Make vty structure and register commands. */
  250. vtysh_init_vty ();
  251. vtysh_init_cmd ();
  252. vtysh_user_init ();
  253. vtysh_config_init ();
  254. vty_init_vtysh ();
  255. /* Read vtysh configuration file before connecting to daemons. */
  256. vtysh_read_config (config_default);
  257. /* Start execution only if not in dry-run mode */
  258. if(dryrun)
  259. return(0);
  260. /* Ignore error messages */
  261. if (no_error)
  262. freopen("/dev/null", "w", stdout);
  263. /* Make sure we pass authentication before proceeding. */
  264. vtysh_auth ();
  265. /* Do not connect until we have passed authentication. */
  266. if (vtysh_connect_all (daemon_name) <= 0)
  267. {
  268. fprintf(stderr, "Exiting: failed to connect to any daemons.\n");
  269. exit(1);
  270. }
  271. /*
  272. * Setup history file for use by both -c and regular input
  273. * If we can't find the home directory, then don't store
  274. * the history information
  275. */
  276. homedir = vtysh_get_home ();
  277. if (homedir)
  278. {
  279. snprintf(history_file, sizeof(history_file), "%s/.history_quagga", homedir);
  280. if (read_history (history_file) != 0)
  281. {
  282. int fp;
  283. fp = open (history_file, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
  284. if (fp)
  285. close (fp);
  286. read_history (history_file);
  287. }
  288. }
  289. /* If eval mode. */
  290. if (cmd)
  291. {
  292. /* Enter into enable node. */
  293. vtysh_execute ("enable");
  294. while (cmd != NULL)
  295. {
  296. int ret;
  297. char *eol;
  298. while ((eol = strchr(cmd->line, '\n')) != NULL)
  299. {
  300. *eol = '\0';
  301. add_history (cmd->line);
  302. append_history (1, history_file);
  303. if (echo_command)
  304. printf("%s%s\n", vtysh_prompt(), cmd->line);
  305. if (logfile)
  306. log_it(cmd->line);
  307. ret = vtysh_execute_no_pager(cmd->line);
  308. if (!no_error &&
  309. ! (ret == CMD_SUCCESS ||
  310. ret == CMD_SUCCESS_DAEMON ||
  311. ret == CMD_WARNING))
  312. exit(1);
  313. cmd->line = eol+1;
  314. }
  315. add_history (cmd->line);
  316. append_history (1, history_file);
  317. if (echo_command)
  318. printf("%s%s\n", vtysh_prompt(), cmd->line);
  319. if (logfile)
  320. log_it(cmd->line);
  321. ret = vtysh_execute_no_pager(cmd->line);
  322. if (!no_error &&
  323. ! (ret == CMD_SUCCESS ||
  324. ret == CMD_SUCCESS_DAEMON ||
  325. ret == CMD_WARNING))
  326. exit(1);
  327. {
  328. struct cmd_rec *cr;
  329. cr = cmd;
  330. cmd = cmd->next;
  331. XFREE(0, cr);
  332. }
  333. }
  334. history_truncate_file(history_file,1000);
  335. exit (0);
  336. }
  337. /* Boot startup configuration file. */
  338. if (boot_flag)
  339. {
  340. if (vtysh_read_config (integrate_default))
  341. {
  342. fprintf (stderr, "Can't open configuration file [%s]\n",
  343. integrate_default);
  344. exit (1);
  345. }
  346. else
  347. exit (0);
  348. }
  349. vtysh_pager_init ();
  350. vtysh_readline_init ();
  351. vty_hello (vty);
  352. /* Enter into enable node. */
  353. vtysh_execute ("enable");
  354. /* Preparation for longjmp() in sigtstp(). */
  355. sigsetjmp (jmpbuf, 1);
  356. jmpflag = 1;
  357. /* Main command loop. */
  358. while (vtysh_rl_gets ())
  359. vtysh_execute (line_read);
  360. history_truncate_file(history_file,1000);
  361. printf ("\n");
  362. /* Rest in peace. */
  363. exit (0);
  364. }