]> git.proxmox.com Git - mirror_frr.git/blame - lib/command.c
Merge pull request #767 from donaldsharp/if_update
[mirror_frr.git] / lib / command.c
CommitLineData
274a4a44 1/*
9547b5d0
QY
2 * CLI backend interface.
3 *
4 * --
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")
9 *
10 * This file is part of GNU Zebra.
11 *
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
15 * later version.
16 *
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.
21 *
896014f4
DL
22 * You should have received a copy of the GNU General Public License along
23 * with this program; see the file COPYING; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
9547b5d0 25 */
718e3744 26
27#include <zebra.h>
28
b21b19c5 29
718e3744 30#include "memory.h"
31#include "log.h"
deaa50db 32#include "log_int.h"
5e4fa164 33#include <lib/version.h>
9ab6812d 34#include "thread.h"
b21b19c5 35#include "vector.h"
d0bfb22c 36#include "linklist.h"
b21b19c5 37#include "vty.h"
38#include "command.h"
354d119a 39#include "workqueue.h"
19dc275e 40#include "vrf.h"
d0bfb22c 41#include "command_match.h"
5894e76d 42#include "command_graph.h"
1bf9f027 43#include "qobj.h"
8efe88ea 44#include "defaults.h"
d0bfb22c 45
4a1ab8e4
DL
46DEFINE_MTYPE( LIB, HOST, "Host config")
47DEFINE_MTYPE( LIB, STRVEC, "String vector")
70d44c5c 48DEFINE_MTYPE( LIB, COMPLETION, "Completion item")
4a1ab8e4 49
718e3744 50/* Command vector which includes some level of command lists. Normally
51 each daemon maintains each own cmdvec. */
eb820afe 52vector cmdvec = NULL;
718e3744 53
54/* Host information structure. */
55struct host host;
56
718e3744 57/* Standard command node structures. */
7fc626de 58static struct cmd_node auth_node =
718e3744 59{
60 AUTH_NODE,
61 "Password: ",
62};
63
7fc626de 64static struct cmd_node view_node =
718e3744 65{
66 VIEW_NODE,
67 "%s> ",
68};
69
7fc626de 70static struct cmd_node auth_enable_node =
718e3744 71{
72 AUTH_ENABLE_NODE,
73 "Password: ",
74};
75
7fc626de 76static struct cmd_node enable_node =
718e3744 77{
78 ENABLE_NODE,
79 "%s# ",
80};
81
7fc626de 82static struct cmd_node config_node =
718e3744 83{
84 CONFIG_NODE,
85 "%s(config)# ",
86 1
87};
6590f2c3 88
89/* Default motd string. */
b2f36157 90static const char *default_motd = FRR_DEFAULT_MOTD;
274a4a44 91
2d362d10 92static const struct facility_map {
274a4a44 93 int facility;
94 const char *name;
95 size_t match;
d0bfb22c 96} syslog_facilities[] =
274a4a44 97 {
98 { LOG_KERN, "kern", 1 },
99 { LOG_USER, "user", 2 },
100 { LOG_MAIL, "mail", 1 },
101 { LOG_DAEMON, "daemon", 1 },
102 { LOG_AUTH, "auth", 1 },
103 { LOG_SYSLOG, "syslog", 1 },
104 { LOG_LPR, "lpr", 2 },
105 { LOG_NEWS, "news", 1 },
106 { LOG_UUCP, "uucp", 2 },
107 { LOG_CRON, "cron", 1 },
108#ifdef LOG_FTP
109 { LOG_FTP, "ftp", 1 },
110#endif
111 { LOG_LOCAL0, "local0", 6 },
112 { LOG_LOCAL1, "local1", 6 },
113 { LOG_LOCAL2, "local2", 6 },
114 { LOG_LOCAL3, "local3", 6 },
115 { LOG_LOCAL4, "local4", 6 },
116 { LOG_LOCAL5, "local5", 6 },
117 { LOG_LOCAL6, "local6", 6 },
118 { LOG_LOCAL7, "local7", 6 },
119 { 0, NULL, 0 },
120 };
121
122static const char *
123facility_name(int facility)
124{
2d362d10 125 const struct facility_map *fm;
274a4a44 126
127 for (fm = syslog_facilities; fm->name; fm++)
128 if (fm->facility == facility)
129 return fm->name;
130 return "";
131}
132
133static int
134facility_match(const char *str)
135{
2d362d10 136 const struct facility_map *fm;
274a4a44 137
138 for (fm = syslog_facilities; fm->name; fm++)
139 if (!strncmp(str,fm->name,fm->match))
140 return fm->facility;
141 return -1;
142}
143
144static int
145level_match(const char *s)
146{
147 int level ;
d0bfb22c 148
274a4a44 149 for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
150 if (!strncmp (s, zlog_priority[level], 2))
151 return level;
152 return ZLOG_DISABLED;
153}
154
cb585b65 155/* This is called from main when a daemon is invoked with -v or --version. */
6590f2c3 156void
157print_version (const char *progname)
158{
b2f36157
DL
159 printf ("%s version %s\n", progname, FRR_VERSION);
160 printf ("%s\n", FRR_COPYRIGHT);
161 printf ("configured with:\n\t%s\n", FRR_CONFIG_ARGS);
6590f2c3 162}
163
6b0655a2 164
718e3744 165/* Utility function to concatenate argv argument into a single string
166 with inserting ' ' character between each argument. */
167char *
d0bfb22c 168argv_concat (struct cmd_token **argv, int argc, int shift)
718e3744 169{
170 int i;
f6834d4c 171 size_t len;
718e3744 172 char *str;
f6834d4c 173 char *p;
718e3744 174
f6834d4c 175 len = 0;
176 for (i = shift; i < argc; i++)
d0bfb22c 177 len += strlen(argv[i]->arg)+1;
f6834d4c 178 if (!len)
179 return NULL;
180 p = str = XMALLOC(MTYPE_TMP, len);
718e3744 181 for (i = shift; i < argc; i++)
182 {
f6834d4c 183 size_t arglen;
d0bfb22c 184 memcpy(p, argv[i]->arg, (arglen = strlen(argv[i]->arg)));
f6834d4c 185 p += arglen;
186 *p++ = ' ';
718e3744 187 }
f6834d4c 188 *(p-1) = '\0';
718e3744 189 return str;
190}
191
ae19d7dd
QY
192/**
193 * Convenience function for accessing argv data.
194 *
195 * @param argc
196 * @param argv
197 * @param text definition snippet of the desired token
198 * @param index the starting index, and where to store the
199 * index of the found token if it exists
200 * @return 1 if found, 0 otherwise
201 */
202int
203argv_find (struct cmd_token **argv, int argc, const char *text, int *index)
204{
205 int found = 0;
206 for (int i = *index; i < argc && found == 0; i++)
207 if ((found = strmatch (text, argv[i]->text)))
208 *index = i;
209 return found;
210}
211
274f29b2
PJ
212static unsigned int
213cmd_hash_key (void *p)
214{
215 return (uintptr_t) p;
216}
217
218static int
219cmd_hash_cmp (const void *a, const void *b)
220{
221 return a == b;
222}
223
718e3744 224/* Install top node of command vector. */
225void
d0bfb22c
QY
226install_node (struct cmd_node *node,
227 int (*func) (struct vty *))
718e3744 228{
229 vector_set_index (cmdvec, node->node, node);
230 node->func = func;
d0bfb22c 231 node->cmdgraph = graph_new ();
76b6abb9
QY
232 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
233 // add start node
5894e76d
DL
234 struct cmd_token *token = cmd_token_new (START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
235 graph_new_node (node->cmdgraph, token, (void (*)(void *)) &cmd_token_del);
274f29b2 236 node->cmd_hash = hash_create (cmd_hash_key, cmd_hash_cmp);
718e3744 237}
238
ebacb4ed
QY
239/**
240 * Tokenizes a string, storing tokens in a vector.
241 * Whitespace is ignored.
242 *
243 * Delimiter string = " \n\r\t".
244 *
245 * @param string to tokenize
246 * @return tokenized string
247 */
718e3744 248vector
ea8e9d97 249cmd_make_strvec (const char *string)
718e3744 250{
ebacb4ed 251 if (!string) return NULL;
d0bfb22c 252
ebacb4ed
QY
253 char *copy, *copystart;
254 copystart = copy = XSTRDUP (MTYPE_TMP, string);
d0bfb22c 255
ebacb4ed
QY
256 // skip leading whitespace
257 while (isspace ((int) *copy) && *copy != '\0') copy++;
718e3744 258
ebacb4ed
QY
259 // if the entire string was whitespace or a comment, return
260 if (*copy == '\0' || *copy == '!' || *copy == '#')
17aca20b
QY
261 {
262 XFREE (MTYPE_TMP, copystart);
718e3744 263 return NULL;
17aca20b 264 }
718e3744 265
ebacb4ed
QY
266 vector strvec = vector_init (VECTOR_MIN_SIZE);
267 const char *delim = " \n\r\t", *tok = NULL;
268 while (copy)
269 {
270 tok = strsep (&copy, delim);
271 if (*tok != '\0')
272 vector_set (strvec, XSTRDUP (MTYPE_STRVEC, tok));
273 }
718e3744 274
ebacb4ed
QY
275 XFREE (MTYPE_TMP, copystart);
276 return strvec;
718e3744 277}
278
279/* Free allocated string vector. */
280void
281cmd_free_strvec (vector v)
282{
8c328f11 283 unsigned int i;
718e3744 284 char *cp;
285
286 if (!v)
287 return;
288
55468c86 289 for (i = 0; i < vector_active (v); i++)
718e3744 290 if ((cp = vector_slot (v, i)) != NULL)
291 XFREE (MTYPE_STRVEC, cp);
292
293 vector_free (v);
294}
295
718e3744 296/* Return prompt character of specified node. */
8c328f11 297const char *
718e3744 298cmd_prompt (enum node_type node)
299{
300 struct cmd_node *cnode;
301
302 cnode = vector_slot (cmdvec, node);
303 return cnode->prompt;
304}
305
306/* Install a command into a node. */
307void
308install_element (enum node_type ntype, struct cmd_element *cmd)
309{
310 struct cmd_node *cnode;
d0bfb22c 311
eb820afe 312 /* cmd_init hasn't been called */
313 if (!cmdvec)
274f29b2
PJ
314 {
315 fprintf (stderr, "%s called before cmd_init, breakage likely\n",
316 __func__);
317 return;
318 }
ebacb4ed 319
718e3744 320 cnode = vector_slot (cmdvec, ntype);
321
d0bfb22c 322 if (cnode == NULL)
718e3744 323 {
324 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
d0bfb22c 325 ntype);
291ca371 326 fprintf (stderr, "Have you called install_node before this install_element?\n");
d0bfb22c 327 exit (EXIT_FAILURE);
718e3744 328 }
ebacb4ed 329
274f29b2 330 if (hash_lookup (cnode->cmd_hash, cmd) != NULL)
c0f9771d 331 {
ebacb4ed 332 fprintf (stderr,
274f29b2
PJ
333 "Multiple command installs to node %d of command:\n%s\n",
334 ntype, cmd->string);
c0f9771d
QY
335 return;
336 }
ebacb4ed 337
274f29b2 338 assert (hash_get (cnode->cmd_hash, cmd, hash_alloc_intern));
ebacb4ed 339
de8f7a39 340 struct graph *graph = graph_new();
5894e76d
DL
341 struct cmd_token *token = cmd_token_new (START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
342 graph_new_node (graph, token, (void (*)(void *)) &cmd_token_del);
de8f7a39 343
5894e76d 344 cmd_graph_parse (graph, cmd);
c09c46ae 345 cmd_graph_names (graph);
5894e76d 346 cmd_graph_merge (cnode->cmdgraph, graph, +1);
de8f7a39
DL
347 graph_delete_graph (graph);
348
718e3744 349 vector_set (cnode->cmd_vector, cmd);
735e62a0
DS
350
351 if (ntype == VIEW_NODE)
352 install_element (ENABLE_NODE, cmd);
718e3744 353}
354
de8f7a39
DL
355void
356uninstall_element (enum node_type ntype, struct cmd_element *cmd)
357{
358 struct cmd_node *cnode;
359
360 /* cmd_init hasn't been called */
361 if (!cmdvec)
362 {
363 fprintf (stderr, "%s called before cmd_init, breakage likely\n",
364 __func__);
365 return;
366 }
367
368 cnode = vector_slot (cmdvec, ntype);
369
370 if (cnode == NULL)
371 {
372 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
373 ntype);
291ca371 374 fprintf (stderr, "Have you called install_node before this install_element?\n");
de8f7a39
DL
375 exit (EXIT_FAILURE);
376 }
377
378 if (hash_release (cnode->cmd_hash, cmd) == NULL)
379 {
380 fprintf (stderr,
381 "Trying to uninstall non-installed command (node %d):\n%s\n",
382 ntype, cmd->string);
383 return;
384 }
385
386 vector_unset_value (cnode->cmd_vector, cmd);
387
388 struct graph *graph = graph_new();
5894e76d
DL
389 struct cmd_token *token = cmd_token_new (START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
390 graph_new_node (graph, token, (void (*)(void *)) &cmd_token_del);
de8f7a39 391
5894e76d 392 cmd_graph_parse (graph, cmd);
c09c46ae 393 cmd_graph_names (graph);
5894e76d 394 cmd_graph_merge (cnode->cmdgraph, graph, -1);
de8f7a39
DL
395 graph_delete_graph (graph);
396
397 if (ntype == VIEW_NODE)
398 uninstall_element (ENABLE_NODE, cmd);
399}
400
401
2d362d10 402static const unsigned char itoa64[] =
718e3744 403"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
404
274a4a44 405static void
718e3744 406to64(char *s, long v, int n)
407{
d0bfb22c 408 while (--n >= 0)
718e3744 409 {
410 *s++ = itoa64[v&0x3f];
411 v >>= 6;
412 }
413}
414
274a4a44 415static char *
416zencrypt (const char *passwd)
718e3744 417{
418 char salt[6];
419 struct timeval tv;
420 char *crypt (const char *, const char *);
421
422 gettimeofday(&tv,0);
d0bfb22c 423
718e3744 424 to64(&salt[0], random(), 3);
425 to64(&salt[3], tv.tv_usec, 3);
426 salt[5] = '\0';
427
428 return crypt (passwd, salt);
429}
430
431/* This function write configuration of this host. */
274a4a44 432static int
718e3744 433config_write_host (struct vty *vty)
434{
435 if (host.name)
96ade3ed 436 vty_outln (vty, "hostname %s", host.name);
718e3744 437
438 if (host.encrypt)
439 {
440 if (host.password_encrypt)
96ade3ed 441 vty_outln (vty, "password 8 %s", host.password_encrypt);
718e3744 442 if (host.enable_encrypt)
96ade3ed 443 vty_outln (vty, "enable password 8 %s", host.enable_encrypt);
718e3744 444 }
445 else
446 {
447 if (host.password)
96ade3ed 448 vty_outln (vty, "password %s", host.password);
718e3744 449 if (host.enable)
96ade3ed 450 vty_outln (vty, "enable password %s", host.enable);
718e3744 451 }
452
274a4a44 453 if (zlog_default->default_lvl != LOG_DEBUG)
82146b88 454 {
96ade3ed
QY
455 vty_outln (vty,"! N.B. The 'log trap' command is deprecated.");
456 vty_outln (vty, "log trap %s",
457 zlog_priority[zlog_default->default_lvl]);
82146b88 458 }
274a4a44 459
460 if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
461 {
462 vty_out (vty, "log file %s", host.logfile);
463 if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
d0bfb22c
QY
464 vty_out (vty, " %s",
465 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
e31b6333 466 vty_out (vty, VTYNL);
274a4a44 467 }
468
469 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
470 {
471 vty_out (vty, "log stdout");
472 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
d0bfb22c
QY
473 vty_out (vty, " %s",
474 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
e31b6333 475 vty_out (vty, VTYNL);
274a4a44 476 }
718e3744 477
274a4a44 478 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
96ade3ed 479 vty_outln (vty,"no log monitor");
274a4a44 480 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
96ade3ed
QY
481 vty_outln (vty,"log monitor %s",
482 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]]);
718e3744 483
274a4a44 484 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
12ab19f1 485 {
486 vty_out (vty, "log syslog");
274a4a44 487 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
d0bfb22c
QY
488 vty_out (vty, " %s",
489 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
e31b6333 490 vty_out (vty, VTYNL);
12ab19f1 491 }
274a4a44 492
493 if (zlog_default->facility != LOG_DAEMON)
96ade3ed
QY
494 vty_outln (vty, "log facility %s",
495 facility_name(zlog_default->facility));
718e3744 496
497 if (zlog_default->record_priority == 1)
96ade3ed 498 vty_outln (vty, "log record-priority");
718e3744 499
1ed72e0b 500 if (zlog_default->timestamp_precision > 0)
96ade3ed
QY
501 vty_outln (vty, "log timestamp precision %d",
502 zlog_default->timestamp_precision);
1ed72e0b 503
718e3744 504 if (host.advanced)
96ade3ed 505 vty_outln (vty, "service advanced-vty");
718e3744 506
507 if (host.encrypt)
96ade3ed 508 vty_outln (vty, "service password-encryption");
718e3744 509
510 if (host.lines >= 0)
96ade3ed 511 vty_outln (vty, "service terminal-length %d",host.lines);
718e3744 512
3b0c5d9a 513 if (host.motdfile)
96ade3ed 514 vty_outln (vty, "banner motd file %s", host.motdfile);
3b0c5d9a 515 else if (! host.motd)
96ade3ed 516 vty_outln (vty, "no banner motd");
718e3744 517
518 return 1;
519}
520
d0bfb22c
QY
521/* Utility function for getting command graph. */
522static struct graph *
523cmd_node_graph (vector v, enum node_type ntype)
718e3744 524{
d0bfb22c
QY
525 struct cmd_node *cnode = vector_slot (v, ntype);
526 return cnode->cmdgraph;
718e3744 527}
528
d0bfb22c
QY
529static int
530cmd_try_do_shortcut (enum node_type node, char* first_word) {
531 if ( first_word != NULL &&
532 node != AUTH_NODE &&
533 node != VIEW_NODE &&
534 node != AUTH_ENABLE_NODE &&
d0bfb22c
QY
535 0 == strcmp( "do", first_word ) )
536 return 1;
537 return 0;
718e3744 538}
539
d0bfb22c
QY
540/**
541 * Compare function for cmd_token.
542 * Used with qsort to sort command completions.
543 */
274a4a44 544static int
d0bfb22c 545compare_completions (const void *fst, const void *snd)
718e3744 546{
d0bfb22c
QY
547 struct cmd_token *first = *(struct cmd_token **) fst,
548 *secnd = *(struct cmd_token **) snd;
549 return strcmp (first->text, secnd->text);
718e3744 550}
551
d0bfb22c
QY
552/**
553 * Takes a list of completions returned by command_complete,
554 * dedeuplicates them based on both text and description,
6011c1b2
QY
555 * sorts them, and returns them as a vector.
556 *
557 * @param completions linked list of cmd_token
558 * @return deduplicated and sorted vector with
d0bfb22c 559 */
af2567b6 560vector
d0bfb22c 561completions_to_vec (struct list *completions)
718e3744 562{
d0bfb22c 563 vector comps = vector_init (VECTOR_MIN_SIZE);
718e3744 564
d0bfb22c 565 struct listnode *ln;
6011c1b2 566 struct cmd_token *token, *cr = NULL;
d0bfb22c
QY
567 unsigned int i, exists;
568 for (ALL_LIST_ELEMENTS_RO(completions,ln,token))
569 {
6011c1b2
QY
570 if (token->type == END_TKN && (cr = token))
571 continue;
572
d0bfb22c
QY
573 // linear search for token in completions vector
574 exists = 0;
575 for (i = 0; i < vector_active (comps) && !exists; i++)
cd40b329 576 {
d0bfb22c 577 struct cmd_token *curr = vector_slot (comps, i);
53205694 578#ifdef VTYSH_DEBUG
d0bfb22c
QY
579 exists = !strcmp (curr->text, token->text) &&
580 !strcmp (curr->desc, token->desc);
53205694
QY
581#else
582 exists = !strcmp (curr->text, token->text);
583#endif /* VTYSH_DEBUG */
cd40b329 584 }
909a2155 585
d0bfb22c 586 if (!exists)
17aca20b 587 vector_set (comps, token);
d0bfb22c 588 }
cd40b329 589
d0bfb22c
QY
590 // sort completions
591 qsort (comps->index,
592 vector_active (comps),
593 sizeof (void *),
594 &compare_completions);
cd40b329 595
ebacb4ed 596 // make <cr> the first element, if it is present
6011c1b2
QY
597 if (cr)
598 {
599 vector_set_index (comps, vector_active (comps), NULL);
600 memmove (comps->index + 1, comps->index, (comps->alloced - 1) * sizeof (void *));
17aca20b 601 vector_set_index (comps, 0, cr);
6011c1b2
QY
602 }
603
d0bfb22c 604 return comps;
cd40b329 605}
d0bfb22c
QY
606/**
607 * Generates a vector of cmd_token representing possible completions
608 * on the current input.
609 *
610 * @param vline the vectorized input line
611 * @param vty the vty with the node to match on
612 * @param status pointer to matcher status code
ebacb4ed 613 * @return vector of struct cmd_token * with possible completions
d0bfb22c
QY
614 */
615static vector
616cmd_complete_command_real (vector vline, struct vty *vty, int *status)
cd40b329 617{
d0bfb22c
QY
618 struct list *completions;
619 struct graph *cmdgraph = cmd_node_graph (cmdvec, vty->node);
cd40b329 620
d0bfb22c 621 enum matcher_rv rv = command_complete (cmdgraph, vline, &completions);
cd40b329 622
d0bfb22c
QY
623 if (MATCHER_ERROR(rv))
624 {
17aca20b 625 *status = CMD_ERR_NO_MATCH;
d0bfb22c 626 return NULL;
b92938a7 627 }
628
d0bfb22c
QY
629 vector comps = completions_to_vec (completions);
630 list_delete (completions);
b92938a7 631
d0bfb22c
QY
632 // set status code appropriately
633 switch (vector_active (comps))
634 {
635 case 0:
636 *status = CMD_ERR_NO_MATCH;
637 break;
638 case 1:
639 *status = CMD_COMPLETE_FULL_MATCH;
640 break;
641 default:
642 *status = CMD_COMPLETE_LIST_MATCH;
643 }
718e3744 644
d0bfb22c
QY
645 return comps;
646}
718e3744 647
d0bfb22c
QY
648vector
649cmd_describe_command (vector vline, struct vty *vty, int *status)
650{
651 vector ret;
718e3744 652
d0bfb22c 653 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
718e3744 654 {
d0bfb22c
QY
655 enum node_type onode;
656 vector shifted_vline;
657 unsigned int index;
718e3744 658
d0bfb22c
QY
659 onode = vty->node;
660 vty->node = ENABLE_NODE;
661 /* We can try it on enable node, cos' the vty is authenticated */
718e3744 662
d0bfb22c
QY
663 shifted_vline = vector_init (vector_count(vline));
664 /* use memcpy? */
665 for (index = 1; index < vector_active (vline); index++)
666 {
667 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
668 }
718e3744 669
d0bfb22c
QY
670 ret = cmd_complete_command_real (shifted_vline, vty, status);
671
672 vector_free(shifted_vline);
673 vty->node = onode;
674 return ret;
675 }
718e3744 676
d0bfb22c 677 return cmd_complete_command_real (vline, vty, status);
718e3744 678}
679
70d44c5c
DL
680static struct list *varhandlers = NULL;
681
682void
683cmd_variable_complete (struct cmd_token *token, const char *arg, vector comps)
684{
685 struct listnode *ln;
686 const struct cmd_variable_handler *cvh;
687 size_t i, argsz;
688 vector tmpcomps;
689
690 tmpcomps = arg ? vector_init (VECTOR_MIN_SIZE) : comps;
691
692 for (ALL_LIST_ELEMENTS_RO(varhandlers, ln, cvh))
693 {
694 if (cvh->tokenname && strcmp(cvh->tokenname, token->text))
695 continue;
696 if (cvh->varname && (!token->varname || strcmp(cvh->varname, token->varname)))
697 continue;
698 cvh->completions(tmpcomps, token);
699 break;
700 }
701
702 if (!arg)
703 return;
704
705 argsz = strlen(arg);
706 for (i = vector_active(tmpcomps); i; i--)
707 {
708 char *item = vector_slot(tmpcomps, i - 1);
709 if (strlen(item) >= argsz
710 && !strncmp(item, arg, argsz))
711 vector_set(comps, item);
712 else
713 XFREE(MTYPE_COMPLETION, item);
714 }
715 vector_free(tmpcomps);
716}
717
718void
719cmd_variable_handler_register (const struct cmd_variable_handler *cvh)
720{
721 if (!varhandlers)
722 return;
723
724 for (; cvh->completions; cvh++)
725 listnode_add(varhandlers, (void *)cvh);
726}
727
7f059ea6
DL
728DEFUN_HIDDEN (autocomplete,
729 autocomplete_cmd,
730 "autocomplete TYPE TEXT VARNAME",
731 "Autocompletion handler (internal, for vtysh)\n"
732 "cmd_token->type\n"
733 "cmd_token->text\n"
734 "cmd_token->varname\n")
735{
736 struct cmd_token tok;
737 vector comps = vector_init(32);
738 size_t i;
739
740 memset(&tok, 0, sizeof(tok));
741 tok.type = atoi(argv[1]->arg);
742 tok.text = argv[2]->arg;
743 tok.varname = argv[3]->arg;
744 if (!strcmp(tok.varname, "-"))
745 tok.varname = NULL;
746
747 cmd_variable_complete(&tok, NULL, comps);
748
749 for (i = 0; i < vector_active(comps); i++)
750 {
751 char *text = vector_slot(comps, i);
752 vty_out(vty, "%s\n", text);
753 XFREE(MTYPE_COMPLETION, text);
754 }
755
756 vector_free(comps);
757 return CMD_SUCCESS;
758}
759
ebacb4ed
QY
760/**
761 * Generate possible tab-completions for the given input. This function only
762 * returns results that would result in a valid command if used as Readline
763 * completions (as is the case in vtysh). For instance, if the passed vline ends
764 * with '4.3.2', the strings 'A.B.C.D' and 'A.B.C.D/M' will _not_ be returned.
765 *
766 * @param vline vectorized input line
767 * @param vty the vty
768 * @param status location to store matcher status code in
769 * @return set of valid strings for use with Readline as tab-completions.
770 */
771
b92938a7 772char **
ebacb4ed 773cmd_complete_command (vector vline, struct vty *vty, int *status)
b92938a7 774{
268316d1
QY
775 char **ret = NULL;
776 int original_node = vty->node;
777 vector input_line = vector_init (vector_count (vline));
778
779 // if the first token is 'do' we'll want to execute the command in the enable node
780 int do_shortcut = cmd_try_do_shortcut (vty->node, vector_slot (vline, 0));
781 vty->node = do_shortcut ? ENABLE_NODE : original_node;
782
783 // construct the input line we'll be matching on
784 unsigned int offset = (do_shortcut) ? 1 : 0;
785 for (unsigned index = 0; index + offset < vector_active (vline); index++)
55d403c9 786 vector_set_index (input_line, index, vector_lookup (vline, index + offset));
268316d1
QY
787
788 // get token completions -- this is a copying operation
ef736f12 789 vector comps = NULL, initial_comps;
ebacb4ed
QY
790 initial_comps = cmd_complete_command_real (input_line, vty, status);
791
268316d1
QY
792 if (!MATCHER_ERROR (*status))
793 {
5b5231b0
QY
794 assert (initial_comps);
795 // filter out everything that is not suitable for a tab-completion
796 comps = vector_init (VECTOR_MIN_SIZE);
797 for (unsigned int i = 0; i < vector_active(initial_comps); i++)
798 {
799 struct cmd_token *token = vector_slot (initial_comps, i);
800 if (token->type == WORD_TKN)
70d44c5c
DL
801 vector_set (comps, XSTRDUP (MTYPE_COMPLETION, token->text));
802 else if (IS_VARYING_TOKEN(token->type))
803 {
804 const char *ref = vector_lookup(vline, vector_active (vline) - 1);
805 cmd_variable_complete (token, ref, comps);
806 }
5b5231b0
QY
807 }
808 vector_free (initial_comps);
809
53d5ec36
DL
810 // since we filtered results, we need to re-set status code
811 switch (vector_active (comps))
812 {
813 case 0:
814 *status = CMD_ERR_NO_MATCH;
815 break;
816 case 1:
817 *status = CMD_COMPLETE_FULL_MATCH;
818 break;
819 default:
820 *status = CMD_COMPLETE_LIST_MATCH;
821 }
822
268316d1 823 // copy completions text into an array of char*
17aca20b 824 ret = XMALLOC (MTYPE_TMP, (vector_active (comps)+1) * sizeof (char *));
268316d1
QY
825 unsigned int i;
826 for (i = 0; i < vector_active (comps); i++)
827 {
70d44c5c 828 ret[i] = vector_slot (comps, i);
268316d1 829 }
ebacb4ed
QY
830 // set the last element to NULL, because this array is used in
831 // a Readline completion_generator function which expects NULL
832 // as a sentinel value
268316d1
QY
833 ret[i] = NULL;
834 vector_free (comps);
835 comps = NULL;
836 }
a31ff449
DL
837 else if (initial_comps)
838 vector_free (initial_comps);
b92938a7 839
268316d1
QY
840 // comps should always be null here
841 assert (!comps);
b92938a7 842
268316d1
QY
843 // free the adjusted input line
844 vector_free (input_line);
b92938a7 845
268316d1
QY
846 // reset vty->node to its original value
847 vty->node = original_node;
d0bfb22c
QY
848
849 return ret;
cde9f101 850}
b92938a7 851
b92938a7 852/* return parent node */
853/* MUST eventually converge on CONFIG_NODE */
13bfca7a 854enum node_type
274a4a44 855node_parent ( enum node_type node )
b92938a7 856{
857 enum node_type ret;
858
9ab6812d 859 assert (node > CONFIG_NODE);
860
861 switch (node)
862 {
863 case BGP_VPNV4_NODE:
8ecd3266 864 case BGP_VPNV6_NODE:
5ff06872 865 case BGP_VRF_POLICY_NODE:
65efcfce 866 case BGP_VNC_DEFAULTS_NODE:
e52702f2
QY
867 case BGP_VNC_NVE_GROUP_NODE:
868 case BGP_VNC_L2_GROUP_NODE:
9ab6812d 869 case BGP_IPV4_NODE:
870 case BGP_IPV4M_NODE:
f51bae9c 871 case BGP_IPV4L_NODE:
9ab6812d 872 case BGP_IPV6_NODE:
1e836590 873 case BGP_IPV6M_NODE:
9e6df0b7 874 case BGP_EVPN_NODE:
f51bae9c 875 case BGP_IPV6L_NODE:
9ab6812d 876 ret = BGP_NODE;
877 break;
878 case KEYCHAIN_KEY_NODE:
879 ret = KEYCHAIN_NODE;
880 break;
16f1b9ee
OD
881 case LINK_PARAMS_NODE:
882 ret = INTERFACE_NODE;
883 break;
eac6e3f0
RW
884 case LDP_IPV4_NODE:
885 case LDP_IPV6_NODE:
886 ret = LDP_NODE;
887 break;
888 case LDP_IPV4_IFACE_NODE:
889 ret = LDP_IPV4_NODE;
890 break;
891 case LDP_IPV6_IFACE_NODE:
892 ret = LDP_IPV6_NODE;
893 break;
894 case LDP_PSEUDOWIRE_NODE:
895 ret = LDP_L2VPN_NODE;
896 break;
9ab6812d 897 default:
898 ret = CONFIG_NODE;
16f1b9ee 899 break;
b92938a7 900 }
901
902 return ret;
903}
904
718e3744 905/* Execute command by argument vline vector. */
274a4a44 906static int
cd40b329 907cmd_execute_command_real (vector vline,
d0bfb22c
QY
908 enum filter_type filter,
909 struct vty *vty,
17aca20b 910 const struct cmd_element **cmd)
d0bfb22c
QY
911{
912 struct list *argv_list;
913 enum matcher_rv status;
17aca20b 914 const struct cmd_element *matched_element = NULL;
c5bd4620 915
d0bfb22c 916 struct graph *cmdgraph = cmd_node_graph (cmdvec, vty->node);
c5bd4620
QY
917 status = command_match (cmdgraph, vline, &argv_list, &matched_element);
918
919 if (cmd)
920 *cmd = matched_element;
d0bfb22c
QY
921
922 // if matcher error, return corresponding CMD_ERR
923 if (MATCHER_ERROR(status))
17aca20b 924 {
a31ff449
DL
925 if (argv_list)
926 list_delete (argv_list);
d0bfb22c
QY
927 switch (status)
928 {
929 case MATCHER_INCOMPLETE:
930 return CMD_ERR_INCOMPLETE;
931 case MATCHER_AMBIGUOUS:
932 return CMD_ERR_AMBIGUOUS;
933 default:
934 return CMD_ERR_NO_MATCH;
718e3744 935 }
17aca20b 936 }
718e3744 937
d0bfb22c
QY
938 // build argv array from argv list
939 struct cmd_token **argv = XMALLOC (MTYPE_TMP, argv_list->count * sizeof (struct cmd_token *));
940 struct listnode *ln;
941 struct cmd_token *token;
942 unsigned int i = 0;
943 for (ALL_LIST_ELEMENTS_RO(argv_list,ln,token))
944 argv[i++] = token;
718e3744 945
d0bfb22c 946 int argc = argv_list->count;
718e3744 947
d0bfb22c 948 int ret;
c5bd4620 949 if (matched_element->daemon)
d0bfb22c
QY
950 ret = CMD_SUCCESS_DAEMON;
951 else
c5bd4620 952 ret = matched_element->func (matched_element, vty, argc, argv);
718e3744 953
d0bfb22c
QY
954 // delete list and cmd_token's in it
955 list_delete (argv_list);
17aca20b 956 XFREE (MTYPE_TMP, argv);
718e3744 957
d0bfb22c 958 return ret;
718e3744 959}
960
cd40b329
CF
961/**
962 * Execute a given command, handling things like "do ..." and checking
963 * whether the given command might apply at a parent node if doesn't
964 * apply for the current node.
965 *
966 * @param vline Command line input, vector of char* where each element is
967 * one input token.
968 * @param vty The vty context in which the command should be executed.
969 * @param cmd Pointer where the struct cmd_element of the matched command
970 * will be stored, if any. May be set to NULL if this info is
971 * not needed.
972 * @param vtysh If set != 0, don't lookup the command at parent nodes.
973 * @return The status of the command that has been executed or an error code
974 * as to why no command could be executed.
975 */
eda031f6 976int
17aca20b
QY
977cmd_execute_command (vector vline, struct vty *vty,
978 const struct cmd_element **cmd,
979 int vtysh)
980{
04e64062 981 int ret, saved_ret = 0;
9ab6812d 982 enum node_type onode, try_node;
eda031f6 983
9ab6812d 984 onode = try_node = vty->node;
b92938a7 985
17aca20b 986 if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0)))
b92938a7 987 {
988 vector shifted_vline;
8c328f11 989 unsigned int index;
b92938a7 990
991 vty->node = ENABLE_NODE;
992 /* We can try it on enable node, cos' the vty is authenticated */
993
994 shifted_vline = vector_init (vector_count(vline));
995 /* use memcpy? */
d0bfb22c 996 for (index = 1; index < vector_active (vline); index++)
04e64062 997 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
b92938a7 998
cd40b329 999 ret = cmd_execute_command_real (shifted_vline, FILTER_RELAXED, vty, cmd);
b92938a7 1000
1001 vector_free(shifted_vline);
1002 vty->node = onode;
1003 return ret;
1004 }
1005
cd40b329 1006 saved_ret = ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
b92938a7 1007
87d683b0 1008 if (vtysh)
1009 return saved_ret;
1010
04e64062 1011 if (ret != CMD_SUCCESS && ret != CMD_WARNING)
b92938a7 1012 {
04e64062
QY
1013 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
1014 while (vty->node > CONFIG_NODE)
1015 {
1016 try_node = node_parent(try_node);
1017 vty->node = try_node;
1018 ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
1019 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
1020 return ret;
1021 }
1022 /* no command succeeded, reset the vty to the original node */
1023 vty->node = onode;
b92938a7 1024 }
04e64062
QY
1025
1026 /* return command status for original node */
9ab6812d 1027 return saved_ret;
b92938a7 1028}
1029
cd40b329
CF
1030/**
1031 * Execute a given command, matching it strictly against the current node.
1032 * This mode is used when reading config files.
1033 *
1034 * @param vline Command line input, vector of char* where each element is
1035 * one input token.
1036 * @param vty The vty context in which the command should be executed.
1037 * @param cmd Pointer where the struct cmd_element* of the matched command
1038 * will be stored, if any. May be set to NULL if this info is
1039 * not needed.
1040 * @return The status of the command that has been executed or an error code
1041 * as to why no command could be executed.
1042 */
718e3744 1043int
909a2155 1044cmd_execute_command_strict (vector vline, struct vty *vty,
17aca20b 1045 const struct cmd_element **cmd)
718e3744 1046{
cd40b329 1047 return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
718e3744 1048}
1049
bed578b8
DS
1050/**
1051 * Parse one line of config, walking up the parse tree attempting to find a match
1052 *
1053 * @param vty The vty context in which the command should be executed.
1054 * @param cmd Pointer where the struct cmd_element* of the match command
1055 * will be stored, if any. May be set to NULL if this info is
1056 * not needed.
1057 * @param use_daemon Boolean to control whether or not we match on CMD_SUCCESS_DAEMON
1058 * or not.
1059 * @return The status of the command that has been executed or an error code
1060 * as to why no command could be executed.
1061 */
1062int
17aca20b 1063command_config_read_one_line (struct vty *vty, const struct cmd_element **cmd, int use_daemon)
bed578b8
DS
1064{
1065 vector vline;
1066 int saved_node;
1067 int ret;
1068
1069 vline = cmd_make_strvec (vty->buf);
1070
1071 /* In case of comment line */
1072 if (vline == NULL)
1073 return CMD_SUCCESS;
1074
1075 /* Execute configuration command : this is strict match */
1076 ret = cmd_execute_command_strict (vline, vty, cmd);
1077
1078 // Climb the tree and try the command again at each node
1079 if (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
fd715b78
DW
1080 !(!use_daemon && ret == CMD_ERR_NOTHING_TODO) &&
1081 ret != CMD_SUCCESS &&
1082 ret != CMD_WARNING &&
1083 vty->node != CONFIG_NODE) {
bed578b8
DS
1084
1085 saved_node = vty->node;
1086
1087 while (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
fd715b78 1088 !(!use_daemon && ret == CMD_ERR_NOTHING_TODO) &&
d0bfb22c 1089 ret != CMD_SUCCESS &&
fd715b78 1090 ret != CMD_WARNING &&
73d2dad0 1091 vty->node > CONFIG_NODE) {
bed578b8 1092 vty->node = node_parent(vty->node);
fd715b78 1093 ret = cmd_execute_command_strict (vline, vty, cmd);
bed578b8
DS
1094 }
1095
1096 // If climbing the tree did not work then ignore the command and
1097 // stay at the same node
1098 if (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
fd715b78 1099 !(!use_daemon && ret == CMD_ERR_NOTHING_TODO) &&
d0bfb22c 1100 ret != CMD_SUCCESS &&
fd715b78 1101 ret != CMD_WARNING)
bed578b8 1102 {
d0bfb22c 1103 vty->node = saved_node;
bed578b8
DS
1104 }
1105 }
1106
cbd7259d
QY
1107 if (ret != CMD_SUCCESS && ret != CMD_WARNING)
1108 memcpy (vty->error_buf, vty->buf, VTY_BUFSIZ);
1109
bed578b8
DS
1110 cmd_free_strvec (vline);
1111
1112 return ret;
1113}
1114
5689fe5f 1115/* Configuration make from file. */
718e3744 1116int
13fbc82d 1117config_from_file (struct vty *vty, FILE *fp, unsigned int *line_num)
718e3744 1118{
5689fe5f 1119 int ret, error_ret=0;
13fbc82d 1120 *line_num = 0;
718e3744 1121
1122 while (fgets (vty->buf, VTY_BUFSIZ, fp))
1123 {
13fbc82d 1124 if (!error_ret)
d0bfb22c 1125 ++(*line_num);
13fbc82d 1126
bed578b8 1127 ret = command_config_read_one_line (vty, NULL, 0);
718e3744 1128
5689fe5f 1129 if (ret != CMD_SUCCESS && ret != CMD_WARNING &&
d0bfb22c
QY
1130 ret != CMD_ERR_NOTHING_TODO)
1131 error_ret = ret;
718e3744 1132 }
5689fe5f
DW
1133
1134 if (error_ret) {
1135 return error_ret;
1136 }
1137
718e3744 1138 return CMD_SUCCESS;
1139}
1140
5689fe5f 1141/* Configuration from terminal */
718e3744 1142DEFUN (config_terminal,
1143 config_terminal_cmd,
1144 "configure terminal",
1145 "Configuration from vty interface\n"
1146 "Configuration terminal\n")
1147{
1148 if (vty_config_lock (vty))
1149 vty->node = CONFIG_NODE;
1150 else
1151 {
96ade3ed 1152 vty_outln (vty, "VTY configuration is locked by other VTY");
718e3744 1153 return CMD_WARNING;
1154 }
1155 return CMD_SUCCESS;
1156}
1157
1158/* Enable command */
d0bfb22c 1159DEFUN (enable,
718e3744 1160 config_enable_cmd,
1161 "enable",
1162 "Turn on privileged mode command\n")
1163{
1164 /* If enable password is NULL, change to ENABLE_NODE */
1165 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
1166 vty->type == VTY_SHELL_SERV)
1167 vty->node = ENABLE_NODE;
1168 else
1169 vty->node = AUTH_ENABLE_NODE;
1170
1171 return CMD_SUCCESS;
1172}
1173
1174/* Disable command */
d0bfb22c 1175DEFUN (disable,
718e3744 1176 config_disable_cmd,
1177 "disable",
1178 "Turn off privileged mode command\n")
1179{
1180 if (vty->node == ENABLE_NODE)
1181 vty->node = VIEW_NODE;
1182 return CMD_SUCCESS;
1183}
1184
1185/* Down vty node level. */
1186DEFUN (config_exit,
1187 config_exit_cmd,
1188 "exit",
1189 "Exit current mode and down to previous mode\n")
0b84f294
DL
1190{
1191 cmd_exit (vty);
1192 return CMD_SUCCESS;
1193}
1194
1195void
1196cmd_exit (struct vty *vty)
718e3744 1197{
1198 switch (vty->node)
1199 {
1200 case VIEW_NODE:
1201 case ENABLE_NODE:
1202 if (vty_shell (vty))
d0bfb22c 1203 exit (0);
718e3744 1204 else
d0bfb22c 1205 vty->status = VTY_CLOSE;
718e3744 1206 break;
1207 case CONFIG_NODE:
1208 vty->node = ENABLE_NODE;
1209 vty_config_unlock (vty);
1210 break;
1211 case INTERFACE_NODE:
13460c44 1212 case NS_NODE:
f93e3f69 1213 case VRF_NODE:
718e3744 1214 case ZEBRA_NODE:
1215 case BGP_NODE:
1216 case RIP_NODE:
7f57883e 1217 case EIGRP_NODE:
a616ea5f 1218 case BABEL_NODE:
718e3744 1219 case RIPNG_NODE:
1220 case OSPF_NODE:
1221 case OSPF6_NODE:
eac6e3f0
RW
1222 case LDP_NODE:
1223 case LDP_L2VPN_NODE:
9e867fe6 1224 case ISIS_NODE:
718e3744 1225 case KEYCHAIN_NODE:
1226 case MASC_NODE:
1227 case RMAP_NODE:
12e41d03 1228 case PIM_NODE:
718e3744 1229 case VTY_NODE:
1230 vty->node = CONFIG_NODE;
1231 break;
718e3744 1232 case BGP_IPV4_NODE:
1233 case BGP_IPV4M_NODE:
f51bae9c 1234 case BGP_IPV4L_NODE:
8ecd3266 1235 case BGP_VPNV4_NODE:
1236 case BGP_VPNV6_NODE:
5ff06872 1237 case BGP_VRF_POLICY_NODE:
65efcfce
LB
1238 case BGP_VNC_DEFAULTS_NODE:
1239 case BGP_VNC_NVE_GROUP_NODE:
1240 case BGP_VNC_L2_GROUP_NODE:
718e3744 1241 case BGP_IPV6_NODE:
1e836590 1242 case BGP_IPV6M_NODE:
9e6df0b7 1243 case BGP_EVPN_NODE:
f51bae9c 1244 case BGP_IPV6L_NODE:
718e3744 1245 vty->node = BGP_NODE;
1246 break;
eac6e3f0
RW
1247 case LDP_IPV4_NODE:
1248 case LDP_IPV6_NODE:
1249 vty->node = LDP_NODE;
1250 break;
1251 case LDP_IPV4_IFACE_NODE:
1252 vty->node = LDP_IPV4_NODE;
1253 break;
1254 case LDP_IPV6_IFACE_NODE:
1255 vty->node = LDP_IPV6_NODE;
1256 break;
1257 case LDP_PSEUDOWIRE_NODE:
1258 vty->node = LDP_L2VPN_NODE;
1259 break;
718e3744 1260 case KEYCHAIN_KEY_NODE:
1261 vty->node = KEYCHAIN_NODE;
1262 break;
16f1b9ee
OD
1263 case LINK_PARAMS_NODE:
1264 vty->node = INTERFACE_NODE;
1265 break;
718e3744 1266 default:
1267 break;
1268 }
718e3744 1269}
1270
f667a580
QY
1271/* ALIAS_FIXME */
1272DEFUN (config_quit,
1273 config_quit_cmd,
1274 "quit",
1275 "Exit current mode and down to previous mode\n")
1276{
1277 return config_exit (self, vty, argc, argv);
1278}
1279
d0bfb22c 1280
718e3744 1281/* End of configuration. */
1282DEFUN (config_end,
1283 config_end_cmd,
1284 "end",
1285 "End current mode and change to enable mode.")
1286{
1287 switch (vty->node)
1288 {
1289 case VIEW_NODE:
1290 case ENABLE_NODE:
1291 /* Nothing to do. */
1292 break;
1293 case CONFIG_NODE:
1294 case INTERFACE_NODE:
13460c44 1295 case NS_NODE:
f93e3f69 1296 case VRF_NODE:
718e3744 1297 case ZEBRA_NODE:
1298 case RIP_NODE:
1299 case RIPNG_NODE:
7f57883e 1300 case EIGRP_NODE:
a616ea5f 1301 case BABEL_NODE:
718e3744 1302 case BGP_NODE:
5ff06872 1303 case BGP_VRF_POLICY_NODE:
65efcfce
LB
1304 case BGP_VNC_DEFAULTS_NODE:
1305 case BGP_VNC_NVE_GROUP_NODE:
1306 case BGP_VNC_L2_GROUP_NODE:
718e3744 1307 case BGP_VPNV4_NODE:
8ecd3266 1308 case BGP_VPNV6_NODE:
718e3744 1309 case BGP_IPV4_NODE:
1310 case BGP_IPV4M_NODE:
f51bae9c 1311 case BGP_IPV4L_NODE:
718e3744 1312 case BGP_IPV6_NODE:
1e836590 1313 case BGP_IPV6M_NODE:
9e6df0b7 1314 case BGP_EVPN_NODE:
f51bae9c 1315 case BGP_IPV6L_NODE:
718e3744 1316 case RMAP_NODE:
1317 case OSPF_NODE:
1318 case OSPF6_NODE:
eac6e3f0
RW
1319 case LDP_NODE:
1320 case LDP_IPV4_NODE:
1321 case LDP_IPV6_NODE:
1322 case LDP_IPV4_IFACE_NODE:
1323 case LDP_IPV6_IFACE_NODE:
1324 case LDP_L2VPN_NODE:
1325 case LDP_PSEUDOWIRE_NODE:
9e867fe6 1326 case ISIS_NODE:
718e3744 1327 case KEYCHAIN_NODE:
1328 case KEYCHAIN_KEY_NODE:
1329 case MASC_NODE:
12e41d03 1330 case PIM_NODE:
718e3744 1331 case VTY_NODE:
16f1b9ee 1332 case LINK_PARAMS_NODE:
718e3744 1333 vty_config_unlock (vty);
1334 vty->node = ENABLE_NODE;
1335 break;
1336 default:
1337 break;
1338 }
1339 return CMD_SUCCESS;
1340}
1341
1342/* Show version. */
1343DEFUN (show_version,
1344 show_version_cmd,
1345 "show version",
1346 SHOW_STR
1347 "Displays zebra version\n")
1348{
96ade3ed
QY
1349 vty_outln (vty, "%s %s (%s).", FRR_FULL_NAME, FRR_VERSION,
1350 host.name ? host.name : "");
1351 vty_outln (vty, "%s%s", FRR_COPYRIGHT, GIT_INFO);
1318e7c8 1352 vty_outln (vty, "configured with:%s %s", VTYNL,
96ade3ed 1353 FRR_CONFIG_ARGS);
718e3744 1354
1355 return CMD_SUCCESS;
1356}
1357
8efe88ea
DL
1358/* "Set" version ... ignore version tags */
1359DEFUN (frr_version_defaults,
1360 frr_version_defaults_cmd,
3e7c8d04 1361 "frr <version|defaults> LINE...",
447a8fe9 1362 "FRRouting global parameters\n"
8efe88ea
DL
1363 "version configuration was written by\n"
1364 "set of configuration defaults used\n"
1365 "version string\n")
1366{
8efe88ea
DL
1367 return CMD_SUCCESS;
1368}
1369
718e3744 1370/* Help display function for all node. */
1371DEFUN (config_help,
1372 config_help_cmd,
1373 "help",
1374 "Description of the interactive help system\n")
1375{
96ade3ed 1376 vty_outln (vty,
d0bfb22c 1377 "Quagga VTY provides advanced help feature. When you need help,%s\
718e3744 1378anytime at the command line please press '?'.%s\
1379%s\
1380If nothing matches, the help list will be empty and you must backup%s\
1381 until entering a '?' shows the available options.%s\
1382Two styles of help are provided:%s\
13831. Full help is available when you are ready to enter a%s\
1384command argument (e.g. 'show ?') and describes each possible%s\
1385argument.%s\
13862. Partial help is provided when an abbreviated argument is entered%s\
1387 and you want to know what arguments match the input%s\
1318e7c8
QY
1388 (e.g. 'show me?'.)%s", VTYNL, VTYNL, VTYNL,
1389 VTYNL, VTYNL, VTYNL, VTYNL, VTYNL,
1390 VTYNL, VTYNL, VTYNL, VTYNL);
718e3744 1391 return CMD_SUCCESS;
1392}
1393
a2454870
QY
1394static void
1395permute (struct graph_node *start, struct vty *vty)
1396{
1397 static struct list *position = NULL;
1398 if (!position) position = list_new ();
1399
e4e63cb6
QY
1400 struct cmd_token *stok = start->data;
1401 struct graph_node *gnn;
1402 struct listnode *ln;
1403
a2454870
QY
1404 // recursive dfs
1405 listnode_add (position, start);
1406 for (unsigned int i = 0; i < vector_active (start->to); i++)
1407 {
1408 struct graph_node *gn = vector_slot (start->to, i);
1409 struct cmd_token *tok = gn->data;
7a4662b4
QY
1410 if (tok->attr == CMD_ATTR_HIDDEN ||
1411 tok->attr == CMD_ATTR_DEPRECATED)
1412 continue;
1413 else if (tok->type == END_TKN || gn == start)
a2454870 1414 {
a2454870
QY
1415 vty_out (vty, " ");
1416 for (ALL_LIST_ELEMENTS_RO (position,ln,gnn))
1417 {
1418 struct cmd_token *tt = gnn->data;
0bf5b1cb 1419 if (tt->type < SPECIAL_TKN)
a2454870
QY
1420 vty_out (vty, " %s", tt->text);
1421 }
1422 if (gn == start)
1423 vty_out (vty, "...");
e31b6333 1424 vty_out (vty, VTYNL);
a2454870
QY
1425 }
1426 else
e4e63cb6
QY
1427 {
1428 bool skip = false;
1429 if (stok->type == FORK_TKN && tok->type != FORK_TKN)
1430 for (ALL_LIST_ELEMENTS_RO (position, ln, gnn))
9bc22111
HWC
1431 if (gnn == gn)
1432 {
1433 skip = true;
e4e63cb6 1434 break;
9bc22111 1435 }
e4e63cb6
QY
1436 if (!skip)
1437 permute (gn, vty);
1438 }
a2454870
QY
1439 }
1440 list_delete_node (position, listtail(position));
1441}
1442
0b84f294
DL
1443int
1444cmd_list_cmds (struct vty *vty, int do_permute)
718e3744 1445{
a2454870
QY
1446 struct cmd_node *node = vector_slot (cmdvec, vty->node);
1447
0b84f294 1448 if (do_permute)
a2454870
QY
1449 permute (vector_slot (node->cmdgraph->nodes, 0), vty);
1450 else
1451 {
1452 /* loop over all commands at this node */
1453 struct cmd_element *element = NULL;
1454 for (unsigned int i = 0; i < vector_active(node->cmd_vector); i++)
1455 if ((element = vector_slot (node->cmd_vector, i)) &&
1456 element->attr != CMD_ATTR_DEPRECATED &&
1457 element->attr != CMD_ATTR_HIDDEN)
96ade3ed 1458 vty_outln (vty, " %s", element->string);
a2454870 1459 }
718e3744 1460 return CMD_SUCCESS;
1461}
1462
0b84f294
DL
1463/* Help display function for all node. */
1464DEFUN (config_list,
1465 config_list_cmd,
1466 "list [permutations]",
1467 "Print command list\n"
1468 "Print all possible command permutations\n")
1469{
1470 return cmd_list_cmds (vty, argc == 2);
1471}
1472
a2454870
QY
1473DEFUN (show_commandtree,
1474 show_commandtree_cmd,
1475 "show commandtree [permutations]",
1476 SHOW_STR
5a1945e4
DS
1477 "Show command tree\n"
1478 "Permutations that we are interested in\n")
a2454870 1479{
0b84f294 1480 return cmd_list_cmds (vty, argc == 3);
a2454870
QY
1481}
1482
8efe88ea
DL
1483static void
1484vty_write_config (struct vty *vty)
1485{
1486 size_t i;
1487 struct cmd_node *node;
1488
1489 if (vty->type == VTY_TERM)
1490 {
1318e7c8 1491 vty_outln (vty, "%sCurrent configuration:",VTYNL);
96ade3ed 1492 vty_outln (vty, "!");
8efe88ea
DL
1493 }
1494
96ade3ed
QY
1495 vty_outln (vty, "frr version %s", FRR_VER_SHORT);
1496 vty_outln (vty, "frr defaults %s", DFLT_NAME);
1497 vty_outln (vty, "!");
8efe88ea
DL
1498
1499 for (i = 0; i < vector_active (cmdvec); i++)
1500 if ((node = vector_slot (cmdvec, i)) && node->func
1501 && (node->vtysh || vty->type != VTY_SHELL))
1502 {
1503 if ((*node->func) (vty))
96ade3ed 1504 vty_outln (vty, "!");
8efe88ea
DL
1505 }
1506
1507 if (vty->type == VTY_TERM)
1508 {
96ade3ed 1509 vty_outln (vty, "end");
8efe88ea
DL
1510 }
1511}
1512
718e3744 1513/* Write current configuration into file. */
d862bffb 1514
d0bfb22c
QY
1515DEFUN (config_write,
1516 config_write_cmd,
1517 "write [<file|memory|terminal>]",
718e3744 1518 "Write running configuration to memory, network, or terminal\n"
d0bfb22c
QY
1519 "Write to configuration file\n"
1520 "Write configuration currently in memory\n"
1521 "Write configuration to terminal\n")
718e3744 1522{
c349116d 1523 int idx_type = 1;
056cfe49 1524 int fd, dirfd;
056cfe49 1525 char *config_file, *slash;
718e3744 1526 char *config_file_tmp = NULL;
1527 char *config_file_sav = NULL;
05865c90 1528 int ret = CMD_WARNING;
718e3744 1529 struct vty *file_vty;
e4421165 1530 struct stat conf_stat;
718e3744 1531
74d57f5a 1532 // if command was 'write terminal' or 'show running-config'
7e045c3d
QY
1533 if (argc == 2 && (strmatch(argv[idx_type]->text, "terminal") ||
1534 strmatch(argv[0]->text, "show")))
3e7c8d04
DL
1535 {
1536 vty_write_config (vty);
1537 return CMD_SUCCESS;
1538 }
d0bfb22c 1539
87f44e2f
DL
1540 if (host.noconfig)
1541 return CMD_SUCCESS;
1542
718e3744 1543 /* Check and see if we are operating under vtysh configuration */
1544 if (host.config == NULL)
1545 {
96ade3ed 1546 vty_outln (vty,"Can't save to configuration file, using vtysh.");
718e3744 1547 return CMD_WARNING;
1548 }
1549
1550 /* Get filename. */
1551 config_file = host.config;
d0bfb22c 1552
056cfe49
DL
1553#ifndef O_DIRECTORY
1554#define O_DIRECTORY 0
1555#endif
1556 slash = strrchr (config_file, '/');
1557 if (slash)
1558 {
1559 char *config_dir = XSTRDUP (MTYPE_TMP, config_file);
1560 config_dir[slash - config_file] = '\0';
1561 dirfd = open(config_dir, O_DIRECTORY | O_RDONLY);
1562 XFREE (MTYPE_TMP, config_dir);
1563 }
1564 else
1565 dirfd = open(".", O_DIRECTORY | O_RDONLY);
1566 /* if dirfd is invalid, directory sync fails, but we're still OK */
1567
05865c90 1568 config_file_sav =
1569 XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
718e3744 1570 strcpy (config_file_sav, config_file);
1571 strcat (config_file_sav, CONF_BACKUP_EXT);
1572
1573
05865c90 1574 config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
718e3744 1575 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
d0bfb22c 1576
718e3744 1577 /* Open file to configuration write. */
1578 fd = mkstemp (config_file_tmp);
1579 if (fd < 0)
1580 {
96ade3ed 1581 vty_outln (vty, "Can't open configuration file %s.",config_file_tmp);
05865c90 1582 goto finished;
718e3744 1583 }
056cfe49
DL
1584 if (fchmod (fd, CONFIGFILE_MASK) != 0)
1585 {
96ade3ed
QY
1586 vty_outln (vty, "Can't chmod configuration file %s: %s (%d).",
1587 config_file_tmp, safe_strerror(errno), errno);
056cfe49
DL
1588 goto finished;
1589 }
d0bfb22c 1590
718e3744 1591 /* Make vty for configuration file. */
1592 file_vty = vty_new ();
c5e69a02 1593 file_vty->wfd = fd;
718e3744 1594 file_vty->type = VTY_FILE;
1595
1596 /* Config file header print. */
1597 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
1598 vty_time_print (file_vty, 1);
1599 vty_out (file_vty, "!\n");
8efe88ea 1600 vty_write_config (file_vty);
718e3744 1601 vty_close (file_vty);
1602
e4421165 1603 if (stat(config_file, &conf_stat) >= 0)
718e3744 1604 {
e4421165 1605 if (unlink (config_file_sav) != 0)
d0bfb22c
QY
1606 if (errno != ENOENT)
1607 {
96ade3ed
QY
1608 vty_outln (vty, "Can't unlink backup configuration file %s.",
1609 config_file_sav);
d0bfb22c
QY
1610 goto finished;
1611 }
e4421165 1612 if (link (config_file, config_file_sav) != 0)
d0bfb22c 1613 {
96ade3ed
QY
1614 vty_outln (vty, "Can't backup old configuration file %s.",
1615 config_file_sav);
d0bfb22c
QY
1616 goto finished;
1617 }
14878121
DL
1618 if (dirfd >= 0)
1619 fsync (dirfd);
718e3744 1620 }
056cfe49 1621 if (rename (config_file_tmp, config_file) != 0)
718e3744 1622 {
96ade3ed 1623 vty_outln (vty, "Can't save configuration file %s.",config_file);
05865c90 1624 goto finished;
718e3744 1625 }
14878121
DL
1626 if (dirfd >= 0)
1627 fsync (dirfd);
aa593d5e 1628
96ade3ed 1629 vty_outln (vty, "Configuration saved to %s",config_file);
05865c90 1630 ret = CMD_SUCCESS;
1631
1632finished:
056cfe49
DL
1633 if (ret != CMD_SUCCESS)
1634 unlink (config_file_tmp);
14878121
DL
1635 if (dirfd >= 0)
1636 close (dirfd);
05865c90 1637 XFREE (MTYPE_TMP, config_file_tmp);
1638 XFREE (MTYPE_TMP, config_file_sav);
1639 return ret;
718e3744 1640}
1641
d862bffb
QY
1642/* ALIAS_FIXME for 'write <terminal|memory>' */
1643DEFUN (show_running_config,
1644 show_running_config_cmd,
1645 "show running-config",
1646 SHOW_STR
1647 "running configuration (same as write terminal/memory)\n")
1648{
1649 return config_write (self, vty, argc, argv);
1650}
718e3744 1651
d862bffb
QY
1652/* ALIAS_FIXME for 'write file' */
1653DEFUN (copy_runningconf_startupconf,
1654 copy_runningconf_startupconf_cmd,
1655 "copy running-config startup-config",
1656 "Copy configuration\n"
1657 "Copy running config to... \n"
1658 "Copy running config to startup config (same as write file)\n")
1659{
8efe88ea
DL
1660 if (!host.noconfig)
1661 vty_write_config (vty);
718e3744 1662 return CMD_SUCCESS;
d862bffb
QY
1663}
1664/** -- **/
718e3744 1665
1666/* Write startup configuration into the terminal. */
1667DEFUN (show_startup_config,
1668 show_startup_config_cmd,
1669 "show startup-config",
1670 SHOW_STR
d0bfb22c 1671 "Contents of startup configuration\n")
718e3744 1672{
1673 char buf[BUFSIZ];
1674 FILE *confp;
1675
87f44e2f
DL
1676 if (host.noconfig)
1677 return CMD_SUCCESS;
1678 if (host.config == NULL)
1679 return CMD_WARNING;
1680
718e3744 1681 confp = fopen (host.config, "r");
1682 if (confp == NULL)
1683 {
96ade3ed
QY
1684 vty_outln (vty, "Can't open configuration file [%s] due to '%s'",
1685 host.config, safe_strerror(errno));
718e3744 1686 return CMD_WARNING;
1687 }
1688
1689 while (fgets (buf, BUFSIZ, confp))
1690 {
1691 char *cp = buf;
1692
1693 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
d0bfb22c 1694 cp++;
718e3744 1695 *cp = '\0';
1696
96ade3ed 1697 vty_outln (vty, "%s", buf);
718e3744 1698 }
1699
1700 fclose (confp);
1701
1702 return CMD_SUCCESS;
1703}
1704
bff9c3e9
DL
1705int
1706cmd_hostname_set (const char *hostname)
1707{
1708 XFREE (MTYPE_HOST, host.name);
1709 host.name = hostname ? XSTRDUP (MTYPE_HOST, hostname) : NULL;
1710 return CMD_SUCCESS;
1711}
1712
718e3744 1713/* Hostname configuration */
d0bfb22c 1714DEFUN (config_hostname,
718e3744 1715 hostname_cmd,
1716 "hostname WORD",
1717 "Set system's network name\n"
1718 "This system's network name\n")
1719{
d0bfb22c
QY
1720 struct cmd_token *word = argv[1];
1721
e4123a9b 1722 if (!isalpha((int) word->arg[0]))
718e3744 1723 {
96ade3ed 1724 vty_outln (vty, "Please specify string starting with alphabet");
718e3744 1725 return CMD_WARNING;
1726 }
1727
bff9c3e9 1728 return cmd_hostname_set (word->arg);
718e3744 1729}
1730
d0bfb22c 1731DEFUN (config_no_hostname,
718e3744 1732 no_hostname_cmd,
1733 "no hostname [HOSTNAME]",
1734 NO_STR
1735 "Reset system's network name\n"
1736 "Host name of this router\n")
1737{
bff9c3e9 1738 return cmd_hostname_set (NULL);
718e3744 1739}
1740
1741/* VTY interface password set. */
f412b39a
DW
1742DEFUN (config_password,
1743 password_cmd,
98463e0a 1744 "password [(8-8)] WORD",
718e3744 1745 "Assign the terminal connection password\n"
1746 "Specifies a HIDDEN password will follow\n"
d0bfb22c 1747 "The password string\n")
718e3744 1748{
c349116d
DW
1749 int idx_8 = 1;
1750 int idx_word = 2;
d0bfb22c
QY
1751 if (argc == 3) // '8' was specified
1752 {
1753 if (host.password)
1754 XFREE (MTYPE_HOST, host.password);
1755 host.password = NULL;
1756 if (host.password_encrypt)
1757 XFREE (MTYPE_HOST, host.password_encrypt);
c349116d 1758 host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[idx_word]->arg);
d0bfb22c
QY
1759 return CMD_SUCCESS;
1760 }
718e3744 1761
c349116d 1762 if (!isalnum (argv[idx_8]->arg[0]))
718e3744 1763 {
96ade3ed
QY
1764 vty_outln (vty,
1765 "Please specify string starting with alphanumeric");
718e3744 1766 return CMD_WARNING;
1767 }
1768
1769 if (host.password)
05865c90 1770 XFREE (MTYPE_HOST, host.password);
718e3744 1771 host.password = NULL;
1772
1773 if (host.encrypt)
1774 {
1775 if (host.password_encrypt)
d0bfb22c 1776 XFREE (MTYPE_HOST, host.password_encrypt);
c349116d 1777 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[idx_8]->arg));
718e3744 1778 }
1779 else
c349116d 1780 host.password = XSTRDUP (MTYPE_HOST, argv[idx_8]->arg);
718e3744 1781
1782 return CMD_SUCCESS;
1783}
1784
718e3744 1785/* VTY enable password set. */
f412b39a
DW
1786DEFUN (config_enable_password,
1787 enable_password_cmd,
98463e0a 1788 "enable password [(8-8)] WORD",
718e3744 1789 "Modify enable password parameters\n"
1790 "Assign the privileged level password\n"
1791 "Specifies a HIDDEN password will follow\n"
718e3744 1792 "The HIDDEN 'enable' password string\n")
1793{
c349116d
DW
1794 int idx_8 = 2;
1795 int idx_word = 3;
58749582 1796
718e3744 1797 /* Crypt type is specified. */
d0bfb22c 1798 if (argc == 4)
718e3744 1799 {
c349116d 1800 if (argv[idx_8]->arg[0] == '8')
d0bfb22c
QY
1801 {
1802 if (host.enable)
1803 XFREE (MTYPE_HOST, host.enable);
1804 host.enable = NULL;
1805
1806 if (host.enable_encrypt)
1807 XFREE (MTYPE_HOST, host.enable_encrypt);
c349116d 1808 host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[idx_word]->arg);
d0bfb22c
QY
1809
1810 return CMD_SUCCESS;
1811 }
718e3744 1812 else
d0bfb22c 1813 {
96ade3ed 1814 vty_outln (vty, "Unknown encryption type.");
d0bfb22c
QY
1815 return CMD_WARNING;
1816 }
718e3744 1817 }
1818
c349116d 1819 if (!isalnum (argv[idx_8]->arg[0]))
718e3744 1820 {
96ade3ed
QY
1821 vty_outln (vty,
1822 "Please specify string starting with alphanumeric");
718e3744 1823 return CMD_WARNING;
1824 }
1825
1826 if (host.enable)
05865c90 1827 XFREE (MTYPE_HOST, host.enable);
718e3744 1828 host.enable = NULL;
1829
1830 /* Plain password input. */
1831 if (host.encrypt)
1832 {
1833 if (host.enable_encrypt)
d0bfb22c 1834 XFREE (MTYPE_HOST, host.enable_encrypt);
c349116d 1835 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[idx_8]->arg));
718e3744 1836 }
1837 else
c349116d 1838 host.enable = XSTRDUP (MTYPE_HOST, argv[idx_8]->arg);
718e3744 1839
1840 return CMD_SUCCESS;
1841}
1842
718e3744 1843/* VTY enable password delete. */
f412b39a
DW
1844DEFUN (no_config_enable_password,
1845 no_enable_password_cmd,
718e3744 1846 "no enable password",
1847 NO_STR
1848 "Modify enable password parameters\n"
1849 "Assign the privileged level password\n")
1850{
1851 if (host.enable)
05865c90 1852 XFREE (MTYPE_HOST, host.enable);
718e3744 1853 host.enable = NULL;
1854
1855 if (host.enable_encrypt)
05865c90 1856 XFREE (MTYPE_HOST, host.enable_encrypt);
718e3744 1857 host.enable_encrypt = NULL;
1858
1859 return CMD_SUCCESS;
1860}
d0bfb22c 1861
718e3744 1862DEFUN (service_password_encrypt,
1863 service_password_encrypt_cmd,
1864 "service password-encryption",
1865 "Set up miscellaneous service\n"
1866 "Enable encrypted passwords\n")
1867{
1868 if (host.encrypt)
1869 return CMD_SUCCESS;
1870
1871 host.encrypt = 1;
1872
1873 if (host.password)
1874 {
1875 if (host.password_encrypt)
d0bfb22c 1876 XFREE (MTYPE_HOST, host.password_encrypt);
05865c90 1877 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
718e3744 1878 }
1879 if (host.enable)
1880 {
1881 if (host.enable_encrypt)
d0bfb22c 1882 XFREE (MTYPE_HOST, host.enable_encrypt);
05865c90 1883 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
718e3744 1884 }
1885
1886 return CMD_SUCCESS;
1887}
1888
1889DEFUN (no_service_password_encrypt,
1890 no_service_password_encrypt_cmd,
1891 "no service password-encryption",
1892 NO_STR
1893 "Set up miscellaneous service\n"
1894 "Enable encrypted passwords\n")
1895{
1896 if (! host.encrypt)
1897 return CMD_SUCCESS;
1898
1899 host.encrypt = 0;
1900
1901 if (host.password_encrypt)
05865c90 1902 XFREE (MTYPE_HOST, host.password_encrypt);
718e3744 1903 host.password_encrypt = NULL;
1904
1905 if (host.enable_encrypt)
05865c90 1906 XFREE (MTYPE_HOST, host.enable_encrypt);
718e3744 1907 host.enable_encrypt = NULL;
1908
1909 return CMD_SUCCESS;
1910}
1911
f412b39a
DW
1912DEFUN (config_terminal_length,
1913 config_terminal_length_cmd,
d0bfb22c 1914 "terminal length (0-512)",
718e3744 1915 "Set terminal line parameters\n"
1916 "Set number of lines on a screen\n"
1917 "Number of lines on screen (0 for no pausing)\n")
1918{
c349116d 1919 int idx_number = 2;
718e3744 1920
dfdbe7e4 1921 vty->lines = atoi (argv[idx_number]->arg);
718e3744 1922
1923 return CMD_SUCCESS;
1924}
1925
f412b39a
DW
1926DEFUN (config_terminal_no_length,
1927 config_terminal_no_length_cmd,
718e3744 1928 "terminal no length",
1929 "Set terminal line parameters\n"
1930 NO_STR
1931 "Set number of lines on a screen\n")
1932{
1933 vty->lines = -1;
1934 return CMD_SUCCESS;
1935}
1936
f412b39a
DW
1937DEFUN (service_terminal_length,
1938 service_terminal_length_cmd,
d0bfb22c 1939 "service terminal-length (0-512)",
718e3744 1940 "Set up miscellaneous service\n"
1941 "System wide terminal length configuration\n"
1942 "Number of lines of VTY (0 means no line control)\n")
1943{
c349116d 1944 int idx_number = 2;
718e3744 1945
dfdbe7e4 1946 host.lines = atoi (argv[idx_number]->arg);
718e3744 1947
1948 return CMD_SUCCESS;
1949}
1950
f412b39a
DW
1951DEFUN (no_service_terminal_length,
1952 no_service_terminal_length_cmd,
d0bfb22c 1953 "no service terminal-length [(0-512)]",
718e3744 1954 NO_STR
1955 "Set up miscellaneous service\n"
1956 "System wide terminal length configuration\n"
1957 "Number of lines of VTY (0 means no line control)\n")
1958{
1959 host.lines = -1;
1960 return CMD_SUCCESS;
1961}
1962
2885f72d 1963DEFUN_HIDDEN (do_echo,
d0bfb22c
QY
1964 echo_cmd,
1965 "echo MESSAGE...",
1966 "Echo a message back to the vty\n"
1967 "The message to echo\n")
2885f72d 1968{
1969 char *message;
1970
96ade3ed
QY
1971 vty_outln (vty, "%s",
1972 ((message = argv_concat(argv, argc, 1)) ? message : ""));
f6834d4c 1973 if (message)
1974 XFREE(MTYPE_TMP, message);
2885f72d 1975 return CMD_SUCCESS;
1976}
1977
274a4a44 1978DEFUN (config_logmsg,
1979 config_logmsg_cmd,
199d90a1 1980 "logmsg <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging> MESSAGE...",
274a4a44 1981 "Send a message to enabled logging destinations\n"
1982 LOG_LEVEL_DESC
1983 "The message to send\n")
1984{
c349116d 1985 int idx_log_level = 1;
58749582 1986 int idx_message = 2;
274a4a44 1987 int level;
1988 char *message;
1989
c349116d 1990 if ((level = level_match(argv[idx_log_level]->arg)) == ZLOG_DISABLED)
274a4a44 1991 return CMD_ERR_NO_MATCH;
1992
bb85d700 1993 zlog(level, "%s", ((message = argv_concat(argv, argc, idx_message)) ? message : ""));
f6834d4c 1994 if (message)
1995 XFREE(MTYPE_TMP, message);
65efcfce 1996
274a4a44 1997 return CMD_SUCCESS;
1998}
1999
2000DEFUN (show_logging,
2001 show_logging_cmd,
2002 "show logging",
2003 SHOW_STR
2004 "Show current logging configuration\n")
2005{
2006 struct zlog *zl = zlog_default;
2007
2008 vty_out (vty, "Syslog logging: ");
2009 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
2010 vty_out (vty, "disabled");
2011 else
2012 vty_out (vty, "level %s, facility %s, ident %s",
d0bfb22c
QY
2013 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
2014 facility_name(zl->facility), zl->ident);
e31b6333 2015 vty_out (vty, VTYNL);
274a4a44 2016
2017 vty_out (vty, "Stdout logging: ");
2018 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
2019 vty_out (vty, "disabled");
2020 else
2021 vty_out (vty, "level %s",
d0bfb22c 2022 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
e31b6333 2023 vty_out (vty, VTYNL);
274a4a44 2024
2025 vty_out (vty, "Monitor logging: ");
2026 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
2027 vty_out (vty, "disabled");
2028 else
2029 vty_out (vty, "level %s",
d0bfb22c 2030 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
e31b6333 2031 vty_out (vty, VTYNL);
274a4a44 2032
2033 vty_out (vty, "File logging: ");
2034 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
2035 !zl->fp)
2036 vty_out (vty, "disabled");
2037 else
2038 vty_out (vty, "level %s, filename %s",
d0bfb22c
QY
2039 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
2040 zl->filename);
e31b6333 2041 vty_out (vty, VTYNL);
96ade3ed
QY
2042
2043 vty_outln (vty, "Protocol name: %s",
2044 zl->protoname);
2045 vty_outln (vty, "Record priority: %s",
2046 (zl->record_priority ? "enabled" : "disabled"));
2047 vty_outln (vty, "Timestamp precision: %d",
2048 zl->timestamp_precision);
274a4a44 2049
2050 return CMD_SUCCESS;
2051}
2052
718e3744 2053DEFUN (config_log_stdout,
2054 config_log_stdout_cmd,
6de69f83 2055 "log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
274a4a44 2056 "Logging control\n"
2057 "Set stdout logging level\n"
2058 LOG_LEVEL_DESC)
2059{
c349116d 2060 int idx_log_level = 2;
58749582
DW
2061
2062 if (argc == idx_log_level)
d0bfb22c 2063 {
dd8376fe 2064 zlog_set_level (ZLOG_DEST_STDOUT, zlog_default->default_lvl);
d0bfb22c
QY
2065 return CMD_SUCCESS;
2066 }
274a4a44 2067 int level;
2068
c349116d 2069 if ((level = level_match(argv[idx_log_level]->arg)) == ZLOG_DISABLED)
274a4a44 2070 return CMD_ERR_NO_MATCH;
dd8376fe 2071 zlog_set_level (ZLOG_DEST_STDOUT, level);
718e3744 2072 return CMD_SUCCESS;
2073}
2074
2075DEFUN (no_config_log_stdout,
2076 no_config_log_stdout_cmd,
6de69f83 2077 "no log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
718e3744 2078 NO_STR
2079 "Logging control\n"
274a4a44 2080 "Cancel logging to stdout\n"
d0bfb22c 2081 LOG_LEVEL_DESC)
718e3744 2082{
dd8376fe 2083 zlog_set_level (ZLOG_DEST_STDOUT, ZLOG_DISABLED);
718e3744 2084 return CMD_SUCCESS;
2085}
2086
274a4a44 2087DEFUN (config_log_monitor,
2088 config_log_monitor_cmd,
6de69f83 2089 "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
274a4a44 2090 "Logging control\n"
2091 "Set terminal line (monitor) logging level\n"
2092 LOG_LEVEL_DESC)
2093{
c349116d 2094 int idx_log_level = 2;
58749582
DW
2095
2096 if (argc == idx_log_level)
d0bfb22c 2097 {
dd8376fe 2098 zlog_set_level (ZLOG_DEST_MONITOR, zlog_default->default_lvl);
d0bfb22c
QY
2099 return CMD_SUCCESS;
2100 }
274a4a44 2101 int level;
2102
c349116d 2103 if ((level = level_match(argv[idx_log_level]->arg)) == ZLOG_DISABLED)
274a4a44 2104 return CMD_ERR_NO_MATCH;
dd8376fe 2105 zlog_set_level (ZLOG_DEST_MONITOR, level);
274a4a44 2106 return CMD_SUCCESS;
2107}
2108
2109DEFUN (no_config_log_monitor,
2110 no_config_log_monitor_cmd,
6de69f83 2111 "no log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
274a4a44 2112 NO_STR
2113 "Logging control\n"
2114 "Disable terminal line (monitor) logging\n"
d0bfb22c 2115 LOG_LEVEL_DESC)
274a4a44 2116{
dd8376fe 2117 zlog_set_level (ZLOG_DEST_MONITOR, ZLOG_DISABLED);
274a4a44 2118 return CMD_SUCCESS;
2119}
2120
2121static int
2122set_log_file(struct vty *vty, const char *fname, int loglevel)
718e3744 2123{
2124 int ret;
9035efaa 2125 char *p = NULL;
2126 const char *fullpath;
d0bfb22c 2127
718e3744 2128 /* Path detection. */
274a4a44 2129 if (! IS_DIRECTORY_SEP (*fname))
718e3744 2130 {
9035efaa 2131 char cwd[MAXPATHLEN+1];
2132 cwd[MAXPATHLEN] = '\0';
d0bfb22c 2133
9035efaa 2134 if (getcwd (cwd, MAXPATHLEN) == NULL)
2135 {
2136 zlog_err ("config_log_file: Unable to alloc mem!");
2137 return CMD_WARNING;
2138 }
d0bfb22c 2139
274a4a44 2140 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
9035efaa 2141 == NULL)
2142 {
2143 zlog_err ("config_log_file: Unable to alloc mem!");
2144 return CMD_WARNING;
2145 }
274a4a44 2146 sprintf (p, "%s/%s", cwd, fname);
9035efaa 2147 fullpath = p;
718e3744 2148 }
2149 else
274a4a44 2150 fullpath = fname;
718e3744 2151
dd8376fe 2152 ret = zlog_set_file (fullpath, loglevel);
718e3744 2153
9035efaa 2154 if (p)
2155 XFREE (MTYPE_TMP, p);
2156
718e3744 2157 if (!ret)
2158 {
274a4a44 2159 vty_out (vty, "can't open logfile %s\n", fname);
718e3744 2160 return CMD_WARNING;
2161 }
2162
2163 if (host.logfile)
05865c90 2164 XFREE (MTYPE_HOST, host.logfile);
718e3744 2165
05865c90 2166 host.logfile = XSTRDUP (MTYPE_HOST, fname);
718e3744 2167
c05795b1
SK
2168#if defined(HAVE_CUMULUS)
2169 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
2170 zlog_default->maxlvl[ZLOG_DEST_SYSLOG] = ZLOG_DISABLED;
2171#endif
718e3744 2172 return CMD_SUCCESS;
2173}
2174
274a4a44 2175DEFUN (config_log_file,
2176 config_log_file_cmd,
6de69f83 2177 "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
274a4a44 2178 "Logging control\n"
2179 "Logging to file\n"
2180 "Logging filename\n"
2181 LOG_LEVEL_DESC)
2182{
c349116d
DW
2183 int idx_filename = 2;
2184 int idx_log_levels = 3;
d0bfb22c
QY
2185 if (argc == 4)
2186 {
2187 int level;
c349116d 2188 if ((level = level_match(argv[idx_log_levels]->arg)) == ZLOG_DISABLED)
d0bfb22c 2189 return CMD_ERR_NO_MATCH;
c349116d 2190 return set_log_file(vty, argv[idx_filename]->arg, level);
d0bfb22c
QY
2191 }
2192 else
c349116d 2193 return set_log_file(vty, argv[idx_filename]->arg, zlog_default->default_lvl);
274a4a44 2194}
2195
718e3744 2196DEFUN (no_config_log_file,
2197 no_config_log_file_cmd,
d0bfb22c 2198 "no log file [FILENAME [LEVEL]]",
718e3744 2199 NO_STR
2200 "Logging control\n"
2201 "Cancel logging to file\n"
d0bfb22c
QY
2202 "Logging file name\n"
2203 "Logging file name\n"
2204 "Logging level\n")
718e3744 2205{
dd8376fe 2206 zlog_reset_file ();
718e3744 2207
2208 if (host.logfile)
05865c90 2209 XFREE (MTYPE_HOST, host.logfile);
718e3744 2210
2211 host.logfile = NULL;
2212
2213 return CMD_SUCCESS;
2214}
2215
2216DEFUN (config_log_syslog,
2217 config_log_syslog_cmd,
6de69f83 2218 "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
12ab19f1 2219 "Logging control\n"
274a4a44 2220 "Set syslog logging level\n"
2221 LOG_LEVEL_DESC)
2222{
c349116d 2223 int idx_log_levels = 2;
d0bfb22c
QY
2224 if (argc == 3)
2225 {
2226 int level;
c349116d 2227 if ((level = level_match (argv[idx_log_levels]->arg)) == ZLOG_DISABLED)
d0bfb22c 2228 return CMD_ERR_NO_MATCH;
dd8376fe 2229 zlog_set_level (ZLOG_DEST_SYSLOG, level);
d0bfb22c
QY
2230 return CMD_SUCCESS;
2231 }
2232 else
2233 {
dd8376fe 2234 zlog_set_level (ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
d0bfb22c
QY
2235 return CMD_SUCCESS;
2236 }
274a4a44 2237}
2238
718e3744 2239DEFUN (no_config_log_syslog,
2240 no_config_log_syslog_cmd,
6de69f83 2241 "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>]",
718e3744 2242 NO_STR
2243 "Logging control\n"
274a4a44 2244 "Cancel logging to syslog\n"
d0bfb22c
QY
2245 LOG_FACILITY_DESC
2246 LOG_LEVEL_DESC)
718e3744 2247{
dd8376fe 2248 zlog_set_level (ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
718e3744 2249 return CMD_SUCCESS;
2250}
2251
274a4a44 2252DEFUN (config_log_facility,
2253 config_log_facility_cmd,
9ccf14f7 2254 "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>",
718e3744 2255 "Logging control\n"
274a4a44 2256 "Facility parameter for syslog messages\n"
2257 LOG_FACILITY_DESC)
718e3744 2258{
c349116d
DW
2259 int idx_target = 2;
2260 int facility = facility_match(argv[idx_target]->arg);
274a4a44 2261
274a4a44 2262 zlog_default->facility = facility;
2263 return CMD_SUCCESS;
718e3744 2264}
2265
274a4a44 2266DEFUN (no_config_log_facility,
2267 no_config_log_facility_cmd,
9ccf14f7 2268 "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
718e3744 2269 NO_STR
2270 "Logging control\n"
274a4a44 2271 "Reset syslog facility to default (daemon)\n"
d0bfb22c 2272 LOG_FACILITY_DESC)
274a4a44 2273{
2274 zlog_default->facility = LOG_DAEMON;
2275 return CMD_SUCCESS;
2276}
2277
2278DEFUN_DEPRECATED (config_log_trap,
d0bfb22c 2279 config_log_trap_cmd,
199d90a1 2280 "log trap <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
d0bfb22c
QY
2281 "Logging control\n"
2282 "(Deprecated) Set logging level and default for all destinations\n"
2283 LOG_LEVEL_DESC)
274a4a44 2284{
2285 int new_level ;
2286 int i;
d0bfb22c
QY
2287
2288 if ((new_level = level_match(argv[2]->arg)) == ZLOG_DISABLED)
274a4a44 2289 return CMD_ERR_NO_MATCH;
2290
2291 zlog_default->default_lvl = new_level;
2292 for (i = 0; i < ZLOG_NUM_DESTS; i++)
2293 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
2294 zlog_default->maxlvl[i] = new_level;
2295 return CMD_SUCCESS;
2296}
2297
2298DEFUN_DEPRECATED (no_config_log_trap,
d0bfb22c 2299 no_config_log_trap_cmd,
199d90a1 2300 "no log trap [emergencies|alerts|critical|errors|warnings|notifications|informational|debugging]",
d0bfb22c
QY
2301 NO_STR
2302 "Logging control\n"
2303 "Permit all logging information\n"
2304 LOG_LEVEL_DESC)
718e3744 2305{
274a4a44 2306 zlog_default->default_lvl = LOG_DEBUG;
718e3744 2307 return CMD_SUCCESS;
2308}
2309
2310DEFUN (config_log_record_priority,
2311 config_log_record_priority_cmd,
2312 "log record-priority",
2313 "Logging control\n"
2314 "Log the priority of the message within the message\n")
2315{
2316 zlog_default->record_priority = 1 ;
2317 return CMD_SUCCESS;
2318}
2319
2320DEFUN (no_config_log_record_priority,
2321 no_config_log_record_priority_cmd,
2322 "no log record-priority",
2323 NO_STR
2324 "Logging control\n"
2325 "Do not log the priority of the message within the message\n")
2326{
2327 zlog_default->record_priority = 0 ;
2328 return CMD_SUCCESS;
2329}
2330
1ed72e0b
AS
2331DEFUN (config_log_timestamp_precision,
2332 config_log_timestamp_precision_cmd,
6147e2c6 2333 "log timestamp precision (0-6)",
1ed72e0b
AS
2334 "Logging control\n"
2335 "Timestamp configuration\n"
2336 "Set the timestamp precision\n"
2337 "Number of subsecond digits\n")
2338{
c349116d 2339 int idx_number = 3;
facfee22 2340 zlog_default->timestamp_precision = strtoul(argv[idx_number]->arg, NULL, 10);
1ed72e0b
AS
2341 return CMD_SUCCESS;
2342}
2343
2344DEFUN (no_config_log_timestamp_precision,
2345 no_config_log_timestamp_precision_cmd,
2346 "no log timestamp precision",
2347 NO_STR
2348 "Logging control\n"
2349 "Timestamp configuration\n"
2350 "Reset the timestamp precision to the default value of 0\n")
2351{
2352 zlog_default->timestamp_precision = 0 ;
2353 return CMD_SUCCESS;
2354}
2355
7cfc61d3
DS
2356int
2357cmd_banner_motd_file (const char *file)
2358{
1ee08155
DS
2359 int success = CMD_SUCCESS;
2360 char p[PATH_MAX];
2361 char *rpath;
2362 char *in;
7cfc61d3 2363
1ee08155
DS
2364 rpath = realpath (file, p);
2365 if (!rpath)
2366 return CMD_ERR_NO_FILE;
2367 in = strstr (rpath, SYSCONFDIR);
2368 if (in == rpath)
2369 {
2370 if (host.motdfile)
844ec28c 2371 XFREE (MTYPE_HOST, host.motdfile);
1ee08155
DS
2372 host.motdfile = XSTRDUP (MTYPE_HOST, file);
2373 }
2374 else
2375 success = CMD_WARNING;
2376
2377 return success;
7cfc61d3
DS
2378}
2379
3b0c5d9a 2380DEFUN (banner_motd_file,
2381 banner_motd_file_cmd,
4d833e55 2382 "banner motd file FILE",
3b0c5d9a 2383 "Set banner\n"
2384 "Banner for motd\n"
2385 "Banner from a file\n"
2386 "Filename\n")
2387{
c349116d
DW
2388 int idx_file = 3;
2389 const char *filename = argv[idx_file]->arg;
97e5b7c0 2390 int cmd = cmd_banner_motd_file (filename);
1ee08155
DS
2391
2392 if (cmd == CMD_ERR_NO_FILE)
97e5b7c0 2393 vty_out (vty, "%s does not exist", filename);
1ee08155 2394 else if (cmd == CMD_WARNING)
97e5b7c0 2395 vty_out (vty, "%s must be in %s", filename, SYSCONFDIR);
1ee08155
DS
2396
2397 return cmd;
3b0c5d9a 2398}
718e3744 2399
2400DEFUN (banner_motd_default,
2401 banner_motd_default_cmd,
2402 "banner motd default",
2403 "Set banner string\n"
2404 "Strings for motd\n"
2405 "Default string\n")
2406{
2407 host.motd = default_motd;
2408 return CMD_SUCCESS;
2409}
2410
2411DEFUN (no_banner_motd,
2412 no_banner_motd_cmd,
2413 "no banner motd",
2414 NO_STR
2415 "Set banner string\n"
2416 "Strings for motd\n")
2417{
2418 host.motd = NULL;
d0bfb22c 2419 if (host.motdfile)
05865c90 2420 XFREE (MTYPE_HOST, host.motdfile);
3b0c5d9a 2421 host.motdfile = NULL;
718e3744 2422 return CMD_SUCCESS;
2423}
2424
2425/* Set config filename. Called from vty.c */
2426void
c0e8c16f 2427host_config_set (const char *filename)
718e3744 2428{
228da428
CC
2429 if (host.config)
2430 XFREE (MTYPE_HOST, host.config);
05865c90 2431 host.config = XSTRDUP (MTYPE_HOST, filename);
718e3744 2432}
2433
57387fb2
CF
2434const char *
2435host_config_get (void)
2436{
2437 return host.config;
2438}
2439
718e3744 2440void
2441install_default (enum node_type node)
2442{
2443 install_element (node, &config_exit_cmd);
d862bffb 2444 install_element (node, &config_quit_cmd);
718e3744 2445 install_element (node, &config_end_cmd);
2446 install_element (node, &config_help_cmd);
2447 install_element (node, &config_list_cmd);
2448
718e3744 2449 install_element (node, &config_write_cmd);
d862bffb 2450 install_element (node, &show_running_config_cmd);
7f059ea6
DL
2451
2452 install_element (node, &autocomplete_cmd);
718e3744 2453}
2454
87f44e2f
DL
2455/* Initialize command interface. Install basic nodes and commands.
2456 *
2457 * terminal = 0 -- vtysh / no logging, no config control
2458 * terminal = 1 -- normal daemon
9473e340 2459 * terminal = -1 -- watchfrr / no logging, but minimal config control */
718e3744 2460void
2461cmd_init (int terminal)
2462{
1bf9f027
DL
2463 qobj_init ();
2464
70d44c5c
DL
2465 varhandlers = list_new ();
2466
718e3744 2467 /* Allocate initial top vector of commands. */
2468 cmdvec = vector_init (VECTOR_MIN_SIZE);
2469
2470 /* Default host value settings. */
2471 host.name = NULL;
2472 host.password = NULL;
2473 host.enable = NULL;
2474 host.logfile = NULL;
2475 host.config = NULL;
87f44e2f 2476 host.noconfig = (terminal < 0);
718e3744 2477 host.lines = -1;
2478 host.motd = default_motd;
3b0c5d9a 2479 host.motdfile = NULL;
718e3744 2480
2481 /* Install top nodes. */
2482 install_node (&view_node, NULL);
2483 install_node (&enable_node, NULL);
2484 install_node (&auth_node, NULL);
2485 install_node (&auth_enable_node, NULL);
2486 install_node (&config_node, config_write_host);
2487
2488 /* Each node's basic commands. */
2489 install_element (VIEW_NODE, &show_version_cmd);
2490 if (terminal)
2491 {
2492 install_element (VIEW_NODE, &config_list_cmd);
2493 install_element (VIEW_NODE, &config_exit_cmd);
d862bffb 2494 install_element (VIEW_NODE, &config_quit_cmd);
718e3744 2495 install_element (VIEW_NODE, &config_help_cmd);
2496 install_element (VIEW_NODE, &config_enable_cmd);
2497 install_element (VIEW_NODE, &config_terminal_length_cmd);
2498 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
274a4a44 2499 install_element (VIEW_NODE, &show_logging_cmd);
bcd9fa7f 2500 install_element (VIEW_NODE, &show_commandtree_cmd);
2885f72d 2501 install_element (VIEW_NODE, &echo_cmd);
7f059ea6 2502 install_element (VIEW_NODE, &autocomplete_cmd);
718e3744 2503 }
2504
2505 if (terminal)
2506 {
6694f68c 2507 install_element (ENABLE_NODE, &config_end_cmd);
718e3744 2508 install_element (ENABLE_NODE, &config_disable_cmd);
2509 install_element (ENABLE_NODE, &config_terminal_cmd);
d862bffb 2510 install_element (ENABLE_NODE, &copy_runningconf_startupconf_cmd);
6694f68c
RW
2511 install_element (ENABLE_NODE, &config_write_cmd);
2512 install_element (ENABLE_NODE, &show_running_config_cmd);
718e3744 2513 }
2514 install_element (ENABLE_NODE, &show_startup_config_cmd);
718e3744 2515
718e3744 2516 if (terminal)
2517 {
274a4a44 2518 install_element (ENABLE_NODE, &config_logmsg_cmd);
e7168df4 2519 install_default (CONFIG_NODE);
87f44e2f 2520
0b84f294
DL
2521 thread_cmd_init ();
2522 workqueue_cmd_init ();
ea8e9d97 2523 }
d0bfb22c 2524
ea8e9d97 2525 install_element (CONFIG_NODE, &hostname_cmd);
2526 install_element (CONFIG_NODE, &no_hostname_cmd);
8efe88ea 2527 install_element (CONFIG_NODE, &frr_version_defaults_cmd);
e7168df4 2528
87f44e2f 2529 if (terminal > 0)
ea8e9d97 2530 {
e7168df4 2531 install_element (CONFIG_NODE, &password_cmd);
e7168df4 2532 install_element (CONFIG_NODE, &enable_password_cmd);
e7168df4 2533 install_element (CONFIG_NODE, &no_enable_password_cmd);
2534
718e3744 2535 install_element (CONFIG_NODE, &config_log_stdout_cmd);
2536 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
274a4a44 2537 install_element (CONFIG_NODE, &config_log_monitor_cmd);
274a4a44 2538 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
718e3744 2539 install_element (CONFIG_NODE, &config_log_file_cmd);
2540 install_element (CONFIG_NODE, &no_config_log_file_cmd);
2541 install_element (CONFIG_NODE, &config_log_syslog_cmd);
2542 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
274a4a44 2543 install_element (CONFIG_NODE, &config_log_facility_cmd);
2544 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
718e3744 2545 install_element (CONFIG_NODE, &config_log_trap_cmd);
2546 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
2547 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
2548 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
1ed72e0b
AS
2549 install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
2550 install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
718e3744 2551 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
2552 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
2553 install_element (CONFIG_NODE, &banner_motd_default_cmd);
3b0c5d9a 2554 install_element (CONFIG_NODE, &banner_motd_file_cmd);
718e3744 2555 install_element (CONFIG_NODE, &no_banner_motd_cmd);
2556 install_element (CONFIG_NODE, &service_terminal_length_cmd);
2557 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
718e3744 2558
19dc275e 2559 vrf_install_commands ();
9ab6812d 2560 }
af2567b6
DL
2561
2562#ifdef DEV_BUILD
2563 grammar_sandbox_init();
2564#endif
718e3744 2565}
228da428
CC
2566
2567void
2568cmd_terminate ()
2569{
228da428 2570 struct cmd_node *cmd_node;
228da428
CC
2571
2572 if (cmdvec)
2573 {
d0bfb22c 2574 for (unsigned int i = 0; i < vector_active (cmdvec); i++)
228da428 2575 if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
d0bfb22c
QY
2576 {
2577 // deleting the graph delets the cmd_element as well
2578 graph_delete_graph (cmd_node->cmdgraph);
2579 vector_free (cmd_node->cmd_vector);
39e92c06
QY
2580 hash_clean (cmd_node->cmd_hash, NULL);
2581 hash_free (cmd_node->cmd_hash);
2582 cmd_node->cmd_hash = NULL;
d0bfb22c 2583 }
228da428
CC
2584
2585 vector_free (cmdvec);
2586 cmdvec = NULL;
2587 }
2588
228da428
CC
2589 if (host.name)
2590 XFREE (MTYPE_HOST, host.name);
2591 if (host.password)
2592 XFREE (MTYPE_HOST, host.password);
2593 if (host.password_encrypt)
2594 XFREE (MTYPE_HOST, host.password_encrypt);
2595 if (host.enable)
2596 XFREE (MTYPE_HOST, host.enable);
2597 if (host.enable_encrypt)
2598 XFREE (MTYPE_HOST, host.enable_encrypt);
2599 if (host.logfile)
2600 XFREE (MTYPE_HOST, host.logfile);
2601 if (host.motdfile)
2602 XFREE (MTYPE_HOST, host.motdfile);
2603 if (host.config)
2604 XFREE (MTYPE_HOST, host.config);
58ac32e2 2605
2b4dc78f 2606 list_delete (varhandlers);
58ac32e2 2607 qobj_finish ();
228da428 2608}