📄 vtysh.c
字号:
/* 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 <sys/resource.h>#include <sys/stat.h>#include <readline/readline.h>#include <readline/history.h>#include "command.h"#include "memory.h"#include "vtysh/vtysh.h"/* Struct VTY. */struct vty *vty;/* VTY shell pager name. */char *vtysh_pager_name = NULL;/* VTY shell client structure. */struct vtysh_client{ int fd;} vtysh_client[VTYSH_INDEX_MAX];/* When '^Z' is received from vty, move down to the enable mode. */intvtysh_end (){ switch (vty->node) { case VIEW_NODE: case ENABLE_NODE: /* Nothing to do. */ break; default: vty->node = ENABLE_NODE; break; } return CMD_SUCCESS;}DEFUNSH (VTYSH_ALL, vtysh_end_all, vtysh_end_all_cmd, "end", "End current mode and down to previous mode\n"){ return vtysh_end (vty);}DEFUNSH (VTYSH_ALL, vtysh_log_stdout, vtysh_log_stdout_cmd, "log stdout", "Logging control\n" "Logging goes to stdout\n"){ return CMD_SUCCESS;}DEFUNSH (VTYSH_ALL, no_vtysh_log_stdout, no_vtysh_log_stdout_cmd, "no log stdout", NO_STR "Logging control\n" "Logging goes to stdout\n"){ return CMD_SUCCESS;}DEFUNSH (VTYSH_ALL, vtysh_log_file, vtysh_log_file_cmd, "log file FILENAME", "Logging control\n" "Logging to file\n" "Logging filename\n"){ return CMD_SUCCESS;}DEFUNSH (VTYSH_ALL, no_vtysh_log_file, no_vtysh_log_file_cmd, "no log file [FILENAME]", NO_STR "Logging control\n" "Cancel logging to file\n" "Logging file name\n"){ return CMD_SUCCESS;}DEFUNSH (VTYSH_ALL, vtysh_log_syslog, vtysh_log_syslog_cmd, "log syslog", "Logging control\n" "Logging goes to syslog\n"){ return CMD_SUCCESS;}DEFUNSH (VTYSH_ALL, no_vtysh_log_syslog, no_vtysh_log_syslog_cmd, "no log syslog", NO_STR "Logging control\n" "Cancel logging to syslog\n"){ return CMD_SUCCESS;}DEFUNSH (VTYSH_ALL, vtysh_log_trap, vtysh_log_trap_cmd, "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)", "Logging control\n" "Limit logging to specifed level\n"){ return CMD_SUCCESS;}DEFUNSH (VTYSH_ALL, no_vtysh_log_trap, no_vtysh_log_trap_cmd, "no log trap", NO_STR "Logging control\n" "Permit all logging information\n"){ return CMD_SUCCESS;}DEFUNSH (VTYSH_ALL, vtysh_log_record_priority, vtysh_log_record_priority_cmd, "log record-priority", "Logging control\n" "Log the priority of the message within the message\n"){ return CMD_SUCCESS;}DEFUNSH (VTYSH_ALL, no_vtysh_log_record_priority, no_vtysh_log_record_priority_cmd, "no log record-priority", NO_STR "Logging control\n" "Do not log the priority of the message within the message\n"){ return CMD_SUCCESS;}voidvclient_close (struct vtysh_client *vclient){ if (vclient->fd > 0) close (vclient->fd); vclient->fd = -1;}/* Following filled with debug code to trace a problematic condition under load - it SHOULD handle it.*/#define ERR_WHERE_STRING "vtysh(): vtysh_client_config(): "intvtysh_client_config (struct vtysh_client *vclient, char *line){ int ret; char *buf; size_t bufsz; char *pbuf; size_t left; char *eoln; int nbytes; int i; int readln; if (vclient->fd < 0) return CMD_SUCCESS; ret = write (vclient->fd, line, strlen (line) + 1); if (ret <= 0) { vclient_close (vclient); return CMD_SUCCESS; } /* Allow enough room for buffer to read more than a few pages from socket */ bufsz = 5 * sysconf(_SC_PAGESIZE) + 1; buf = XMALLOC(MTYPE_TMP, bufsz); memset(buf, 0, bufsz); pbuf = buf; while (1) { if (pbuf >= ((buf + bufsz) -1)) { fprintf (stderr, ERR_WHERE_STRING \ "warning - pbuf beyond buffer end.\n"); return CMD_WARNING; } readln = (buf + bufsz) - pbuf - 1; nbytes = read (vclient->fd, pbuf, readln); if (nbytes <= 0) { if (errno == EINTR) continue; fprintf(stderr, ERR_WHERE_STRING "(%u)", errno); perror(""); if (errno == EAGAIN || errno == EIO) continue; vclient_close (vclient); XFREE(MTYPE_TMP, buf); return CMD_SUCCESS; } pbuf[nbytes] = '\0'; if (nbytes >= 4) { i = nbytes - 4; if (pbuf[i] == '\0' && pbuf[i + 1] == '\0' && pbuf[i + 2] == '\0') { ret = pbuf[i + 3]; break; } } pbuf += nbytes; /* See if a line exists in buffer, if so parse and consume it, and reset read position */ if ((eoln = strrchr(buf, '\n')) == NULL) continue; if (eoln >= ((buf + bufsz) - 1)) { fprintf (stderr, ERR_WHERE_STRING \ "warning - eoln beyond buffer end.\n"); } vtysh_config_parse(buf); eoln++; left = (size_t)(buf + bufsz - eoln); memmove(buf, eoln, left); buf[bufsz-1] = '\0'; pbuf = buf + strlen(buf); } /* parse anything left in the buffer */ vtysh_config_parse (buf); XFREE(MTYPE_TMP, buf); return ret;}intvtysh_client_execute (struct vtysh_client *vclient, char *line, FILE *fp){ int ret; char buf[1001]; int nbytes; int i; if (vclient->fd < 0) return CMD_SUCCESS; ret = write (vclient->fd, line, strlen (line) + 1); if (ret <= 0) { vclient_close (vclient); return CMD_SUCCESS; } while (1) { nbytes = read (vclient->fd, buf, sizeof(buf)-1); if (nbytes <= 0 && errno != EINTR) { vclient_close (vclient); return CMD_SUCCESS; } if (nbytes > 0) { buf[nbytes] = '\0'; fprintf (fp, "%s", buf); fflush (fp); if (nbytes >= 4) { i = nbytes - 4; if (buf[i] == '\0' && buf[i + 1] == '\0' && buf[i + 2] == '\0') { ret = buf[i + 3]; break; } } } } return ret;}voidvtysh_exit_ripd_only (){ vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIP], "exit", stdout);}voidvtysh_pager_init (){ vtysh_pager_name = getenv ("VTYSH_PAGER"); if (! vtysh_pager_name) vtysh_pager_name = "more";}/* Command execution over the vty interface. */voidvtysh_execute_func (char *line, int pager){ int ret, cmd_stat; vector vline; struct cmd_element *cmd; FILE *fp = NULL; /* Split readline string up into the vector */ vline = cmd_make_strvec (line); if (vline == NULL) return; ret = cmd_execute_command (vline, vty, &cmd); cmd_free_strvec (vline); switch (ret) { case CMD_WARNING: if (vty->type == VTY_FILE) printf ("Warning...\n"); break; case CMD_ERR_AMBIGUOUS: printf ("%% Ambiguous command.\n"); break; case CMD_ERR_NO_MATCH: printf ("%% Unknown command.\n"); break; case CMD_ERR_INCOMPLETE: printf ("%% Command incomplete.\n"); break; case CMD_SUCCESS_DAEMON: { if (pager && vtysh_pager_name) { fp = popen ("more", "w"); if (fp == NULL) { perror ("popen"); exit (1); } } else fp = stdout; if (! strcmp(cmd->string,"configure terminal")) { cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_ZEBRA], line, fp); if (cmd_stat != CMD_WARNING) cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIP], line, fp); if (cmd_stat != CMD_WARNING) cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIPNG], line, fp); if (cmd_stat != CMD_WARNING) cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF], line, fp); if (cmd_stat != CMD_WARNING) cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF6], line, fp); if (cmd_stat != CMD_WARNING) cmd_stat = vtysh_client_execute (&vtysh_client[VTYSH_INDEX_BGP], line, fp); if (cmd_stat) { line = "end"; vline = cmd_make_strvec (line); if (vline == NULL) { if (pager && vtysh_pager_name && fp) { if (pclose (fp) == -1) { perror ("pclose"); exit (1); } fp = NULL; } return; } ret = cmd_execute_command (vline, vty, &cmd); cmd_free_strvec (vline); if (ret != CMD_SUCCESS_DAEMON) break; } else if (cmd->func) { (*cmd->func) (cmd, vty, 0, NULL); break; } } if (cmd->daemon & VTYSH_ZEBRA) if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_ZEBRA], line, fp) != CMD_SUCCESS) break; if (cmd->daemon & VTYSH_RIPD) if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIP], line, fp) != CMD_SUCCESS) break; if (cmd->daemon & VTYSH_RIPNGD) if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIPNG], line, fp) != CMD_SUCCESS) break; if (cmd->daemon & VTYSH_OSPFD) if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF], line, fp) != CMD_SUCCESS) break; if (cmd->daemon & VTYSH_OSPF6D) if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF6], line, fp) != CMD_SUCCESS) break; if (cmd->daemon & VTYSH_BGPD) if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_BGP], line, fp) != CMD_SUCCESS) break; if (cmd->func) (*cmd->func) (cmd, vty, 0, NULL); } } if (pager && vtysh_pager_name && fp) { if (pclose (fp) == -1) { perror ("pclose"); exit (1); } fp = NULL; }}voidvtysh_execute_no_pager (char *line){ vtysh_execute_func (line, 0);}voidvtysh_execute (char *line){ vtysh_execute_func (line, 1);}/* Configration make from file. */intvtysh_config_from_file (struct vty *vty, FILE *fp){ int ret; vector vline; struct cmd_element *cmd; while (fgets (vty->buf, VTY_BUFSIZ, fp)) { if (vty->buf[0] == '!' || vty->buf[1] == '#') continue; vline = cmd_make_strvec (vty->buf); /* In case of comment line */ if (vline == NULL) continue; /* Execute configuration command : this is strict match */ ret = cmd_execute_command_strict (vline, vty, &cmd); /* Try again with setting node to CONFIG_NODE */ if (ret != CMD_SUCCESS && ret != CMD_SUCCESS_DAEMON && ret != CMD_WARNING) { if (vty->node == KEYCHAIN_KEY_NODE) { vty->node = KEYCHAIN_NODE; vtysh_exit_ripd_only (); ret = cmd_execute_command_strict (vline, vty, &cmd); if (ret != CMD_SUCCESS && ret != CMD_SUCCESS_DAEMON && ret != CMD_WARNING) { vtysh_exit_ripd_only (); vty->node = CONFIG_NODE; ret = cmd_execute_command_strict (vline, vty, &cmd); } } else { vtysh_execute ("end"); vtysh_execute ("configure terminal"); vty->node = CONFIG_NODE; ret = cmd_execute_command_strict (vline, vty, &cmd); } } cmd_free_strvec (vline); switch (ret) { case CMD_WARNING: if (vty->type == VTY_FILE) printf ("Warning...\n"); break; case CMD_ERR_AMBIGUOUS: printf ("%% Ambiguous command.\n"); break; case CMD_ERR_NO_MATCH: printf ("%% Unknown command: %s", vty->buf); break; case CMD_ERR_INCOMPLETE: printf ("%% Command incomplete.\n"); break; case CMD_SUCCESS_DAEMON: { if (cmd->daemon & VTYSH_ZEBRA) if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_ZEBRA], vty->buf, stdout) != CMD_SUCCESS) break; if (cmd->daemon & VTYSH_RIPD) if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIP], vty->buf, stdout) != CMD_SUCCESS) break; if (cmd->daemon & VTYSH_RIPNGD) if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_RIPNG], vty->buf, stdout) != CMD_SUCCESS) break; if (cmd->daemon & VTYSH_OSPFD) if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF], vty->buf, stdout) != CMD_SUCCESS) break; if (cmd->daemon & VTYSH_OSPF6D) if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_OSPF6], vty->buf, stdout) != CMD_SUCCESS) break; if (cmd->daemon & VTYSH_BGPD) if (vtysh_client_execute (&vtysh_client[VTYSH_INDEX_BGP], vty->buf, stdout) != CMD_SUCCESS) break; if (cmd->func) (*cmd->func) (cmd, vty, 0, NULL); } } } return CMD_SUCCESS;}/* We don't care about the point of the cursor when '?' is typed. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -