Annotation of embedaddon/quagga/vtysh/vtysh_main.c, revision 1.1.1.2

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. */
1.1.1.2 ! misho      66: static void
1.1       misho      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.  */
1.1.1.2 ! misho      87: static void
1.1       misho      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 */
1.1.1.2 ! misho     101: static void
1.1       misho     102: vtysh_signal_set (int signo, void (*func)(int))
                    103: {
                    104:   struct sigaction sig;
                    105:   struct sigaction osig;
                    106: 
                    107:   sig.sa_handler = func;
                    108:   sigemptyset (&sig.sa_mask);
                    109:   sig.sa_flags = 0;
                    110: #ifdef SA_RESTART
                    111:   sig.sa_flags |= SA_RESTART;
                    112: #endif /* SA_RESTART */
                    113: 
1.1.1.2 ! misho     114:   sigaction (signo, &sig, &osig);
1.1       misho     115: }
                    116: 
                    117: /* Initialization of signal handles. */
1.1.1.2 ! misho     118: static void
1.1       misho     119: vtysh_signal_init ()
                    120: {
                    121:   vtysh_signal_set (SIGINT, sigint);
                    122:   vtysh_signal_set (SIGTSTP, sigtstp);
                    123:   vtysh_signal_set (SIGPIPE, SIG_IGN);
                    124: }
                    125: 
                    126: /* Help information display. */
                    127: static void
                    128: usage (int status)
                    129: {
                    130:   if (status != 0)
                    131:     fprintf (stderr, "Try `%s --help' for more information.\n", progname);
                    132:   else
                    133:     printf ("Usage : %s [OPTION...]\n\n" \
                    134:            "Integrated shell for Quagga routing software suite. \n\n" \
                    135:            "-b, --boot               Execute boot startup configuration\n" \
                    136:            "-c, --command            Execute argument as command\n" \
                    137:            "-d, --daemon             Connect only to the specified daemon\n" \
                    138:            "-E, --echo               Echo prompt and command in -c mode\n" \
                    139:            "-C, --dryrun             Check configuration for validity and exit\n" \
                    140:            "-h, --help               Display this help and exit\n\n" \
                    141:            "Note that multiple commands may be executed from the command\n" \
                    142:            "line by passing multiple -c args, or by embedding linefeed\n" \
                    143:            "characters in one or more of the commands.\n\n" \
                    144:            "Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
                    145: 
                    146:   exit (status);
                    147: }
                    148: 
                    149: /* VTY shell options, we use GNU getopt library. */
                    150: struct option longopts[] = 
                    151: {
                    152:   { "boot",                 no_argument,             NULL, 'b'},
                    153:   /* For compatibility with older zebra/quagga versions */
                    154:   { "eval",                 required_argument,       NULL, 'e'},
                    155:   { "command",              required_argument,       NULL, 'c'},
                    156:   { "daemon",               required_argument,       NULL, 'd'},
                    157:   { "echo",                 no_argument,             NULL, 'E'},
                    158:   { "dryrun",              no_argument,             NULL, 'C'},
                    159:   { "help",                 no_argument,             NULL, 'h'},
                    160:   { "noerror",             no_argument,             NULL, 'n'},
                    161:   { 0 }
                    162: };
                    163: 
                    164: /* Read a string, and return a pointer to it.  Returns NULL on EOF. */
1.1.1.2 ! misho     165: static char *
1.1       misho     166: vtysh_rl_gets ()
                    167: {
                    168:   HIST_ENTRY *last;
                    169:   /* If the buffer has already been allocated, return the memory
                    170:    * to the free pool. */
                    171:   if (line_read)
                    172:     {
                    173:       free (line_read);
                    174:       line_read = NULL;
                    175:     }
                    176:      
                    177:   /* Get a line from the user.  Change prompt according to node.  XXX. */
                    178:   line_read = readline (vtysh_prompt ());
                    179:      
                    180:   /* If the line has any text in it, save it on the history. But only if
                    181:    * last command in history isn't the same one. */
                    182:   if (line_read && *line_read)
                    183:     {
                    184:       using_history();
                    185:       last = previous_history();
                    186:       if (!last || strcmp (last->line, line_read) != 0) {
                    187:        add_history (line_read);
                    188:        append_history(1,history_file);
                    189:       }
                    190:     }
                    191:      
                    192:   return (line_read);
                    193: }
                    194: 
                    195: static void log_it(const char *line)
                    196: {
                    197:   time_t t = time(NULL);
                    198:   struct tm *tmp = localtime(&t);
1.1.1.2 ! misho     199:   const char *user = getenv("USER");
1.1       misho     200:   char tod[64];
                    201: 
1.1.1.2 ! misho     202:   if (!user)
        !           203:     user = "boot";
        !           204: 
1.1       misho     205:   strftime(tod, sizeof tod, "%Y%m%d-%H:%M.%S", tmp);
                    206:   
                    207:   fprintf(logfile, "%s:%s %s\n", tod, user, line);
                    208: }
                    209: 
                    210: /* VTY shell main routine. */
                    211: int
                    212: main (int argc, char **argv, char **env)
                    213: {
                    214:   char *p;
                    215:   int opt;
                    216:   int dryrun = 0;
                    217:   int boot_flag = 0;
                    218:   const char *daemon_name = NULL;
                    219:   struct cmd_rec {
                    220:     const char *line;
                    221:     struct cmd_rec *next;
                    222:   } *cmd = NULL;
                    223:   struct cmd_rec *tail = NULL;
                    224:   int echo_command = 0;
                    225:   int no_error = 0;
1.1.1.2 ! misho     226:   char *homedir = NULL;
1.1       misho     227: 
                    228:   /* Preserve name of myself. */
                    229:   progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
                    230: 
                    231:   /* if logging open now */
                    232:   if ((p = getenv("VTYSH_LOG")) != NULL)
                    233:       logfile = fopen(p, "a");
                    234: 
                    235:   /* Option handling. */
                    236:   while (1) 
                    237:     {
                    238:       opt = getopt_long (argc, argv, "be:c:d:nEhC", longopts, 0);
                    239:     
                    240:       if (opt == EOF)
                    241:        break;
                    242: 
                    243:       switch (opt) 
                    244:        {
                    245:        case 0:
                    246:          break;
                    247:        case 'b':
                    248:          boot_flag = 1;
                    249:          break;
                    250:        case 'e':
                    251:        case 'c':
                    252:          {
                    253:            struct cmd_rec *cr;
                    254:            cr = XMALLOC(0, sizeof(*cr));
                    255:            cr->line = optarg;
                    256:            cr->next = NULL;
                    257:            if (tail)
                    258:              tail->next = cr;
                    259:            else
                    260:              cmd = cr;
                    261:            tail = cr;
                    262:          }
                    263:          break;
                    264:        case 'd':
                    265:          daemon_name = optarg;
                    266:          break;
                    267:        case 'n':
                    268:          no_error = 1;
                    269:          break;
                    270:        case 'E':
                    271:          echo_command = 1;
                    272:          break;
                    273:        case 'C':
                    274:          dryrun = 1;
                    275:          break;
                    276:        case 'h':
                    277:          usage (0);
                    278:          break;
                    279:        default:
                    280:          usage (1);
                    281:          break;
                    282:        }
                    283:     }
                    284: 
                    285:   /* Initialize user input buffer. */
                    286:   line_read = NULL;
                    287:   setlinebuf(stdout);
                    288: 
                    289:   /* Signal and others. */
                    290:   vtysh_signal_init ();
                    291: 
                    292:   /* Make vty structure and register commands. */
                    293:   vtysh_init_vty ();
                    294:   vtysh_init_cmd ();
                    295:   vtysh_user_init ();
                    296:   vtysh_config_init ();
                    297: 
                    298:   vty_init_vtysh ();
                    299: 
                    300:   /* Read vtysh configuration file before connecting to daemons. */
                    301:   vtysh_read_config (config_default);
                    302: 
                    303:   /* Start execution only if not in dry-run mode */
                    304:   if(dryrun)
                    305:     return(0);
                    306:   
                    307:   /* Ignore error messages */
                    308:   if (no_error)
                    309:     freopen("/dev/null", "w", stdout);
                    310: 
                    311:   /* Make sure we pass authentication before proceeding. */
                    312:   vtysh_auth ();
                    313: 
                    314:   /* Do not connect until we have passed authentication. */
                    315:   if (vtysh_connect_all (daemon_name) <= 0)
                    316:     {
                    317:       fprintf(stderr, "Exiting: failed to connect to any daemons.\n");
                    318:       exit(1);
                    319:     }
                    320: 
1.1.1.2 ! misho     321:   /*
        !           322:    * Setup history file for use by both -c and regular input
        !           323:    * If we can't find the home directory, then don't store
        !           324:    * the history information
        !           325:    */
        !           326:   homedir = vtysh_get_home ();
        !           327:   if (homedir)
        !           328:     {
        !           329:       snprintf(history_file, sizeof(history_file), "%s/.history_quagga", homedir);
        !           330:       if (read_history (history_file) != 0)
        !           331:        {
        !           332:          int fp;
        !           333: 
        !           334:          fp = open (history_file, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
        !           335:          if (fp)
        !           336:            close (fp);
        !           337: 
        !           338:          read_history (history_file);
        !           339:        }
        !           340:     }
        !           341: 
1.1       misho     342:   /* If eval mode. */
                    343:   if (cmd)
                    344:     {
                    345:       /* Enter into enable node. */
                    346:       vtysh_execute ("enable");
                    347: 
                    348:       while (cmd != NULL)
                    349:         {
                    350:          int ret;
                    351:          char *eol;
                    352: 
                    353:          while ((eol = strchr(cmd->line, '\n')) != NULL)
                    354:            {
                    355:              *eol = '\0';
                    356: 
1.1.1.2 ! misho     357:              add_history (cmd->line);
        !           358:              append_history (1, history_file);
        !           359: 
1.1       misho     360:              if (echo_command)
                    361:                printf("%s%s\n", vtysh_prompt(), cmd->line);
                    362:              
                    363:              if (logfile)
                    364:                log_it(cmd->line);
                    365: 
                    366:              ret = vtysh_execute_no_pager(cmd->line);
                    367:              if (!no_error &&
                    368:                  ! (ret == CMD_SUCCESS ||
                    369:                     ret == CMD_SUCCESS_DAEMON ||
                    370:                     ret == CMD_WARNING))
                    371:                exit(1);
                    372: 
                    373:              cmd->line = eol+1;
                    374:            }
                    375: 
1.1.1.2 ! misho     376:          add_history (cmd->line);
        !           377:          append_history (1, history_file);
        !           378: 
1.1       misho     379:          if (echo_command)
                    380:            printf("%s%s\n", vtysh_prompt(), cmd->line);
                    381: 
                    382:          if (logfile)
                    383:            log_it(cmd->line);
                    384: 
                    385:          ret = vtysh_execute_no_pager(cmd->line);
                    386:          if (!no_error &&
                    387:              ! (ret == CMD_SUCCESS ||
                    388:                 ret == CMD_SUCCESS_DAEMON ||
                    389:                 ret == CMD_WARNING))
                    390:            exit(1);
                    391: 
                    392:          {
                    393:            struct cmd_rec *cr;
                    394:            cr = cmd;
                    395:            cmd = cmd->next;
                    396:            XFREE(0, cr);
                    397:          }
                    398:         }
1.1.1.2 ! misho     399: 
        !           400:       history_truncate_file(history_file,1000);
1.1       misho     401:       exit (0);
                    402:     }
                    403:   
                    404:   /* Boot startup configuration file. */
                    405:   if (boot_flag)
                    406:     {
                    407:       if (vtysh_read_config (integrate_default))
                    408:        {
                    409:          fprintf (stderr, "Can't open configuration file [%s]\n",
                    410:                   integrate_default);
                    411:          exit (1);
                    412:        }
                    413:       else
                    414:        exit (0);
                    415:     }
                    416: 
                    417:   vtysh_pager_init ();
                    418: 
                    419:   vtysh_readline_init ();
                    420: 
                    421:   vty_hello (vty);
                    422: 
                    423:   /* Enter into enable node. */
                    424:   vtysh_execute ("enable");
                    425: 
                    426:   /* Preparation for longjmp() in sigtstp(). */
                    427:   sigsetjmp (jmpbuf, 1);
                    428:   jmpflag = 1;
                    429: 
                    430:   /* Main command loop. */
                    431:   while (vtysh_rl_gets ())
                    432:     vtysh_execute (line_read);
                    433: 
                    434:   history_truncate_file(history_file,1000);
                    435:   printf ("\n");
                    436: 
                    437:   /* Rest in peace. */
                    438:   exit (0);
                    439: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>