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