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