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