mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-05 02:46:37 +00:00
vtysh-add-mark-cmd.patch
VTYSH: Add support for marking a file with appropriate end of context To support applying only differences to the existing config, this patch enables supplying the appropriate end markers to a provided file (or stdin). By end markers, I mean, adding "end" and "exit-address-family" at the appropriate places in the configuration to ease finding the differences with the running configuration.
This commit is contained in:
parent
70c0f18432
commit
0846286b09
161
vtysh/vtysh.c
161
vtysh/vtysh.c
@ -500,6 +500,157 @@ vtysh_execute (const char *line)
|
||||
return vtysh_execute_func (line, 1);
|
||||
}
|
||||
|
||||
int
|
||||
vtysh_mark_file (char *filename)
|
||||
{
|
||||
struct vty *vty;
|
||||
FILE *confp = NULL;
|
||||
int ret;
|
||||
vector vline;
|
||||
int tried = 0;
|
||||
struct cmd_element *cmd;
|
||||
int saved_ret, prev_node;
|
||||
int lineno = 0;
|
||||
|
||||
if (strncmp("-", filename, 1) == 0)
|
||||
confp = stdin;
|
||||
else
|
||||
confp = fopen (filename, "r");
|
||||
|
||||
if (confp == NULL)
|
||||
return (1);
|
||||
|
||||
vty = vty_new ();
|
||||
vty->fd = 0; /* stdout */
|
||||
vty->type = VTY_TERM;
|
||||
vty->node = CONFIG_NODE;
|
||||
|
||||
vtysh_execute_no_pager ("enable");
|
||||
vtysh_execute_no_pager ("configure terminal");
|
||||
|
||||
while (fgets (vty->buf, VTY_BUFSIZ, confp))
|
||||
{
|
||||
lineno++;
|
||||
tried = 0;
|
||||
|
||||
if (vty->buf[0] == '!' || vty->buf[1] == '#')
|
||||
{
|
||||
fprintf(stdout, "%s", vty->buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Split readline string up into the vector. */
|
||||
vline = cmd_make_strvec (vty->buf);
|
||||
|
||||
if (vline == NULL)
|
||||
{
|
||||
fprintf(stdout, "%s", vty->buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
prev_node = vty->node;
|
||||
saved_ret = ret = cmd_execute_command_strict (vline, vty, &cmd);
|
||||
|
||||
/* If command doesn't succeeded in current node, try to walk up in node tree.
|
||||
* Changing vty->node is enough to try it just out without actual walkup in
|
||||
* the vtysh. */
|
||||
while (ret != CMD_SUCCESS && ret != CMD_SUCCESS_DAEMON && ret != CMD_WARNING
|
||||
&& vty->node > CONFIG_NODE)
|
||||
{
|
||||
vty->node = node_parent(vty->node);
|
||||
ret = cmd_execute_command_strict (vline, vty, &cmd);
|
||||
tried++;
|
||||
}
|
||||
|
||||
/* If command succeeded in any other node than current (tried > 0) we have
|
||||
* to move into node in the vtysh where it succeeded. */
|
||||
if (ret == CMD_SUCCESS || ret == CMD_SUCCESS_DAEMON || ret == CMD_WARNING)
|
||||
{
|
||||
if ((prev_node == BGP_VPNV4_NODE || prev_node == BGP_IPV4_NODE
|
||||
|| prev_node == BGP_IPV6_NODE || prev_node == BGP_IPV4M_NODE
|
||||
|| prev_node == BGP_IPV6M_NODE)
|
||||
&& (tried == 1))
|
||||
{
|
||||
fprintf(stdout, "exit-address-family\n");
|
||||
}
|
||||
else if ((prev_node == KEYCHAIN_KEY_NODE) && (tried == 1))
|
||||
{
|
||||
fprintf(stdout, "exit\n");
|
||||
}
|
||||
else if (tried)
|
||||
{
|
||||
fprintf(stdout, "end\n");
|
||||
}
|
||||
}
|
||||
/* If command didn't succeed in any node, continue with return value from
|
||||
* first try. */
|
||||
else if (tried)
|
||||
{
|
||||
ret = saved_ret;
|
||||
vty->node = prev_node;
|
||||
}
|
||||
|
||||
cmd_free_strvec (vline);
|
||||
switch (ret)
|
||||
{
|
||||
case CMD_WARNING:
|
||||
if (vty->type == VTY_FILE)
|
||||
fprintf (stderr,"line %d: Warning...: %s\n", lineno, vty->buf);
|
||||
fclose(confp);
|
||||
vty_close(vty);
|
||||
return (1);
|
||||
case CMD_ERR_AMBIGUOUS:
|
||||
fprintf (stderr,"line %d: %% Ambiguous command: %s\n", lineno, vty->buf);
|
||||
fclose(confp);
|
||||
vty_close(vty);
|
||||
return(1);
|
||||
case CMD_ERR_NO_MATCH:
|
||||
fprintf (stderr,"line %d: %% Unknown command: %s\n", lineno, vty->buf);
|
||||
fclose(confp);
|
||||
vty_close(vty);
|
||||
return(1);
|
||||
case CMD_ERR_INCOMPLETE:
|
||||
fprintf (stderr,"line %d: %% Command incomplete: %s\n", lineno, vty->buf);
|
||||
fclose(confp);
|
||||
vty_close(vty);
|
||||
return(1);
|
||||
case CMD_SUCCESS:
|
||||
fprintf(stdout, "%s", vty->buf);
|
||||
break;
|
||||
case CMD_SUCCESS_DAEMON:
|
||||
{
|
||||
u_int i;
|
||||
int cmd_stat = CMD_SUCCESS;
|
||||
|
||||
fprintf(stdout, "%s", vty->buf);
|
||||
for (i = 0; i < array_size(vtysh_client); i++)
|
||||
{
|
||||
if (cmd->daemon & vtysh_client[i].flag)
|
||||
{
|
||||
cmd_stat = vtysh_client_execute (&vtysh_client[i],
|
||||
vty->buf, stdout);
|
||||
if (cmd_stat != CMD_SUCCESS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cmd_stat != CMD_SUCCESS)
|
||||
break;
|
||||
|
||||
if (cmd->func)
|
||||
(*cmd->func) (cmd, vty, 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* This is the end */
|
||||
fprintf(stdout, "end\n");
|
||||
vty_close(vty);
|
||||
|
||||
if (confp != stdin)
|
||||
fclose(confp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Configration make from file. */
|
||||
int
|
||||
vtysh_config_from_file (struct vty *vty, FILE *fp)
|
||||
@ -507,6 +658,7 @@ vtysh_config_from_file (struct vty *vty, FILE *fp)
|
||||
int ret;
|
||||
vector vline;
|
||||
struct cmd_element *cmd;
|
||||
int save_node = CONFIG_NODE;
|
||||
|
||||
while (fgets (vty->buf, VTY_BUFSIZ, fp))
|
||||
{
|
||||
@ -544,10 +696,15 @@ vtysh_config_from_file (struct vty *vty, FILE *fp)
|
||||
}
|
||||
else
|
||||
{
|
||||
save_node = vty->node;
|
||||
vtysh_execute ("end");
|
||||
vtysh_execute ("configure terminal");
|
||||
vty->node = CONFIG_NODE;
|
||||
ret = cmd_execute_command_strict (vline, vty, &cmd);
|
||||
if ((ret != CMD_SUCCESS) &&
|
||||
(ret != CMD_SUCCESS_DAEMON) &&
|
||||
(ret != CMD_WARNING))
|
||||
vty->node = save_node;
|
||||
}
|
||||
}
|
||||
|
||||
@ -560,13 +717,13 @@ vtysh_config_from_file (struct vty *vty, FILE *fp)
|
||||
fprintf (stdout,"Warning...\n");
|
||||
break;
|
||||
case CMD_ERR_AMBIGUOUS:
|
||||
fprintf (stdout,"%% Ambiguous command.\n");
|
||||
fprintf (stdout,"%% Ambiguous command: %s\n", vty->buf);
|
||||
break;
|
||||
case CMD_ERR_NO_MATCH:
|
||||
fprintf (stdout,"%% Unknown command: %s", vty->buf);
|
||||
break;
|
||||
case CMD_ERR_INCOMPLETE:
|
||||
fprintf (stdout,"%% Command incomplete.\n");
|
||||
fprintf (stdout,"%% Command incomplete: %s\n", vty->buf);
|
||||
break;
|
||||
case CMD_SUCCESS_DAEMON:
|
||||
{
|
||||
|
@ -52,6 +52,8 @@ void vtysh_config_write (void);
|
||||
|
||||
int vtysh_config_from_file (struct vty *, FILE *);
|
||||
|
||||
int vtysh_mark_file(char *filename);
|
||||
|
||||
int vtysh_read_config (char *);
|
||||
|
||||
void vtysh_config_parse (char *);
|
||||
|
@ -141,8 +141,10 @@ usage (int status)
|
||||
"-b, --boot Execute boot startup configuration\n" \
|
||||
"-c, --command Execute argument as command\n" \
|
||||
"-d, --daemon Connect only to the specified daemon\n" \
|
||||
"-f, --inputfile Execute commands from specific file and exit\n" \
|
||||
"-E, --echo Echo prompt and command in -c mode\n" \
|
||||
"-C, --dryrun Check configuration for validity and exit\n" \
|
||||
"-m, --markfile Mark input file with context end\n"
|
||||
"-h, --help Display this help and exit\n\n" \
|
||||
"Note that multiple commands may be executed from the command\n" \
|
||||
"line by passing multiple -c args, or by embedding linefeed\n" \
|
||||
@ -160,10 +162,12 @@ struct option longopts[] =
|
||||
{ "eval", required_argument, NULL, 'e'},
|
||||
{ "command", required_argument, NULL, 'c'},
|
||||
{ "daemon", required_argument, NULL, 'd'},
|
||||
{ "inputfile", required_argument, NULL, 'f'},
|
||||
{ "echo", no_argument, NULL, 'E'},
|
||||
{ "dryrun", no_argument, NULL, 'C'},
|
||||
{ "help", no_argument, NULL, 'h'},
|
||||
{ "noerror", no_argument, NULL, 'n'},
|
||||
{ "mark", no_argument, NULL, 'm'},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
@ -219,6 +223,7 @@ main (int argc, char **argv, char **env)
|
||||
int dryrun = 0;
|
||||
int boot_flag = 0;
|
||||
const char *daemon_name = NULL;
|
||||
const char *inputfile = NULL;
|
||||
struct cmd_rec {
|
||||
const char *line;
|
||||
struct cmd_rec *next;
|
||||
@ -226,6 +231,7 @@ main (int argc, char **argv, char **env)
|
||||
struct cmd_rec *tail = NULL;
|
||||
int echo_command = 0;
|
||||
int no_error = 0;
|
||||
int markfile = 0;
|
||||
|
||||
/* Preserve name of myself. */
|
||||
progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
|
||||
@ -237,7 +243,7 @@ main (int argc, char **argv, char **env)
|
||||
/* Option handling. */
|
||||
while (1)
|
||||
{
|
||||
opt = getopt_long (argc, argv, "be:c:d:nEhC", longopts, 0);
|
||||
opt = getopt_long (argc, argv, "be:c:d:nf:mEhC", longopts, 0);
|
||||
|
||||
if (opt == EOF)
|
||||
break;
|
||||
@ -266,6 +272,12 @@ main (int argc, char **argv, char **env)
|
||||
case 'd':
|
||||
daemon_name = optarg;
|
||||
break;
|
||||
case 'f':
|
||||
inputfile = optarg;
|
||||
break;
|
||||
case 'm':
|
||||
markfile = 1;
|
||||
break;
|
||||
case 'n':
|
||||
no_error = 1;
|
||||
break;
|
||||
@ -300,12 +312,28 @@ main (int argc, char **argv, char **env)
|
||||
vty_init_vtysh ();
|
||||
|
||||
/* Read vtysh configuration file before connecting to daemons. */
|
||||
vtysh_read_config (config_default);
|
||||
vtysh_read_config(config_default);
|
||||
|
||||
if (markfile)
|
||||
{
|
||||
if (!inputfile)
|
||||
{
|
||||
fprintf(stderr, "-f option MUST be specified with -m option\n");
|
||||
return(1);
|
||||
}
|
||||
return(vtysh_mark_file(inputfile));
|
||||
}
|
||||
|
||||
/* Start execution only if not in dry-run mode */
|
||||
if(dryrun)
|
||||
return(0);
|
||||
|
||||
{
|
||||
if (inputfile)
|
||||
{
|
||||
vtysh_read_config(inputfile);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Ignore error messages */
|
||||
if (no_error)
|
||||
freopen("/dev/null", "w", stdout);
|
||||
@ -320,6 +348,12 @@ main (int argc, char **argv, char **env)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (inputfile)
|
||||
{
|
||||
vtysh_read_config(inputfile);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* If eval mode. */
|
||||
if (cmd)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user