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