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