2 * CLI backend interface.
5 * Copyright (C) 2016 Cumulus Networks, Inc.
6 * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
7 * Copyright (C) 2013 by Open Source Routing.
8 * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
10 * This file is part of GNU Zebra.
12 * GNU Zebra is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2, or (at your option) any
17 * GNU Zebra is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with GNU Zebra; see the file COPYING. If not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
34 #include <lib/version.h>
40 #include "workqueue.h"
42 #include "command_match.h"
46 DEFINE_MTYPE( LIB
, HOST
, "Host config")
47 DEFINE_MTYPE( LIB
, STRVEC
, "String vector")
48 DEFINE_MTYPE_STATIC(LIB
, CMD_TOKENS
, "Command Tokens")
49 DEFINE_MTYPE_STATIC(LIB
, CMD_DESC
, "Command Token Text")
50 DEFINE_MTYPE_STATIC(LIB
, CMD_TEXT
, "Command Token Help")
51 DEFINE_MTYPE( LIB
, CMD_ARG
, "Command Argument")
53 /* Command vector which includes some level of command lists. Normally
54 each daemon maintains each own cmdvec. */
57 /* Host information structure. */
60 /* Standard command node structures. */
61 static struct cmd_node auth_node
=
67 static struct cmd_node view_node
=
73 static struct cmd_node auth_enable_node
=
79 static struct cmd_node enable_node
=
85 static struct cmd_node config_node
=
92 /* Default motd string. */
93 static const char *default_motd
= FRR_DEFAULT_MOTD
;
95 static const struct facility_map
{
99 } syslog_facilities
[] =
101 { LOG_KERN
, "kern", 1 },
102 { LOG_USER
, "user", 2 },
103 { LOG_MAIL
, "mail", 1 },
104 { LOG_DAEMON
, "daemon", 1 },
105 { LOG_AUTH
, "auth", 1 },
106 { LOG_SYSLOG
, "syslog", 1 },
107 { LOG_LPR
, "lpr", 2 },
108 { LOG_NEWS
, "news", 1 },
109 { LOG_UUCP
, "uucp", 2 },
110 { LOG_CRON
, "cron", 1 },
112 { LOG_FTP
, "ftp", 1 },
114 { LOG_LOCAL0
, "local0", 6 },
115 { LOG_LOCAL1
, "local1", 6 },
116 { LOG_LOCAL2
, "local2", 6 },
117 { LOG_LOCAL3
, "local3", 6 },
118 { LOG_LOCAL4
, "local4", 6 },
119 { LOG_LOCAL5
, "local5", 6 },
120 { LOG_LOCAL6
, "local6", 6 },
121 { LOG_LOCAL7
, "local7", 6 },
126 facility_name(int facility
)
128 const struct facility_map
*fm
;
130 for (fm
= syslog_facilities
; fm
->name
; fm
++)
131 if (fm
->facility
== facility
)
137 facility_match(const char *str
)
139 const struct facility_map
*fm
;
141 for (fm
= syslog_facilities
; fm
->name
; fm
++)
142 if (!strncmp(str
,fm
->name
,fm
->match
))
148 level_match(const char *s
)
152 for ( level
= 0 ; zlog_priority
[level
] != NULL
; level
++ )
153 if (!strncmp (s
, zlog_priority
[level
], 2))
155 return ZLOG_DISABLED
;
158 /* This is called from main when a daemon is invoked with -v or --version. */
160 print_version (const char *progname
)
162 printf ("%s version %s\n", progname
, FRR_VERSION
);
163 printf ("%s\n", FRR_COPYRIGHT
);
164 printf ("configured with:\n\t%s\n", FRR_CONFIG_ARGS
);
168 /* Utility function to concatenate argv argument into a single string
169 with inserting ' ' character between each argument. */
171 argv_concat (struct cmd_token
**argv
, int argc
, int shift
)
179 for (i
= shift
; i
< argc
; i
++)
180 len
+= strlen(argv
[i
]->arg
)+1;
183 p
= str
= XMALLOC(MTYPE_TMP
, len
);
184 for (i
= shift
; i
< argc
; i
++)
187 memcpy(p
, argv
[i
]->arg
, (arglen
= strlen(argv
[i
]->arg
)));
196 * Convenience function for accessing argv data.
200 * @param text definition snippet of the desired token
201 * @param index the starting index, and where to store the
202 * index of the found token if it exists
203 * @return 1 if found, 0 otherwise
206 argv_find (struct cmd_token
**argv
, int argc
, const char *text
, int *index
)
209 for (int i
= *index
; i
< argc
&& found
== 0; i
++)
210 if ((found
= strmatch (text
, argv
[i
]->text
)))
216 cmd_hash_key (void *p
)
218 return (uintptr_t) p
;
222 cmd_hash_cmp (const void *a
, const void *b
)
227 /* Install top node of command vector. */
229 install_node (struct cmd_node
*node
,
230 int (*func
) (struct vty
*))
232 vector_set_index (cmdvec
, node
->node
, node
);
234 node
->cmdgraph
= graph_new ();
235 node
->cmd_vector
= vector_init (VECTOR_MIN_SIZE
);
237 struct cmd_token
*token
= new_cmd_token (START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
238 graph_new_node (node
->cmdgraph
, token
, (void (*)(void *)) &del_cmd_token
);
239 node
->cmd_hash
= hash_create (cmd_hash_key
, cmd_hash_cmp
);
243 * Tokenizes a string, storing tokens in a vector.
244 * Whitespace is ignored.
246 * Delimiter string = " \n\r\t".
248 * @param string to tokenize
249 * @return tokenized string
252 cmd_make_strvec (const char *string
)
254 if (!string
) return NULL
;
256 char *copy
, *copystart
;
257 copystart
= copy
= XSTRDUP (MTYPE_TMP
, string
);
259 // skip leading whitespace
260 while (isspace ((int) *copy
) && *copy
!= '\0') copy
++;
262 // if the entire string was whitespace or a comment, return
263 if (*copy
== '\0' || *copy
== '!' || *copy
== '#')
265 XFREE (MTYPE_TMP
, copystart
);
269 vector strvec
= vector_init (VECTOR_MIN_SIZE
);
270 const char *delim
= " \n\r\t", *tok
= NULL
;
273 tok
= strsep (©
, delim
);
275 vector_set (strvec
, XSTRDUP (MTYPE_STRVEC
, tok
));
278 XFREE (MTYPE_TMP
, copystart
);
282 /* Free allocated string vector. */
284 cmd_free_strvec (vector v
)
292 for (i
= 0; i
< vector_active (v
); i
++)
293 if ((cp
= vector_slot (v
, i
)) != NULL
)
294 XFREE (MTYPE_STRVEC
, cp
);
299 /* Return prompt character of specified node. */
301 cmd_prompt (enum node_type node
)
303 struct cmd_node
*cnode
;
305 cnode
= vector_slot (cmdvec
, node
);
306 return cnode
->prompt
;
310 cmd_nodes_link (struct graph_node
*from
, struct graph_node
*to
)
312 for (size_t i
= 0; i
< vector_active (from
->to
); i
++)
313 if (vector_slot (from
->to
, i
) == to
)
318 static bool cmd_nodes_equal (struct graph_node
*ga
, struct graph_node
*gb
);
320 /* returns a single node to be excluded as "next" from iteration
321 * - for JOIN_TKN, never continue back to the FORK_TKN
322 * - in all other cases, don't try the node itself (in case of "...")
324 static inline struct graph_node
*
325 cmd_loopstop(struct graph_node
*gn
)
327 struct cmd_token
*tok
= gn
->data
;
328 if (tok
->type
== JOIN_TKN
)
329 return tok
->forkjoin
;
335 cmd_subgraph_equal (struct graph_node
*ga
, struct graph_node
*gb
,
336 struct graph_node
*a_join
)
339 struct graph_node
*a_fork
, *b_fork
;
340 a_fork
= cmd_loopstop (ga
);
341 b_fork
= cmd_loopstop (gb
);
343 if (vector_active (ga
->to
) != vector_active (gb
->to
))
345 for (i
= 0; i
< vector_active (ga
->to
); i
++)
347 struct graph_node
*cga
= vector_slot (ga
->to
, i
);
349 for (j
= 0; j
< vector_active (gb
->to
); j
++)
351 struct graph_node
*cgb
= vector_slot (gb
->to
, i
);
353 if (cga
== a_fork
&& cgb
!= b_fork
)
355 if (cga
== a_fork
&& cgb
== b_fork
)
358 if (cmd_nodes_equal (cga
, cgb
))
362 if (cmd_subgraph_equal (cga
, cgb
, a_join
))
366 if (j
== vector_active (gb
->to
))
372 /* deep compare -- for FORK_TKN, the entire subgraph is compared.
373 * this is what's needed since we're not currently trying to partially
376 cmd_nodes_equal (struct graph_node
*ga
, struct graph_node
*gb
)
378 struct cmd_token
*a
= ga
->data
, *b
= gb
->data
;
380 if (a
->type
!= b
->type
|| a
->allowrepeat
!= b
->allowrepeat
)
382 if (a
->type
< SPECIAL_TKN
&& strcmp (a
->text
, b
->text
))
384 /* one a ..., the other not. */
385 if (cmd_nodes_link (ga
, ga
) != cmd_nodes_link (gb
, gb
))
391 return a
->min
== b
->min
&& a
->max
== b
->max
;
394 /* one is keywords, the other just option or selector ... */
395 if (cmd_nodes_link (a
->forkjoin
, ga
) != cmd_nodes_link (b
->forkjoin
, gb
))
397 if (cmd_nodes_link (ga
, a
->forkjoin
) != cmd_nodes_link (gb
, b
->forkjoin
))
399 return cmd_subgraph_equal (ga
, gb
, a
->forkjoin
);
407 cmd_fork_bump_attr (struct graph_node
*gn
, struct graph_node
*join
,
411 struct cmd_token
*tok
= gn
->data
;
412 struct graph_node
*stop
= cmd_loopstop (gn
);
415 for (i
= 0; i
< vector_active (gn
->to
); i
++)
417 struct graph_node
*next
= vector_slot (gn
->to
, i
);
418 if (next
== stop
|| next
== join
)
420 cmd_fork_bump_attr (next
, join
, attr
);
424 /* move an entire subtree from the temporary graph resulting from
425 * parse() into the permanent graph for the command node.
427 * this touches rather deeply into the graph code unfortunately.
430 cmd_reparent_tree (struct graph
*fromgraph
, struct graph
*tograph
,
431 struct graph_node
*node
)
433 struct graph_node
*stop
= cmd_loopstop (node
);
436 for (i
= 0; i
< vector_active (fromgraph
->nodes
); i
++)
437 if (vector_slot (fromgraph
->nodes
, i
) == node
)
439 /* agressive iteration punching through subgraphs - may hit some
440 * nodes twice. reparent only if found on old graph */
441 vector_unset (fromgraph
->nodes
, i
);
442 vector_set (tograph
->nodes
, node
);
446 for (i
= 0; i
< vector_active (node
->to
); i
++)
448 struct graph_node
*next
= vector_slot (node
->to
, i
);
450 cmd_reparent_tree (fromgraph
, tograph
, next
);
455 cmd_free_recur (struct graph
*graph
, struct graph_node
*node
,
456 struct graph_node
*stop
)
458 struct graph_node
*next
, *nstop
;
460 for (size_t i
= vector_active (node
->to
); i
; i
--)
462 next
= vector_slot (node
->to
, i
- 1);
465 nstop
= cmd_loopstop (next
);
467 cmd_free_recur (graph
, next
, nstop
);
468 cmd_free_recur (graph
, nstop
, stop
);
470 graph_delete_node (graph
, node
);
474 cmd_free_node (struct graph
*graph
, struct graph_node
*node
)
476 struct cmd_token
*tok
= node
->data
;
477 if (tok
->type
== JOIN_TKN
)
478 cmd_free_recur (graph
, tok
->forkjoin
, node
);
479 graph_delete_node (graph
, node
);
482 /* recursive graph merge. call with
484 * (which holds true for old == START_TKN, new == START_TKN)
487 cmd_merge_nodes (struct graph
*oldgraph
, struct graph
*newgraph
,
488 struct graph_node
*old
, struct graph_node
*new,
491 struct cmd_token
*tok
;
492 struct graph_node
*old_skip
, *new_skip
;
493 old_skip
= cmd_loopstop (old
);
494 new_skip
= cmd_loopstop (new);
496 assert (direction
== 1 || direction
== -1);
499 tok
->refcnt
+= direction
;
502 for (j
= 0; j
< vector_active (new->to
); j
++)
504 struct graph_node
*cnew
= vector_slot (new->to
, j
);
505 if (cnew
== new_skip
)
508 for (i
= 0; i
< vector_active (old
->to
); i
++)
510 struct graph_node
*cold
= vector_slot (old
->to
, i
);
511 if (cold
== old_skip
)
514 if (cmd_nodes_equal (cold
, cnew
))
516 struct cmd_token
*told
= cold
->data
, *tnew
= cnew
->data
;
518 if (told
->type
== END_TKN
)
522 graph_delete_node (oldgraph
, vector_slot (cold
->to
, 0));
523 graph_delete_node (oldgraph
, cold
);
526 /* force no-match handling to install END_TKN */
527 i
= vector_active (old
->to
);
531 /* the entire fork compared as equal, we continue after it. */
532 if (told
->type
== FORK_TKN
)
534 if (tnew
->attr
< told
->attr
&& direction
> 0)
535 cmd_fork_bump_attr (cold
, told
->forkjoin
, tnew
->attr
);
536 /* XXX: no reverse bump on uninstall */
537 told
= (cold
= told
->forkjoin
)->data
;
538 tnew
= (cnew
= tnew
->forkjoin
)->data
;
540 if (tnew
->attr
< told
->attr
)
541 told
->attr
= tnew
->attr
;
543 cmd_merge_nodes (oldgraph
, newgraph
, cold
, cnew
, direction
);
547 /* nothing found => add new to old */
548 if (i
== vector_active (old
->to
) && direction
> 0)
550 assert (vector_count (cnew
->from
) ==
551 cmd_nodes_link (cnew
, cnew
) ? 2 : 1);
552 graph_remove_edge (new, cnew
);
554 cmd_reparent_tree (newgraph
, oldgraph
, cnew
);
556 graph_add_edge (old
, cnew
);
561 cmd_free_node (oldgraph
, old
);
565 cmd_merge_graphs (struct graph
*old
, struct graph
*new, int direction
)
567 assert (vector_active (old
->nodes
) >= 1);
568 assert (vector_active (new->nodes
) >= 1);
570 cmd_merge_nodes (old
, new,
571 vector_slot (old
->nodes
, 0), vector_slot (new->nodes
, 0),
575 /* Install a command into a node. */
577 install_element (enum node_type ntype
, struct cmd_element
*cmd
)
579 struct cmd_node
*cnode
;
581 /* cmd_init hasn't been called */
584 fprintf (stderr
, "%s called before cmd_init, breakage likely\n",
589 cnode
= vector_slot (cmdvec
, ntype
);
593 fprintf (stderr
, "Command node %d doesn't exist, please check it\n",
598 if (hash_lookup (cnode
->cmd_hash
, cmd
) != NULL
)
601 "Multiple command installs to node %d of command:\n%s\n",
606 assert (hash_get (cnode
->cmd_hash
, cmd
, hash_alloc_intern
));
608 struct graph
*graph
= graph_new();
609 struct cmd_token
*token
= new_cmd_token (START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
610 graph_new_node (graph
, token
, (void (*)(void *)) &del_cmd_token
);
612 command_parse_format (graph
, cmd
);
613 cmd_merge_graphs (cnode
->cmdgraph
, graph
, +1);
614 graph_delete_graph (graph
);
616 vector_set (cnode
->cmd_vector
, cmd
);
618 if (ntype
== VIEW_NODE
)
619 install_element (ENABLE_NODE
, cmd
);
623 uninstall_element (enum node_type ntype
, struct cmd_element
*cmd
)
625 struct cmd_node
*cnode
;
627 /* cmd_init hasn't been called */
630 fprintf (stderr
, "%s called before cmd_init, breakage likely\n",
635 cnode
= vector_slot (cmdvec
, ntype
);
639 fprintf (stderr
, "Command node %d doesn't exist, please check it\n",
644 if (hash_release (cnode
->cmd_hash
, cmd
) == NULL
)
647 "Trying to uninstall non-installed command (node %d):\n%s\n",
652 vector_unset_value (cnode
->cmd_vector
, cmd
);
654 struct graph
*graph
= graph_new();
655 struct cmd_token
*token
= new_cmd_token (START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
656 graph_new_node (graph
, token
, (void (*)(void *)) &del_cmd_token
);
658 command_parse_format (graph
, cmd
);
659 cmd_merge_graphs (cnode
->cmdgraph
, graph
, -1);
660 graph_delete_graph (graph
);
662 if (ntype
== VIEW_NODE
)
663 uninstall_element (ENABLE_NODE
, cmd
);
667 static const unsigned char itoa64
[] =
668 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
671 to64(char *s
, long v
, int n
)
675 *s
++ = itoa64
[v
&0x3f];
681 zencrypt (const char *passwd
)
685 char *crypt (const char *, const char *);
689 to64(&salt
[0], random(), 3);
690 to64(&salt
[3], tv
.tv_usec
, 3);
693 return crypt (passwd
, salt
);
696 /* This function write configuration of this host. */
698 config_write_host (struct vty
*vty
)
701 vty_out (vty
, "hostname %s%s", host
.name
, VTY_NEWLINE
);
705 if (host
.password_encrypt
)
706 vty_out (vty
, "password 8 %s%s", host
.password_encrypt
, VTY_NEWLINE
);
707 if (host
.enable_encrypt
)
708 vty_out (vty
, "enable password 8 %s%s", host
.enable_encrypt
, VTY_NEWLINE
);
713 vty_out (vty
, "password %s%s", host
.password
, VTY_NEWLINE
);
715 vty_out (vty
, "enable password %s%s", host
.enable
, VTY_NEWLINE
);
718 if (zlog_default
->default_lvl
!= LOG_DEBUG
)
720 vty_out (vty
, "! N.B. The 'log trap' command is deprecated.%s",
722 vty_out (vty
, "log trap %s%s",
723 zlog_priority
[zlog_default
->default_lvl
], VTY_NEWLINE
);
726 if (host
.logfile
&& (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != ZLOG_DISABLED
))
728 vty_out (vty
, "log file %s", host
.logfile
);
729 if (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != zlog_default
->default_lvl
)
731 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_FILE
]]);
732 vty_out (vty
, "%s", VTY_NEWLINE
);
735 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != ZLOG_DISABLED
)
737 vty_out (vty
, "log stdout");
738 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != zlog_default
->default_lvl
)
740 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
]]);
741 vty_out (vty
, "%s", VTY_NEWLINE
);
744 if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
745 vty_out(vty
,"no log monitor%s",VTY_NEWLINE
);
746 else if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] != zlog_default
->default_lvl
)
747 vty_out(vty
,"log monitor %s%s",
748 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
]],VTY_NEWLINE
);
750 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
)
752 vty_out (vty
, "log syslog");
753 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != zlog_default
->default_lvl
)
755 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
]]);
756 vty_out (vty
, "%s", VTY_NEWLINE
);
759 if (zlog_default
->facility
!= LOG_DAEMON
)
760 vty_out (vty
, "log facility %s%s",
761 facility_name(zlog_default
->facility
), VTY_NEWLINE
);
763 if (zlog_default
->record_priority
== 1)
764 vty_out (vty
, "log record-priority%s", VTY_NEWLINE
);
766 if (zlog_default
->timestamp_precision
> 0)
767 vty_out (vty
, "log timestamp precision %d%s",
768 zlog_default
->timestamp_precision
, VTY_NEWLINE
);
771 vty_out (vty
, "service advanced-vty%s", VTY_NEWLINE
);
774 vty_out (vty
, "service password-encryption%s", VTY_NEWLINE
);
777 vty_out (vty
, "service terminal-length %d%s", host
.lines
,
781 vty_out (vty
, "banner motd file %s%s", host
.motdfile
, VTY_NEWLINE
);
782 else if (! host
.motd
)
783 vty_out (vty
, "no banner motd%s", VTY_NEWLINE
);
788 /* Utility function for getting command graph. */
789 static struct graph
*
790 cmd_node_graph (vector v
, enum node_type ntype
)
792 struct cmd_node
*cnode
= vector_slot (v
, ntype
);
793 return cnode
->cmdgraph
;
797 cmd_try_do_shortcut (enum node_type node
, char* first_word
) {
798 if ( first_word
!= NULL
&&
801 node
!= AUTH_ENABLE_NODE
&&
802 node
!= ENABLE_NODE
&&
803 0 == strcmp( "do", first_word
) )
809 * Compare function for cmd_token.
810 * Used with qsort to sort command completions.
813 compare_completions (const void *fst
, const void *snd
)
815 struct cmd_token
*first
= *(struct cmd_token
**) fst
,
816 *secnd
= *(struct cmd_token
**) snd
;
817 return strcmp (first
->text
, secnd
->text
);
821 * Takes a list of completions returned by command_complete,
822 * dedeuplicates them based on both text and description,
823 * sorts them, and returns them as a vector.
825 * @param completions linked list of cmd_token
826 * @return deduplicated and sorted vector with
829 completions_to_vec (struct list
*completions
)
831 vector comps
= vector_init (VECTOR_MIN_SIZE
);
834 struct cmd_token
*token
, *cr
= NULL
;
835 unsigned int i
, exists
;
836 for (ALL_LIST_ELEMENTS_RO(completions
,ln
,token
))
838 if (token
->type
== END_TKN
&& (cr
= token
))
841 // linear search for token in completions vector
843 for (i
= 0; i
< vector_active (comps
) && !exists
; i
++)
845 struct cmd_token
*curr
= vector_slot (comps
, i
);
847 exists
= !strcmp (curr
->text
, token
->text
) &&
848 !strcmp (curr
->desc
, token
->desc
);
850 exists
= !strcmp (curr
->text
, token
->text
);
851 #endif /* VTYSH_DEBUG */
855 vector_set (comps
, token
);
860 vector_active (comps
),
862 &compare_completions
);
864 // make <cr> the first element, if it is present
867 vector_set_index (comps
, vector_active (comps
), NULL
);
868 memmove (comps
->index
+ 1, comps
->index
, (comps
->alloced
- 1) * sizeof (void *));
869 vector_set_index (comps
, 0, cr
);
875 * Generates a vector of cmd_token representing possible completions
876 * on the current input.
878 * @param vline the vectorized input line
879 * @param vty the vty with the node to match on
880 * @param status pointer to matcher status code
881 * @return vector of struct cmd_token * with possible completions
884 cmd_complete_command_real (vector vline
, struct vty
*vty
, int *status
)
886 struct list
*completions
;
887 struct graph
*cmdgraph
= cmd_node_graph (cmdvec
, vty
->node
);
889 enum matcher_rv rv
= command_complete (cmdgraph
, vline
, &completions
);
891 if (MATCHER_ERROR(rv
))
893 *status
= CMD_ERR_NO_MATCH
;
897 vector comps
= completions_to_vec (completions
);
898 list_delete (completions
);
900 // set status code appropriately
901 switch (vector_active (comps
))
904 *status
= CMD_ERR_NO_MATCH
;
907 *status
= CMD_COMPLETE_FULL_MATCH
;
910 *status
= CMD_COMPLETE_LIST_MATCH
;
917 cmd_describe_command (vector vline
, struct vty
*vty
, int *status
)
921 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
923 enum node_type onode
;
924 vector shifted_vline
;
928 vty
->node
= ENABLE_NODE
;
929 /* We can try it on enable node, cos' the vty is authenticated */
931 shifted_vline
= vector_init (vector_count(vline
));
933 for (index
= 1; index
< vector_active (vline
); index
++)
935 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
938 ret
= cmd_complete_command_real (shifted_vline
, vty
, status
);
940 vector_free(shifted_vline
);
945 return cmd_complete_command_real (vline
, vty
, status
);
949 * Generate possible tab-completions for the given input. This function only
950 * returns results that would result in a valid command if used as Readline
951 * completions (as is the case in vtysh). For instance, if the passed vline ends
952 * with '4.3.2', the strings 'A.B.C.D' and 'A.B.C.D/M' will _not_ be returned.
954 * @param vline vectorized input line
956 * @param status location to store matcher status code in
957 * @return set of valid strings for use with Readline as tab-completions.
961 cmd_complete_command (vector vline
, struct vty
*vty
, int *status
)
964 int original_node
= vty
->node
;
965 vector input_line
= vector_init (vector_count (vline
));
967 // if the first token is 'do' we'll want to execute the command in the enable node
968 int do_shortcut
= cmd_try_do_shortcut (vty
->node
, vector_slot (vline
, 0));
969 vty
->node
= do_shortcut
? ENABLE_NODE
: original_node
;
971 // construct the input line we'll be matching on
972 unsigned int offset
= (do_shortcut
) ? 1 : 0;
973 for (unsigned index
= 0; index
+ offset
< vector_active (vline
); index
++)
974 vector_set_index (input_line
, index
, vector_lookup (vline
, index
+ offset
));
976 // get token completions -- this is a copying operation
977 vector comps
= NULL
, initial_comps
;
978 initial_comps
= cmd_complete_command_real (input_line
, vty
, status
);
980 if (!MATCHER_ERROR (*status
))
982 assert (initial_comps
);
983 // filter out everything that is not suitable for a tab-completion
984 comps
= vector_init (VECTOR_MIN_SIZE
);
985 for (unsigned int i
= 0; i
< vector_active(initial_comps
); i
++)
987 struct cmd_token
*token
= vector_slot (initial_comps
, i
);
988 if (token
->type
== WORD_TKN
)
989 vector_set (comps
, token
);
991 vector_free (initial_comps
);
993 // since we filtered results, we need to re-set status code
994 switch (vector_active (comps
))
997 *status
= CMD_ERR_NO_MATCH
;
1000 *status
= CMD_COMPLETE_FULL_MATCH
;
1003 *status
= CMD_COMPLETE_LIST_MATCH
;
1006 // copy completions text into an array of char*
1007 ret
= XMALLOC (MTYPE_TMP
, (vector_active (comps
)+1) * sizeof (char *));
1009 for (i
= 0; i
< vector_active (comps
); i
++)
1011 struct cmd_token
*token
= vector_slot (comps
, i
);
1012 ret
[i
] = XSTRDUP (MTYPE_TMP
, token
->text
);
1013 vector_unset (comps
, i
);
1015 // set the last element to NULL, because this array is used in
1016 // a Readline completion_generator function which expects NULL
1017 // as a sentinel value
1019 vector_free (comps
);
1022 else if (initial_comps
)
1023 vector_free (initial_comps
);
1025 // comps should always be null here
1028 // free the adjusted input line
1029 vector_free (input_line
);
1031 // reset vty->node to its original value
1032 vty
->node
= original_node
;
1037 /* return parent node */
1038 /* MUST eventually converge on CONFIG_NODE */
1040 node_parent ( enum node_type node
)
1044 assert (node
> CONFIG_NODE
);
1048 case BGP_VPNV4_NODE
:
1049 case BGP_VPNV6_NODE
:
1050 case BGP_ENCAP_NODE
:
1051 case BGP_ENCAPV6_NODE
:
1052 case BGP_VRF_POLICY_NODE
:
1053 case BGP_VNC_DEFAULTS_NODE
:
1054 case BGP_VNC_NVE_GROUP_NODE
:
1055 case BGP_VNC_L2_GROUP_NODE
:
1057 case BGP_IPV4M_NODE
:
1058 case BGP_IPV4L_NODE
:
1060 case BGP_IPV6M_NODE
:
1062 case BGP_IPV6L_NODE
:
1065 case KEYCHAIN_KEY_NODE
:
1066 ret
= KEYCHAIN_NODE
;
1068 case LINK_PARAMS_NODE
:
1069 ret
= INTERFACE_NODE
;
1075 case LDP_IPV4_IFACE_NODE
:
1076 ret
= LDP_IPV4_NODE
;
1078 case LDP_IPV6_IFACE_NODE
:
1079 ret
= LDP_IPV6_NODE
;
1081 case LDP_PSEUDOWIRE_NODE
:
1082 ret
= LDP_L2VPN_NODE
;
1092 /* Execute command by argument vline vector. */
1094 cmd_execute_command_real (vector vline
,
1095 enum filter_type filter
,
1097 const struct cmd_element
**cmd
)
1099 struct list
*argv_list
;
1100 enum matcher_rv status
;
1101 const struct cmd_element
*matched_element
= NULL
;
1103 struct graph
*cmdgraph
= cmd_node_graph (cmdvec
, vty
->node
);
1104 status
= command_match (cmdgraph
, vline
, &argv_list
, &matched_element
);
1107 *cmd
= matched_element
;
1109 // if matcher error, return corresponding CMD_ERR
1110 if (MATCHER_ERROR(status
))
1113 list_delete (argv_list
);
1116 case MATCHER_INCOMPLETE
:
1117 return CMD_ERR_INCOMPLETE
;
1118 case MATCHER_AMBIGUOUS
:
1119 return CMD_ERR_AMBIGUOUS
;
1121 return CMD_ERR_NO_MATCH
;
1125 // build argv array from argv list
1126 struct cmd_token
**argv
= XMALLOC (MTYPE_TMP
, argv_list
->count
* sizeof (struct cmd_token
*));
1127 struct listnode
*ln
;
1128 struct cmd_token
*token
;
1130 for (ALL_LIST_ELEMENTS_RO(argv_list
,ln
,token
))
1133 int argc
= argv_list
->count
;
1136 if (matched_element
->daemon
)
1137 ret
= CMD_SUCCESS_DAEMON
;
1139 ret
= matched_element
->func (matched_element
, vty
, argc
, argv
);
1141 // delete list and cmd_token's in it
1142 list_delete (argv_list
);
1143 XFREE (MTYPE_TMP
, argv
);
1149 * Execute a given command, handling things like "do ..." and checking
1150 * whether the given command might apply at a parent node if doesn't
1151 * apply for the current node.
1153 * @param vline Command line input, vector of char* where each element is
1155 * @param vty The vty context in which the command should be executed.
1156 * @param cmd Pointer where the struct cmd_element of the matched command
1157 * will be stored, if any. May be set to NULL if this info is
1159 * @param vtysh If set != 0, don't lookup the command at parent nodes.
1160 * @return The status of the command that has been executed or an error code
1161 * as to why no command could be executed.
1164 cmd_execute_command (vector vline
, struct vty
*vty
,
1165 const struct cmd_element
**cmd
,
1168 int ret
, saved_ret
= 0;
1169 enum node_type onode
, try_node
;
1171 onode
= try_node
= vty
->node
;
1173 if (cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0)))
1175 vector shifted_vline
;
1178 vty
->node
= ENABLE_NODE
;
1179 /* We can try it on enable node, cos' the vty is authenticated */
1181 shifted_vline
= vector_init (vector_count(vline
));
1183 for (index
= 1; index
< vector_active (vline
); index
++)
1184 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
1186 ret
= cmd_execute_command_real (shifted_vline
, FILTER_RELAXED
, vty
, cmd
);
1188 vector_free(shifted_vline
);
1193 saved_ret
= ret
= cmd_execute_command_real (vline
, FILTER_RELAXED
, vty
, cmd
);
1198 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
)
1200 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
1201 while (vty
->node
> CONFIG_NODE
)
1203 try_node
= node_parent(try_node
);
1204 vty
->node
= try_node
;
1205 ret
= cmd_execute_command_real (vline
, FILTER_RELAXED
, vty
, cmd
);
1206 if (ret
== CMD_SUCCESS
|| ret
== CMD_WARNING
)
1209 /* no command succeeded, reset the vty to the original node */
1213 /* return command status for original node */
1218 * Execute a given command, matching it strictly against the current node.
1219 * This mode is used when reading config files.
1221 * @param vline Command line input, vector of char* where each element is
1223 * @param vty The vty context in which the command should be executed.
1224 * @param cmd Pointer where the struct cmd_element* of the matched command
1225 * will be stored, if any. May be set to NULL if this info is
1227 * @return The status of the command that has been executed or an error code
1228 * as to why no command could be executed.
1231 cmd_execute_command_strict (vector vline
, struct vty
*vty
,
1232 const struct cmd_element
**cmd
)
1234 return cmd_execute_command_real(vline
, FILTER_STRICT
, vty
, cmd
);
1238 * Parse one line of config, walking up the parse tree attempting to find a match
1240 * @param vty The vty context in which the command should be executed.
1241 * @param cmd Pointer where the struct cmd_element* of the match command
1242 * will be stored, if any. May be set to NULL if this info is
1244 * @param use_daemon Boolean to control whether or not we match on CMD_SUCCESS_DAEMON
1246 * @return The status of the command that has been executed or an error code
1247 * as to why no command could be executed.
1250 command_config_read_one_line (struct vty
*vty
, const struct cmd_element
**cmd
, int use_daemon
)
1256 vline
= cmd_make_strvec (vty
->buf
);
1258 /* In case of comment line */
1262 /* Execute configuration command : this is strict match */
1263 ret
= cmd_execute_command_strict (vline
, vty
, cmd
);
1265 // Climb the tree and try the command again at each node
1266 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
1267 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
1268 ret
!= CMD_SUCCESS
&&
1269 ret
!= CMD_WARNING
&&
1270 vty
->node
!= CONFIG_NODE
) {
1272 saved_node
= vty
->node
;
1274 while (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
1275 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
1276 ret
!= CMD_SUCCESS
&&
1277 ret
!= CMD_WARNING
&&
1278 vty
->node
> CONFIG_NODE
) {
1279 vty
->node
= node_parent(vty
->node
);
1280 ret
= cmd_execute_command_strict (vline
, vty
, cmd
);
1283 // If climbing the tree did not work then ignore the command and
1284 // stay at the same node
1285 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
1286 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
1287 ret
!= CMD_SUCCESS
&&
1290 vty
->node
= saved_node
;
1294 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
)
1295 memcpy (vty
->error_buf
, vty
->buf
, VTY_BUFSIZ
);
1297 cmd_free_strvec (vline
);
1302 /* Configuration make from file. */
1304 config_from_file (struct vty
*vty
, FILE *fp
, unsigned int *line_num
)
1306 int ret
, error_ret
=0;
1309 while (fgets (vty
->buf
, VTY_BUFSIZ
, fp
))
1314 ret
= command_config_read_one_line (vty
, NULL
, 0);
1316 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
&&
1317 ret
!= CMD_ERR_NOTHING_TODO
)
1328 /* Configuration from terminal */
1329 DEFUN (config_terminal
,
1330 config_terminal_cmd
,
1331 "configure terminal",
1332 "Configuration from vty interface\n"
1333 "Configuration terminal\n")
1335 if (vty_config_lock (vty
))
1336 vty
->node
= CONFIG_NODE
;
1339 vty_out (vty
, "VTY configuration is locked by other VTY%s", VTY_NEWLINE
);
1345 /* Enable command */
1349 "Turn on privileged mode command\n")
1351 /* If enable password is NULL, change to ENABLE_NODE */
1352 if ((host
.enable
== NULL
&& host
.enable_encrypt
== NULL
) ||
1353 vty
->type
== VTY_SHELL_SERV
)
1354 vty
->node
= ENABLE_NODE
;
1356 vty
->node
= AUTH_ENABLE_NODE
;
1361 /* Disable command */
1365 "Turn off privileged mode command\n")
1367 if (vty
->node
== ENABLE_NODE
)
1368 vty
->node
= VIEW_NODE
;
1372 /* Down vty node level. */
1376 "Exit current mode and down to previous mode\n")
1383 cmd_exit (struct vty
*vty
)
1389 if (vty_shell (vty
))
1392 vty
->status
= VTY_CLOSE
;
1395 vty
->node
= ENABLE_NODE
;
1396 vty_config_unlock (vty
);
1398 case INTERFACE_NODE
:
1409 case LDP_L2VPN_NODE
:
1416 vty
->node
= CONFIG_NODE
;
1419 case BGP_IPV4M_NODE
:
1420 case BGP_IPV4L_NODE
:
1421 case BGP_VPNV4_NODE
:
1422 case BGP_VPNV6_NODE
:
1423 case BGP_ENCAP_NODE
:
1424 case BGP_ENCAPV6_NODE
:
1425 case BGP_VRF_POLICY_NODE
:
1426 case BGP_VNC_DEFAULTS_NODE
:
1427 case BGP_VNC_NVE_GROUP_NODE
:
1428 case BGP_VNC_L2_GROUP_NODE
:
1430 case BGP_IPV6M_NODE
:
1432 case BGP_IPV6L_NODE
:
1433 vty
->node
= BGP_NODE
;
1437 vty
->node
= LDP_NODE
;
1439 case LDP_IPV4_IFACE_NODE
:
1440 vty
->node
= LDP_IPV4_NODE
;
1442 case LDP_IPV6_IFACE_NODE
:
1443 vty
->node
= LDP_IPV6_NODE
;
1445 case LDP_PSEUDOWIRE_NODE
:
1446 vty
->node
= LDP_L2VPN_NODE
;
1448 case KEYCHAIN_KEY_NODE
:
1449 vty
->node
= KEYCHAIN_NODE
;
1451 case LINK_PARAMS_NODE
:
1452 vty
->node
= INTERFACE_NODE
;
1463 "Exit current mode and down to previous mode\n")
1465 return config_exit (self
, vty
, argc
, argv
);
1469 /* End of configuration. */
1473 "End current mode and change to enable mode.")
1479 /* Nothing to do. */
1482 case INTERFACE_NODE
:
1490 case BGP_ENCAP_NODE
:
1491 case BGP_ENCAPV6_NODE
:
1492 case BGP_VRF_POLICY_NODE
:
1493 case BGP_VNC_DEFAULTS_NODE
:
1494 case BGP_VNC_NVE_GROUP_NODE
:
1495 case BGP_VNC_L2_GROUP_NODE
:
1496 case BGP_VPNV4_NODE
:
1497 case BGP_VPNV6_NODE
:
1499 case BGP_IPV4M_NODE
:
1500 case BGP_IPV4L_NODE
:
1502 case BGP_IPV6M_NODE
:
1504 case BGP_IPV6L_NODE
:
1511 case LDP_IPV4_IFACE_NODE
:
1512 case LDP_IPV6_IFACE_NODE
:
1513 case LDP_L2VPN_NODE
:
1514 case LDP_PSEUDOWIRE_NODE
:
1517 case KEYCHAIN_KEY_NODE
:
1521 case LINK_PARAMS_NODE
:
1522 vty_config_unlock (vty
);
1523 vty
->node
= ENABLE_NODE
;
1532 DEFUN (show_version
,
1536 "Displays zebra version\n")
1538 vty_out (vty
, "%s %s (%s).%s", FRR_FULL_NAME
, FRR_VERSION
,
1539 host
.name
? host
.name
: "",
1541 vty_out (vty
, "%s%s%s", FRR_COPYRIGHT
, GIT_INFO
, VTY_NEWLINE
);
1542 vty_out (vty
, "configured with:%s %s%s", VTY_NEWLINE
,
1543 FRR_CONFIG_ARGS
, VTY_NEWLINE
);
1548 /* "Set" version ... ignore version tags */
1549 DEFUN (frr_version_defaults
,
1550 frr_version_defaults_cmd
,
1551 "frr <version|defaults> LINE...",
1552 "FRRouting global parameters\n"
1553 "version configuration was written by\n"
1554 "set of configuration defaults used\n"
1557 if (vty
->type
== VTY_TERM
|| vty
->type
== VTY_SHELL
)
1558 /* only print this when the user tries to do run it */
1559 vty_out (vty
, "%% NOTE: This command currently does nothing.%s"
1560 "%% It is written to the configuration for future reference.%s",
1561 VTY_NEWLINE
, VTY_NEWLINE
);
1565 /* Help display function for all node. */
1569 "Description of the interactive help system\n")
1572 "Quagga VTY provides advanced help feature. When you need help,%s\
1573 anytime at the command line please press '?'.%s\
1575 If nothing matches, the help list will be empty and you must backup%s\
1576 until entering a '?' shows the available options.%s\
1577 Two styles of help are provided:%s\
1578 1. Full help is available when you are ready to enter a%s\
1579 command argument (e.g. 'show ?') and describes each possible%s\
1581 2. Partial help is provided when an abbreviated argument is entered%s\
1582 and you want to know what arguments match the input%s\
1583 (e.g. 'show me?'.)%s%s", VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
,
1584 VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
,
1585 VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
);
1590 permute (struct graph_node
*start
, struct vty
*vty
)
1592 static struct list
*position
= NULL
;
1593 if (!position
) position
= list_new ();
1595 struct cmd_token
*stok
= start
->data
;
1596 struct graph_node
*gnn
;
1597 struct listnode
*ln
;
1600 listnode_add (position
, start
);
1601 for (unsigned int i
= 0; i
< vector_active (start
->to
); i
++)
1603 struct graph_node
*gn
= vector_slot (start
->to
, i
);
1604 struct cmd_token
*tok
= gn
->data
;
1605 if (tok
->attr
== CMD_ATTR_HIDDEN
||
1606 tok
->attr
== CMD_ATTR_DEPRECATED
)
1608 else if (tok
->type
== END_TKN
|| gn
== start
)
1611 for (ALL_LIST_ELEMENTS_RO (position
,ln
,gnn
))
1613 struct cmd_token
*tt
= gnn
->data
;
1614 if (tt
->type
< SPECIAL_TKN
)
1615 vty_out (vty
, " %s", tt
->text
);
1618 vty_out (vty
, "...");
1619 vty_out (vty
, VTY_NEWLINE
);
1624 if (stok
->type
== FORK_TKN
&& tok
->type
!= FORK_TKN
)
1625 for (ALL_LIST_ELEMENTS_RO (position
, ln
, gnn
))
1626 if (gnn
== gn
&& (skip
= true))
1632 list_delete_node (position
, listtail(position
));
1636 cmd_list_cmds (struct vty
*vty
, int do_permute
)
1638 struct cmd_node
*node
= vector_slot (cmdvec
, vty
->node
);
1641 permute (vector_slot (node
->cmdgraph
->nodes
, 0), vty
);
1644 /* loop over all commands at this node */
1645 struct cmd_element
*element
= NULL
;
1646 for (unsigned int i
= 0; i
< vector_active(node
->cmd_vector
); i
++)
1647 if ((element
= vector_slot (node
->cmd_vector
, i
)) &&
1648 element
->attr
!= CMD_ATTR_DEPRECATED
&&
1649 element
->attr
!= CMD_ATTR_HIDDEN
)
1650 vty_out (vty
, " %s%s", element
->string
, VTY_NEWLINE
);
1655 /* Help display function for all node. */
1658 "list [permutations]",
1659 "Print command list\n"
1660 "Print all possible command permutations\n")
1662 return cmd_list_cmds (vty
, argc
== 2);
1665 DEFUN (show_commandtree
,
1666 show_commandtree_cmd
,
1667 "show commandtree [permutations]",
1669 "Show command tree\n"
1670 "Permutations that we are interested in\n")
1672 return cmd_list_cmds (vty
, argc
== 3);
1676 vty_write_config (struct vty
*vty
)
1679 struct cmd_node
*node
;
1681 if (vty
->type
== VTY_TERM
)
1683 vty_out (vty
, "%sCurrent configuration:%s", VTY_NEWLINE
,
1685 vty_out (vty
, "!%s", VTY_NEWLINE
);
1688 vty_out (vty
, "frr version %s%s", FRR_VER_SHORT
, VTY_NEWLINE
);
1689 vty_out (vty
, "frr defaults %s%s", DFLT_NAME
, VTY_NEWLINE
);
1690 vty_out (vty
, "!%s", VTY_NEWLINE
);
1692 for (i
= 0; i
< vector_active (cmdvec
); i
++)
1693 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
1694 && (node
->vtysh
|| vty
->type
!= VTY_SHELL
))
1696 if ((*node
->func
) (vty
))
1697 vty_out (vty
, "!%s", VTY_NEWLINE
);
1700 if (vty
->type
== VTY_TERM
)
1702 vty_out (vty
, "end%s",VTY_NEWLINE
);
1706 /* Write current configuration into file. */
1708 DEFUN (config_write
,
1710 "write [<file|memory|terminal>]",
1711 "Write running configuration to memory, network, or terminal\n"
1712 "Write to configuration file\n"
1713 "Write configuration currently in memory\n"
1714 "Write configuration to terminal\n")
1718 char *config_file
, *slash
;
1719 char *config_file_tmp
= NULL
;
1720 char *config_file_sav
= NULL
;
1721 int ret
= CMD_WARNING
;
1722 struct vty
*file_vty
;
1723 struct stat conf_stat
;
1725 // if command was 'write terminal' or 'show running-config'
1726 if (argc
== 2 && (!strcmp(argv
[idx_type
]->text
, "terminal") ||
1727 !strcmp(argv
[0]->text
, "show")))
1729 vty_write_config (vty
);
1736 /* Check and see if we are operating under vtysh configuration */
1737 if (host
.config
== NULL
)
1739 vty_out (vty
, "Can't save to configuration file, using vtysh.%s",
1745 config_file
= host
.config
;
1748 #define O_DIRECTORY 0
1750 slash
= strrchr (config_file
, '/');
1753 char *config_dir
= XSTRDUP (MTYPE_TMP
, config_file
);
1754 config_dir
[slash
- config_file
] = '\0';
1755 dirfd
= open(config_dir
, O_DIRECTORY
| O_RDONLY
);
1756 XFREE (MTYPE_TMP
, config_dir
);
1759 dirfd
= open(".", O_DIRECTORY
| O_RDONLY
);
1760 /* if dirfd is invalid, directory sync fails, but we're still OK */
1763 XMALLOC (MTYPE_TMP
, strlen (config_file
) + strlen (CONF_BACKUP_EXT
) + 1);
1764 strcpy (config_file_sav
, config_file
);
1765 strcat (config_file_sav
, CONF_BACKUP_EXT
);
1768 config_file_tmp
= XMALLOC (MTYPE_TMP
, strlen (config_file
) + 8);
1769 sprintf (config_file_tmp
, "%s.XXXXXX", config_file
);
1771 /* Open file to configuration write. */
1772 fd
= mkstemp (config_file_tmp
);
1775 vty_out (vty
, "Can't open configuration file %s.%s", config_file_tmp
,
1779 if (fchmod (fd
, CONFIGFILE_MASK
) != 0)
1781 vty_out (vty
, "Can't chmod configuration file %s: %s (%d).%s",
1782 config_file_tmp
, safe_strerror(errno
), errno
, VTY_NEWLINE
);
1786 /* Make vty for configuration file. */
1787 file_vty
= vty_new ();
1789 file_vty
->type
= VTY_FILE
;
1791 /* Config file header print. */
1792 vty_out (file_vty
, "!\n! Zebra configuration saved from vty\n! ");
1793 vty_time_print (file_vty
, 1);
1794 vty_out (file_vty
, "!\n");
1795 vty_write_config (file_vty
);
1796 vty_close (file_vty
);
1798 if (stat(config_file
, &conf_stat
) >= 0)
1800 if (unlink (config_file_sav
) != 0)
1801 if (errno
!= ENOENT
)
1803 vty_out (vty
, "Can't unlink backup configuration file %s.%s", config_file_sav
,
1807 if (link (config_file
, config_file_sav
) != 0)
1809 vty_out (vty
, "Can't backup old configuration file %s.%s", config_file_sav
,
1816 if (rename (config_file_tmp
, config_file
) != 0)
1818 vty_out (vty
, "Can't save configuration file %s.%s", config_file
,
1825 vty_out (vty
, "Configuration saved to %s%s", config_file
,
1830 if (ret
!= CMD_SUCCESS
)
1831 unlink (config_file_tmp
);
1834 XFREE (MTYPE_TMP
, config_file_tmp
);
1835 XFREE (MTYPE_TMP
, config_file_sav
);
1839 /* ALIAS_FIXME for 'write <terminal|memory>' */
1840 DEFUN (show_running_config
,
1841 show_running_config_cmd
,
1842 "show running-config",
1844 "running configuration (same as write terminal/memory)\n")
1846 return config_write (self
, vty
, argc
, argv
);
1849 /* ALIAS_FIXME for 'write file' */
1850 DEFUN (copy_runningconf_startupconf
,
1851 copy_runningconf_startupconf_cmd
,
1852 "copy running-config startup-config",
1853 "Copy configuration\n"
1854 "Copy running config to... \n"
1855 "Copy running config to startup config (same as write file)\n")
1858 vty_write_config (vty
);
1863 /* Write startup configuration into the terminal. */
1864 DEFUN (show_startup_config
,
1865 show_startup_config_cmd
,
1866 "show startup-config",
1868 "Contents of startup configuration\n")
1875 if (host
.config
== NULL
)
1878 confp
= fopen (host
.config
, "r");
1881 vty_out (vty
, "Can't open configuration file [%s] due to '%s'%s",
1882 host
.config
, safe_strerror(errno
), VTY_NEWLINE
);
1886 while (fgets (buf
, BUFSIZ
, confp
))
1890 while (*cp
!= '\r' && *cp
!= '\n' && *cp
!= '\0')
1894 vty_out (vty
, "%s%s", buf
, VTY_NEWLINE
);
1903 cmd_hostname_set (const char *hostname
)
1905 XFREE (MTYPE_HOST
, host
.name
);
1906 host
.name
= hostname
? XSTRDUP (MTYPE_HOST
, hostname
) : NULL
;
1910 /* Hostname configuration */
1911 DEFUN (config_hostname
,
1914 "Set system's network name\n"
1915 "This system's network name\n")
1917 struct cmd_token
*word
= argv
[1];
1919 if (!isalpha((int) word
->arg
[0]))
1921 vty_out (vty
, "Please specify string starting with alphabet%s", VTY_NEWLINE
);
1925 return cmd_hostname_set (word
->arg
);
1928 DEFUN (config_no_hostname
,
1930 "no hostname [HOSTNAME]",
1932 "Reset system's network name\n"
1933 "Host name of this router\n")
1935 return cmd_hostname_set (NULL
);
1938 /* VTY interface password set. */
1939 DEFUN (config_password
,
1941 "password [(8-8)] WORD",
1942 "Assign the terminal connection password\n"
1943 "Specifies a HIDDEN password will follow\n"
1944 "The password string\n")
1948 if (argc
== 3) // '8' was specified
1951 XFREE (MTYPE_HOST
, host
.password
);
1952 host
.password
= NULL
;
1953 if (host
.password_encrypt
)
1954 XFREE (MTYPE_HOST
, host
.password_encrypt
);
1955 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, argv
[idx_word
]->arg
);
1959 if (!isalnum (argv
[idx_8
]->arg
[0]))
1962 "Please specify string starting with alphanumeric%s", VTY_NEWLINE
);
1967 XFREE (MTYPE_HOST
, host
.password
);
1968 host
.password
= NULL
;
1972 if (host
.password_encrypt
)
1973 XFREE (MTYPE_HOST
, host
.password_encrypt
);
1974 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (argv
[idx_8
]->arg
));
1977 host
.password
= XSTRDUP (MTYPE_HOST
, argv
[idx_8
]->arg
);
1982 /* VTY enable password set. */
1983 DEFUN (config_enable_password
,
1984 enable_password_cmd
,
1985 "enable password [(8-8)] WORD",
1986 "Modify enable password parameters\n"
1987 "Assign the privileged level password\n"
1988 "Specifies a HIDDEN password will follow\n"
1989 "The HIDDEN 'enable' password string\n")
1994 /* Crypt type is specified. */
1997 if (argv
[idx_8
]->arg
[0] == '8')
2000 XFREE (MTYPE_HOST
, host
.enable
);
2003 if (host
.enable_encrypt
)
2004 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
2005 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, argv
[idx_word
]->arg
);
2011 vty_out (vty
, "Unknown encryption type.%s", VTY_NEWLINE
);
2016 if (!isalnum (argv
[idx_8
]->arg
[0]))
2019 "Please specify string starting with alphanumeric%s", VTY_NEWLINE
);
2024 XFREE (MTYPE_HOST
, host
.enable
);
2027 /* Plain password input. */
2030 if (host
.enable_encrypt
)
2031 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
2032 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (argv
[idx_8
]->arg
));
2035 host
.enable
= XSTRDUP (MTYPE_HOST
, argv
[idx_8
]->arg
);
2040 /* VTY enable password delete. */
2041 DEFUN (no_config_enable_password
,
2042 no_enable_password_cmd
,
2043 "no enable password",
2045 "Modify enable password parameters\n"
2046 "Assign the privileged level password\n")
2049 XFREE (MTYPE_HOST
, host
.enable
);
2052 if (host
.enable_encrypt
)
2053 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
2054 host
.enable_encrypt
= NULL
;
2059 DEFUN (service_password_encrypt
,
2060 service_password_encrypt_cmd
,
2061 "service password-encryption",
2062 "Set up miscellaneous service\n"
2063 "Enable encrypted passwords\n")
2072 if (host
.password_encrypt
)
2073 XFREE (MTYPE_HOST
, host
.password_encrypt
);
2074 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (host
.password
));
2078 if (host
.enable_encrypt
)
2079 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
2080 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (host
.enable
));
2086 DEFUN (no_service_password_encrypt
,
2087 no_service_password_encrypt_cmd
,
2088 "no service password-encryption",
2090 "Set up miscellaneous service\n"
2091 "Enable encrypted passwords\n")
2098 if (host
.password_encrypt
)
2099 XFREE (MTYPE_HOST
, host
.password_encrypt
);
2100 host
.password_encrypt
= NULL
;
2102 if (host
.enable_encrypt
)
2103 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
2104 host
.enable_encrypt
= NULL
;
2109 DEFUN (config_terminal_length
,
2110 config_terminal_length_cmd
,
2111 "terminal length (0-512)",
2112 "Set terminal line parameters\n"
2113 "Set number of lines on a screen\n"
2114 "Number of lines on screen (0 for no pausing)\n")
2118 char *endptr
= NULL
;
2120 lines
= strtol (argv
[idx_number
]->arg
, &endptr
, 10);
2121 if (lines
< 0 || lines
> 512 || *endptr
!= '\0')
2123 vty_out (vty
, "length is malformed%s", VTY_NEWLINE
);
2131 DEFUN (config_terminal_no_length
,
2132 config_terminal_no_length_cmd
,
2133 "terminal no length",
2134 "Set terminal line parameters\n"
2136 "Set number of lines on a screen\n")
2142 DEFUN (service_terminal_length
,
2143 service_terminal_length_cmd
,
2144 "service terminal-length (0-512)",
2145 "Set up miscellaneous service\n"
2146 "System wide terminal length configuration\n"
2147 "Number of lines of VTY (0 means no line control)\n")
2151 char *endptr
= NULL
;
2153 lines
= strtol (argv
[idx_number
]->arg
, &endptr
, 10);
2154 if (lines
< 0 || lines
> 512 || *endptr
!= '\0')
2156 vty_out (vty
, "length is malformed%s", VTY_NEWLINE
);
2164 DEFUN (no_service_terminal_length
,
2165 no_service_terminal_length_cmd
,
2166 "no service terminal-length [(0-512)]",
2168 "Set up miscellaneous service\n"
2169 "System wide terminal length configuration\n"
2170 "Number of lines of VTY (0 means no line control)\n")
2176 DEFUN_HIDDEN (do_echo
,
2179 "Echo a message back to the vty\n"
2180 "The message to echo\n")
2184 vty_out (vty
, "%s%s", ((message
= argv_concat (argv
, argc
, 1)) ? message
: ""),
2187 XFREE(MTYPE_TMP
, message
);
2191 DEFUN (config_logmsg
,
2193 "logmsg <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging> MESSAGE...",
2194 "Send a message to enabled logging destinations\n"
2196 "The message to send\n")
2198 int idx_log_level
= 1;
2199 int idx_message
= 2;
2203 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2204 return CMD_ERR_NO_MATCH
;
2206 zlog(level
, "%s", ((message
= argv_concat(argv
, argc
, idx_message
)) ? message
: ""));
2208 XFREE(MTYPE_TMP
, message
);
2213 DEFUN (show_logging
,
2217 "Show current logging configuration\n")
2219 struct zlog
*zl
= zlog_default
;
2221 vty_out (vty
, "Syslog logging: ");
2222 if (zl
->maxlvl
[ZLOG_DEST_SYSLOG
] == ZLOG_DISABLED
)
2223 vty_out (vty
, "disabled");
2225 vty_out (vty
, "level %s, facility %s, ident %s",
2226 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_SYSLOG
]],
2227 facility_name(zl
->facility
), zl
->ident
);
2228 vty_out (vty
, "%s", VTY_NEWLINE
);
2230 vty_out (vty
, "Stdout logging: ");
2231 if (zl
->maxlvl
[ZLOG_DEST_STDOUT
] == ZLOG_DISABLED
)
2232 vty_out (vty
, "disabled");
2234 vty_out (vty
, "level %s",
2235 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_STDOUT
]]);
2236 vty_out (vty
, "%s", VTY_NEWLINE
);
2238 vty_out (vty
, "Monitor logging: ");
2239 if (zl
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
2240 vty_out (vty
, "disabled");
2242 vty_out (vty
, "level %s",
2243 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_MONITOR
]]);
2244 vty_out (vty
, "%s", VTY_NEWLINE
);
2246 vty_out (vty
, "File logging: ");
2247 if ((zl
->maxlvl
[ZLOG_DEST_FILE
] == ZLOG_DISABLED
) ||
2249 vty_out (vty
, "disabled");
2251 vty_out (vty
, "level %s, filename %s",
2252 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_FILE
]],
2254 vty_out (vty
, "%s", VTY_NEWLINE
);
2256 vty_out (vty
, "Protocol name: %s%s",
2257 zl
->protoname
, VTY_NEWLINE
);
2258 vty_out (vty
, "Record priority: %s%s",
2259 (zl
->record_priority
? "enabled" : "disabled"), VTY_NEWLINE
);
2260 vty_out (vty
, "Timestamp precision: %d%s",
2261 zl
->timestamp_precision
, VTY_NEWLINE
);
2266 DEFUN (config_log_stdout
,
2267 config_log_stdout_cmd
,
2268 "log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2270 "Set stdout logging level\n"
2273 int idx_log_level
= 2;
2275 if (argc
== idx_log_level
)
2277 zlog_set_level (ZLOG_DEST_STDOUT
, zlog_default
->default_lvl
);
2282 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2283 return CMD_ERR_NO_MATCH
;
2284 zlog_set_level (ZLOG_DEST_STDOUT
, level
);
2288 DEFUN (no_config_log_stdout
,
2289 no_config_log_stdout_cmd
,
2290 "no log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2293 "Cancel logging to stdout\n"
2296 zlog_set_level (ZLOG_DEST_STDOUT
, ZLOG_DISABLED
);
2300 DEFUN (config_log_monitor
,
2301 config_log_monitor_cmd
,
2302 "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2304 "Set terminal line (monitor) logging level\n"
2307 int idx_log_level
= 2;
2309 if (argc
== idx_log_level
)
2311 zlog_set_level (ZLOG_DEST_MONITOR
, zlog_default
->default_lvl
);
2316 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2317 return CMD_ERR_NO_MATCH
;
2318 zlog_set_level (ZLOG_DEST_MONITOR
, level
);
2322 DEFUN (no_config_log_monitor
,
2323 no_config_log_monitor_cmd
,
2324 "no log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2327 "Disable terminal line (monitor) logging\n"
2330 zlog_set_level (ZLOG_DEST_MONITOR
, ZLOG_DISABLED
);
2335 set_log_file(struct vty
*vty
, const char *fname
, int loglevel
)
2339 const char *fullpath
;
2341 /* Path detection. */
2342 if (! IS_DIRECTORY_SEP (*fname
))
2344 char cwd
[MAXPATHLEN
+1];
2345 cwd
[MAXPATHLEN
] = '\0';
2347 if (getcwd (cwd
, MAXPATHLEN
) == NULL
)
2349 zlog_err ("config_log_file: Unable to alloc mem!");
2353 if ( (p
= XMALLOC (MTYPE_TMP
, strlen (cwd
) + strlen (fname
) + 2))
2356 zlog_err ("config_log_file: Unable to alloc mem!");
2359 sprintf (p
, "%s/%s", cwd
, fname
);
2365 ret
= zlog_set_file (fullpath
, loglevel
);
2368 XFREE (MTYPE_TMP
, p
);
2372 vty_out (vty
, "can't open logfile %s\n", fname
);
2377 XFREE (MTYPE_HOST
, host
.logfile
);
2379 host
.logfile
= XSTRDUP (MTYPE_HOST
, fname
);
2381 #if defined(HAVE_CUMULUS)
2382 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
)
2383 zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] = ZLOG_DISABLED
;
2388 DEFUN (config_log_file
,
2389 config_log_file_cmd
,
2390 "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2393 "Logging filename\n"
2396 int idx_filename
= 2;
2397 int idx_log_levels
= 3;
2401 if ((level
= level_match(argv
[idx_log_levels
]->arg
)) == ZLOG_DISABLED
)
2402 return CMD_ERR_NO_MATCH
;
2403 return set_log_file(vty
, argv
[idx_filename
]->arg
, level
);
2406 return set_log_file(vty
, argv
[idx_filename
]->arg
, zlog_default
->default_lvl
);
2409 DEFUN (no_config_log_file
,
2410 no_config_log_file_cmd
,
2411 "no log file [FILENAME [LEVEL]]",
2414 "Cancel logging to file\n"
2415 "Logging file name\n"
2416 "Logging file name\n"
2422 XFREE (MTYPE_HOST
, host
.logfile
);
2424 host
.logfile
= NULL
;
2429 DEFUN (config_log_syslog
,
2430 config_log_syslog_cmd
,
2431 "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2433 "Set syslog logging level\n"
2436 int idx_log_levels
= 2;
2440 if ((level
= level_match (argv
[idx_log_levels
]->arg
)) == ZLOG_DISABLED
)
2441 return CMD_ERR_NO_MATCH
;
2442 zlog_set_level (ZLOG_DEST_SYSLOG
, level
);
2447 zlog_set_level (ZLOG_DEST_SYSLOG
, zlog_default
->default_lvl
);
2452 DEFUN (no_config_log_syslog
,
2453 no_config_log_syslog_cmd
,
2454 "no log syslog [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>] [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2457 "Cancel logging to syslog\n"
2461 zlog_set_level (ZLOG_DEST_SYSLOG
, ZLOG_DISABLED
);
2465 DEFUN (config_log_facility
,
2466 config_log_facility_cmd
,
2467 "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>",
2469 "Facility parameter for syslog messages\n"
2473 int facility
= facility_match(argv
[idx_target
]->arg
);
2475 zlog_default
->facility
= facility
;
2479 DEFUN (no_config_log_facility
,
2480 no_config_log_facility_cmd
,
2481 "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
2484 "Reset syslog facility to default (daemon)\n"
2487 zlog_default
->facility
= LOG_DAEMON
;
2491 DEFUN_DEPRECATED (config_log_trap
,
2492 config_log_trap_cmd
,
2493 "log trap <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
2495 "(Deprecated) Set logging level and default for all destinations\n"
2501 if ((new_level
= level_match(argv
[2]->arg
)) == ZLOG_DISABLED
)
2502 return CMD_ERR_NO_MATCH
;
2504 zlog_default
->default_lvl
= new_level
;
2505 for (i
= 0; i
< ZLOG_NUM_DESTS
; i
++)
2506 if (zlog_default
->maxlvl
[i
] != ZLOG_DISABLED
)
2507 zlog_default
->maxlvl
[i
] = new_level
;
2511 DEFUN_DEPRECATED (no_config_log_trap
,
2512 no_config_log_trap_cmd
,
2513 "no log trap [emergencies|alerts|critical|errors|warnings|notifications|informational|debugging]",
2516 "Permit all logging information\n"
2519 zlog_default
->default_lvl
= LOG_DEBUG
;
2523 DEFUN (config_log_record_priority
,
2524 config_log_record_priority_cmd
,
2525 "log record-priority",
2527 "Log the priority of the message within the message\n")
2529 zlog_default
->record_priority
= 1 ;
2533 DEFUN (no_config_log_record_priority
,
2534 no_config_log_record_priority_cmd
,
2535 "no log record-priority",
2538 "Do not log the priority of the message within the message\n")
2540 zlog_default
->record_priority
= 0 ;
2544 DEFUN (config_log_timestamp_precision
,
2545 config_log_timestamp_precision_cmd
,
2546 "log timestamp precision (0-6)",
2548 "Timestamp configuration\n"
2549 "Set the timestamp precision\n"
2550 "Number of subsecond digits\n")
2553 VTY_GET_INTEGER_RANGE("Timestamp Precision",
2554 zlog_default
->timestamp_precision
, argv
[idx_number
]->arg
, 0, 6);
2558 DEFUN (no_config_log_timestamp_precision
,
2559 no_config_log_timestamp_precision_cmd
,
2560 "no log timestamp precision",
2563 "Timestamp configuration\n"
2564 "Reset the timestamp precision to the default value of 0\n")
2566 zlog_default
->timestamp_precision
= 0 ;
2571 cmd_banner_motd_file (const char *file
)
2573 int success
= CMD_SUCCESS
;
2578 rpath
= realpath (file
, p
);
2580 return CMD_ERR_NO_FILE
;
2581 in
= strstr (rpath
, SYSCONFDIR
);
2585 XFREE (MTYPE_HOST
, host
.motdfile
);
2586 host
.motdfile
= XSTRDUP (MTYPE_HOST
, file
);
2589 success
= CMD_WARNING
;
2594 DEFUN (banner_motd_file
,
2595 banner_motd_file_cmd
,
2596 "banner motd file FILE",
2599 "Banner from a file\n"
2603 const char *filename
= argv
[idx_file
]->arg
;
2604 int cmd
= cmd_banner_motd_file (filename
);
2606 if (cmd
== CMD_ERR_NO_FILE
)
2607 vty_out (vty
, "%s does not exist", filename
);
2608 else if (cmd
== CMD_WARNING
)
2609 vty_out (vty
, "%s must be in %s", filename
, SYSCONFDIR
);
2614 DEFUN (banner_motd_default
,
2615 banner_motd_default_cmd
,
2616 "banner motd default",
2617 "Set banner string\n"
2618 "Strings for motd\n"
2621 host
.motd
= default_motd
;
2625 DEFUN (no_banner_motd
,
2629 "Set banner string\n"
2630 "Strings for motd\n")
2634 XFREE (MTYPE_HOST
, host
.motdfile
);
2635 host
.motdfile
= NULL
;
2639 /* Set config filename. Called from vty.c */
2641 host_config_set (const char *filename
)
2644 XFREE (MTYPE_HOST
, host
.config
);
2645 host
.config
= XSTRDUP (MTYPE_HOST
, filename
);
2649 host_config_get (void)
2655 install_default (enum node_type node
)
2657 install_element (node
, &config_exit_cmd
);
2658 install_element (node
, &config_quit_cmd
);
2659 install_element (node
, &config_end_cmd
);
2660 install_element (node
, &config_help_cmd
);
2661 install_element (node
, &config_list_cmd
);
2663 install_element (node
, &config_write_cmd
);
2664 install_element (node
, &show_running_config_cmd
);
2667 /* Initialize command interface. Install basic nodes and commands.
2669 * terminal = 0 -- vtysh / no logging, no config control
2670 * terminal = 1 -- normal daemon
2671 * terminal = -1 -- watchfrr / no logging, but minimal config control */
2673 cmd_init (int terminal
)
2677 /* Allocate initial top vector of commands. */
2678 cmdvec
= vector_init (VECTOR_MIN_SIZE
);
2680 /* Default host value settings. */
2682 host
.password
= NULL
;
2684 host
.logfile
= NULL
;
2686 host
.noconfig
= (terminal
< 0);
2688 host
.motd
= default_motd
;
2689 host
.motdfile
= NULL
;
2691 /* Install top nodes. */
2692 install_node (&view_node
, NULL
);
2693 install_node (&enable_node
, NULL
);
2694 install_node (&auth_node
, NULL
);
2695 install_node (&auth_enable_node
, NULL
);
2696 install_node (&config_node
, config_write_host
);
2698 /* Each node's basic commands. */
2699 install_element (VIEW_NODE
, &show_version_cmd
);
2702 install_element (VIEW_NODE
, &config_list_cmd
);
2703 install_element (VIEW_NODE
, &config_exit_cmd
);
2704 install_element (VIEW_NODE
, &config_quit_cmd
);
2705 install_element (VIEW_NODE
, &config_help_cmd
);
2706 install_element (VIEW_NODE
, &config_enable_cmd
);
2707 install_element (VIEW_NODE
, &config_terminal_length_cmd
);
2708 install_element (VIEW_NODE
, &config_terminal_no_length_cmd
);
2709 install_element (VIEW_NODE
, &show_logging_cmd
);
2710 install_element (VIEW_NODE
, &show_commandtree_cmd
);
2711 install_element (VIEW_NODE
, &echo_cmd
);
2716 install_element (ENABLE_NODE
, &config_end_cmd
);
2717 install_element (ENABLE_NODE
, &config_disable_cmd
);
2718 install_element (ENABLE_NODE
, &config_terminal_cmd
);
2719 install_element (ENABLE_NODE
, ©_runningconf_startupconf_cmd
);
2720 install_element (ENABLE_NODE
, &config_write_cmd
);
2721 install_element (ENABLE_NODE
, &show_running_config_cmd
);
2723 install_element (ENABLE_NODE
, &show_startup_config_cmd
);
2727 install_element (ENABLE_NODE
, &config_logmsg_cmd
);
2728 install_default (CONFIG_NODE
);
2731 workqueue_cmd_init ();
2734 install_element (CONFIG_NODE
, &hostname_cmd
);
2735 install_element (CONFIG_NODE
, &no_hostname_cmd
);
2736 install_element (CONFIG_NODE
, &frr_version_defaults_cmd
);
2740 install_element (CONFIG_NODE
, &password_cmd
);
2741 install_element (CONFIG_NODE
, &enable_password_cmd
);
2742 install_element (CONFIG_NODE
, &no_enable_password_cmd
);
2744 install_element (CONFIG_NODE
, &config_log_stdout_cmd
);
2745 install_element (CONFIG_NODE
, &no_config_log_stdout_cmd
);
2746 install_element (CONFIG_NODE
, &config_log_monitor_cmd
);
2747 install_element (CONFIG_NODE
, &no_config_log_monitor_cmd
);
2748 install_element (CONFIG_NODE
, &config_log_file_cmd
);
2749 install_element (CONFIG_NODE
, &no_config_log_file_cmd
);
2750 install_element (CONFIG_NODE
, &config_log_syslog_cmd
);
2751 install_element (CONFIG_NODE
, &no_config_log_syslog_cmd
);
2752 install_element (CONFIG_NODE
, &config_log_facility_cmd
);
2753 install_element (CONFIG_NODE
, &no_config_log_facility_cmd
);
2754 install_element (CONFIG_NODE
, &config_log_trap_cmd
);
2755 install_element (CONFIG_NODE
, &no_config_log_trap_cmd
);
2756 install_element (CONFIG_NODE
, &config_log_record_priority_cmd
);
2757 install_element (CONFIG_NODE
, &no_config_log_record_priority_cmd
);
2758 install_element (CONFIG_NODE
, &config_log_timestamp_precision_cmd
);
2759 install_element (CONFIG_NODE
, &no_config_log_timestamp_precision_cmd
);
2760 install_element (CONFIG_NODE
, &service_password_encrypt_cmd
);
2761 install_element (CONFIG_NODE
, &no_service_password_encrypt_cmd
);
2762 install_element (CONFIG_NODE
, &banner_motd_default_cmd
);
2763 install_element (CONFIG_NODE
, &banner_motd_file_cmd
);
2764 install_element (CONFIG_NODE
, &no_banner_motd_cmd
);
2765 install_element (CONFIG_NODE
, &service_terminal_length_cmd
);
2766 install_element (CONFIG_NODE
, &no_service_terminal_length_cmd
);
2768 vrf_install_commands ();
2772 grammar_sandbox_init();
2777 new_cmd_token (enum cmd_token_type type
, u_char attr
,
2778 const char *text
, const char *desc
)
2780 struct cmd_token
*token
= XCALLOC (MTYPE_CMD_TOKENS
, sizeof (struct cmd_token
));
2783 token
->text
= text
? XSTRDUP (MTYPE_CMD_TEXT
, text
) : NULL
;
2784 token
->desc
= desc
? XSTRDUP (MTYPE_CMD_DESC
, desc
) : NULL
;
2787 token
->allowrepeat
= false;
2793 del_cmd_token (struct cmd_token
*token
)
2798 XFREE (MTYPE_CMD_TEXT
, token
->text
);
2800 XFREE (MTYPE_CMD_DESC
, token
->desc
);
2802 XFREE (MTYPE_CMD_ARG
, token
->arg
);
2804 XFREE (MTYPE_CMD_TOKENS
, token
);
2808 copy_cmd_token (struct cmd_token
*token
)
2810 struct cmd_token
*copy
= new_cmd_token (token
->type
, token
->attr
, NULL
, NULL
);
2811 copy
->max
= token
->max
;
2812 copy
->min
= token
->min
;
2813 copy
->text
= token
->text
? XSTRDUP (MTYPE_CMD_TEXT
, token
->text
) : NULL
;
2814 copy
->desc
= token
->desc
? XSTRDUP (MTYPE_CMD_DESC
, token
->desc
) : NULL
;
2815 copy
->arg
= token
->arg
? XSTRDUP (MTYPE_CMD_ARG
, token
->arg
) : NULL
;
2823 struct cmd_node
*cmd_node
;
2827 for (unsigned int i
= 0; i
< vector_active (cmdvec
); i
++)
2828 if ((cmd_node
= vector_slot (cmdvec
, i
)) != NULL
)
2830 // deleting the graph delets the cmd_element as well
2831 graph_delete_graph (cmd_node
->cmdgraph
);
2832 vector_free (cmd_node
->cmd_vector
);
2833 hash_clean (cmd_node
->cmd_hash
, NULL
);
2834 hash_free (cmd_node
->cmd_hash
);
2835 cmd_node
->cmd_hash
= NULL
;
2838 vector_free (cmdvec
);
2843 XFREE (MTYPE_HOST
, host
.name
);
2845 XFREE (MTYPE_HOST
, host
.password
);
2846 if (host
.password_encrypt
)
2847 XFREE (MTYPE_HOST
, host
.password_encrypt
);
2849 XFREE (MTYPE_HOST
, host
.enable
);
2850 if (host
.enable_encrypt
)
2851 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
2853 XFREE (MTYPE_HOST
, host
.logfile
);
2855 XFREE (MTYPE_HOST
, host
.motdfile
);
2857 XFREE (MTYPE_HOST
, host
.config
);