]> git.proxmox.com Git - mirror_frr.git/blame - lib/command.c
Merge pull request #262 from donaldsharp/pim_jp_fixes
[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:
1401 case RIPNG_NODE:
1402 case OSPF_NODE:
1403 case OSPF6_NODE:
eac6e3f0
RW
1404 case LDP_NODE:
1405 case LDP_L2VPN_NODE:
9e867fe6 1406 case ISIS_NODE:
718e3744 1407 case KEYCHAIN_NODE:
1408 case MASC_NODE:
1409 case RMAP_NODE:
12e41d03 1410 case PIM_NODE:
718e3744 1411 case VTY_NODE:
1412 vty->node = CONFIG_NODE;
1413 break;
718e3744 1414 case BGP_IPV4_NODE:
1415 case BGP_IPV4M_NODE:
8ecd3266 1416 case BGP_VPNV4_NODE:
1417 case BGP_VPNV6_NODE:
8b1fb8be
LB
1418 case BGP_ENCAP_NODE:
1419 case BGP_ENCAPV6_NODE:
5ff06872 1420 case BGP_VRF_POLICY_NODE:
65efcfce
LB
1421 case BGP_VNC_DEFAULTS_NODE:
1422 case BGP_VNC_NVE_GROUP_NODE:
1423 case BGP_VNC_L2_GROUP_NODE:
718e3744 1424 case BGP_IPV6_NODE:
1e836590 1425 case BGP_IPV6M_NODE:
9e6df0b7 1426 case BGP_EVPN_NODE:
718e3744 1427 vty->node = BGP_NODE;
1428 break;
eac6e3f0
RW
1429 case LDP_IPV4_NODE:
1430 case LDP_IPV6_NODE:
1431 vty->node = LDP_NODE;
1432 break;
1433 case LDP_IPV4_IFACE_NODE:
1434 vty->node = LDP_IPV4_NODE;
1435 break;
1436 case LDP_IPV6_IFACE_NODE:
1437 vty->node = LDP_IPV6_NODE;
1438 break;
1439 case LDP_PSEUDOWIRE_NODE:
1440 vty->node = LDP_L2VPN_NODE;
1441 break;
718e3744 1442 case KEYCHAIN_KEY_NODE:
1443 vty->node = KEYCHAIN_NODE;
1444 break;
16f1b9ee
OD
1445 case LINK_PARAMS_NODE:
1446 vty->node = INTERFACE_NODE;
1447 break;
718e3744 1448 default:
1449 break;
1450 }
718e3744 1451}
1452
f667a580
QY
1453/* ALIAS_FIXME */
1454DEFUN (config_quit,
1455 config_quit_cmd,
1456 "quit",
1457 "Exit current mode and down to previous mode\n")
1458{
1459 return config_exit (self, vty, argc, argv);
1460}
1461
d0bfb22c 1462
718e3744 1463/* End of configuration. */
1464DEFUN (config_end,
1465 config_end_cmd,
1466 "end",
1467 "End current mode and change to enable mode.")
1468{
1469 switch (vty->node)
1470 {
1471 case VIEW_NODE:
1472 case ENABLE_NODE:
1473 /* Nothing to do. */
1474 break;
1475 case CONFIG_NODE:
1476 case INTERFACE_NODE:
13460c44 1477 case NS_NODE:
f93e3f69 1478 case VRF_NODE:
718e3744 1479 case ZEBRA_NODE:
1480 case RIP_NODE:
1481 case RIPNG_NODE:
1482 case BGP_NODE:
8b1fb8be
LB
1483 case BGP_ENCAP_NODE:
1484 case BGP_ENCAPV6_NODE:
5ff06872 1485 case BGP_VRF_POLICY_NODE:
65efcfce
LB
1486 case BGP_VNC_DEFAULTS_NODE:
1487 case BGP_VNC_NVE_GROUP_NODE:
1488 case BGP_VNC_L2_GROUP_NODE:
718e3744 1489 case BGP_VPNV4_NODE:
8ecd3266 1490 case BGP_VPNV6_NODE:
718e3744 1491 case BGP_IPV4_NODE:
1492 case BGP_IPV4M_NODE:
1493 case BGP_IPV6_NODE:
1e836590 1494 case BGP_IPV6M_NODE:
9e6df0b7 1495 case BGP_EVPN_NODE:
718e3744 1496 case RMAP_NODE:
1497 case OSPF_NODE:
1498 case OSPF6_NODE:
eac6e3f0
RW
1499 case LDP_NODE:
1500 case LDP_IPV4_NODE:
1501 case LDP_IPV6_NODE:
1502 case LDP_IPV4_IFACE_NODE:
1503 case LDP_IPV6_IFACE_NODE:
1504 case LDP_L2VPN_NODE:
1505 case LDP_PSEUDOWIRE_NODE:
9e867fe6 1506 case ISIS_NODE:
718e3744 1507 case KEYCHAIN_NODE:
1508 case KEYCHAIN_KEY_NODE:
1509 case MASC_NODE:
12e41d03 1510 case PIM_NODE:
718e3744 1511 case VTY_NODE:
16f1b9ee 1512 case LINK_PARAMS_NODE:
718e3744 1513 vty_config_unlock (vty);
1514 vty->node = ENABLE_NODE;
1515 break;
1516 default:
1517 break;
1518 }
1519 return CMD_SUCCESS;
1520}
1521
1522/* Show version. */
1523DEFUN (show_version,
1524 show_version_cmd,
1525 "show version",
1526 SHOW_STR
1527 "Displays zebra version\n")
1528{
b2f36157
DL
1529 vty_out (vty, "%s %s (%s).%s", FRR_FULL_NAME, FRR_VERSION,
1530 host.name ? host.name : "",
12f6ea23 1531 VTY_NEWLINE);
b2f36157 1532 vty_out (vty, "%s%s%s", FRR_COPYRIGHT, GIT_INFO, VTY_NEWLINE);
80db5ac1 1533 vty_out (vty, "configured with:%s %s%s", VTY_NEWLINE,
b2f36157 1534 FRR_CONFIG_ARGS, VTY_NEWLINE);
718e3744 1535
1536 return CMD_SUCCESS;
1537}
1538
1539/* Help display function for all node. */
1540DEFUN (config_help,
1541 config_help_cmd,
1542 "help",
1543 "Description of the interactive help system\n")
1544{
d0bfb22c
QY
1545 vty_out (vty,
1546 "Quagga VTY provides advanced help feature. When you need help,%s\
718e3744 1547anytime at the command line please press '?'.%s\
1548%s\
1549If nothing matches, the help list will be empty and you must backup%s\
1550 until entering a '?' shows the available options.%s\
1551Two styles of help are provided:%s\
15521. Full help is available when you are ready to enter a%s\
1553command argument (e.g. 'show ?') and describes each possible%s\
1554argument.%s\
15552. Partial help is provided when an abbreviated argument is entered%s\
1556 and you want to know what arguments match the input%s\
1557 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
d0bfb22c
QY
1558 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
1559 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
718e3744 1560 return CMD_SUCCESS;
1561}
1562
a2454870
QY
1563static void
1564permute (struct graph_node *start, struct vty *vty)
1565{
1566 static struct list *position = NULL;
1567 if (!position) position = list_new ();
1568
1569 // recursive dfs
1570 listnode_add (position, start);
1571 for (unsigned int i = 0; i < vector_active (start->to); i++)
1572 {
1573 struct graph_node *gn = vector_slot (start->to, i);
1574 struct cmd_token *tok = gn->data;
7a4662b4
QY
1575 if (tok->attr == CMD_ATTR_HIDDEN ||
1576 tok->attr == CMD_ATTR_DEPRECATED)
1577 continue;
1578 else if (tok->type == END_TKN || gn == start)
a2454870
QY
1579 {
1580 struct graph_node *gnn;
1581 struct listnode *ln;
1582 vty_out (vty, " ");
1583 for (ALL_LIST_ELEMENTS_RO (position,ln,gnn))
1584 {
1585 struct cmd_token *tt = gnn->data;
0bf5b1cb 1586 if (tt->type < SPECIAL_TKN)
a2454870
QY
1587 vty_out (vty, " %s", tt->text);
1588 }
1589 if (gn == start)
1590 vty_out (vty, "...");
1591 vty_out (vty, VTY_NEWLINE);
1592 }
1593 else
1594 permute (gn, vty);
1595 }
1596 list_delete_node (position, listtail(position));
1597}
1598
0b84f294
DL
1599int
1600cmd_list_cmds (struct vty *vty, int do_permute)
718e3744 1601{
a2454870
QY
1602 struct cmd_node *node = vector_slot (cmdvec, vty->node);
1603
0b84f294 1604 if (do_permute)
a2454870
QY
1605 permute (vector_slot (node->cmdgraph->nodes, 0), vty);
1606 else
1607 {
1608 /* loop over all commands at this node */
1609 struct cmd_element *element = NULL;
1610 for (unsigned int i = 0; i < vector_active(node->cmd_vector); i++)
1611 if ((element = vector_slot (node->cmd_vector, i)) &&
1612 element->attr != CMD_ATTR_DEPRECATED &&
1613 element->attr != CMD_ATTR_HIDDEN)
1614 vty_out (vty, " %s%s", element->string, VTY_NEWLINE);
1615 }
718e3744 1616 return CMD_SUCCESS;
1617}
1618
0b84f294
DL
1619/* Help display function for all node. */
1620DEFUN (config_list,
1621 config_list_cmd,
1622 "list [permutations]",
1623 "Print command list\n"
1624 "Print all possible command permutations\n")
1625{
1626 return cmd_list_cmds (vty, argc == 2);
1627}
1628
a2454870
QY
1629DEFUN (show_commandtree,
1630 show_commandtree_cmd,
1631 "show commandtree [permutations]",
1632 SHOW_STR
5a1945e4
DS
1633 "Show command tree\n"
1634 "Permutations that we are interested in\n")
a2454870 1635{
0b84f294 1636 return cmd_list_cmds (vty, argc == 3);
a2454870
QY
1637}
1638
718e3744 1639/* Write current configuration into file. */
d862bffb 1640
d0bfb22c
QY
1641DEFUN (config_write,
1642 config_write_cmd,
1643 "write [<file|memory|terminal>]",
718e3744 1644 "Write running configuration to memory, network, or terminal\n"
d0bfb22c
QY
1645 "Write to configuration file\n"
1646 "Write configuration currently in memory\n"
1647 "Write configuration to terminal\n")
718e3744 1648{
c349116d 1649 int idx_type = 1;
8c328f11 1650 unsigned int i;
056cfe49 1651 int fd, dirfd;
718e3744 1652 struct cmd_node *node;
056cfe49 1653 char *config_file, *slash;
718e3744 1654 char *config_file_tmp = NULL;
1655 char *config_file_sav = NULL;
05865c90 1656 int ret = CMD_WARNING;
718e3744 1657 struct vty *file_vty;
e4421165 1658 struct stat conf_stat;
718e3744 1659
74d57f5a 1660 // if command was 'write terminal' or 'show running-config'
d862bffb 1661 if (argc == 2 && (!strcmp(argv[idx_type]->text, "terminal") ||
d862bffb 1662 !strcmp(argv[0]->text, "show")))
d0bfb22c
QY
1663 {
1664 if (vty->type == VTY_SHELL_SERV)
1665 {
1666 for (i = 0; i < vector_active (cmdvec); i++)
1667 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
1668 {
1669 if ((*node->func) (vty))
1670 vty_out (vty, "!%s", VTY_NEWLINE);
1671 }
1672 }
1673 else
1674 {
1675 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
1676 VTY_NEWLINE);
1677 vty_out (vty, "!%s", VTY_NEWLINE);
1678
1679 for (i = 0; i < vector_active (cmdvec); i++)
1680 if ((node = vector_slot (cmdvec, i)) && node->func)
1681 {
1682 if ((*node->func) (vty))
1683 vty_out (vty, "!%s", VTY_NEWLINE);
1684 }
1685 vty_out (vty, "end%s",VTY_NEWLINE);
1686 }
1687 return CMD_SUCCESS;
1688 }
1689
87f44e2f
DL
1690 if (host.noconfig)
1691 return CMD_SUCCESS;
1692
718e3744 1693 /* Check and see if we are operating under vtysh configuration */
1694 if (host.config == NULL)
1695 {
1696 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
d0bfb22c 1697 VTY_NEWLINE);
718e3744 1698 return CMD_WARNING;
1699 }
1700
1701 /* Get filename. */
1702 config_file = host.config;
d0bfb22c 1703
056cfe49
DL
1704#ifndef O_DIRECTORY
1705#define O_DIRECTORY 0
1706#endif
1707 slash = strrchr (config_file, '/');
1708 if (slash)
1709 {
1710 char *config_dir = XSTRDUP (MTYPE_TMP, config_file);
1711 config_dir[slash - config_file] = '\0';
1712 dirfd = open(config_dir, O_DIRECTORY | O_RDONLY);
1713 XFREE (MTYPE_TMP, config_dir);
1714 }
1715 else
1716 dirfd = open(".", O_DIRECTORY | O_RDONLY);
1717 /* if dirfd is invalid, directory sync fails, but we're still OK */
1718
05865c90 1719 config_file_sav =
1720 XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
718e3744 1721 strcpy (config_file_sav, config_file);
1722 strcat (config_file_sav, CONF_BACKUP_EXT);
1723
1724
05865c90 1725 config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
718e3744 1726 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
d0bfb22c 1727
718e3744 1728 /* Open file to configuration write. */
1729 fd = mkstemp (config_file_tmp);
1730 if (fd < 0)
1731 {
1732 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
d0bfb22c 1733 VTY_NEWLINE);
05865c90 1734 goto finished;
718e3744 1735 }
056cfe49
DL
1736 if (fchmod (fd, CONFIGFILE_MASK) != 0)
1737 {
1738 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
1739 config_file_tmp, safe_strerror(errno), errno, VTY_NEWLINE);
1740 goto finished;
1741 }
d0bfb22c 1742
718e3744 1743 /* Make vty for configuration file. */
1744 file_vty = vty_new ();
c5e69a02 1745 file_vty->wfd = fd;
718e3744 1746 file_vty->type = VTY_FILE;
1747
1748 /* Config file header print. */
1749 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
1750 vty_time_print (file_vty, 1);
1751 vty_out (file_vty, "!\n");
1752
55468c86 1753 for (i = 0; i < vector_active (cmdvec); i++)
718e3744 1754 if ((node = vector_slot (cmdvec, i)) && node->func)
1755 {
d0bfb22c
QY
1756 if ((*node->func) (file_vty))
1757 vty_out (file_vty, "!\n");
718e3744 1758 }
1759 vty_close (file_vty);
1760
e4421165 1761 if (stat(config_file, &conf_stat) >= 0)
718e3744 1762 {
e4421165 1763 if (unlink (config_file_sav) != 0)
d0bfb22c
QY
1764 if (errno != ENOENT)
1765 {
1766 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
1767 VTY_NEWLINE);
1768 goto finished;
1769 }
e4421165 1770 if (link (config_file, config_file_sav) != 0)
d0bfb22c
QY
1771 {
1772 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
1773 VTY_NEWLINE);
1774 goto finished;
1775 }
14878121
DL
1776 if (dirfd >= 0)
1777 fsync (dirfd);
718e3744 1778 }
056cfe49 1779 if (rename (config_file_tmp, config_file) != 0)
718e3744 1780 {
1781 vty_out (vty, "Can't save configuration file %s.%s", config_file,
d0bfb22c 1782 VTY_NEWLINE);
05865c90 1783 goto finished;
718e3744 1784 }
14878121
DL
1785 if (dirfd >= 0)
1786 fsync (dirfd);
aa593d5e 1787
718e3744 1788 vty_out (vty, "Configuration saved to %s%s", config_file,
d0bfb22c 1789 VTY_NEWLINE);
05865c90 1790 ret = CMD_SUCCESS;
1791
1792finished:
056cfe49
DL
1793 if (ret != CMD_SUCCESS)
1794 unlink (config_file_tmp);
14878121
DL
1795 if (dirfd >= 0)
1796 close (dirfd);
05865c90 1797 XFREE (MTYPE_TMP, config_file_tmp);
1798 XFREE (MTYPE_TMP, config_file_sav);
1799 return ret;
718e3744 1800}
1801
d862bffb
QY
1802/* ALIAS_FIXME for 'write <terminal|memory>' */
1803DEFUN (show_running_config,
1804 show_running_config_cmd,
1805 "show running-config",
1806 SHOW_STR
1807 "running configuration (same as write terminal/memory)\n")
1808{
1809 return config_write (self, vty, argc, argv);
1810}
718e3744 1811
d862bffb
QY
1812/* ALIAS_FIXME for 'write file' */
1813DEFUN (copy_runningconf_startupconf,
1814 copy_runningconf_startupconf_cmd,
1815 "copy running-config startup-config",
1816 "Copy configuration\n"
1817 "Copy running config to... \n"
1818 "Copy running config to startup config (same as write file)\n")
1819{
1820 return config_write (self, vty, argc, argv);
1821}
1822/** -- **/
718e3744 1823
1824/* Write startup configuration into the terminal. */
1825DEFUN (show_startup_config,
1826 show_startup_config_cmd,
1827 "show startup-config",
1828 SHOW_STR
d0bfb22c 1829 "Contents of startup configuration\n")
718e3744 1830{
1831 char buf[BUFSIZ];
1832 FILE *confp;
1833
87f44e2f
DL
1834 if (host.noconfig)
1835 return CMD_SUCCESS;
1836 if (host.config == NULL)
1837 return CMD_WARNING;
1838
718e3744 1839 confp = fopen (host.config, "r");
1840 if (confp == NULL)
1841 {
1db63918 1842 vty_out (vty, "Can't open configuration file [%s] due to '%s'%s",
d0bfb22c 1843 host.config, safe_strerror(errno), VTY_NEWLINE);
718e3744 1844 return CMD_WARNING;
1845 }
1846
1847 while (fgets (buf, BUFSIZ, confp))
1848 {
1849 char *cp = buf;
1850
1851 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
d0bfb22c 1852 cp++;
718e3744 1853 *cp = '\0';
1854
1855 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
1856 }
1857
1858 fclose (confp);
1859
1860 return CMD_SUCCESS;
1861}
1862
bff9c3e9
DL
1863int
1864cmd_hostname_set (const char *hostname)
1865{
1866 XFREE (MTYPE_HOST, host.name);
1867 host.name = hostname ? XSTRDUP (MTYPE_HOST, hostname) : NULL;
1868 return CMD_SUCCESS;
1869}
1870
718e3744 1871/* Hostname configuration */
d0bfb22c 1872DEFUN (config_hostname,
718e3744 1873 hostname_cmd,
1874 "hostname WORD",
1875 "Set system's network name\n"
1876 "This system's network name\n")
1877{
d0bfb22c
QY
1878 struct cmd_token *word = argv[1];
1879
e4123a9b 1880 if (!isalpha((int) word->arg[0]))
718e3744 1881 {
1882 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
1883 return CMD_WARNING;
1884 }
1885
bff9c3e9 1886 return cmd_hostname_set (word->arg);
718e3744 1887}
1888
d0bfb22c 1889DEFUN (config_no_hostname,
718e3744 1890 no_hostname_cmd,
1891 "no hostname [HOSTNAME]",
1892 NO_STR
1893 "Reset system's network name\n"
1894 "Host name of this router\n")
1895{
bff9c3e9 1896 return cmd_hostname_set (NULL);
718e3744 1897}
1898
1899/* VTY interface password set. */
f412b39a
DW
1900DEFUN (config_password,
1901 password_cmd,
98463e0a 1902 "password [(8-8)] WORD",
718e3744 1903 "Assign the terminal connection password\n"
1904 "Specifies a HIDDEN password will follow\n"
d0bfb22c 1905 "The password string\n")
718e3744 1906{
c349116d
DW
1907 int idx_8 = 1;
1908 int idx_word = 2;
d0bfb22c
QY
1909 if (argc == 3) // '8' was specified
1910 {
1911 if (host.password)
1912 XFREE (MTYPE_HOST, host.password);
1913 host.password = NULL;
1914 if (host.password_encrypt)
1915 XFREE (MTYPE_HOST, host.password_encrypt);
c349116d 1916 host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[idx_word]->arg);
d0bfb22c
QY
1917 return CMD_SUCCESS;
1918 }
718e3744 1919
c349116d 1920 if (!isalnum (argv[idx_8]->arg[0]))
718e3744 1921 {
d0bfb22c
QY
1922 vty_out (vty,
1923 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
718e3744 1924 return CMD_WARNING;
1925 }
1926
1927 if (host.password)
05865c90 1928 XFREE (MTYPE_HOST, host.password);
718e3744 1929 host.password = NULL;
1930
1931 if (host.encrypt)
1932 {
1933 if (host.password_encrypt)
d0bfb22c 1934 XFREE (MTYPE_HOST, host.password_encrypt);
c349116d 1935 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[idx_8]->arg));
718e3744 1936 }
1937 else
c349116d 1938 host.password = XSTRDUP (MTYPE_HOST, argv[idx_8]->arg);
718e3744 1939
1940 return CMD_SUCCESS;
1941}
1942
718e3744 1943/* VTY enable password set. */
f412b39a
DW
1944DEFUN (config_enable_password,
1945 enable_password_cmd,
98463e0a 1946 "enable password [(8-8)] WORD",
718e3744 1947 "Modify enable password parameters\n"
1948 "Assign the privileged level password\n"
1949 "Specifies a HIDDEN password will follow\n"
718e3744 1950 "The HIDDEN 'enable' password string\n")
1951{
c349116d
DW
1952 int idx_8 = 2;
1953 int idx_word = 3;
58749582 1954
718e3744 1955 /* Crypt type is specified. */
d0bfb22c 1956 if (argc == 4)
718e3744 1957 {
c349116d 1958 if (argv[idx_8]->arg[0] == '8')
d0bfb22c
QY
1959 {
1960 if (host.enable)
1961 XFREE (MTYPE_HOST, host.enable);
1962 host.enable = NULL;
1963
1964 if (host.enable_encrypt)
1965 XFREE (MTYPE_HOST, host.enable_encrypt);
c349116d 1966 host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[idx_word]->arg);
d0bfb22c
QY
1967
1968 return CMD_SUCCESS;
1969 }
718e3744 1970 else
d0bfb22c
QY
1971 {
1972 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
1973 return CMD_WARNING;
1974 }
718e3744 1975 }
1976
c349116d 1977 if (!isalnum (argv[idx_8]->arg[0]))
718e3744 1978 {
d0bfb22c
QY
1979 vty_out (vty,
1980 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
718e3744 1981 return CMD_WARNING;
1982 }
1983
1984 if (host.enable)
05865c90 1985 XFREE (MTYPE_HOST, host.enable);
718e3744 1986 host.enable = NULL;
1987
1988 /* Plain password input. */
1989 if (host.encrypt)
1990 {
1991 if (host.enable_encrypt)
d0bfb22c 1992 XFREE (MTYPE_HOST, host.enable_encrypt);
c349116d 1993 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[idx_8]->arg));
718e3744 1994 }
1995 else
c349116d 1996 host.enable = XSTRDUP (MTYPE_HOST, argv[idx_8]->arg);
718e3744 1997
1998 return CMD_SUCCESS;
1999}
2000
718e3744 2001/* VTY enable password delete. */
f412b39a
DW
2002DEFUN (no_config_enable_password,
2003 no_enable_password_cmd,
718e3744 2004 "no enable password",
2005 NO_STR
2006 "Modify enable password parameters\n"
2007 "Assign the privileged level password\n")
2008{
2009 if (host.enable)
05865c90 2010 XFREE (MTYPE_HOST, host.enable);
718e3744 2011 host.enable = NULL;
2012
2013 if (host.enable_encrypt)
05865c90 2014 XFREE (MTYPE_HOST, host.enable_encrypt);
718e3744 2015 host.enable_encrypt = NULL;
2016
2017 return CMD_SUCCESS;
2018}
d0bfb22c 2019
718e3744 2020DEFUN (service_password_encrypt,
2021 service_password_encrypt_cmd,
2022 "service password-encryption",
2023 "Set up miscellaneous service\n"
2024 "Enable encrypted passwords\n")
2025{
2026 if (host.encrypt)
2027 return CMD_SUCCESS;
2028
2029 host.encrypt = 1;
2030
2031 if (host.password)
2032 {
2033 if (host.password_encrypt)
d0bfb22c 2034 XFREE (MTYPE_HOST, host.password_encrypt);
05865c90 2035 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
718e3744 2036 }
2037 if (host.enable)
2038 {
2039 if (host.enable_encrypt)
d0bfb22c 2040 XFREE (MTYPE_HOST, host.enable_encrypt);
05865c90 2041 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
718e3744 2042 }
2043
2044 return CMD_SUCCESS;
2045}
2046
2047DEFUN (no_service_password_encrypt,
2048 no_service_password_encrypt_cmd,
2049 "no service password-encryption",
2050 NO_STR
2051 "Set up miscellaneous service\n"
2052 "Enable encrypted passwords\n")
2053{
2054 if (! host.encrypt)
2055 return CMD_SUCCESS;
2056
2057 host.encrypt = 0;
2058
2059 if (host.password_encrypt)
05865c90 2060 XFREE (MTYPE_HOST, host.password_encrypt);
718e3744 2061 host.password_encrypt = NULL;
2062
2063 if (host.enable_encrypt)
05865c90 2064 XFREE (MTYPE_HOST, host.enable_encrypt);
718e3744 2065 host.enable_encrypt = NULL;
2066
2067 return CMD_SUCCESS;
2068}
2069
f412b39a
DW
2070DEFUN (config_terminal_length,
2071 config_terminal_length_cmd,
d0bfb22c 2072 "terminal length (0-512)",
718e3744 2073 "Set terminal line parameters\n"
2074 "Set number of lines on a screen\n"
2075 "Number of lines on screen (0 for no pausing)\n")
2076{
c349116d 2077 int idx_number = 2;
718e3744 2078 int lines;
2079 char *endptr = NULL;
2080
c349116d 2081 lines = strtol (argv[idx_number]->arg, &endptr, 10);
718e3744 2082 if (lines < 0 || lines > 512 || *endptr != '\0')
2083 {
2084 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2085 return CMD_WARNING;
2086 }
2087 vty->lines = lines;
2088
2089 return CMD_SUCCESS;
2090}
2091
f412b39a
DW
2092DEFUN (config_terminal_no_length,
2093 config_terminal_no_length_cmd,
718e3744 2094 "terminal no length",
2095 "Set terminal line parameters\n"
2096 NO_STR
2097 "Set number of lines on a screen\n")
2098{
2099 vty->lines = -1;
2100 return CMD_SUCCESS;
2101}
2102
f412b39a
DW
2103DEFUN (service_terminal_length,
2104 service_terminal_length_cmd,
d0bfb22c 2105 "service terminal-length (0-512)",
718e3744 2106 "Set up miscellaneous service\n"
2107 "System wide terminal length configuration\n"
2108 "Number of lines of VTY (0 means no line control)\n")
2109{
c349116d 2110 int idx_number = 2;
718e3744 2111 int lines;
2112 char *endptr = NULL;
2113
c349116d 2114 lines = strtol (argv[idx_number]->arg, &endptr, 10);
718e3744 2115 if (lines < 0 || lines > 512 || *endptr != '\0')
2116 {
2117 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2118 return CMD_WARNING;
2119 }
2120 host.lines = lines;
2121
2122 return CMD_SUCCESS;
2123}
2124
f412b39a
DW
2125DEFUN (no_service_terminal_length,
2126 no_service_terminal_length_cmd,
d0bfb22c 2127 "no service terminal-length [(0-512)]",
718e3744 2128 NO_STR
2129 "Set up miscellaneous service\n"
2130 "System wide terminal length configuration\n"
2131 "Number of lines of VTY (0 means no line control)\n")
2132{
2133 host.lines = -1;
2134 return CMD_SUCCESS;
2135}
2136
2885f72d 2137DEFUN_HIDDEN (do_echo,
d0bfb22c
QY
2138 echo_cmd,
2139 "echo MESSAGE...",
2140 "Echo a message back to the vty\n"
2141 "The message to echo\n")
2885f72d 2142{
2143 char *message;
2144
58749582 2145 vty_out (vty, "%s%s", ((message = argv_concat (argv, argc, 1)) ? message : ""),
d0bfb22c 2146 VTY_NEWLINE);
f6834d4c 2147 if (message)
2148 XFREE(MTYPE_TMP, message);
2885f72d 2149 return CMD_SUCCESS;
2150}
2151
274a4a44 2152DEFUN (config_logmsg,
2153 config_logmsg_cmd,
199d90a1 2154 "logmsg <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging> MESSAGE...",
274a4a44 2155 "Send a message to enabled logging destinations\n"
2156 LOG_LEVEL_DESC
2157 "The message to send\n")
2158{
c349116d 2159 int idx_log_level = 1;
58749582 2160 int idx_message = 2;
274a4a44 2161 int level;
2162 char *message;
2163
c349116d 2164 if ((level = level_match(argv[idx_log_level]->arg)) == ZLOG_DISABLED)
274a4a44 2165 return CMD_ERR_NO_MATCH;
2166
bb85d700 2167 zlog(level, "%s", ((message = argv_concat(argv, argc, idx_message)) ? message : ""));
f6834d4c 2168 if (message)
2169 XFREE(MTYPE_TMP, message);
65efcfce 2170
274a4a44 2171 return CMD_SUCCESS;
2172}
2173
2174DEFUN (show_logging,
2175 show_logging_cmd,
2176 "show logging",
2177 SHOW_STR
2178 "Show current logging configuration\n")
2179{
2180 struct zlog *zl = zlog_default;
2181
2182 vty_out (vty, "Syslog logging: ");
2183 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
2184 vty_out (vty, "disabled");
2185 else
2186 vty_out (vty, "level %s, facility %s, ident %s",
d0bfb22c
QY
2187 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
2188 facility_name(zl->facility), zl->ident);
274a4a44 2189 vty_out (vty, "%s", VTY_NEWLINE);
2190
2191 vty_out (vty, "Stdout logging: ");
2192 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
2193 vty_out (vty, "disabled");
2194 else
2195 vty_out (vty, "level %s",
d0bfb22c 2196 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
274a4a44 2197 vty_out (vty, "%s", VTY_NEWLINE);
2198
2199 vty_out (vty, "Monitor logging: ");
2200 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
2201 vty_out (vty, "disabled");
2202 else
2203 vty_out (vty, "level %s",
d0bfb22c 2204 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
274a4a44 2205 vty_out (vty, "%s", VTY_NEWLINE);
2206
2207 vty_out (vty, "File logging: ");
2208 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
2209 !zl->fp)
2210 vty_out (vty, "disabled");
2211 else
2212 vty_out (vty, "level %s, filename %s",
d0bfb22c
QY
2213 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
2214 zl->filename);
274a4a44 2215 vty_out (vty, "%s", VTY_NEWLINE);
2216
2217 vty_out (vty, "Protocol name: %s%s",
bf1013e6 2218 zl->protoname, VTY_NEWLINE);
274a4a44 2219 vty_out (vty, "Record priority: %s%s",
d0bfb22c 2220 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
1ed72e0b 2221 vty_out (vty, "Timestamp precision: %d%s",
d0bfb22c 2222 zl->timestamp_precision, VTY_NEWLINE);
274a4a44 2223
2224 return CMD_SUCCESS;
2225}
2226
718e3744 2227DEFUN (config_log_stdout,
2228 config_log_stdout_cmd,
6de69f83 2229 "log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
274a4a44 2230 "Logging control\n"
2231 "Set stdout logging level\n"
2232 LOG_LEVEL_DESC)
2233{
c349116d 2234 int idx_log_level = 2;
58749582
DW
2235
2236 if (argc == idx_log_level)
d0bfb22c 2237 {
dd8376fe 2238 zlog_set_level (ZLOG_DEST_STDOUT, zlog_default->default_lvl);
d0bfb22c
QY
2239 return CMD_SUCCESS;
2240 }
274a4a44 2241 int level;
2242
c349116d 2243 if ((level = level_match(argv[idx_log_level]->arg)) == ZLOG_DISABLED)
274a4a44 2244 return CMD_ERR_NO_MATCH;
dd8376fe 2245 zlog_set_level (ZLOG_DEST_STDOUT, level);
718e3744 2246 return CMD_SUCCESS;
2247}
2248
2249DEFUN (no_config_log_stdout,
2250 no_config_log_stdout_cmd,
6de69f83 2251 "no log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
718e3744 2252 NO_STR
2253 "Logging control\n"
274a4a44 2254 "Cancel logging to stdout\n"
d0bfb22c 2255 LOG_LEVEL_DESC)
718e3744 2256{
dd8376fe 2257 zlog_set_level (ZLOG_DEST_STDOUT, ZLOG_DISABLED);
718e3744 2258 return CMD_SUCCESS;
2259}
2260
274a4a44 2261DEFUN (config_log_monitor,
2262 config_log_monitor_cmd,
6de69f83 2263 "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
274a4a44 2264 "Logging control\n"
2265 "Set terminal line (monitor) logging level\n"
2266 LOG_LEVEL_DESC)
2267{
c349116d 2268 int idx_log_level = 2;
58749582
DW
2269
2270 if (argc == idx_log_level)
d0bfb22c 2271 {
dd8376fe 2272 zlog_set_level (ZLOG_DEST_MONITOR, zlog_default->default_lvl);
d0bfb22c
QY
2273 return CMD_SUCCESS;
2274 }
274a4a44 2275 int level;
2276
c349116d 2277 if ((level = level_match(argv[idx_log_level]->arg)) == ZLOG_DISABLED)
274a4a44 2278 return CMD_ERR_NO_MATCH;
dd8376fe 2279 zlog_set_level (ZLOG_DEST_MONITOR, level);
274a4a44 2280 return CMD_SUCCESS;
2281}
2282
2283DEFUN (no_config_log_monitor,
2284 no_config_log_monitor_cmd,
6de69f83 2285 "no log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
274a4a44 2286 NO_STR
2287 "Logging control\n"
2288 "Disable terminal line (monitor) logging\n"
d0bfb22c 2289 LOG_LEVEL_DESC)
274a4a44 2290{
dd8376fe 2291 zlog_set_level (ZLOG_DEST_MONITOR, ZLOG_DISABLED);
274a4a44 2292 return CMD_SUCCESS;
2293}
2294
2295static int
2296set_log_file(struct vty *vty, const char *fname, int loglevel)
718e3744 2297{
2298 int ret;
9035efaa 2299 char *p = NULL;
2300 const char *fullpath;
d0bfb22c 2301
718e3744 2302 /* Path detection. */
274a4a44 2303 if (! IS_DIRECTORY_SEP (*fname))
718e3744 2304 {
9035efaa 2305 char cwd[MAXPATHLEN+1];
2306 cwd[MAXPATHLEN] = '\0';
d0bfb22c 2307
9035efaa 2308 if (getcwd (cwd, MAXPATHLEN) == NULL)
2309 {
2310 zlog_err ("config_log_file: Unable to alloc mem!");
2311 return CMD_WARNING;
2312 }
d0bfb22c 2313
274a4a44 2314 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
9035efaa 2315 == NULL)
2316 {
2317 zlog_err ("config_log_file: Unable to alloc mem!");
2318 return CMD_WARNING;
2319 }
274a4a44 2320 sprintf (p, "%s/%s", cwd, fname);
9035efaa 2321 fullpath = p;
718e3744 2322 }
2323 else
274a4a44 2324 fullpath = fname;
718e3744 2325
dd8376fe 2326 ret = zlog_set_file (fullpath, loglevel);
718e3744 2327
9035efaa 2328 if (p)
2329 XFREE (MTYPE_TMP, p);
2330
718e3744 2331 if (!ret)
2332 {
274a4a44 2333 vty_out (vty, "can't open logfile %s\n", fname);
718e3744 2334 return CMD_WARNING;
2335 }
2336
2337 if (host.logfile)
05865c90 2338 XFREE (MTYPE_HOST, host.logfile);
718e3744 2339
05865c90 2340 host.logfile = XSTRDUP (MTYPE_HOST, fname);
718e3744 2341
c05795b1
SK
2342#if defined(HAVE_CUMULUS)
2343 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
2344 zlog_default->maxlvl[ZLOG_DEST_SYSLOG] = ZLOG_DISABLED;
2345#endif
718e3744 2346 return CMD_SUCCESS;
2347}
2348
274a4a44 2349DEFUN (config_log_file,
2350 config_log_file_cmd,
6de69f83 2351 "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
274a4a44 2352 "Logging control\n"
2353 "Logging to file\n"
2354 "Logging filename\n"
2355 LOG_LEVEL_DESC)
2356{
c349116d
DW
2357 int idx_filename = 2;
2358 int idx_log_levels = 3;
d0bfb22c
QY
2359 if (argc == 4)
2360 {
2361 int level;
c349116d 2362 if ((level = level_match(argv[idx_log_levels]->arg)) == ZLOG_DISABLED)
d0bfb22c 2363 return CMD_ERR_NO_MATCH;
c349116d 2364 return set_log_file(vty, argv[idx_filename]->arg, level);
d0bfb22c
QY
2365 }
2366 else
c349116d 2367 return set_log_file(vty, argv[idx_filename]->arg, zlog_default->default_lvl);
274a4a44 2368}
2369
718e3744 2370DEFUN (no_config_log_file,
2371 no_config_log_file_cmd,
d0bfb22c 2372 "no log file [FILENAME [LEVEL]]",
718e3744 2373 NO_STR
2374 "Logging control\n"
2375 "Cancel logging to file\n"
d0bfb22c
QY
2376 "Logging file name\n"
2377 "Logging file name\n"
2378 "Logging level\n")
718e3744 2379{
dd8376fe 2380 zlog_reset_file ();
718e3744 2381
2382 if (host.logfile)
05865c90 2383 XFREE (MTYPE_HOST, host.logfile);
718e3744 2384
2385 host.logfile = NULL;
2386
2387 return CMD_SUCCESS;
2388}
2389
2390DEFUN (config_log_syslog,
2391 config_log_syslog_cmd,
6de69f83 2392 "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
12ab19f1 2393 "Logging control\n"
274a4a44 2394 "Set syslog logging level\n"
2395 LOG_LEVEL_DESC)
2396{
c349116d 2397 int idx_log_levels = 2;
d0bfb22c
QY
2398 if (argc == 3)
2399 {
2400 int level;
c349116d 2401 if ((level = level_match (argv[idx_log_levels]->arg)) == ZLOG_DISABLED)
d0bfb22c 2402 return CMD_ERR_NO_MATCH;
dd8376fe 2403 zlog_set_level (ZLOG_DEST_SYSLOG, level);
d0bfb22c
QY
2404 return CMD_SUCCESS;
2405 }
2406 else
2407 {
dd8376fe 2408 zlog_set_level (ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
d0bfb22c
QY
2409 return CMD_SUCCESS;
2410 }
274a4a44 2411}
2412
718e3744 2413DEFUN (no_config_log_syslog,
2414 no_config_log_syslog_cmd,
6de69f83 2415 "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 2416 NO_STR
2417 "Logging control\n"
274a4a44 2418 "Cancel logging to syslog\n"
d0bfb22c
QY
2419 LOG_FACILITY_DESC
2420 LOG_LEVEL_DESC)
718e3744 2421{
dd8376fe 2422 zlog_set_level (ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
718e3744 2423 return CMD_SUCCESS;
2424}
2425
274a4a44 2426DEFUN (config_log_facility,
2427 config_log_facility_cmd,
9ccf14f7 2428 "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>",
718e3744 2429 "Logging control\n"
274a4a44 2430 "Facility parameter for syslog messages\n"
2431 LOG_FACILITY_DESC)
718e3744 2432{
c349116d
DW
2433 int idx_target = 2;
2434 int facility = facility_match(argv[idx_target]->arg);
274a4a44 2435
274a4a44 2436 zlog_default->facility = facility;
2437 return CMD_SUCCESS;
718e3744 2438}
2439
274a4a44 2440DEFUN (no_config_log_facility,
2441 no_config_log_facility_cmd,
9ccf14f7 2442 "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
718e3744 2443 NO_STR
2444 "Logging control\n"
274a4a44 2445 "Reset syslog facility to default (daemon)\n"
d0bfb22c 2446 LOG_FACILITY_DESC)
274a4a44 2447{
2448 zlog_default->facility = LOG_DAEMON;
2449 return CMD_SUCCESS;
2450}
2451
2452DEFUN_DEPRECATED (config_log_trap,
d0bfb22c 2453 config_log_trap_cmd,
199d90a1 2454 "log trap <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
d0bfb22c
QY
2455 "Logging control\n"
2456 "(Deprecated) Set logging level and default for all destinations\n"
2457 LOG_LEVEL_DESC)
274a4a44 2458{
2459 int new_level ;
2460 int i;
d0bfb22c
QY
2461
2462 if ((new_level = level_match(argv[2]->arg)) == ZLOG_DISABLED)
274a4a44 2463 return CMD_ERR_NO_MATCH;
2464
2465 zlog_default->default_lvl = new_level;
2466 for (i = 0; i < ZLOG_NUM_DESTS; i++)
2467 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
2468 zlog_default->maxlvl[i] = new_level;
2469 return CMD_SUCCESS;
2470}
2471
2472DEFUN_DEPRECATED (no_config_log_trap,
d0bfb22c 2473 no_config_log_trap_cmd,
199d90a1 2474 "no log trap [emergencies|alerts|critical|errors|warnings|notifications|informational|debugging]",
d0bfb22c
QY
2475 NO_STR
2476 "Logging control\n"
2477 "Permit all logging information\n"
2478 LOG_LEVEL_DESC)
718e3744 2479{
274a4a44 2480 zlog_default->default_lvl = LOG_DEBUG;
718e3744 2481 return CMD_SUCCESS;
2482}
2483
2484DEFUN (config_log_record_priority,
2485 config_log_record_priority_cmd,
2486 "log record-priority",
2487 "Logging control\n"
2488 "Log the priority of the message within the message\n")
2489{
2490 zlog_default->record_priority = 1 ;
2491 return CMD_SUCCESS;
2492}
2493
2494DEFUN (no_config_log_record_priority,
2495 no_config_log_record_priority_cmd,
2496 "no log record-priority",
2497 NO_STR
2498 "Logging control\n"
2499 "Do not log the priority of the message within the message\n")
2500{
2501 zlog_default->record_priority = 0 ;
2502 return CMD_SUCCESS;
2503}
2504
1ed72e0b
AS
2505DEFUN (config_log_timestamp_precision,
2506 config_log_timestamp_precision_cmd,
6147e2c6 2507 "log timestamp precision (0-6)",
1ed72e0b
AS
2508 "Logging control\n"
2509 "Timestamp configuration\n"
2510 "Set the timestamp precision\n"
2511 "Number of subsecond digits\n")
2512{
c349116d 2513 int idx_number = 3;
1ed72e0b 2514 VTY_GET_INTEGER_RANGE("Timestamp Precision",
c349116d 2515 zlog_default->timestamp_precision, argv[idx_number]->arg, 0, 6);
1ed72e0b
AS
2516 return CMD_SUCCESS;
2517}
2518
2519DEFUN (no_config_log_timestamp_precision,
2520 no_config_log_timestamp_precision_cmd,
2521 "no log timestamp precision",
2522 NO_STR
2523 "Logging control\n"
2524 "Timestamp configuration\n"
2525 "Reset the timestamp precision to the default value of 0\n")
2526{
2527 zlog_default->timestamp_precision = 0 ;
2528 return CMD_SUCCESS;
2529}
2530
7cfc61d3
DS
2531int
2532cmd_banner_motd_file (const char *file)
2533{
1ee08155
DS
2534 int success = CMD_SUCCESS;
2535 char p[PATH_MAX];
2536 char *rpath;
2537 char *in;
7cfc61d3 2538
1ee08155
DS
2539 rpath = realpath (file, p);
2540 if (!rpath)
2541 return CMD_ERR_NO_FILE;
2542 in = strstr (rpath, SYSCONFDIR);
2543 if (in == rpath)
2544 {
2545 if (host.motdfile)
844ec28c 2546 XFREE (MTYPE_HOST, host.motdfile);
1ee08155
DS
2547 host.motdfile = XSTRDUP (MTYPE_HOST, file);
2548 }
2549 else
2550 success = CMD_WARNING;
2551
2552 return success;
7cfc61d3
DS
2553}
2554
3b0c5d9a 2555DEFUN (banner_motd_file,
2556 banner_motd_file_cmd,
4d833e55 2557 "banner motd file FILE",
3b0c5d9a 2558 "Set banner\n"
2559 "Banner for motd\n"
2560 "Banner from a file\n"
2561 "Filename\n")
2562{
c349116d
DW
2563 int idx_file = 3;
2564 const char *filename = argv[idx_file]->arg;
97e5b7c0 2565 int cmd = cmd_banner_motd_file (filename);
1ee08155
DS
2566
2567 if (cmd == CMD_ERR_NO_FILE)
97e5b7c0 2568 vty_out (vty, "%s does not exist", filename);
1ee08155 2569 else if (cmd == CMD_WARNING)
97e5b7c0 2570 vty_out (vty, "%s must be in %s", filename, SYSCONFDIR);
1ee08155
DS
2571
2572 return cmd;
3b0c5d9a 2573}
718e3744 2574
2575DEFUN (banner_motd_default,
2576 banner_motd_default_cmd,
2577 "banner motd default",
2578 "Set banner string\n"
2579 "Strings for motd\n"
2580 "Default string\n")
2581{
2582 host.motd = default_motd;
2583 return CMD_SUCCESS;
2584}
2585
2586DEFUN (no_banner_motd,
2587 no_banner_motd_cmd,
2588 "no banner motd",
2589 NO_STR
2590 "Set banner string\n"
2591 "Strings for motd\n")
2592{
2593 host.motd = NULL;
d0bfb22c 2594 if (host.motdfile)
05865c90 2595 XFREE (MTYPE_HOST, host.motdfile);
3b0c5d9a 2596 host.motdfile = NULL;
718e3744 2597 return CMD_SUCCESS;
2598}
2599
2600/* Set config filename. Called from vty.c */
2601void
c0e8c16f 2602host_config_set (const char *filename)
718e3744 2603{
228da428
CC
2604 if (host.config)
2605 XFREE (MTYPE_HOST, host.config);
05865c90 2606 host.config = XSTRDUP (MTYPE_HOST, filename);
718e3744 2607}
2608
57387fb2
CF
2609const char *
2610host_config_get (void)
2611{
2612 return host.config;
2613}
2614
718e3744 2615void
2616install_default (enum node_type node)
2617{
2618 install_element (node, &config_exit_cmd);
d862bffb 2619 install_element (node, &config_quit_cmd);
718e3744 2620 install_element (node, &config_end_cmd);
2621 install_element (node, &config_help_cmd);
2622 install_element (node, &config_list_cmd);
2623
718e3744 2624 install_element (node, &config_write_cmd);
d862bffb 2625 install_element (node, &show_running_config_cmd);
718e3744 2626}
2627
87f44e2f
DL
2628/* Initialize command interface. Install basic nodes and commands.
2629 *
2630 * terminal = 0 -- vtysh / no logging, no config control
2631 * terminal = 1 -- normal daemon
9473e340 2632 * terminal = -1 -- watchfrr / no logging, but minimal config control */
718e3744 2633void
2634cmd_init (int terminal)
2635{
1bf9f027
DL
2636 qobj_init ();
2637
718e3744 2638 /* Allocate initial top vector of commands. */
2639 cmdvec = vector_init (VECTOR_MIN_SIZE);
2640
2641 /* Default host value settings. */
2642 host.name = NULL;
2643 host.password = NULL;
2644 host.enable = NULL;
2645 host.logfile = NULL;
2646 host.config = NULL;
87f44e2f 2647 host.noconfig = (terminal < 0);
718e3744 2648 host.lines = -1;
2649 host.motd = default_motd;
3b0c5d9a 2650 host.motdfile = NULL;
718e3744 2651
2652 /* Install top nodes. */
2653 install_node (&view_node, NULL);
2654 install_node (&enable_node, NULL);
2655 install_node (&auth_node, NULL);
2656 install_node (&auth_enable_node, NULL);
2657 install_node (&config_node, config_write_host);
2658
2659 /* Each node's basic commands. */
2660 install_element (VIEW_NODE, &show_version_cmd);
2661 if (terminal)
2662 {
2663 install_element (VIEW_NODE, &config_list_cmd);
2664 install_element (VIEW_NODE, &config_exit_cmd);
d862bffb 2665 install_element (VIEW_NODE, &config_quit_cmd);
718e3744 2666 install_element (VIEW_NODE, &config_help_cmd);
2667 install_element (VIEW_NODE, &config_enable_cmd);
2668 install_element (VIEW_NODE, &config_terminal_length_cmd);
2669 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
274a4a44 2670 install_element (VIEW_NODE, &show_logging_cmd);
bcd9fa7f 2671 install_element (VIEW_NODE, &show_commandtree_cmd);
2885f72d 2672 install_element (VIEW_NODE, &echo_cmd);
718e3744 2673 }
2674
2675 if (terminal)
2676 {
6694f68c 2677 install_element (ENABLE_NODE, &config_end_cmd);
718e3744 2678 install_element (ENABLE_NODE, &config_disable_cmd);
2679 install_element (ENABLE_NODE, &config_terminal_cmd);
d862bffb 2680 install_element (ENABLE_NODE, &copy_runningconf_startupconf_cmd);
6694f68c
RW
2681 install_element (ENABLE_NODE, &config_write_cmd);
2682 install_element (ENABLE_NODE, &show_running_config_cmd);
718e3744 2683 }
2684 install_element (ENABLE_NODE, &show_startup_config_cmd);
718e3744 2685
718e3744 2686 if (terminal)
2687 {
274a4a44 2688 install_element (ENABLE_NODE, &config_logmsg_cmd);
e7168df4 2689 install_default (CONFIG_NODE);
87f44e2f 2690
0b84f294
DL
2691 thread_cmd_init ();
2692 workqueue_cmd_init ();
ea8e9d97 2693 }
d0bfb22c 2694
ea8e9d97 2695 install_element (CONFIG_NODE, &hostname_cmd);
2696 install_element (CONFIG_NODE, &no_hostname_cmd);
e7168df4 2697
87f44e2f 2698 if (terminal > 0)
ea8e9d97 2699 {
e7168df4 2700 install_element (CONFIG_NODE, &password_cmd);
e7168df4 2701 install_element (CONFIG_NODE, &enable_password_cmd);
e7168df4 2702 install_element (CONFIG_NODE, &no_enable_password_cmd);
2703
718e3744 2704 install_element (CONFIG_NODE, &config_log_stdout_cmd);
2705 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
274a4a44 2706 install_element (CONFIG_NODE, &config_log_monitor_cmd);
274a4a44 2707 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
718e3744 2708 install_element (CONFIG_NODE, &config_log_file_cmd);
2709 install_element (CONFIG_NODE, &no_config_log_file_cmd);
2710 install_element (CONFIG_NODE, &config_log_syslog_cmd);
2711 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
274a4a44 2712 install_element (CONFIG_NODE, &config_log_facility_cmd);
2713 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
718e3744 2714 install_element (CONFIG_NODE, &config_log_trap_cmd);
2715 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
2716 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
2717 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
1ed72e0b
AS
2718 install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
2719 install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
718e3744 2720 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
2721 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
2722 install_element (CONFIG_NODE, &banner_motd_default_cmd);
3b0c5d9a 2723 install_element (CONFIG_NODE, &banner_motd_file_cmd);
718e3744 2724 install_element (CONFIG_NODE, &no_banner_motd_cmd);
2725 install_element (CONFIG_NODE, &service_terminal_length_cmd);
2726 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
718e3744 2727
19dc275e 2728 vrf_install_commands ();
9ab6812d 2729 }
af2567b6
DL
2730
2731#ifdef DEV_BUILD
2732 grammar_sandbox_init();
2733#endif
718e3744 2734}
228da428 2735
d0bfb22c 2736struct cmd_token *
83364d20
DL
2737new_cmd_token (enum cmd_token_type type, u_char attr,
2738 const char *text, const char *desc)
cd40b329 2739{
a8e4ddd4 2740 struct cmd_token *token = XCALLOC (MTYPE_CMD_TOKENS, sizeof (struct cmd_token));
d0bfb22c 2741 token->type = type;
ce882f81 2742 token->attr = attr;
83364d20
DL
2743 token->text = text ? XSTRDUP (MTYPE_CMD_TEXT, text) : NULL;
2744 token->desc = desc ? XSTRDUP (MTYPE_CMD_DESC, desc) : NULL;
de8f7a39 2745 token->refcnt = 1;
d0bfb22c 2746 token->arg = NULL;
a8e4ddd4 2747 token->allowrepeat = false;
cd40b329 2748
d0bfb22c
QY
2749 return token;
2750}
cd40b329 2751
d0bfb22c
QY
2752void
2753del_cmd_token (struct cmd_token *token)
2754{
2755 if (!token) return;
cd40b329 2756
d0bfb22c 2757 if (token->text)
83364d20 2758 XFREE (MTYPE_CMD_TEXT, token->text);
d0bfb22c 2759 if (token->desc)
83364d20 2760 XFREE (MTYPE_CMD_DESC, token->desc);
d0bfb22c 2761 if (token->arg)
83364d20 2762 XFREE (MTYPE_CMD_ARG, token->arg);
cd40b329 2763
17aca20b 2764 XFREE (MTYPE_CMD_TOKENS, token);
cd40b329
CF
2765}
2766
d0bfb22c
QY
2767struct cmd_token *
2768copy_cmd_token (struct cmd_token *token)
cd40b329 2769{
ce882f81 2770 struct cmd_token *copy = new_cmd_token (token->type, token->attr, NULL, NULL);
d0bfb22c
QY
2771 copy->max = token->max;
2772 copy->min = token->min;
83364d20
DL
2773 copy->text = token->text ? XSTRDUP (MTYPE_CMD_TEXT, token->text) : NULL;
2774 copy->desc = token->desc ? XSTRDUP (MTYPE_CMD_DESC, token->desc) : NULL;
2775 copy->arg = token->arg ? XSTRDUP (MTYPE_CMD_ARG, token->arg) : NULL;
cd40b329 2776
d0bfb22c 2777 return copy;
cd40b329
CF
2778}
2779
228da428
CC
2780void
2781cmd_terminate ()
2782{
228da428 2783 struct cmd_node *cmd_node;
228da428
CC
2784
2785 if (cmdvec)
2786 {
d0bfb22c 2787 for (unsigned int i = 0; i < vector_active (cmdvec); i++)
228da428 2788 if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
d0bfb22c
QY
2789 {
2790 // deleting the graph delets the cmd_element as well
2791 graph_delete_graph (cmd_node->cmdgraph);
2792 vector_free (cmd_node->cmd_vector);
39e92c06
QY
2793 hash_clean (cmd_node->cmd_hash, NULL);
2794 hash_free (cmd_node->cmd_hash);
2795 cmd_node->cmd_hash = NULL;
d0bfb22c 2796 }
228da428
CC
2797
2798 vector_free (cmdvec);
2799 cmdvec = NULL;
2800 }
2801
228da428
CC
2802 if (host.name)
2803 XFREE (MTYPE_HOST, host.name);
2804 if (host.password)
2805 XFREE (MTYPE_HOST, host.password);
2806 if (host.password_encrypt)
2807 XFREE (MTYPE_HOST, host.password_encrypt);
2808 if (host.enable)
2809 XFREE (MTYPE_HOST, host.enable);
2810 if (host.enable_encrypt)
2811 XFREE (MTYPE_HOST, host.enable_encrypt);
2812 if (host.logfile)
2813 XFREE (MTYPE_HOST, host.logfile);
2814 if (host.motdfile)
2815 XFREE (MTYPE_HOST, host.motdfile);
2816 if (host.config)
2817 XFREE (MTYPE_HOST, host.config);
58ac32e2
RW
2818
2819 qobj_finish ();
228da428 2820}