| /* Virtual terminal interface shell. |
| * Copyright (C) 2000 Kunihiro Ishiguro |
| * |
| * This file is part of GNU Zebra. |
| * |
| * GNU Zebra is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by the |
| * Free Software Foundation; either version 2, or (at your option) any |
| * later version. |
| * |
| * GNU Zebra is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with GNU Zebra; see the file COPYING. If not, write to the Free |
| * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |
| * 02111-1307, USA. |
| */ |
| |
| #include <zebra.h> |
| |
| #include <sys/un.h> |
| #include <setjmp.h> |
| #include <sys/wait.h> |
| #include <pwd.h> |
| |
| #include <readline/readline.h> |
| #include <readline/history.h> |
| |
| #include <lib/version.h> |
| #include "getopt.h" |
| #include "command.h" |
| |
| #include "vtysh/vtysh.h" |
| #include "vtysh/vtysh_user.h" |
| |
| /* VTY shell program name. */ |
| char *progname; |
| |
| /* Configuration file name and directory. */ |
| char config_default[] = SYSCONFDIR VTYSH_DEFAULT_CONFIG; |
| |
| /* Flag for indicate executing child command. */ |
| int execute_flag = 0; |
| |
| /* For sigsetjmp() & siglongjmp(). */ |
| static sigjmp_buf jmpbuf; |
| |
| /* Flag for avoid recursive siglongjmp() call. */ |
| static int jmpflag = 0; |
| |
| /* A static variable for holding the line. */ |
| static char *line_read; |
| |
| /* Master of threads. */ |
| struct thread_master *master; |
| |
| /* SIGTSTP handler. This function care user's ^Z input. */ |
| void |
| sigtstp (int sig) |
| { |
| /* Execute "end" command. */ |
| vtysh_execute ("end"); |
| |
| /* Initialize readline. */ |
| rl_initialize (); |
| printf ("\n"); |
| |
| /* Check jmpflag for duplicate siglongjmp(). */ |
| if (! jmpflag) |
| return; |
| |
| jmpflag = 0; |
| |
| /* Back to main command loop. */ |
| siglongjmp (jmpbuf, 1); |
| } |
| |
| /* SIGINT handler. This function care user's ^Z input. */ |
| void |
| sigint (int sig) |
| { |
| /* Check this process is not child process. */ |
| if (! execute_flag) |
| { |
| rl_initialize (); |
| printf ("\n"); |
| rl_forced_update_display (); |
| } |
| } |
| |
| /* Signale wrapper for vtysh. We don't use sigevent because |
| * vtysh doesn't use threads. TODO */ |
| RETSIGTYPE * |
| vtysh_signal_set (int signo, void (*func)(int)) |
| { |
| int ret; |
| struct sigaction sig; |
| struct sigaction osig; |
| |
| sig.sa_handler = func; |
| sigemptyset (&sig.sa_mask); |
| sig.sa_flags = 0; |
| #ifdef SA_RESTART |
| sig.sa_flags |= SA_RESTART; |
| #endif /* SA_RESTART */ |
| |
| ret = sigaction (signo, &sig, &osig); |
| |
| if (ret < 0) |
| return (SIG_ERR); |
| else |
| return (osig.sa_handler); |
| } |
| |
| /* Initialization of signal handles. */ |
| void |
| vtysh_signal_init () |
| { |
| vtysh_signal_set (SIGINT, sigint); |
| vtysh_signal_set (SIGTSTP, sigtstp); |
| vtysh_signal_set (SIGPIPE, SIG_IGN); |
| } |
| |
| /* Help information display. */ |
| static void |
| usage (int status) |
| { |
| if (status != 0) |
| fprintf (stderr, "Try `%s --help' for more information.\n", progname); |
| else |
| printf ("Usage : %s [OPTION...]\n\n" \ |
| "Integrated shell for Quagga routing software suite. \n\n"\ |
| "-b, --boot Execute boot startup configuration\n" \ |
| "-c, --command Execute argument as command\n "\ |
| "-h, --help Display this help and exit\n\n" \ |
| "Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); |
| |
| exit (status); |
| } |
| |
| /* VTY shell options, we use GNU getopt library. */ |
| struct option longopts[] = |
| { |
| { "boot", no_argument, NULL, 'b'}, |
| /* For compatibility with older zebra/quagga versions */ |
| { "eval", required_argument, NULL, 'e'}, |
| { "command", required_argument, NULL, 'c'}, |
| { "help", no_argument, NULL, 'h'}, |
| { 0 } |
| }; |
| |
| /* Read a string, and return a pointer to it. Returns NULL on EOF. */ |
| char * |
| vtysh_rl_gets () |
| { |
| HIST_ENTRY *last; |
| /* If the buffer has already been allocated, return the memory |
| * to the free pool. */ |
| if (line_read) |
| { |
| free (line_read); |
| line_read = NULL; |
| } |
| |
| /* Get a line from the user. Change prompt according to node. XXX. */ |
| line_read = readline (vtysh_prompt ()); |
| |
| /* If the line has any text in it, save it on the history. But only if |
| * last command in history isn't the same one. */ |
| if (line_read && *line_read) |
| { |
| using_history(); |
| last = previous_history(); |
| if (!last || strcmp (last->line, line_read) != 0) |
| add_history (line_read); |
| } |
| |
| return (line_read); |
| } |
| |
| /* VTY shell main routine. */ |
| int |
| main (int argc, char **argv, char **env) |
| { |
| char *p; |
| int opt; |
| int eval_flag = 0; |
| int boot_flag = 0; |
| char *eval_line = NULL; |
| char *integrated_file = NULL; |
| |
| /* Preserve name of myself. */ |
| progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); |
| |
| /* Option handling. */ |
| while (1) |
| { |
| opt = getopt_long (argc, argv, "be:c:h", longopts, 0); |
| |
| if (opt == EOF) |
| break; |
| |
| switch (opt) |
| { |
| case 0: |
| break; |
| case 'b': |
| boot_flag = 1; |
| break; |
| case 'e': |
| case 'c': |
| eval_flag = 1; |
| eval_line = optarg; |
| break; |
| case 'h': |
| usage (0); |
| break; |
| default: |
| usage (1); |
| break; |
| } |
| } |
| |
| /* Initialize user input buffer. */ |
| line_read = NULL; |
| |
| /* Signal and others. */ |
| vtysh_signal_init (); |
| |
| /* Make vty structure and register commands. */ |
| vtysh_init_vty (); |
| vtysh_init_cmd (); |
| vtysh_user_init (); |
| vtysh_config_init (); |
| |
| vty_init_vtysh (); |
| |
| sort_node (); |
| |
| vtysh_connect_all (); |
| |
| /* Read vtysh configuration file. */ |
| vtysh_read_config (config_default); |
| |
| /* If eval mode. */ |
| if (eval_flag) |
| { |
| vtysh_execute_no_pager (eval_line); |
| exit (0); |
| } |
| |
| /* Boot startup configuration file. */ |
| if (boot_flag) |
| { |
| if (vtysh_read_config (integrate_default)) |
| { |
| fprintf (stderr, "Can't open configuration file [%s]\n", |
| integrate_default); |
| exit (1); |
| } |
| else |
| exit (0); |
| } |
| |
| vtysh_pager_init (); |
| |
| vtysh_readline_init (); |
| |
| vty_hello (vty); |
| |
| vtysh_auth (); |
| |
| /* Enter into enable node. */ |
| vtysh_execute ("enable"); |
| |
| /* Preparation for longjmp() in sigtstp(). */ |
| sigsetjmp (jmpbuf, 1); |
| jmpflag = 1; |
| |
| /* Main command loop. */ |
| while (vtysh_rl_gets ()) |
| vtysh_execute (line_read); |
| |
| printf ("\n"); |
| |
| /* Rest in peace. */ |
| exit (0); |
| } |