2 $Id: command.c,v 1.47 2005/04/25 16:26:42 paul Exp $
4 Command interpreter routine for virtual terminal [aka TeletYpe]
5 Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
7 This file is part of GNU Zebra.
9 GNU Zebra is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published
11 by the Free Software Foundation; either version 2, or (at your
12 option) any later version.
14 GNU Zebra is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GNU Zebra; see the file COPYING. If not, write to the
21 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
24 #include "cardshell.h"
39 #include <vty/vector.h>
41 #include <vty/command.h>
43 #include <osmocom/file.h>
44 #include <osmocore/talloc.h>
46 void *tall_vty_cmd_ctx;
48 /* Command vector which includes some level of command lists. Normally
49 each daemon maintains each own cmdvec. */
52 /* Host information structure. */
55 /* Standard command node structures. */
56 struct cmd_node auth_node = {
61 struct cmd_node view_node = {
66 struct cmd_node auth_enable_node = {
71 struct cmd_node enable_node = {
76 struct cmd_node config_node = {
82 /* Default motd string. */
83 const char *default_motd = "\r\n\
84 Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
85 " QUAGGA_COPYRIGHT "\r\n\
89 static struct facility_map {
93 } syslog_facilities[] = {
95 LOG_KERN, "kern", 1}, {
96 LOG_USER, "user", 2}, {
97 LOG_MAIL, "mail", 1}, {
98 LOG_DAEMON, "daemon", 1}, {
99 LOG_AUTH, "auth", 1}, {
100 LOG_SYSLOG, "syslog", 1}, {
101 LOG_LPR, "lpr", 2}, {
102 LOG_NEWS, "news", 1}, {
103 LOG_UUCP, "uucp", 2}, {
104 LOG_CRON, "cron", 1},
110 LOG_LOCAL0, "local0", 6}, {
111 LOG_LOCAL1, "local1", 6}, {
112 LOG_LOCAL2, "local2", 6}, {
113 LOG_LOCAL3, "local3", 6}, {
114 LOG_LOCAL4, "local4", 6}, {
115 LOG_LOCAL5, "local5", 6}, {
116 LOG_LOCAL6, "local6", 6}, {
117 LOG_LOCAL7, "local7", 6}, {
120 static const char *facility_name(int facility)
122 struct facility_map *fm;
124 for (fm = syslog_facilities; fm->name; fm++)
125 if (fm->facility == facility)
130 static int facility_match(const char *str)
132 struct facility_map *fm;
134 for (fm = syslog_facilities; fm->name; fm++)
135 if (!strncmp(str, fm->name, fm->match))
140 static int level_match(const char *s)
144 for (level = 0; zlog_priority[level] != NULL; level++)
145 if (!strncmp(s, zlog_priority[level], 2))
147 return ZLOG_DISABLED;
151 /* This is called from main when a daemon is invoked with -v or --version. */
152 void print_version(const char *progname)
154 printf("%s version %s\n", progname, QUAGGA_VERSION);
155 printf("%s\n", QUAGGA_COPYRIGHT);
158 /* Utility function to concatenate argv argument into a single string
159 with inserting ' ' character between each argument. */
160 char *argv_concat(const char **argv, int argc, int shift)
168 for (i = shift; i < argc; i++)
169 len += strlen(argv[i]) + 1;
172 p = str = _talloc_zero(tall_vty_cmd_ctx, len, "arvg_concat");
173 for (i = shift; i < argc; i++) {
175 memcpy(p, argv[i], (arglen = strlen(argv[i])));
183 /* Install top node of command vector. */
184 void install_node(struct cmd_node *node, int (*func) (struct vty *))
186 vector_set_index(cmdvec, node->node, node);
188 node->cmd_vector = vector_init(VECTOR_MIN_SIZE);
191 /* Compare two command's string. Used in sort_node (). */
192 static int cmp_node(const void *p, const void *q)
194 struct cmd_element *a = *(struct cmd_element **)p;
195 struct cmd_element *b = *(struct cmd_element **)q;
197 return strcmp(a->string, b->string);
200 static int cmp_desc(const void *p, const void *q)
202 struct desc *a = *(struct desc **)p;
203 struct desc *b = *(struct desc **)q;
205 return strcmp(a->cmd, b->cmd);
208 /* Sort each node's command element according to command string. */
212 struct cmd_node *cnode;
214 struct cmd_element *cmd_element;
216 for (i = 0; i < vector_active(cmdvec); i++)
217 if ((cnode = vector_slot(cmdvec, i)) != NULL) {
218 vector cmd_vector = cnode->cmd_vector;
219 qsort(cmd_vector->index, vector_active(cmd_vector),
220 sizeof(void *), cmp_node);
222 for (j = 0; j < vector_active(cmd_vector); j++)
224 vector_slot(cmd_vector, j)) != NULL
225 && vector_active(cmd_element->strvec)) {
227 vector_slot(cmd_element->strvec,
229 (cmd_element->strvec) -
231 qsort(descvec->index,
232 vector_active(descvec),
233 sizeof(void *), cmp_desc);
238 /* Breaking up string into each command piece. I assume given
239 character is separated by a space character. Return value is a
240 vector which includes char ** data element. */
241 vector cmd_make_strvec(const char *string)
243 const char *cp, *start;
253 /* Skip white spaces. */
254 while (isspace((int)*cp) && *cp != '\0')
257 /* Return if there is only white spaces */
261 if (*cp == '!' || *cp == '#')
264 /* Prepare return vector. */
265 strvec = vector_init(VECTOR_MIN_SIZE);
267 /* Copy each command piece and set into vector. */
270 while (!(isspace((int)*cp) || *cp == '\r' || *cp == '\n') &&
274 token = _talloc_zero(tall_vty_cmd_ctx, strlen + 1, "make_strvec");
275 memcpy(token, start, strlen);
276 *(token + strlen) = '\0';
277 vector_set(strvec, token);
279 while ((isspace((int)*cp) || *cp == '\n' || *cp == '\r') &&
288 /* Free allocated string vector. */
289 void cmd_free_strvec(vector v)
297 for (i = 0; i < vector_active(v); i++)
298 if ((cp = vector_slot(v, i)) != NULL)
304 /* Fetch next description. Used in cmd_make_descvec(). */
305 static char *cmd_desc_str(const char **string)
307 const char *cp, *start;
316 /* Skip white spaces. */
317 while (isspace((int)*cp) && *cp != '\0')
320 /* Return if there is only white spaces */
326 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
330 token = _talloc_zero(tall_vty_cmd_ctx, strlen + 1, "cmd_desc_str");
331 memcpy(token, start, strlen);
332 *(token + strlen) = '\0';
339 /* New string vector. */
340 static vector cmd_make_descvec(const char *string, const char *descstr)
349 vector strvec = NULL;
358 allvec = vector_init(VECTOR_MIN_SIZE);
361 while (isspace((int)*cp) && *cp != '\0')
374 fprintf(stderr, "Command parse error!: %s\n",
381 while (isspace((int)*cp) && *cp != '\0')
395 (isspace((int)*cp) || *cp == '\r' || *cp == '\n'
396 || *cp == ')' || *cp == '|') && *cp != '\0')
401 token = _talloc_zero(tall_vty_cmd_ctx, len + 1, "cmd_make_descvec");
402 memcpy(token, sp, len);
403 *(token + len) = '\0';
405 desc = talloc_zero(tall_vty_cmd_ctx, struct desc);
407 desc->str = cmd_desc_str(&dp);
411 strvec = vector_init(VECTOR_MIN_SIZE);
412 vector_set(allvec, strvec);
416 strvec = vector_init(VECTOR_MIN_SIZE);
417 vector_set(allvec, strvec);
419 vector_set(strvec, desc);
423 /* Count mandantory string vector size. This is to determine inputed
424 command has enough command length. */
425 static int cmd_cmdsize(vector strvec)
432 for (i = 0; i < vector_active(strvec); i++)
433 if ((descvec = vector_slot(strvec, i)) != NULL) {
434 if ((vector_active(descvec)) == 1
435 && (desc = vector_slot(descvec, 0)) != NULL) {
436 if (desc->cmd == NULL || CMD_OPTION(desc->cmd))
446 /* Return prompt character of specified node. */
447 const char *cmd_prompt(enum node_type node)
449 struct cmd_node *cnode;
451 cnode = vector_slot(cmdvec, node);
452 return cnode->prompt;
455 /* Install a command into a node. */
456 void install_element(enum node_type ntype, struct cmd_element *cmd)
458 struct cmd_node *cnode;
460 cnode = vector_slot(cmdvec, ntype);
464 "Command node %d doesn't exist, please check it\n",
469 vector_set(cnode->cmd_vector, cmd);
471 cmd->strvec = cmd_make_descvec(cmd->string, cmd->doc);
472 cmd->cmdsize = cmd_cmdsize(cmd->strvec);
476 static unsigned char itoa64[] =
477 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
479 static void to64(char *s, long v, int n)
482 *s++ = itoa64[v & 0x3f];
487 static char *zencrypt(const char *passwd)
491 char *crypt(const char *, const char *);
493 gettimeofday(&tv, 0);
495 to64(&salt[0], random(), 3);
496 to64(&salt[3], tv.tv_usec, 3);
499 return crypt(passwd, salt);
503 /* This function write configuration of this host. */
504 static int config_write_host(struct vty *vty)
507 vty_out(vty, "hostname %s%s", host.name, VTY_NEWLINE);
510 if (host.password_encrypt)
511 vty_out(vty, "password 8 %s%s", host.password_encrypt,
513 if (host.enable_encrypt)
514 vty_out(vty, "enable password 8 %s%s",
515 host.enable_encrypt, VTY_NEWLINE);
518 vty_out(vty, "password %s%s", host.password,
521 vty_out(vty, "enable password %s%s", host.enable,
526 if (zlog_default->default_lvl != LOG_DEBUG) {
527 vty_out(vty, "! N.B. The 'log trap' command is deprecated.%s",
529 vty_out(vty, "log trap %s%s",
530 zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
534 && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED)) {
535 vty_out(vty, "log file %s", host.logfile);
536 if (zlog_default->maxlvl[ZLOG_DEST_FILE] !=
537 zlog_default->default_lvl)
539 zlog_priority[zlog_default->
540 maxlvl[ZLOG_DEST_FILE]]);
541 vty_out(vty, "%s", VTY_NEWLINE);
544 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED) {
545 vty_out(vty, "log stdout");
546 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] !=
547 zlog_default->default_lvl)
549 zlog_priority[zlog_default->
550 maxlvl[ZLOG_DEST_STDOUT]]);
551 vty_out(vty, "%s", VTY_NEWLINE);
554 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
555 vty_out(vty, "no log monitor%s", VTY_NEWLINE);
556 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] !=
557 zlog_default->default_lvl)
558 vty_out(vty, "log monitor %s%s",
559 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],
562 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED) {
563 vty_out(vty, "log syslog");
564 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] !=
565 zlog_default->default_lvl)
567 zlog_priority[zlog_default->
568 maxlvl[ZLOG_DEST_SYSLOG]]);
569 vty_out(vty, "%s", VTY_NEWLINE);
572 if (zlog_default->facility != LOG_DAEMON)
573 vty_out(vty, "log facility %s%s",
574 facility_name(zlog_default->facility), VTY_NEWLINE);
576 if (zlog_default->record_priority == 1)
577 vty_out(vty, "log record-priority%s", VTY_NEWLINE);
580 vty_out(vty, "service advanced-vty%s", VTY_NEWLINE);
583 vty_out(vty, "service password-encryption%s", VTY_NEWLINE);
586 vty_out(vty, "service terminal-length %d%s", host.lines,
590 vty_out(vty, "banner motd file %s%s", host.motdfile,
593 vty_out(vty, "no banner motd%s", VTY_NEWLINE);
598 /* Utility function for getting command vector. */
599 static vector cmd_node_vector(vector v, enum node_type ntype)
601 struct cmd_node *cnode = vector_slot(v, ntype);
602 return cnode->cmd_vector;
606 /* Filter command vector by symbol. This function is not actually used;
607 * should it be deleted? */
608 static int cmd_filter_by_symbol(char *command, char *symbol)
612 if (strcmp(symbol, "IPV4_ADDRESS") == 0) {
614 lim = strlen(command);
617 (isdigit((int)command[i]) || command[i] == '.'
618 || command[i] == '/'))
624 if (strcmp(symbol, "STRING") == 0) {
626 lim = strlen(command);
629 (isalpha((int)command[i]) || command[i] == '_'
630 || command[i] == '-'))
636 if (strcmp(symbol, "IFNAME") == 0) {
638 lim = strlen(command);
640 if (!isalnum((int)command[i]))
650 /* Completion match types. */
664 static enum match_type cmd_ipv4_match(const char *str)
667 int dots = 0, nums = 0;
674 memset(buf, 0, sizeof(buf));
676 while (*str != '\0') {
681 if (*(str + 1) == '.')
684 if (*(str + 1) == '\0')
690 if (!isdigit((int)*str))
699 strncpy(buf, sp, str - sp);
717 static enum match_type cmd_ipv4_prefix_match(const char *str)
727 memset(buf, 0, sizeof(buf));
729 while (*str != '\0' && *str != '/') {
734 if (*(str + 1) == '.' || *(str + 1) == '/')
737 if (*(str + 1) == '\0')
744 if (!isdigit((int)*str))
753 strncpy(buf, sp, str - sp);
759 if (*(str + 1) == '\0')
764 } else if (*str == '\0')
775 while (*str != '\0') {
776 if (!isdigit((int)*str))
788 #define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
789 #define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
790 #define STATE_START 1
791 #define STATE_COLON 2
792 #define STATE_DOUBLE 3
795 #define STATE_SLASH 6
800 static enum match_type cmd_ipv6_match(const char *str)
802 int state = STATE_START;
803 int colons = 0, nums = 0, double_colon = 0;
804 const char *sp = NULL;
805 struct sockaddr_in6 sin6_dummy;
811 if (strspn(str, IPV6_ADDR_STR) != strlen(str))
814 /* use inet_pton that has a better support,
815 * for example inet_pton can support the automatic addresses:
818 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
823 while (*str != '\0') {
827 if (*(str + 1) != ':' && *(str + 1) != '\0')
839 if (*(str + 1) == ':')
840 state = STATE_DOUBLE;
850 if (*(str + 1) == ':')
853 if (*(str + 1) != '\0')
863 if (*(str + 1) == ':' || *(str + 1) == '\0') {
870 if (*(str + 1) == '.')
897 static enum match_type cmd_ipv6_prefix_match(const char *str)
899 int state = STATE_START;
900 int colons = 0, nums = 0, double_colon = 0;
902 const char *sp = NULL;
908 if (strspn(str, IPV6_PREFIX_STR) != strlen(str))
911 while (*str != '\0' && state != STATE_MASK) {
915 if (*(str + 1) != ':' && *(str + 1) != '\0')
927 if (*(str + 1) == '/')
929 else if (*(str + 1) == ':')
930 state = STATE_DOUBLE;
940 if (*(str + 1) == ':')
943 if (*(str + 1) != '\0' && *(str + 1) != '/')
947 if (*(str + 1) == '/')
957 if (*(str + 1) == ':' || *(str + 1) == '.'
958 || *(str + 1) == '\0' || *(str + 1) == '/') {
962 for (; sp <= str; sp++)
968 if (*(str + 1) == ':')
970 else if (*(str + 1) == '.')
972 else if (*(str + 1) == '/')
980 if (*(str + 1) == '\0')
998 if (state < STATE_MASK)
1001 mask = strtol(str, &endptr, 10);
1002 if (*endptr != '\0')
1005 if (mask < 0 || mask > 128)
1008 /* I don't know why mask < 13 makes command match partly.
1009 Forgive me to make this comments. I Want to set static default route
1010 because of lack of function to originate default in ospf6d; sorry
1013 return partly_match;
1019 #endif /* HAVE_IPV6 */
1021 #define DECIMAL_STRLEN_MAX 10
1023 static int cmd_range_match(const char *range, const char *str)
1026 char buf[DECIMAL_STRLEN_MAX + 1];
1027 char *endptr = NULL;
1028 unsigned long min, max, val;
1033 val = strtoul(str, &endptr, 10);
1034 if (*endptr != '\0')
1038 p = strchr(range, '-');
1041 if (p - range > DECIMAL_STRLEN_MAX)
1043 strncpy(buf, range, p - range);
1044 buf[p - range] = '\0';
1045 min = strtoul(buf, &endptr, 10);
1046 if (*endptr != '\0')
1050 p = strchr(range, '>');
1053 if (p - range > DECIMAL_STRLEN_MAX)
1055 strncpy(buf, range, p - range);
1056 buf[p - range] = '\0';
1057 max = strtoul(buf, &endptr, 10);
1058 if (*endptr != '\0')
1061 if (val < min || val > max)
1067 /* Make completion match and return match type flag. */
1068 static enum match_type
1069 cmd_filter_by_completion(char *command, vector v, unsigned int index)
1073 struct cmd_element *cmd_element;
1074 enum match_type match_type;
1078 match_type = no_match;
1080 /* If command and cmd_element string does not match set NULL to vector */
1081 for (i = 0; i < vector_active(v); i++)
1082 if ((cmd_element = vector_slot(v, i)) != NULL) {
1083 if (index >= vector_active(cmd_element->strvec))
1084 vector_slot(v, i) = NULL;
1090 vector_slot(cmd_element->strvec, index);
1092 for (j = 0; j < vector_active(descvec); j++)
1093 if ((desc = vector_slot(descvec, j))) {
1096 if (CMD_VARARG(str)) {
1102 } else if (CMD_RANGE(str)) {
1115 else if (CMD_IPV6(str)) {
1126 } else if (CMD_IPV6_PREFIX(str)) {
1127 if (cmd_ipv6_prefix_match(command)) {
1137 #endif /* HAVE_IPV6 */
1138 else if (CMD_IPV4(str)) {
1149 } else if (CMD_IPV4_PREFIX(str)) {
1150 if (cmd_ipv4_prefix_match(command)) {
1159 /* Check is this point's argument optional ? */
1162 CMD_VARIABLE(str)) {
1173 if (strcmp(command, str)
1188 vector_slot(v, i) = NULL;
1194 /* Filter vector by command character with index. */
1195 static enum match_type
1196 cmd_filter_by_string(char *command, vector v, unsigned int index)
1200 struct cmd_element *cmd_element;
1201 enum match_type match_type;
1205 match_type = no_match;
1207 /* If command and cmd_element string does not match set NULL to vector */
1208 for (i = 0; i < vector_active(v); i++)
1209 if ((cmd_element = vector_slot(v, i)) != NULL) {
1210 /* If given index is bigger than max string vector of command,
1212 if (index >= vector_active(cmd_element->strvec))
1213 vector_slot(v, i) = NULL;
1219 vector_slot(cmd_element->strvec, index);
1221 for (j = 0; j < vector_active(descvec); j++)
1222 if ((desc = vector_slot(descvec, j))) {
1225 if (CMD_VARARG(str)) {
1231 } else if (CMD_RANGE(str)) {
1243 else if (CMD_IPV6(str)) {
1254 } else if (CMD_IPV6_PREFIX(str)) {
1255 if (cmd_ipv6_prefix_match(command) == exact_match) {
1264 #endif /* HAVE_IPV6 */
1265 else if (CMD_IPV4(str)) {
1276 } else if (CMD_IPV4_PREFIX(str)) {
1277 if (cmd_ipv4_prefix_match(command) == exact_match) {
1285 } else if (CMD_OPTION(str)
1286 || CMD_VARIABLE(str))
1294 if (strcmp(command, str)
1303 vector_slot(v, i) = NULL;
1309 /* Check ambiguous match */
1311 is_cmd_ambiguous(char *command, vector v, int index, enum match_type type)
1315 const char *str = NULL;
1316 struct cmd_element *cmd_element;
1317 const char *matched = NULL;
1321 for (i = 0; i < vector_active(v); i++)
1322 if ((cmd_element = vector_slot(v, i)) != NULL) {
1325 descvec = vector_slot(cmd_element->strvec, index);
1327 for (j = 0; j < vector_active(descvec); j++)
1328 if ((desc = vector_slot(descvec, j))) {
1329 enum match_type ret;
1337 || CMD_VARIABLE(str))
1338 && strcmp(command, str) == 0)
1344 || CMD_VARIABLE(str))
1345 && strncmp(command, str, strlen(command)) == 0) {
1349 return 1; /* There is ambiguous match. */
1372 case ipv6_prefix_match:
1374 cmd_ipv6_prefix_match
1375 (command)) != no_match) {
1376 if (ret == partly_match)
1377 return 2; /* There is incomplete match. */
1382 #endif /* HAVE_IPV6 */
1387 case ipv4_prefix_match:
1389 cmd_ipv4_prefix_match
1390 (command)) != no_match) {
1391 if (ret == partly_match)
1392 return 2; /* There is incomplete match. */
1399 || CMD_VARIABLE(str))
1408 vector_slot(v, i) = NULL;
1413 /* If src matches dst return dst string, otherwise return NULL */
1414 static const char *cmd_entry_function(const char *src, const char *dst)
1416 /* Skip variable arguments. */
1417 if (CMD_OPTION(dst) || CMD_VARIABLE(dst) || CMD_VARARG(dst) ||
1418 CMD_IPV4(dst) || CMD_IPV4_PREFIX(dst) || CMD_RANGE(dst))
1421 /* In case of 'command \t', given src is NULL string. */
1425 /* Matched with input string. */
1426 if (strncmp(src, dst, strlen(src)) == 0)
1432 /* If src matches dst return dst string, otherwise return NULL */
1433 /* This version will return the dst string always if it is
1434 CMD_VARIABLE for '?' key processing */
1435 static const char *cmd_entry_function_desc(const char *src, const char *dst)
1437 if (CMD_VARARG(dst))
1440 if (CMD_RANGE(dst)) {
1441 if (cmd_range_match(dst, src))
1447 if (CMD_IPV6(dst)) {
1448 if (cmd_ipv6_match(src))
1454 if (CMD_IPV6_PREFIX(dst)) {
1455 if (cmd_ipv6_prefix_match(src))
1460 #endif /* HAVE_IPV6 */
1462 if (CMD_IPV4(dst)) {
1463 if (cmd_ipv4_match(src))
1469 if (CMD_IPV4_PREFIX(dst)) {
1470 if (cmd_ipv4_prefix_match(src))
1476 /* Optional or variable commands always match on '?' */
1477 if (CMD_OPTION(dst) || CMD_VARIABLE(dst))
1480 /* In case of 'command \t', given src is NULL string. */
1484 if (strncmp(src, dst, strlen(src)) == 0)
1490 /* Check same string element existence. If it isn't there return
1492 static int cmd_unique_string(vector v, const char *str)
1497 for (i = 0; i < vector_active(v); i++)
1498 if ((match = vector_slot(v, i)) != NULL)
1499 if (strcmp(match, str) == 0)
1504 /* Compare string to description vector. If there is same string
1505 return 1 else return 0. */
1506 static int desc_unique_string(vector v, const char *str)
1511 for (i = 0; i < vector_active(v); i++)
1512 if ((desc = vector_slot(v, i)) != NULL)
1513 if (strcmp(desc->cmd, str) == 0)
1518 static int cmd_try_do_shortcut(enum node_type node, char *first_word)
1520 if (first_word != NULL &&
1521 node != AUTH_NODE &&
1522 node != VIEW_NODE &&
1523 node != AUTH_ENABLE_NODE &&
1524 node != ENABLE_NODE && 0 == strcmp("do", first_word))
1529 /* '?' describe command support. */
1531 cmd_describe_command_real(vector vline, struct vty *vty, int *status)
1535 #define INIT_MATCHVEC_SIZE 10
1537 struct cmd_element *cmd_element;
1540 enum match_type match;
1542 static struct desc desc_cr = { "<cr>", "" };
1545 if (vector_active(vline) == 0) {
1546 *status = CMD_ERR_NO_MATCH;
1549 index = vector_active(vline) - 1;
1551 /* Make copy vector of current node's command vector. */
1552 cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
1554 /* Prepare match vector */
1555 matchvec = vector_init(INIT_MATCHVEC_SIZE);
1557 /* Filter commands. */
1558 /* Only words precedes current word will be checked in this loop. */
1559 for (i = 0; i < index; i++)
1560 if ((command = vector_slot(vline, i))) {
1562 cmd_filter_by_completion(command, cmd_vector, i);
1564 if (match == vararg_match) {
1565 struct cmd_element *cmd_element;
1569 for (j = 0; j < vector_active(cmd_vector); j++)
1571 vector_slot(cmd_vector, j)) != NULL
1574 (cmd_element->strvec))) {
1576 vector_slot(cmd_element->
1582 k < vector_active(descvec);
1585 vector_slot(descvec,
1587 vector_set(matchvec,
1592 vector_set(matchvec, &desc_cr);
1593 vector_free(cmd_vector);
1599 is_cmd_ambiguous(command, cmd_vector, i,
1601 vector_free(cmd_vector);
1602 *status = CMD_ERR_AMBIGUOUS;
1604 } else if (ret == 2) {
1605 vector_free(cmd_vector);
1606 *status = CMD_ERR_NO_MATCH;
1611 /* Prepare match vector */
1612 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1614 /* Make sure that cmd_vector is filtered based on current word */
1615 command = vector_slot(vline, index);
1617 match = cmd_filter_by_completion(command, cmd_vector, index);
1619 /* Make description vector. */
1620 for (i = 0; i < vector_active(cmd_vector); i++)
1621 if ((cmd_element = vector_slot(cmd_vector, i)) != NULL) {
1622 const char *string = NULL;
1623 vector strvec = cmd_element->strvec;
1625 /* if command is NULL, index may be equal to vector_active */
1626 if (command && index >= vector_active(strvec))
1627 vector_slot(cmd_vector, i) = NULL;
1629 /* Check if command is completed. */
1631 && index == vector_active(strvec)) {
1633 if (!desc_unique_string
1635 vector_set(matchvec, &desc_cr);
1639 vector_slot(strvec, index);
1642 for (j = 0; j < vector_active(descvec);
1645 vector_slot(descvec, j))) {
1647 cmd_entry_function_desc
1651 /* Uniqueness check */
1652 if (!desc_unique_string(matchvec, string))
1661 vector_free(cmd_vector);
1663 if (vector_slot(matchvec, 0) == NULL) {
1664 vector_free(matchvec);
1665 *status = CMD_ERR_NO_MATCH;
1667 *status = CMD_SUCCESS;
1672 vector cmd_describe_command(vector vline, struct vty * vty, int *status)
1676 if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
1677 enum node_type onode;
1678 vector shifted_vline;
1682 vty->node = ENABLE_NODE;
1683 /* We can try it on enable node, cos' the vty is authenticated */
1685 shifted_vline = vector_init(vector_count(vline));
1687 for (index = 1; index < vector_active(vline); index++) {
1688 vector_set_index(shifted_vline, index - 1,
1689 vector_lookup(vline, index));
1692 ret = cmd_describe_command_real(shifted_vline, vty, status);
1694 vector_free(shifted_vline);
1699 return cmd_describe_command_real(vline, vty, status);
1702 /* Check LCD of matched command. */
1703 static int cmd_lcd(char **matched)
1711 if (matched[0] == NULL || matched[1] == NULL)
1714 for (i = 1; matched[i] != NULL; i++) {
1715 s1 = matched[i - 1];
1718 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1732 /* Command line completion support. */
1733 static char **cmd_complete_command_real(vector vline, struct vty *vty,
1737 vector cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
1738 #define INIT_MATCHVEC_SIZE 10
1740 struct cmd_element *cmd_element;
1748 if (vector_active(vline) == 0) {
1749 *status = CMD_ERR_NO_MATCH;
1752 index = vector_active(vline) - 1;
1754 /* First, filter by preceeding command string */
1755 for (i = 0; i < index; i++)
1756 if ((command = vector_slot(vline, i))) {
1757 enum match_type match;
1760 /* First try completion match, if there is exactly match return 1 */
1762 cmd_filter_by_completion(command, cmd_vector, i);
1764 /* If there is exact match then filter ambiguous match else check
1767 is_cmd_ambiguous(command, cmd_vector, i,
1769 vector_free(cmd_vector);
1770 *status = CMD_ERR_AMBIGUOUS;
1776 vector_free (cmd_vector);
1777 *status = CMD_ERR_NO_MATCH;
1783 /* Prepare match vector. */
1784 matchvec = vector_init(INIT_MATCHVEC_SIZE);
1786 /* Now we got into completion */
1787 for (i = 0; i < vector_active(cmd_vector); i++)
1788 if ((cmd_element = vector_slot(cmd_vector, i))) {
1790 vector strvec = cmd_element->strvec;
1792 /* Check field length */
1793 if (index >= vector_active(strvec))
1794 vector_slot(cmd_vector, i) = NULL;
1798 descvec = vector_slot(strvec, index);
1799 for (j = 0; j < vector_active(descvec); j++)
1800 if ((desc = vector_slot(descvec, j))) {
1801 if ((string = cmd_entry_function(vector_slot(vline, index), desc->cmd)))
1802 if (cmd_unique_string (matchvec, string))
1803 vector_set (matchvec, talloc_strdup(tall_vty_cmd_ctx, string));
1808 /* We don't need cmd_vector any more. */
1809 vector_free(cmd_vector);
1811 /* No matched command */
1812 if (vector_slot(matchvec, 0) == NULL) {
1813 vector_free(matchvec);
1815 /* In case of 'command \t' pattern. Do you need '?' command at
1816 the end of the line. */
1817 if (vector_slot(vline, index) == '\0')
1818 *status = CMD_ERR_NOTHING_TODO;
1820 *status = CMD_ERR_NO_MATCH;
1824 /* Only one matched */
1825 if (vector_slot(matchvec, 1) == NULL) {
1826 match_str = (char **)matchvec->index;
1827 vector_only_wrapper_free(matchvec);
1828 *status = CMD_COMPLETE_FULL_MATCH;
1831 /* Make it sure last element is NULL. */
1832 vector_set(matchvec, NULL);
1834 /* Check LCD of matched strings. */
1835 if (vector_slot(vline, index) != NULL) {
1836 lcd = cmd_lcd((char **)matchvec->index);
1839 int len = strlen(vector_slot(vline, index));
1844 lcdstr = _talloc_zero(tall_vty_cmd_ctx, lcd + 1,
1846 memcpy(lcdstr, matchvec->index[0], lcd);
1849 /* match_str = (char **) &lcdstr; */
1851 /* Free matchvec. */
1852 for (i = 0; i < vector_active(matchvec); i++) {
1853 if (vector_slot(matchvec, i))
1854 talloc_free(vector_slot(matchvec, i));
1856 vector_free(matchvec);
1858 /* Make new matchvec. */
1859 matchvec = vector_init(INIT_MATCHVEC_SIZE);
1860 vector_set(matchvec, lcdstr);
1861 match_str = (char **)matchvec->index;
1862 vector_only_wrapper_free(matchvec);
1864 *status = CMD_COMPLETE_MATCH;
1870 match_str = (char **)matchvec->index;
1871 vector_only_wrapper_free(matchvec);
1872 *status = CMD_COMPLETE_LIST_MATCH;
1876 char **cmd_complete_command(vector vline, struct vty *vty, int *status)
1880 if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
1881 enum node_type onode;
1882 vector shifted_vline;
1886 vty->node = ENABLE_NODE;
1887 /* We can try it on enable node, cos' the vty is authenticated */
1889 shifted_vline = vector_init(vector_count(vline));
1891 for (index = 1; index < vector_active(vline); index++) {
1892 vector_set_index(shifted_vline, index - 1,
1893 vector_lookup(vline, index));
1896 ret = cmd_complete_command_real(shifted_vline, vty, status);
1898 vector_free(shifted_vline);
1903 return cmd_complete_command_real(vline, vty, status);
1906 /* return parent node */
1907 /* MUST eventually converge on CONFIG_NODE */
1908 enum node_type vty_go_parent(struct vty *vty)
1910 assert(vty->node > CONFIG_NODE);
1912 switch (vty->node) {
1914 vty->node = CONFIG_NODE;
1918 vty->node = MS_NODE;
1922 vty->node = GSMNET_NODE;
1924 /* set vty->index correctly ! */
1925 struct gsm_bts *bts = vty->index;
1926 vty->index = bts->network;
1930 vty->node = BTS_NODE;
1932 /* set vty->index correctly ! */
1933 struct gsm_bts_trx *trx = vty->index;
1934 vty->index = trx->bts;
1938 vty->node = TRX_NODE;
1940 /* set vty->index correctly ! */
1941 struct gsm_bts_trx_ts *ts = vty->index;
1942 vty->index = ts->trx;
1946 vty->node = VIEW_NODE;
1947 subscr_put(vty->index);
1952 vty->node = CONFIG_NODE;
1958 /* Execute command by argument vline vector. */
1960 cmd_execute_command_real(vector vline, struct vty *vty,
1961 struct cmd_element **cmd)
1966 struct cmd_element *cmd_element;
1967 struct cmd_element *matched_element;
1968 unsigned int matched_count, incomplete_count;
1970 const char *argv[CMD_ARGC_MAX];
1971 enum match_type match = 0;
1975 /* Make copy of command elements. */
1976 cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
1978 for (index = 0; index < vector_active(vline); index++)
1979 if ((command = vector_slot(vline, index))) {
1983 cmd_filter_by_completion(command, cmd_vector,
1986 if (match == vararg_match)
1990 is_cmd_ambiguous(command, cmd_vector, index, match);
1993 vector_free(cmd_vector);
1994 return CMD_ERR_AMBIGUOUS;
1995 } else if (ret == 2) {
1996 vector_free(cmd_vector);
1997 return CMD_ERR_NO_MATCH;
2001 /* Check matched count. */
2002 matched_element = NULL;
2004 incomplete_count = 0;
2006 for (i = 0; i < vector_active(cmd_vector); i++)
2007 if ((cmd_element = vector_slot(cmd_vector, i))) {
2008 if (match == vararg_match
2009 || index >= cmd_element->cmdsize) {
2010 matched_element = cmd_element;
2012 printf("DEBUG: %s\n", cmd_element->string);
2020 /* Finish of using cmd_vector. */
2021 vector_free(cmd_vector);
2023 /* To execute command, matched_count must be 1. */
2024 if (matched_count == 0) {
2025 if (incomplete_count)
2026 return CMD_ERR_INCOMPLETE;
2028 return CMD_ERR_NO_MATCH;
2031 if (matched_count > 1)
2032 return CMD_ERR_AMBIGUOUS;
2034 /* Argument treatment */
2038 for (i = 0; i < vector_active(vline); i++) {
2040 argv[argc++] = vector_slot(vline, i);
2043 vector_slot(matched_element->strvec, i);
2045 if (vector_active(descvec) == 1) {
2046 struct desc *desc = vector_slot(descvec, 0);
2048 if (CMD_VARARG(desc->cmd))
2051 if (varflag || CMD_VARIABLE(desc->cmd)
2052 || CMD_OPTION(desc->cmd))
2053 argv[argc++] = vector_slot(vline, i);
2055 argv[argc++] = vector_slot(vline, i);
2058 if (argc >= CMD_ARGC_MAX)
2059 return CMD_ERR_EXEED_ARGC_MAX;
2062 /* For vtysh execution. */
2064 *cmd = matched_element;
2066 if (matched_element->daemon)
2067 return CMD_SUCCESS_DAEMON;
2069 /* Execute matched command. */
2070 return (*matched_element->func) (matched_element, vty, argc, argv);
2074 cmd_execute_command(vector vline, struct vty *vty, struct cmd_element **cmd,
2077 int ret, saved_ret, tried = 0;
2078 enum node_type onode;
2082 oindex = vty->index;
2084 if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
2085 vector shifted_vline;
2088 vty->node = ENABLE_NODE;
2089 /* We can try it on enable node, cos' the vty is authenticated */
2091 shifted_vline = vector_init(vector_count(vline));
2093 for (index = 1; index < vector_active(vline); index++) {
2094 vector_set_index(shifted_vline, index - 1,
2095 vector_lookup(vline, index));
2098 ret = cmd_execute_command_real(shifted_vline, vty, cmd);
2100 vector_free(shifted_vline);
2105 saved_ret = ret = cmd_execute_command_real(vline, vty, cmd);
2110 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
2111 while (ret != CMD_SUCCESS && ret != CMD_WARNING
2112 && vty->node > CONFIG_NODE) {
2114 ret = cmd_execute_command_real(vline, vty, cmd);
2116 if (ret == CMD_SUCCESS || ret == CMD_WARNING) {
2117 /* succesfull command, leave the node as is */
2121 /* no command succeeded, reset the vty to the original node and
2122 return the error for this node */
2125 vty->index = oindex;
2130 /* Execute command by argument readline. */
2132 cmd_execute_command_strict(vector vline, struct vty *vty,
2133 struct cmd_element **cmd)
2138 struct cmd_element *cmd_element;
2139 struct cmd_element *matched_element;
2140 unsigned int matched_count, incomplete_count;
2142 const char *argv[CMD_ARGC_MAX];
2144 enum match_type match = 0;
2147 /* Make copy of command element */
2148 cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
2150 for (index = 0; index < vector_active(vline); index++)
2151 if ((command = vector_slot(vline, index))) {
2154 match = cmd_filter_by_string(vector_slot(vline, index),
2157 /* If command meets '.VARARG' then finish matching. */
2158 if (match == vararg_match)
2162 is_cmd_ambiguous(command, cmd_vector, index, match);
2164 vector_free(cmd_vector);
2165 return CMD_ERR_AMBIGUOUS;
2168 vector_free(cmd_vector);
2169 return CMD_ERR_NO_MATCH;
2173 /* Check matched count. */
2174 matched_element = NULL;
2176 incomplete_count = 0;
2177 for (i = 0; i < vector_active(cmd_vector); i++)
2178 if (vector_slot(cmd_vector, i) != NULL) {
2179 cmd_element = vector_slot(cmd_vector, i);
2181 if (match == vararg_match
2182 || index >= cmd_element->cmdsize) {
2183 matched_element = cmd_element;
2189 /* Finish of using cmd_vector. */
2190 vector_free(cmd_vector);
2192 /* To execute command, matched_count must be 1. */
2193 if (matched_count == 0) {
2194 if (incomplete_count)
2195 return CMD_ERR_INCOMPLETE;
2197 return CMD_ERR_NO_MATCH;
2200 if (matched_count > 1)
2201 return CMD_ERR_AMBIGUOUS;
2203 /* Argument treatment */
2207 for (i = 0; i < vector_active(vline); i++) {
2209 argv[argc++] = vector_slot(vline, i);
2212 vector_slot(matched_element->strvec, i);
2214 if (vector_active(descvec) == 1) {
2215 struct desc *desc = vector_slot(descvec, 0);
2217 if (CMD_VARARG(desc->cmd))
2220 if (varflag || CMD_VARIABLE(desc->cmd)
2221 || CMD_OPTION(desc->cmd))
2222 argv[argc++] = vector_slot(vline, i);
2224 argv[argc++] = vector_slot(vline, i);
2227 if (argc >= CMD_ARGC_MAX)
2228 return CMD_ERR_EXEED_ARGC_MAX;
2231 /* For vtysh execution. */
2233 *cmd = matched_element;
2235 if (matched_element->daemon)
2236 return CMD_SUCCESS_DAEMON;
2238 /* Now execute matched command */
2239 return (*matched_element->func) (matched_element, vty, argc, argv);
2242 /* Configration make from file. */
2243 int config_from_file(struct vty *vty, OSMOCOM_FILE * fp)
2248 while (osmocom_fgets(vty->buf, VTY_BUFSIZ, fp)) {
2249 vline = cmd_make_strvec(vty->buf);
2251 /* In case of comment line */
2254 /* Execute configuration command : this is strict match */
2255 ret = cmd_execute_command_strict(vline, vty, NULL);
2257 /* Try again with setting node to CONFIG_NODE */
2258 while (ret != CMD_SUCCESS && ret != CMD_WARNING
2259 && ret != CMD_ERR_NOTHING_TODO
2260 && vty->node != CONFIG_NODE) {
2262 ret = cmd_execute_command_strict(vline, vty, NULL);
2265 cmd_free_strvec(vline);
2267 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2268 && ret != CMD_ERR_NOTHING_TODO)
2274 /* Configration from terminal */
2275 DEFUN(config_terminal,
2276 config_terminal_cmd,
2277 "configure terminal",
2278 "Configuration from vty interface\n" "Configuration terminal\n")
2280 if (vty_config_lock(vty))
2281 vty->node = CONFIG_NODE;
2283 vty_out(vty, "VTY configuration is locked by other VTY%s",
2290 /* Enable command */
2291 DEFUN(enable, config_enable_cmd, "enable", "Turn on privileged mode command\n")
2293 /* If enable password is NULL, change to ENABLE_NODE */
2294 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2295 vty->type == VTY_SHELL_SERV)
2296 vty->node = ENABLE_NODE;
2298 vty->node = AUTH_ENABLE_NODE;
2303 /* Disable command */
2305 config_disable_cmd, "disable", "Turn off privileged mode command\n")
2307 if (vty->node == ENABLE_NODE)
2308 vty->node = VIEW_NODE;
2312 /* Down vty node level. */
2314 config_exit_cmd, "exit", "Exit current mode and down to previous mode\n")
2316 switch (vty->node) {
2318 vty->node = CONFIG_NODE;
2322 vty->node = MS_NODE;
2326 vty->node = GSMNET_NODE;
2328 /* set vty->index correctly ! */
2329 struct gsm_bts *bts = vty->index;
2330 vty->index = bts->network;
2334 vty->node = BTS_NODE;
2336 /* set vty->index correctly ! */
2337 struct gsm_bts_trx *trx = vty->index;
2338 vty->index = trx->bts;
2342 vty->node = TRX_NODE;
2344 /* set vty->index correctly ! */
2345 struct gsm_bts_trx_ts *ts = vty->index;
2346 vty->index = ts->trx;
2350 vty->node = VIEW_NODE;
2351 subscr_put(vty->index);
2357 if (0) //vty_shell (vty))
2360 vty->status = VTY_CLOSE;
2363 vty->node = ENABLE_NODE;
2364 vty_config_unlock(vty);
2367 vty->node = CONFIG_NODE;
2375 /* quit is alias of exit. */
2377 config_quit_cmd, "quit", "Exit current mode and down to previous mode\n")
2379 /* End of configuration. */
2381 config_end_cmd, "end", "End current mode and change to enable mode.")
2383 switch (vty->node) {
2386 /* Nothing to do. */
2392 vty_config_unlock(vty);
2393 vty->node = ENABLE_NODE;
2403 show_version_cmd, "show version", SHOW_STR "Displays program version\n")
2405 vty_out(vty, "%s %s (%s).%s", QUAGGA_PROGNAME, QUAGGA_VERSION,
2406 host.name ? host.name : "", VTY_NEWLINE);
2407 vty_out(vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
2412 /* Help display function for all node. */
2414 config_help_cmd, "help", "Description of the interactive help system\n")
2417 "This VTY provides advanced help features. When you need help,%s\
2418 anytime at the command line please press '?'.%s\
2420 If nothing matches, the help list will be empty and you must backup%s\
2421 until entering a '?' shows the available options.%s\
2422 Two styles of help are provided:%s\
2423 1. Full help is available when you are ready to enter a%s\
2424 command argument (e.g. 'show ?') and describes each possible%s\
2426 2. Partial help is provided when an abbreviated argument is entered%s\
2427 and you want to know what arguments match the input%s\
2428 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2429 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2433 /* Help display function for all node. */
2434 DEFUN(config_list, config_list_cmd, "list", "Print command list\n")
2437 struct cmd_node *cnode = vector_slot(cmdvec, vty->node);
2438 struct cmd_element *cmd;
2440 for (i = 0; i < vector_active(cnode->cmd_vector); i++)
2441 if ((cmd = vector_slot(cnode->cmd_vector, i)) != NULL
2442 && !(cmd->attr == CMD_ATTR_DEPRECATED
2443 || cmd->attr == CMD_ATTR_HIDDEN))
2444 vty_out(vty, " %s%s", cmd->string, VTY_NEWLINE);
2448 /* Write current configuration into file. */
2449 DEFUN(config_write_file,
2450 config_write_file_cmd,
2452 "Write running configuration to memory, network, or terminal\n"
2453 "Write to configuration file\n")
2457 struct cmd_node *node;
2459 char *config_file_tmp = NULL;
2460 char *config_file_sav = NULL;
2461 struct vty *file_vty;
2463 /* Check and see if we are operating under vtysh configuration */
2464 if (host.config == NULL) {
2465 vty_out(vty, "Can't save to configuration file, using vtysh.%s",
2471 config_file = host.config;
2474 _talloc_zero(tall_vty_cmd_ctx,
2475 strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1,
2477 strcpy(config_file_sav, config_file);
2478 strcat(config_file_sav, CONF_BACKUP_EXT);
2480 config_file_tmp = _talloc_zero(tall_vty_cmd_ctx, strlen(config_file) + 8,
2482 sprintf(config_file_tmp, "%s.XXXXXX", config_file);
2484 /* Open file to configuration write. */
2485 fd = OSMOCOM_MKSTEMP(config_file_tmp);
2487 vty_out(vty, "Can't open configuration file %s.%s",
2488 config_file_tmp, VTY_NEWLINE);
2489 talloc_free(config_file_tmp);
2490 talloc_free(config_file_sav);
2494 /* Make vty for configuration file. */
2495 file_vty = vty_new();
2497 file_vty->type = VTY_FILE;
2499 /* Config file header print. */
2500 vty_out(file_vty, "!\n! Osmocom configuration saved from vty\n! ");
2501 //vty_time_print (file_vty, 1);
2502 vty_out(file_vty, "!\n");
2504 for (i = 0; i < vector_active(cmdvec); i++)
2505 if ((node = vector_slot(cmdvec, i)) && node->func) {
2506 if ((*node->func) (file_vty))
2507 vty_out(file_vty, "!\n");
2509 vty_close(file_vty);
2511 if (OSMOCOM_UNLINK(config_file_sav) != 0)
2512 if (errno != ENOENT) {
2514 "Can't unlink backup configuration file %s.%s",
2515 config_file_sav, VTY_NEWLINE);
2516 talloc_free(config_file_sav);
2517 talloc_free(config_file_tmp);
2518 OSMOCOM_UNLINK(config_file_tmp);
2521 if (OSMOCOM_LINK(config_file, config_file_sav) != 0) {
2522 vty_out(vty, "Can't backup old configuration file %s.%s",
2523 config_file_sav, VTY_NEWLINE);
2524 talloc_free(config_file_sav);
2525 talloc_free(config_file_tmp);
2526 OSMOCOM_UNLINK(config_file_tmp);
2530 if (OSMOCOM_UNLINK(config_file) != 0) {
2531 vty_out(vty, "Can't unlink configuration file %s.%s",
2532 config_file, VTY_NEWLINE);
2533 talloc_free(config_file_sav);
2534 talloc_free(config_file_tmp);
2535 OSMOCOM_UNLINK(config_file_tmp);
2538 if (OSMOCOM_LINK(config_file_tmp, config_file) != 0) {
2539 vty_out(vty, "Can't save configuration file %s.%s", config_file,
2541 talloc_free(config_file_sav);
2542 talloc_free(config_file_tmp);
2543 OSMOCOM_UNLINK(config_file_tmp);
2546 OSMOCOM_UNLINK(config_file_tmp);
2549 talloc_free(config_file_sav);
2550 talloc_free(config_file_tmp);
2552 if (OSMOCOM_CHMOD(config_file, 0666 & ~CONFIGFILE_MASK) != 0) {
2553 vty_out(vty, "Can't chmod configuration file %s: %s (%d).%s",
2554 config_file, strerror(errno), errno, VTY_NEWLINE);
2558 vty_out(vty, "Configuration saved to %s%s", config_file, VTY_NEWLINE);
2562 ALIAS(config_write_file,
2564 "write", "Write running configuration to memory, network, or terminal\n")
2566 ALIAS(config_write_file,
2567 config_write_memory_cmd,
2569 "Write running configuration to memory, network, or terminal\n"
2570 "Write configuration to the file (same as write file)\n")
2572 ALIAS(config_write_file,
2573 copy_runningconfig_startupconfig_cmd,
2574 "copy running-config startup-config",
2575 "Copy configuration\n"
2576 "Copy running config to... \n"
2577 "Copy running config to startup config (same as write file)\n")
2579 /* Write current configuration into the terminal. */
2580 DEFUN(config_write_terminal,
2581 config_write_terminal_cmd,
2583 "Write running configuration to memory, network, or terminal\n"
2584 "Write to terminal\n")
2587 struct cmd_node *node;
2589 if (vty->type == VTY_SHELL_SERV) {
2590 for (i = 0; i < vector_active(cmdvec); i++)
2591 if ((node = vector_slot(cmdvec, i)) && node->func
2593 if ((*node->func) (vty))
2594 vty_out(vty, "!%s", VTY_NEWLINE);
2597 vty_out(vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2599 vty_out(vty, "!%s", VTY_NEWLINE);
2601 for (i = 0; i < vector_active(cmdvec); i++)
2602 if ((node = vector_slot(cmdvec, i)) && node->func) {
2603 if ((*node->func) (vty))
2604 vty_out(vty, "!%s", VTY_NEWLINE);
2606 vty_out(vty, "end%s", VTY_NEWLINE);
2611 /* Write current configuration into the terminal. */
2612 ALIAS(config_write_terminal,
2613 show_running_config_cmd,
2614 "show running-config", SHOW_STR "running configuration\n")
2616 /* Write startup configuration into the terminal. */
2617 DEFUN(show_startup_config,
2618 show_startup_config_cmd,
2619 "show startup-config", SHOW_STR "Contentes of startup configuration\n")
2622 OSMOCOM_FILE *confp;
2624 confp = osmocom_fopen(host.config, "r");
2625 if (confp == NULL) {
2626 vty_out(vty, "Can't open configuration file [%s]%s",
2627 host.config, VTY_NEWLINE);
2631 while (osmocom_fgets(buf, BUFSIZ, confp)) {
2634 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2638 vty_out(vty, "%s%s", buf, VTY_NEWLINE);
2641 osmocom_fclose(confp);
2646 /* Hostname configuration */
2647 DEFUN(config_hostname,
2650 "Set system's network name\n" "This system's network name\n")
2652 if (!isalpha((int)*argv[0])) {
2653 vty_out(vty, "Please specify string starting with alphabet%s",
2659 talloc_free(host.name);
2661 host.name = talloc_strdup(tall_vty_cmd_ctx, argv[0]);
2665 DEFUN(config_no_hostname,
2667 "no hostname [HOSTNAME]",
2668 NO_STR "Reset system's network name\n" "Host name of this router\n")
2671 talloc_free(host.name);
2676 /* VTY interface password set. */
2677 DEFUN(config_password, password_cmd,
2678 "password (8|) WORD",
2679 "Assign the terminal connection password\n"
2680 "Specifies a HIDDEN password will follow\n"
2681 "dummy string \n" "The HIDDEN line password string\n")
2683 /* Argument check. */
2685 vty_out(vty, "Please specify password.%s", VTY_NEWLINE);
2690 if (*argv[0] == '8') {
2692 talloc_free(host.password);
2693 host.password = NULL;
2694 if (host.password_encrypt)
2695 talloc_free(host.password_encrypt);
2696 host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, argv[1]);
2699 vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE);
2704 if (!isalnum((int)*argv[0])) {
2706 "Please specify string starting with alphanumeric%s",
2712 talloc_free(host.password);
2713 host.password = NULL;
2717 if (host.password_encrypt)
2718 talloc_free(host.password_encrypt);
2719 host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(argv[0]));
2722 host.password = talloc_strdup(tall_vty_cmd_ctx, argv[0]);
2727 ALIAS(config_password, password_text_cmd,
2729 "Assign the terminal connection password\n"
2730 "The UNENCRYPTED (cleartext) line password\n")
2732 /* VTY enable password set. */
2733 DEFUN(config_enable_password, enable_password_cmd,
2734 "enable password (8|) WORD",
2735 "Modify enable password parameters\n"
2736 "Assign the privileged level password\n"
2737 "Specifies a HIDDEN password will follow\n"
2738 "dummy string \n" "The HIDDEN 'enable' password string\n")
2740 /* Argument check. */
2742 vty_out(vty, "Please specify password.%s", VTY_NEWLINE);
2746 /* Crypt type is specified. */
2748 if (*argv[0] == '8') {
2750 talloc_free(host.enable);
2753 if (host.enable_encrypt)
2754 talloc_free(host.enable_encrypt);
2755 host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, argv[1]);
2759 vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE);
2764 if (!isalnum((int)*argv[0])) {
2766 "Please specify string starting with alphanumeric%s",
2772 talloc_free(host.enable);
2775 /* Plain password input. */
2778 if (host.enable_encrypt)
2779 talloc_free(host.enable_encrypt);
2780 host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(argv[0]));
2783 host.enable = talloc_strdup(tall_vty_cmd_ctx, argv[0]);
2788 ALIAS(config_enable_password,
2789 enable_password_text_cmd,
2790 "enable password LINE",
2791 "Modify enable password parameters\n"
2792 "Assign the privileged level password\n"
2793 "The UNENCRYPTED (cleartext) 'enable' password\n")
2795 /* VTY enable password delete. */
2796 DEFUN(no_config_enable_password, no_enable_password_cmd,
2797 "no enable password",
2799 "Modify enable password parameters\n"
2800 "Assign the privileged level password\n")
2803 talloc_free(host.enable);
2806 if (host.enable_encrypt)
2807 talloc_free(host.enable_encrypt);
2808 host.enable_encrypt = NULL;
2814 DEFUN(service_password_encrypt,
2815 service_password_encrypt_cmd,
2816 "service password-encryption",
2817 "Set up miscellaneous service\n" "Enable encrypted passwords\n")
2824 if (host.password) {
2825 if (host.password_encrypt)
2826 talloc_free(host.password_encrypt);
2827 host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(host.password));
2830 if (host.enable_encrypt)
2831 talloc_free(host.enable_encrypt);
2832 host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(host.enable));
2838 DEFUN(no_service_password_encrypt,
2839 no_service_password_encrypt_cmd,
2840 "no service password-encryption",
2841 NO_STR "Set up miscellaneous service\n" "Enable encrypted passwords\n")
2848 if (host.password_encrypt)
2849 talloc_free(host.password_encrypt);
2850 host.password_encrypt = NULL;
2852 if (host.enable_encrypt)
2853 talloc_free(host.enable_encrypt);
2854 host.enable_encrypt = NULL;
2860 DEFUN(config_terminal_length, config_terminal_length_cmd,
2861 "terminal length <0-512>",
2862 "Set terminal line parameters\n"
2863 "Set number of lines on a screen\n"
2864 "Number of lines on screen (0 for no pausing)\n")
2867 char *endptr = NULL;
2869 lines = strtol(argv[0], &endptr, 10);
2870 if (lines < 0 || lines > 512 || *endptr != '\0') {
2871 vty_out(vty, "length is malformed%s", VTY_NEWLINE);
2879 DEFUN(config_terminal_no_length, config_terminal_no_length_cmd,
2880 "terminal no length",
2881 "Set terminal line parameters\n"
2882 NO_STR "Set number of lines on a screen\n")
2888 DEFUN(service_terminal_length, service_terminal_length_cmd,
2889 "service terminal-length <0-512>",
2890 "Set up miscellaneous service\n"
2891 "System wide terminal length configuration\n"
2892 "Number of lines of VTY (0 means no line control)\n")
2895 char *endptr = NULL;
2897 lines = strtol(argv[0], &endptr, 10);
2898 if (lines < 0 || lines > 512 || *endptr != '\0') {
2899 vty_out(vty, "length is malformed%s", VTY_NEWLINE);
2907 DEFUN(no_service_terminal_length, no_service_terminal_length_cmd,
2908 "no service terminal-length [<0-512>]",
2910 "Set up miscellaneous service\n"
2911 "System wide terminal length configuration\n"
2912 "Number of lines of VTY (0 means no line control)\n")
2918 DEFUN_HIDDEN(do_echo,
2921 "Echo a message back to the vty\n" "The message to echo\n")
2925 vty_out(vty, "%s%s",
2927 argv_concat(argv, argc, 0)) ? message : ""), VTY_NEWLINE);
2929 talloc_free(message);
2934 DEFUN(config_logmsg,
2936 "logmsg " LOG_LEVELS " .MESSAGE",
2937 "Send a message to enabled logging destinations\n"
2938 LOG_LEVEL_DESC "The message to send\n")
2943 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
2944 return CMD_ERR_NO_MATCH;
2947 ((message = argv_concat(argv, argc, 1)) ? message : ""));
2949 talloc_free(message);
2955 "show logging", SHOW_STR "Show current logging configuration\n")
2957 struct zlog *zl = zlog_default;
2959 vty_out(vty, "Syslog logging: ");
2960 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
2961 vty_out(vty, "disabled");
2963 vty_out(vty, "level %s, facility %s, ident %s",
2964 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
2965 facility_name(zl->facility), zl->ident);
2966 vty_out(vty, "%s", VTY_NEWLINE);
2968 vty_out(vty, "Stdout logging: ");
2969 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
2970 vty_out(vty, "disabled");
2972 vty_out(vty, "level %s",
2973 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
2974 vty_out(vty, "%s", VTY_NEWLINE);
2976 vty_out(vty, "Monitor logging: ");
2977 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
2978 vty_out(vty, "disabled");
2980 vty_out(vty, "level %s",
2981 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
2982 vty_out(vty, "%s", VTY_NEWLINE);
2984 vty_out(vty, "File logging: ");
2985 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) || !zl->fp)
2986 vty_out(vty, "disabled");
2988 vty_out(vty, "level %s, filename %s",
2989 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
2991 vty_out(vty, "%s", VTY_NEWLINE);
2993 vty_out(vty, "Protocol name: %s%s",
2994 zlog_proto_names[zl->protocol], VTY_NEWLINE);
2995 vty_out(vty, "Record priority: %s%s",
2996 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
3001 DEFUN(config_log_stdout,
3002 config_log_stdout_cmd,
3003 "log stdout", "Logging control\n" "Set stdout logging level\n")
3005 zlog_set_level(NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3009 DEFUN(config_log_stdout_level,
3010 config_log_stdout_level_cmd,
3011 "log stdout " LOG_LEVELS,
3012 "Logging control\n" "Set stdout logging level\n" LOG_LEVEL_DESC)
3016 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3017 return CMD_ERR_NO_MATCH;
3018 zlog_set_level(NULL, ZLOG_DEST_STDOUT, level);
3022 DEFUN(no_config_log_stdout,
3023 no_config_log_stdout_cmd,
3024 "no log stdout [LEVEL]",
3025 NO_STR "Logging control\n" "Cancel logging to stdout\n" "Logging level\n")
3027 zlog_set_level(NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
3031 DEFUN(config_log_monitor,
3032 config_log_monitor_cmd,
3034 "Logging control\n" "Set terminal line (monitor) logging level\n")
3036 zlog_set_level(NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3040 DEFUN(config_log_monitor_level,
3041 config_log_monitor_level_cmd,
3042 "log monitor " LOG_LEVELS,
3044 "Set terminal line (monitor) logging level\n" LOG_LEVEL_DESC)
3048 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3049 return CMD_ERR_NO_MATCH;
3050 zlog_set_level(NULL, ZLOG_DEST_MONITOR, level);
3054 DEFUN(no_config_log_monitor,
3055 no_config_log_monitor_cmd,
3056 "no log monitor [LEVEL]",
3059 "Disable terminal line (monitor) logging\n" "Logging level\n")
3061 zlog_set_level(NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3065 static int set_log_file(struct vty *vty, const char *fname, int loglevel)
3069 const char *fullpath;
3071 /* Path detection. */
3072 if (!IS_DIRECTORY_SEP(*fname)) {
3073 char cwd[MAXPATHLEN + 1];
3074 cwd[MAXPATHLEN] = '\0';
3076 if (getcwd(cwd, MAXPATHLEN) == NULL) {
3077 zlog_err("config_log_file: Unable to alloc mem!");
3081 if ((p = _talloc_zero(tall_vcmd_ctx,
3082 strlen(cwd) + strlen(fname) + 2),
3085 zlog_err("config_log_file: Unable to alloc mem!");
3088 sprintf(p, "%s/%s", cwd, fname);
3093 ret = zlog_set_file(NULL, fullpath, loglevel);
3099 vty_out(vty, "can't open logfile %s\n", fname);
3104 talloc_free(host.logfile);
3106 host.logfile = talloc_strdup(tall_vty_cmd_ctx, fname);
3111 DEFUN(config_log_file,
3112 config_log_file_cmd,
3113 "log file FILENAME",
3114 "Logging control\n" "Logging to file\n" "Logging filename\n")
3116 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3119 DEFUN(config_log_file_level,
3120 config_log_file_level_cmd,
3121 "log file FILENAME " LOG_LEVELS,
3123 "Logging to file\n" "Logging filename\n" LOG_LEVEL_DESC)
3127 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3128 return CMD_ERR_NO_MATCH;
3129 return set_log_file(vty, argv[0], level);
3132 DEFUN(no_config_log_file,
3133 no_config_log_file_cmd,
3134 "no log file [FILENAME]",
3136 "Logging control\n" "Cancel logging to file\n" "Logging file name\n")
3138 zlog_reset_file(NULL);
3141 talloc_free(host.logfile);
3143 host.logfile = NULL;
3148 ALIAS(no_config_log_file,
3149 no_config_log_file_level_cmd,
3150 "no log file FILENAME LEVEL",
3153 "Cancel logging to file\n" "Logging file name\n" "Logging level\n")
3155 DEFUN(config_log_syslog,
3156 config_log_syslog_cmd,
3157 "log syslog", "Logging control\n" "Set syslog logging level\n")
3159 zlog_set_level(NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3163 DEFUN(config_log_syslog_level,
3164 config_log_syslog_level_cmd,
3165 "log syslog " LOG_LEVELS,
3166 "Logging control\n" "Set syslog logging level\n" LOG_LEVEL_DESC)
3170 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3171 return CMD_ERR_NO_MATCH;
3172 zlog_set_level(NULL, ZLOG_DEST_SYSLOG, level);
3176 DEFUN_DEPRECATED(config_log_syslog_facility,
3177 config_log_syslog_facility_cmd,
3178 "log syslog facility " LOG_FACILITIES,
3180 "Logging goes to syslog\n"
3181 "(Deprecated) Facility parameter for syslog messages\n"
3186 if ((facility = facility_match(argv[0])) < 0)
3187 return CMD_ERR_NO_MATCH;
3189 zlog_set_level(NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3190 zlog_default->facility = facility;
3194 DEFUN(no_config_log_syslog,
3195 no_config_log_syslog_cmd,
3196 "no log syslog [LEVEL]",
3197 NO_STR "Logging control\n" "Cancel logging to syslog\n" "Logging level\n")
3199 zlog_set_level(NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
3203 ALIAS(no_config_log_syslog,
3204 no_config_log_syslog_facility_cmd,
3205 "no log syslog facility " LOG_FACILITIES,
3208 "Logging goes to syslog\n"
3209 "Facility parameter for syslog messages\n" LOG_FACILITY_DESC)
3211 DEFUN(config_log_facility,
3212 config_log_facility_cmd,
3213 "log facility " LOG_FACILITIES,
3215 "Facility parameter for syslog messages\n" LOG_FACILITY_DESC)
3219 if ((facility = facility_match(argv[0])) < 0)
3220 return CMD_ERR_NO_MATCH;
3221 zlog_default->facility = facility;
3225 DEFUN(no_config_log_facility,
3226 no_config_log_facility_cmd,
3227 "no log facility [FACILITY]",
3230 "Reset syslog facility to default (daemon)\n" "Syslog facility\n")
3232 zlog_default->facility = LOG_DAEMON;
3236 DEFUN_DEPRECATED(config_log_trap,
3237 config_log_trap_cmd,
3238 "log trap " LOG_LEVELS,
3240 "(Deprecated) Set logging level and default for all destinations\n"
3246 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3247 return CMD_ERR_NO_MATCH;
3249 zlog_default->default_lvl = new_level;
3250 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3251 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3252 zlog_default->maxlvl[i] = new_level;
3256 DEFUN_DEPRECATED(no_config_log_trap,
3257 no_config_log_trap_cmd,
3258 "no log trap [LEVEL]",
3261 "Permit all logging information\n" "Logging level\n")
3263 zlog_default->default_lvl = LOG_DEBUG;
3267 DEFUN(config_log_record_priority,
3268 config_log_record_priority_cmd,
3269 "log record-priority",
3271 "Log the priority of the message within the message\n")
3273 zlog_default->record_priority = 1;
3277 DEFUN(no_config_log_record_priority,
3278 no_config_log_record_priority_cmd,
3279 "no log record-priority",
3282 "Do not log the priority of the message within the message\n")
3284 zlog_default->record_priority = 0;
3289 DEFUN(banner_motd_file,
3290 banner_motd_file_cmd,
3291 "banner motd file [FILE]",
3292 "Set banner\n" "Banner for motd\n" "Banner from a file\n" "Filename\n")
3295 talloc_free(host.motdfile);
3296 host.motdfile = talloc_strdup(tall_vty_cmd_ctx, argv[0]);
3301 DEFUN(banner_motd_default,
3302 banner_motd_default_cmd,
3303 "banner motd default",
3304 "Set banner string\n" "Strings for motd\n" "Default string\n")
3306 host.motd = default_motd;
3310 DEFUN(no_banner_motd,
3312 "no banner motd", NO_STR "Set banner string\n" "Strings for motd\n")
3316 talloc_free(host.motdfile);
3317 host.motdfile = NULL;
3321 /* Set config filename. Called from vty.c */
3322 void host_config_set(const char *filename)
3324 host.config = talloc_strdup(tall_vty_cmd_ctx, filename);
3327 void install_default(enum node_type node)
3329 install_element(node, &config_exit_cmd);
3330 install_element(node, &config_quit_cmd);
3331 install_element(node, &config_end_cmd);
3332 install_element(node, &config_help_cmd);
3333 install_element(node, &config_list_cmd);
3335 install_element(node, &config_write_terminal_cmd);
3336 install_element(node, &config_write_file_cmd);
3337 install_element(node, &config_write_memory_cmd);
3338 install_element(node, &config_write_cmd);
3339 install_element(node, &show_running_config_cmd);
3342 /* Initialize command interface. Install basic nodes and commands. */
3343 void cmd_init(int terminal)
3345 /* Allocate initial top vector of commands. */
3346 cmdvec = vector_init(VECTOR_MIN_SIZE);
3348 /* Default host value settings. */
3350 host.password = NULL;
3352 host.logfile = NULL;
3355 host.motd = default_motd;
3356 host.motdfile = NULL;
3358 /* Install top nodes. */
3359 install_node(&view_node, NULL);
3360 install_node(&enable_node, NULL);
3361 install_node(&auth_node, NULL);
3362 install_node(&auth_enable_node, NULL);
3363 install_node(&config_node, config_write_host);
3365 /* Each node's basic commands. */
3366 install_element(VIEW_NODE, &show_version_cmd);
3368 install_element(VIEW_NODE, &config_list_cmd);
3369 install_element(VIEW_NODE, &config_exit_cmd);
3370 install_element(VIEW_NODE, &config_quit_cmd);
3371 install_element(VIEW_NODE, &config_help_cmd);
3372 install_element(VIEW_NODE, &config_enable_cmd);
3373 install_element(VIEW_NODE, &config_terminal_length_cmd);
3374 install_element(VIEW_NODE, &config_terminal_no_length_cmd);
3375 install_element(VIEW_NODE, &echo_cmd);
3379 install_default(ENABLE_NODE);
3380 install_element(ENABLE_NODE, &config_disable_cmd);
3381 install_element(ENABLE_NODE, &config_terminal_cmd);
3382 install_element (ENABLE_NODE, ©_runningconfig_startupconfig_cmd);
3384 install_element (ENABLE_NODE, &show_startup_config_cmd);
3385 install_element(ENABLE_NODE, &show_version_cmd);
3388 install_element(ENABLE_NODE, &config_terminal_length_cmd);
3389 install_element(ENABLE_NODE, &config_terminal_no_length_cmd);
3390 install_element(ENABLE_NODE, &echo_cmd);
3392 install_default(CONFIG_NODE);
3395 install_element(CONFIG_NODE, &hostname_cmd);
3396 install_element(CONFIG_NODE, &no_hostname_cmd);
3399 install_element(CONFIG_NODE, &password_cmd);
3400 install_element(CONFIG_NODE, &password_text_cmd);
3401 install_element(CONFIG_NODE, &enable_password_cmd);
3402 install_element(CONFIG_NODE, &enable_password_text_cmd);
3403 install_element(CONFIG_NODE, &no_enable_password_cmd);
3406 install_element(CONFIG_NODE, &service_password_encrypt_cmd);
3407 install_element(CONFIG_NODE, &no_service_password_encrypt_cmd);
3409 install_element(CONFIG_NODE, &banner_motd_default_cmd);
3410 install_element(CONFIG_NODE, &banner_motd_file_cmd);
3411 install_element(CONFIG_NODE, &no_banner_motd_cmd);
3412 install_element(CONFIG_NODE, &service_terminal_length_cmd);
3413 install_element(CONFIG_NODE, &no_service_terminal_length_cmd);
3416 //??? srand(time(NULL));