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