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