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