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