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