1 /* Virtual terminal interface shell.
2 * Copyright (C) 2000 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
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
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.
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
29 #include <readline/readline.h>
30 #include <readline/history.h>
32 #include <lib/version.h>
37 #include "vtysh/vtysh.h"
38 #include "vtysh/vtysh_user.h"
40 /* VTY shell program name. */
43 /* Configuration file name and directory. */
44 char config_default
[] = SYSCONFDIR VTYSH_DEFAULT_CONFIG
;
45 char history_file
[MAXPATHLEN
];
47 /* Flag for indicate executing child command. */
50 /* For sigsetjmp() & siglongjmp(). */
51 static sigjmp_buf jmpbuf
;
53 /* Flag for avoid recursive siglongjmp() call. */
54 static int jmpflag
= 0;
56 /* A static variable for holding the line. */
57 static char *line_read
;
59 /* Master of threads. */
60 struct thread_master
*master
;
65 /* SIGTSTP handler. This function care user's ^Z input. */
69 /* Execute "end" command. */
70 vtysh_execute ("end");
72 /* Initialize readline. */
76 /* Check jmpflag for duplicate siglongjmp(). */
82 /* Back to main command loop. */
83 siglongjmp (jmpbuf
, 1);
86 /* SIGINT handler. This function care user's ^Z input. */
90 /* Check this process is not child process. */
95 rl_forced_update_display ();
99 /* Signale wrapper for vtysh. We don't use sigevent because
100 * vtysh doesn't use threads. TODO */
102 vtysh_signal_set (int signo
, void (*func
)(int))
105 struct sigaction sig
;
106 struct sigaction osig
;
108 sig
.sa_handler
= func
;
109 sigemptyset (&sig
.sa_mask
);
112 sig
.sa_flags
|= SA_RESTART
;
113 #endif /* SA_RESTART */
115 ret
= sigaction (signo
, &sig
, &osig
);
120 return (osig
.sa_handler
);
123 /* Initialization of signal handles. */
127 vtysh_signal_set (SIGINT
, sigint
);
128 vtysh_signal_set (SIGTSTP
, sigtstp
);
129 vtysh_signal_set (SIGPIPE
, SIG_IGN
);
132 /* Help information display. */
137 fprintf (stderr
, "Try `%s --help' for more information.\n", progname
);
139 printf ("Usage : %s [OPTION...]\n\n" \
140 "Integrated shell for Quagga routing software suite. \n\n" \
141 "-b, --boot Execute boot startup configuration\n" \
142 "-c, --command Execute argument as command\n" \
143 "-d, --daemon Connect only to the specified daemon\n" \
144 "-E, --echo Echo prompt and command in -c mode\n" \
145 "-C, --dryrun Check configuration for validity and exit\n" \
146 "-h, --help Display this help and exit\n\n" \
147 "Note that multiple commands may be executed from the command\n" \
148 "line by passing multiple -c args, or by embedding linefeed\n" \
149 "characters in one or more of the commands.\n\n" \
150 "Report bugs to %s\n", progname
, ZEBRA_BUG_ADDRESS
);
155 /* VTY shell options, we use GNU getopt library. */
156 struct option longopts
[] =
158 { "boot", no_argument
, NULL
, 'b'},
159 /* For compatibility with older zebra/quagga versions */
160 { "eval", required_argument
, NULL
, 'e'},
161 { "command", required_argument
, NULL
, 'c'},
162 { "daemon", required_argument
, NULL
, 'd'},
163 { "echo", no_argument
, NULL
, 'E'},
164 { "dryrun", no_argument
, NULL
, 'C'},
165 { "help", no_argument
, NULL
, 'h'},
166 { "noerror", no_argument
, NULL
, 'n'},
170 /* Read a string, and return a pointer to it. Returns NULL on EOF. */
175 /* If the buffer has already been allocated, return the memory
176 * to the free pool. */
183 /* Get a line from the user. Change prompt according to node. XXX. */
184 line_read
= readline (vtysh_prompt ());
186 /* If the line has any text in it, save it on the history. But only if
187 * last command in history isn't the same one. */
188 if (line_read
&& *line_read
)
191 last
= previous_history();
192 if (!last
|| strcmp (last
->line
, line_read
) != 0) {
193 add_history (line_read
);
194 append_history(1,history_file
);
201 static void log_it(const char *line
)
203 time_t t
= time(NULL
);
204 struct tm
*tmp
= localtime(&t
);
205 char *user
= getenv("USER") ? : "boot";
208 strftime(tod
, sizeof tod
, "%Y%m%d-%H:%M.%S", tmp
);
210 fprintf(logfile
, "%s:%s %s\n", tod
, user
, line
);
213 /* VTY shell main routine. */
215 main (int argc
, char **argv
, char **env
)
221 const char *daemon_name
= NULL
;
224 struct cmd_rec
*next
;
226 struct cmd_rec
*tail
= NULL
;
227 int echo_command
= 0;
230 /* Preserve name of myself. */
231 progname
= ((p
= strrchr (argv
[0], '/')) ? ++p
: argv
[0]);
233 /* if logging open now */
234 if ((p
= getenv("VTYSH_LOG")) != NULL
)
235 logfile
= fopen(p
, "a");
237 /* Option handling. */
240 opt
= getopt_long (argc
, argv
, "be:c:d:nEhC", longopts
, 0);
256 cr
= XMALLOC(0, sizeof(*cr
));
267 daemon_name
= optarg
;
287 /* Initialize user input buffer. */
291 /* Signal and others. */
292 vtysh_signal_init ();
294 /* Make vty structure and register commands. */
298 vtysh_config_init ();
304 /* Read vtysh configuration file before connecting to daemons. */
305 vtysh_read_config (config_default
);
307 /* Start execution only if not in dry-run mode */
311 /* Ignore error messages */
313 freopen("/dev/null", "w", stdout
);
315 /* Make sure we pass authentication before proceeding. */
318 /* Do not connect until we have passed authentication. */
319 if (vtysh_connect_all (daemon_name
) <= 0)
321 fprintf(stderr
, "Exiting: failed to connect to any daemons.\n");
328 /* Enter into enable node. */
329 vtysh_execute ("enable");
336 while ((eol
= strchr(cmd
->line
, '\n')) != NULL
)
341 printf("%s%s\n", vtysh_prompt(), cmd
->line
);
346 ret
= vtysh_execute_no_pager(cmd
->line
);
348 ! (ret
== CMD_SUCCESS
||
349 ret
== CMD_SUCCESS_DAEMON
||
357 printf("%s%s\n", vtysh_prompt(), cmd
->line
);
362 ret
= vtysh_execute_no_pager(cmd
->line
);
364 ! (ret
== CMD_SUCCESS
||
365 ret
== CMD_SUCCESS_DAEMON
||
379 /* Boot startup configuration file. */
382 if (vtysh_read_config (integrate_default
))
384 fprintf (stderr
, "Can't open configuration file [%s]\n",
394 vtysh_readline_init ();
398 /* Enter into enable node. */
399 vtysh_execute ("enable");
401 /* Preparation for longjmp() in sigtstp(). */
402 sigsetjmp (jmpbuf
, 1);
405 snprintf(history_file
, sizeof(history_file
), "%s/.history_quagga", getenv("HOME"));
406 read_history(history_file
);
407 /* Main command loop. */
408 while (vtysh_rl_gets ())
409 vtysh_execute (line_read
);
411 history_truncate_file(history_file
,1000);