Annotation of embedaddon/quagga/vtysh/vtysh_main.c, revision 1.1
1.1 ! misho 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:
! 22: #include <zebra.h>
! 23:
! 24: #include <sys/un.h>
! 25: #include <setjmp.h>
! 26: #include <sys/wait.h>
! 27: #include <pwd.h>
! 28:
! 29: #include <readline/readline.h>
! 30: #include <readline/history.h>
! 31:
! 32: #include <lib/version.h>
! 33: #include "getopt.h"
! 34: #include "command.h"
! 35: #include "memory.h"
! 36:
! 37: #include "vtysh/vtysh.h"
! 38: #include "vtysh/vtysh_user.h"
! 39:
! 40: /* VTY shell program name. */
! 41: char *progname;
! 42:
! 43: /* Configuration file name and directory. */
! 44: char config_default[] = SYSCONFDIR VTYSH_DEFAULT_CONFIG;
! 45: char history_file[MAXPATHLEN];
! 46:
! 47: /* Flag for indicate executing child command. */
! 48: int execute_flag = 0;
! 49:
! 50: /* For sigsetjmp() & siglongjmp(). */
! 51: static sigjmp_buf jmpbuf;
! 52:
! 53: /* Flag for avoid recursive siglongjmp() call. */
! 54: static int jmpflag = 0;
! 55:
! 56: /* A static variable for holding the line. */
! 57: static char *line_read;
! 58:
! 59: /* Master of threads. */
! 60: struct thread_master *master;
! 61:
! 62: /* Command logging */
! 63: FILE *logfile;
! 64:
! 65: /* SIGTSTP handler. This function care user's ^Z input. */
! 66: void
! 67: sigtstp (int sig)
! 68: {
! 69: /* Execute "end" command. */
! 70: vtysh_execute ("end");
! 71:
! 72: /* Initialize readline. */
! 73: rl_initialize ();
! 74: printf ("\n");
! 75:
! 76: /* Check jmpflag for duplicate siglongjmp(). */
! 77: if (! jmpflag)
! 78: return;
! 79:
! 80: jmpflag = 0;
! 81:
! 82: /* Back to main command loop. */
! 83: siglongjmp (jmpbuf, 1);
! 84: }
! 85:
! 86: /* SIGINT handler. This function care user's ^Z input. */
! 87: void
! 88: sigint (int sig)
! 89: {
! 90: /* Check this process is not child process. */
! 91: if (! execute_flag)
! 92: {
! 93: rl_initialize ();
! 94: printf ("\n");
! 95: rl_forced_update_display ();
! 96: }
! 97: }
! 98:
! 99: /* Signale wrapper for vtysh. We don't use sigevent because
! 100: * vtysh doesn't use threads. TODO */
! 101: RETSIGTYPE *
! 102: vtysh_signal_set (int signo, void (*func)(int))
! 103: {
! 104: int ret;
! 105: struct sigaction sig;
! 106: struct sigaction osig;
! 107:
! 108: sig.sa_handler = func;
! 109: sigemptyset (&sig.sa_mask);
! 110: sig.sa_flags = 0;
! 111: #ifdef SA_RESTART
! 112: sig.sa_flags |= SA_RESTART;
! 113: #endif /* SA_RESTART */
! 114:
! 115: ret = sigaction (signo, &sig, &osig);
! 116:
! 117: if (ret < 0)
! 118: return (SIG_ERR);
! 119: else
! 120: return (osig.sa_handler);
! 121: }
! 122:
! 123: /* Initialization of signal handles. */
! 124: void
! 125: vtysh_signal_init ()
! 126: {
! 127: vtysh_signal_set (SIGINT, sigint);
! 128: vtysh_signal_set (SIGTSTP, sigtstp);
! 129: vtysh_signal_set (SIGPIPE, SIG_IGN);
! 130: }
! 131:
! 132: /* Help information display. */
! 133: static void
! 134: usage (int status)
! 135: {
! 136: if (status != 0)
! 137: fprintf (stderr, "Try `%s --help' for more information.\n", progname);
! 138: else
! 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);
! 151:
! 152: exit (status);
! 153: }
! 154:
! 155: /* VTY shell options, we use GNU getopt library. */
! 156: struct option longopts[] =
! 157: {
! 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'},
! 167: { 0 }
! 168: };
! 169:
! 170: /* Read a string, and return a pointer to it. Returns NULL on EOF. */
! 171: char *
! 172: vtysh_rl_gets ()
! 173: {
! 174: HIST_ENTRY *last;
! 175: /* If the buffer has already been allocated, return the memory
! 176: * to the free pool. */
! 177: if (line_read)
! 178: {
! 179: free (line_read);
! 180: line_read = NULL;
! 181: }
! 182:
! 183: /* Get a line from the user. Change prompt according to node. XXX. */
! 184: line_read = readline (vtysh_prompt ());
! 185:
! 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)
! 189: {
! 190: using_history();
! 191: last = previous_history();
! 192: if (!last || strcmp (last->line, line_read) != 0) {
! 193: add_history (line_read);
! 194: append_history(1,history_file);
! 195: }
! 196: }
! 197:
! 198: return (line_read);
! 199: }
! 200:
! 201: static void log_it(const char *line)
! 202: {
! 203: time_t t = time(NULL);
! 204: struct tm *tmp = localtime(&t);
! 205: char *user = getenv("USER") ? : "boot";
! 206: char tod[64];
! 207:
! 208: strftime(tod, sizeof tod, "%Y%m%d-%H:%M.%S", tmp);
! 209:
! 210: fprintf(logfile, "%s:%s %s\n", tod, user, line);
! 211: }
! 212:
! 213: /* VTY shell main routine. */
! 214: int
! 215: main (int argc, char **argv, char **env)
! 216: {
! 217: char *p;
! 218: int opt;
! 219: int dryrun = 0;
! 220: int boot_flag = 0;
! 221: const char *daemon_name = NULL;
! 222: struct cmd_rec {
! 223: const char *line;
! 224: struct cmd_rec *next;
! 225: } *cmd = NULL;
! 226: struct cmd_rec *tail = NULL;
! 227: int echo_command = 0;
! 228: int no_error = 0;
! 229:
! 230: /* Preserve name of myself. */
! 231: progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
! 232:
! 233: /* if logging open now */
! 234: if ((p = getenv("VTYSH_LOG")) != NULL)
! 235: logfile = fopen(p, "a");
! 236:
! 237: /* Option handling. */
! 238: while (1)
! 239: {
! 240: opt = getopt_long (argc, argv, "be:c:d:nEhC", longopts, 0);
! 241:
! 242: if (opt == EOF)
! 243: break;
! 244:
! 245: switch (opt)
! 246: {
! 247: case 0:
! 248: break;
! 249: case 'b':
! 250: boot_flag = 1;
! 251: break;
! 252: case 'e':
! 253: case 'c':
! 254: {
! 255: struct cmd_rec *cr;
! 256: cr = XMALLOC(0, sizeof(*cr));
! 257: cr->line = optarg;
! 258: cr->next = NULL;
! 259: if (tail)
! 260: tail->next = cr;
! 261: else
! 262: cmd = cr;
! 263: tail = cr;
! 264: }
! 265: break;
! 266: case 'd':
! 267: daemon_name = optarg;
! 268: break;
! 269: case 'n':
! 270: no_error = 1;
! 271: break;
! 272: case 'E':
! 273: echo_command = 1;
! 274: break;
! 275: case 'C':
! 276: dryrun = 1;
! 277: break;
! 278: case 'h':
! 279: usage (0);
! 280: break;
! 281: default:
! 282: usage (1);
! 283: break;
! 284: }
! 285: }
! 286:
! 287: /* Initialize user input buffer. */
! 288: line_read = NULL;
! 289: setlinebuf(stdout);
! 290:
! 291: /* Signal and others. */
! 292: vtysh_signal_init ();
! 293:
! 294: /* Make vty structure and register commands. */
! 295: vtysh_init_vty ();
! 296: vtysh_init_cmd ();
! 297: vtysh_user_init ();
! 298: vtysh_config_init ();
! 299:
! 300: vty_init_vtysh ();
! 301:
! 302: sort_node ();
! 303:
! 304: /* Read vtysh configuration file before connecting to daemons. */
! 305: vtysh_read_config (config_default);
! 306:
! 307: /* Start execution only if not in dry-run mode */
! 308: if(dryrun)
! 309: return(0);
! 310:
! 311: /* Ignore error messages */
! 312: if (no_error)
! 313: freopen("/dev/null", "w", stdout);
! 314:
! 315: /* Make sure we pass authentication before proceeding. */
! 316: vtysh_auth ();
! 317:
! 318: /* Do not connect until we have passed authentication. */
! 319: if (vtysh_connect_all (daemon_name) <= 0)
! 320: {
! 321: fprintf(stderr, "Exiting: failed to connect to any daemons.\n");
! 322: exit(1);
! 323: }
! 324:
! 325: /* If eval mode. */
! 326: if (cmd)
! 327: {
! 328: /* Enter into enable node. */
! 329: vtysh_execute ("enable");
! 330:
! 331: while (cmd != NULL)
! 332: {
! 333: int ret;
! 334: char *eol;
! 335:
! 336: while ((eol = strchr(cmd->line, '\n')) != NULL)
! 337: {
! 338: *eol = '\0';
! 339:
! 340: if (echo_command)
! 341: printf("%s%s\n", vtysh_prompt(), cmd->line);
! 342:
! 343: if (logfile)
! 344: log_it(cmd->line);
! 345:
! 346: ret = vtysh_execute_no_pager(cmd->line);
! 347: if (!no_error &&
! 348: ! (ret == CMD_SUCCESS ||
! 349: ret == CMD_SUCCESS_DAEMON ||
! 350: ret == CMD_WARNING))
! 351: exit(1);
! 352:
! 353: cmd->line = eol+1;
! 354: }
! 355:
! 356: if (echo_command)
! 357: printf("%s%s\n", vtysh_prompt(), cmd->line);
! 358:
! 359: if (logfile)
! 360: log_it(cmd->line);
! 361:
! 362: ret = vtysh_execute_no_pager(cmd->line);
! 363: if (!no_error &&
! 364: ! (ret == CMD_SUCCESS ||
! 365: ret == CMD_SUCCESS_DAEMON ||
! 366: ret == CMD_WARNING))
! 367: exit(1);
! 368:
! 369: {
! 370: struct cmd_rec *cr;
! 371: cr = cmd;
! 372: cmd = cmd->next;
! 373: XFREE(0, cr);
! 374: }
! 375: }
! 376: exit (0);
! 377: }
! 378:
! 379: /* Boot startup configuration file. */
! 380: if (boot_flag)
! 381: {
! 382: if (vtysh_read_config (integrate_default))
! 383: {
! 384: fprintf (stderr, "Can't open configuration file [%s]\n",
! 385: integrate_default);
! 386: exit (1);
! 387: }
! 388: else
! 389: exit (0);
! 390: }
! 391:
! 392: vtysh_pager_init ();
! 393:
! 394: vtysh_readline_init ();
! 395:
! 396: vty_hello (vty);
! 397:
! 398: /* Enter into enable node. */
! 399: vtysh_execute ("enable");
! 400:
! 401: /* Preparation for longjmp() in sigtstp(). */
! 402: sigsetjmp (jmpbuf, 1);
! 403: jmpflag = 1;
! 404:
! 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);
! 410:
! 411: history_truncate_file(history_file,1000);
! 412: printf ("\n");
! 413:
! 414: /* Rest in peace. */
! 415: exit (0);
! 416: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>