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