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