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