Annotation of embedaddon/quagga/vtysh/vtysh_main.c, revision 1.1.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>