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